From 1f804505b07ebcddd4ed809e21b5e3a9f728f715 Mon Sep 17 00:00:00 2001 From: stansmith Date: Mon, 13 Jul 2009 16:44:09 +0000 Subject: [PATCH] git-svn-id: svn://openib.tc.cornell.edu/gen1@2289 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86 --- branches/WOF2-1/WinOF/BuildRelease.bat | 581 + branches/WOF2-1/WinOF/WIX/CustomActions.vbs | 1806 +++ branches/WOF2-1/WinOF/WIX/License.rtf | Bin 0 -> 1644 bytes branches/WOF2-1/WinOF/WIX/README.txt | 165 + branches/WOF2-1/WinOF/WIX/README_checked.txt | 18 + branches/WOF2-1/WinOF/WIX/README_release.txt | 141 + branches/WOF2-1/WinOF/WIX/Release_notes.htm | 1358 ++ .../WinOF/WIX/SDK_Samples/DDK/README.txt | 99 + .../WOF2-1/WinOF/WIX/SDK_Samples/DDK/SOURCES | 21 + .../WinOF/WIX/SDK_Samples/DDK/cmtest.rc | 48 + .../WOF2-1/WinOF/WIX/SDK_Samples/DDK/makefile | 7 + .../WinOF/WIX/SDK_Samples/VS/Makefile.x64 | 97 + .../WinOF/WIX/SDK_Samples/VS/Makefile.x86 | 97 + .../WinOF/WIX/SDK_Samples/VS/README.txt | 111 + .../WOF2-1/WinOF/WIX/SDK_Samples/VS/cmtest.rc | 55 + .../WOF2-1/WinOF/WIX/WIX_tools/README.txt | 23 + branches/WOF2-1/WinOF/WIX/build-OFA-dist.bat | 245 + branches/WOF2-1/WinOF/WIX/build-all-MSI.bat | 141 + .../WOF2-1/WinOF/WIX/common/DAT_config.inc | 149 + branches/WOF2-1/WinOF/WIX/common/Docs.inc | 57 + branches/WOF2-1/WinOF/WIX/common/IBcore.inc | 21 + .../WinOF/WIX/common/InstallExecuteSeq.inc | 69 + .../WinOF/WIX/common/OpenSM_service.inc | 33 + .../WOF2-1/WinOF/WIX/common/WinOF_cfg.inc | 11 + branches/WOF2-1/WinOF/WIX/common/arp.inc | 15 + branches/WOF2-1/WinOF/WIX/common/checked.inc | 180 + branches/WOF2-1/WinOF/WIX/common/dapl_rt.inc | 170 + .../WOF2-1/WinOF/WIX/common/hca_filters.inc | 78 + branches/WOF2-1/WinOF/WIX/common/ib_sdk.inc | 354 + branches/WOF2-1/WinOF/WIX/common/iou.inc | 27 + branches/WOF2-1/WinOF/WIX/common/ipoib.inc | 90 + .../WOF2-1/WinOF/WIX/common/mlnx_drivers.inc | 183 + .../WOF2-1/WinOF/WIX/common/qlgc_vnic.inc | 28 + .../WOF2-1/WinOF/WIX/common/requirements.inc | 57 + branches/WOF2-1/WinOF/WIX/common/srp.inc | 33 + .../WOF2-1/WinOF/WIX/common/std_features.inc | 175 + branches/WOF2-1/WinOF/WIX/common/tools.inc | 54 + .../WOF2-1/WinOF/WIX/common/winverbs_OFED.inc | 314 + .../WinOF/WIX/common/winverbs_drivers.inc | 47 + branches/WOF2-1/WinOF/WIX/dat.conf | 39 + branches/WOF2-1/WinOF/WIX/dpinst.xml | 5 + .../WOF2-1/WinOF/WIX/ia64/Command Window.lnk | Bin 0 -> 1350 bytes branches/WOF2-1/WinOF/WIX/ia64/devman.exe | Bin 0 -> 129536 bytes branches/WOF2-1/WinOF/WIX/openfabrics.gif | Bin 0 -> 3660 bytes branches/WOF2-1/WinOF/WIX/openfabrics.ico | Bin 0 -> 12618 bytes .../WOF2-1/WinOF/WIX/sign-all-drivers.bat | 79 + branches/WOF2-1/WinOF/WIX/win7/build-MSI.bat | 69 + branches/WOF2-1/WinOF/WIX/win7/ia64/Makefile | 57 + branches/WOF2-1/WinOF/WIX/win7/ia64/wof.wxs | 118 + .../WOF2-1/WinOF/WIX/win7/signDrivers.bat | 160 + branches/WOF2-1/WinOF/WIX/win7/x64/Makefile | 57 + branches/WOF2-1/WinOF/WIX/win7/x64/wof.wxs | 128 + branches/WOF2-1/WinOF/WIX/win7/x86/Makefile | 57 + branches/WOF2-1/WinOF/WIX/win7/x86/wof.wxs | 112 + branches/WOF2-1/WinOF/WIX/wlh/build-MSI.bat | 69 + branches/WOF2-1/WinOF/WIX/wlh/ia64/Makefile | 57 + branches/WOF2-1/WinOF/WIX/wlh/ia64/wof.wxs | 119 + branches/WOF2-1/WinOF/WIX/wlh/signDrivers.bat | 159 + branches/WOF2-1/WinOF/WIX/wlh/x64/Makefile | 57 + .../WOF2-1/WinOF/WIX/wlh/x64/cert-add.bat | 127 + .../WOF2-1/WinOF/WIX/wlh/x64/rem-cert-ADD.bat | 40 + branches/WOF2-1/WinOF/WIX/wlh/x64/wof.wxs | 129 + branches/WOF2-1/WinOF/WIX/wlh/x86/Makefile | 57 + branches/WOF2-1/WinOF/WIX/wlh/x86/wof.wxs | 115 + branches/WOF2-1/WinOF/WIX/wnet/build-MSI.bat | 66 + branches/WOF2-1/WinOF/WIX/wnet/ia64/Makefile | 57 + branches/WOF2-1/WinOF/WIX/wnet/ia64/wof.wxs | 118 + .../WOF2-1/WinOF/WIX/wnet/signDrivers.bat | 159 + branches/WOF2-1/WinOF/WIX/wnet/x64/Makefile | 57 + branches/WOF2-1/WinOF/WIX/wnet/x64/wof.wxs | 118 + branches/WOF2-1/WinOF/WIX/wnet/x86/Makefile | 57 + branches/WOF2-1/WinOF/WIX/wnet/x86/wof.wxs | 112 + branches/WOF2-1/WinOF/WIX/wxp/build-MSI.bat | 68 + branches/WOF2-1/WinOF/WIX/wxp/signDrivers.bat | 159 + branches/WOF2-1/WinOF/WIX/wxp/x86/Makefile | 57 + branches/WOF2-1/WinOF/WIX/wxp/x86/wof.wxs | 115 + .../WOF2-1/WinOF/WIX/x64/Command Window.lnk | Bin 0 -> 1350 bytes branches/WOF2-1/WinOF/WIX/x64/devman.exe | Bin 0 -> 80896 bytes .../WOF2-1/WinOF/WIX/x86/Command Window.lnk | Bin 0 -> 1340 bytes branches/WOF2-1/WinOF/WIX/x86/devman.exe | Bin 0 -> 77312 bytes branches/WOF2-1/WinOF/WIX/zip-OFA-dist.bat | 113 + branches/WOF2-1/core/al/al.c | 433 + branches/WOF2-1/core/al/al.h | 294 + branches/WOF2-1/core/al/al_av.c | 345 + branches/WOF2-1/core/al/al_av.h | 91 + branches/WOF2-1/core/al/al_ca.c | 425 + branches/WOF2-1/core/al/al_ca.h | 85 + branches/WOF2-1/core/al/al_ci_ca.h | 228 + branches/WOF2-1/core/al/al_ci_ca_shared.c | 615 + branches/WOF2-1/core/al/al_cm_cep.h | 516 + branches/WOF2-1/core/al/al_cm_conn.h | 1308 ++ branches/WOF2-1/core/al/al_cm_qp.c | 1953 +++ branches/WOF2-1/core/al/al_cm_sidr.h | 173 + branches/WOF2-1/core/al/al_common.c | 693 + branches/WOF2-1/core/al/al_common.h | 338 + branches/WOF2-1/core/al/al_cq.c | 508 + branches/WOF2-1/core/al/al_cq.h | 159 + branches/WOF2-1/core/al/al_debug.h | 262 + branches/WOF2-1/core/al/al_dev.h | 572 + branches/WOF2-1/core/al/al_dm.c | 1800 +++ branches/WOF2-1/core/al/al_dm.h | 125 + branches/WOF2-1/core/al/al_init.c | 173 + branches/WOF2-1/core/al/al_init.h | 92 + branches/WOF2-1/core/al/al_ioc_pnp.h | 53 + branches/WOF2-1/core/al/al_mad.c | 3267 +++++ branches/WOF2-1/core/al/al_mad.h | 237 + branches/WOF2-1/core/al/al_mad_pool.h | 278 + branches/WOF2-1/core/al/al_mcast.c | 691 + branches/WOF2-1/core/al/al_mcast.h | 115 + branches/WOF2-1/core/al/al_mgr.h | 123 + branches/WOF2-1/core/al/al_mgr_shared.c | 676 + branches/WOF2-1/core/al/al_mr.h | 182 + branches/WOF2-1/core/al/al_mr_shared.c | 635 + branches/WOF2-1/core/al/al_mw.c | 260 + branches/WOF2-1/core/al/al_mw.h | 75 + branches/WOF2-1/core/al/al_pd.c | 486 + branches/WOF2-1/core/al/al_pd.h | 81 + branches/WOF2-1/core/al/al_pnp.h | 242 + branches/WOF2-1/core/al/al_proxy.h | 263 + branches/WOF2-1/core/al/al_proxy_ioctl.h | 160 + branches/WOF2-1/core/al/al_proxy_ndi.h | 70 + branches/WOF2-1/core/al/al_qp.c | 2128 +++ branches/WOF2-1/core/al/al_qp.h | 295 + branches/WOF2-1/core/al/al_query.c | 377 + branches/WOF2-1/core/al/al_query.h | 153 + branches/WOF2-1/core/al/al_reg_svc.c | 359 + branches/WOF2-1/core/al/al_reg_svc.h | 65 + branches/WOF2-1/core/al/al_res_mgr.c | 300 + branches/WOF2-1/core/al/al_res_mgr.h | 98 + branches/WOF2-1/core/al/al_srq.c | 439 + branches/WOF2-1/core/al/al_srq.h | 109 + branches/WOF2-1/core/al/al_sub.c | 92 + branches/WOF2-1/core/al/al_verbs.h | 645 + branches/WOF2-1/core/al/dirs | 3 + branches/WOF2-1/core/al/ib_common.c | 134 + branches/WOF2-1/core/al/ib_common.h | 50 + branches/WOF2-1/core/al/ib_statustext.c | 271 + branches/WOF2-1/core/al/kernel/SOURCES | 78 + branches/WOF2-1/core/al/kernel/al_ci_ca.c | 532 + branches/WOF2-1/core/al/kernel/al_cm.c | 362 + branches/WOF2-1/core/al/kernel/al_cm_cep.c | 6696 ++++++++++ branches/WOF2-1/core/al/kernel/al_dev.c | 566 + branches/WOF2-1/core/al/kernel/al_exports.def | 7 + branches/WOF2-1/core/al/kernel/al_fmr_pool.c | 750 ++ branches/WOF2-1/core/al/kernel/al_fmr_pool.h | 117 + branches/WOF2-1/core/al/kernel/al_ioc_pnp.c | 3330 +++++ branches/WOF2-1/core/al/kernel/al_mad_pool.c | 961 ++ branches/WOF2-1/core/al/kernel/al_mgr.c | 626 + branches/WOF2-1/core/al/kernel/al_mr.c | 615 + branches/WOF2-1/core/al/kernel/al_ndi_cm.c | 2014 +++ branches/WOF2-1/core/al/kernel/al_ndi_cm.h | 166 + branches/WOF2-1/core/al/kernel/al_ndi_cq.c | 294 + branches/WOF2-1/core/al/kernel/al_ndi_cq.h | 63 + branches/WOF2-1/core/al/kernel/al_pnp.c | 1813 +++ branches/WOF2-1/core/al/kernel/al_proxy.c | 1284 ++ branches/WOF2-1/core/al/kernel/al_proxy_cep.c | 999 ++ branches/WOF2-1/core/al/kernel/al_proxy_ioc.c | 70 + branches/WOF2-1/core/al/kernel/al_proxy_ndi.c | 814 ++ .../WOF2-1/core/al/kernel/al_proxy_subnet.c | 1162 ++ .../WOF2-1/core/al/kernel/al_proxy_verbs.c | 3916 ++++++ branches/WOF2-1/core/al/kernel/al_sa_req.c | 812 ++ branches/WOF2-1/core/al/kernel/al_smi.c | 3757 ++++++ branches/WOF2-1/core/al/kernel/al_smi.h | 250 + branches/WOF2-1/core/al/kernel/ibal.rc | 47 + branches/WOF2-1/core/al/kernel/makefile | 7 + branches/WOF2-1/core/al/user/SOURCES | 100 + branches/WOF2-1/core/al/user/al_dll.c | 205 + branches/WOF2-1/core/al/user/al_exports.src | 191 + branches/WOF2-1/core/al/user/al_mad_pool.c | 1508 +++ branches/WOF2-1/core/al/user/ibal.rc | 48 + branches/WOF2-1/core/al/user/makefile | 7 + branches/WOF2-1/core/al/user/ual_av.c | 404 + branches/WOF2-1/core/al/user/ual_ca.c | 535 + branches/WOF2-1/core/al/user/ual_ca.h | 59 + branches/WOF2-1/core/al/user/ual_ci_ca.c | 339 + branches/WOF2-1/core/al/user/ual_ci_ca.h | 287 + branches/WOF2-1/core/al/user/ual_cm_cep.c | 1475 +++ branches/WOF2-1/core/al/user/ual_cq.c | 550 + branches/WOF2-1/core/al/user/ual_mad.c | 531 + branches/WOF2-1/core/al/user/ual_mad.h | 97 + branches/WOF2-1/core/al/user/ual_mad_pool.c | 140 + branches/WOF2-1/core/al/user/ual_mcast.c | 174 + branches/WOF2-1/core/al/user/ual_mcast.h | 45 + branches/WOF2-1/core/al/user/ual_mgr.c | 1061 ++ branches/WOF2-1/core/al/user/ual_mgr.h | 143 + branches/WOF2-1/core/al/user/ual_mr.c | 354 + branches/WOF2-1/core/al/user/ual_mw.c | 303 + branches/WOF2-1/core/al/user/ual_pd.c | 170 + branches/WOF2-1/core/al/user/ual_pnp.c | 568 + branches/WOF2-1/core/al/user/ual_qp.c | 673 + branches/WOF2-1/core/al/user/ual_qp.h | 47 + branches/WOF2-1/core/al/user/ual_res_mgr.h | 71 + branches/WOF2-1/core/al/user/ual_sa_req.c | 309 + branches/WOF2-1/core/al/user/ual_srq.c | 439 + branches/WOF2-1/core/al/user/ual_support.h | 123 + branches/WOF2-1/core/bus/dirs | 2 + branches/WOF2-1/core/bus/kernel/SOURCES | 41 + branches/WOF2-1/core/bus/kernel/bus_driver.c | 1083 ++ branches/WOF2-1/core/bus/kernel/bus_driver.h | 303 + branches/WOF2-1/core/bus/kernel/bus_ev_log.mc | 56 + branches/WOF2-1/core/bus/kernel/bus_iou_mgr.c | 1696 +++ branches/WOF2-1/core/bus/kernel/bus_iou_mgr.h | 67 + branches/WOF2-1/core/bus/kernel/bus_pnp.c | 1600 +++ branches/WOF2-1/core/bus/kernel/bus_pnp.h | 84 + .../WOF2-1/core/bus/kernel/bus_port_mgr.c | 2147 +++ .../WOF2-1/core/bus/kernel/bus_port_mgr.h | 68 + branches/WOF2-1/core/bus/kernel/ibbus.rc | 49 + branches/WOF2-1/core/bus/kernel/makefile | 7 + branches/WOF2-1/core/complib/cl_async_proc.c | 160 + branches/WOF2-1/core/complib/cl_list.c | 650 + branches/WOF2-1/core/complib/cl_map.c | 2218 ++++ branches/WOF2-1/core/complib/cl_memory.c | 353 + branches/WOF2-1/core/complib/cl_memtrack.h | 86 + branches/WOF2-1/core/complib/cl_obj.c | 781 ++ branches/WOF2-1/core/complib/cl_perf.c | 269 + branches/WOF2-1/core/complib/cl_pool.c | 708 + branches/WOF2-1/core/complib/cl_ptr_vector.c | 357 + branches/WOF2-1/core/complib/cl_reqmgr.c | 288 + branches/WOF2-1/core/complib/cl_statustext.c | 71 + branches/WOF2-1/core/complib/cl_threadpool.c | 237 + branches/WOF2-1/core/complib/cl_vector.c | 617 + branches/WOF2-1/core/complib/dirs | 3 + branches/WOF2-1/core/complib/kernel/SOURCES | 32 + .../WOF2-1/core/complib/kernel/cl_bus_ifc.c | 86 + .../WOF2-1/core/complib/kernel/cl_driver.c | 81 + .../WOF2-1/core/complib/kernel/cl_event.c | 74 + .../WOF2-1/core/complib/kernel/cl_exports.def | 7 + branches/WOF2-1/core/complib/kernel/cl_log.c | 216 + .../core/complib/kernel/cl_memory_osd.c | 60 + .../WOF2-1/core/complib/kernel/cl_pnp_po.c | 1429 ++ .../core/complib/kernel/cl_syscallback.c | 88 + .../WOF2-1/core/complib/kernel/cl_thread.c | 138 + .../WOF2-1/core/complib/kernel/cl_timer.c | 160 + branches/WOF2-1/core/complib/kernel/makefile | 7 + branches/WOF2-1/core/complib/user/SOURCES | 50 + branches/WOF2-1/core/complib/user/cl_debug.c | 61 + branches/WOF2-1/core/complib/user/cl_dll.c | 89 + branches/WOF2-1/core/complib/user/cl_event.c | 64 + branches/WOF2-1/core/complib/user/cl_log.c | 78 + .../WOF2-1/core/complib/user/cl_memory_osd.c | 54 + .../WOF2-1/core/complib/user/cl_nodenamemap.c | 186 + .../WOF2-1/core/complib/user/cl_syscallback.c | 122 + branches/WOF2-1/core/complib/user/cl_thread.c | 127 + branches/WOF2-1/core/complib/user/cl_timer.c | 195 + branches/WOF2-1/core/complib/user/complib.rc | 48 + branches/WOF2-1/core/complib/user/complib.src | 298 + branches/WOF2-1/core/complib/user/makefile | 7 + branches/WOF2-1/core/dirs | 8 + branches/WOF2-1/core/ibat/dirs | 2 + branches/WOF2-1/core/ibat/user/SOURCES | 9 + branches/WOF2-1/core/ibat/user/ibat.cpp | 377 + branches/WOF2-1/core/ibat/user/makefile | 7 + branches/WOF2-1/core/iou/dirs | 2 + branches/WOF2-1/core/iou/kernel/SOURCES | 52 + branches/WOF2-1/core/iou/kernel/ib_iou.cdf | 8 + branches/WOF2-1/core/iou/kernel/ib_iou.inx | 128 + branches/WOF2-1/core/iou/kernel/ibiou.rc | 47 + branches/WOF2-1/core/iou/kernel/iou_driver.c | 903 ++ branches/WOF2-1/core/iou/kernel/iou_driver.h | 263 + branches/WOF2-1/core/iou/kernel/iou_ioc_mgr.c | 1716 +++ branches/WOF2-1/core/iou/kernel/iou_ioc_mgr.h | 126 + branches/WOF2-1/core/iou/kernel/iou_pnp.c | 637 + branches/WOF2-1/core/iou/kernel/iou_pnp.h | 80 + branches/WOF2-1/core/iou/kernel/makefile | 7 + branches/WOF2-1/core/iou/kernel/makefile.inc | 17 + branches/WOF2-1/core/winmad/dirs | 3 + branches/WOF2-1/core/winmad/kernel/SOURCES | 21 + branches/WOF2-1/core/winmad/kernel/makefile | 7 + .../WOF2-1/core/winmad/kernel/makefile.inc | 9 + branches/WOF2-1/core/winmad/kernel/winmad.inx | 108 + branches/WOF2-1/core/winmad/kernel/winmad.rc | 44 + .../WOF2-1/core/winmad/kernel/wm_driver.c | 415 + .../WOF2-1/core/winmad/kernel/wm_driver.h | 81 + .../WOF2-1/core/winmad/kernel/wm_provider.c | 432 + .../WOF2-1/core/winmad/kernel/wm_provider.h | 82 + branches/WOF2-1/core/winmad/kernel/wm_reg.c | 285 + branches/WOF2-1/core/winmad/kernel/wm_reg.h | 67 + branches/WOF2-1/core/winmad/user/SOURCES | 27 + branches/WOF2-1/core/winmad/user/makefile | 7 + branches/WOF2-1/core/winmad/user/winmad.rc | 46 + .../WOF2-1/core/winmad/user/wm_exports.src | 9 + branches/WOF2-1/core/winmad/user/wm_main.cpp | 56 + branches/WOF2-1/core/winmad/user/wm_memory.h | 47 + .../WOF2-1/core/winmad/user/wm_provider.cpp | 242 + .../WOF2-1/core/winmad/user/wm_provider.h | 118 + branches/WOF2-1/core/winmad/wm_ioctl.h | 118 + branches/WOF2-1/core/winverbs/dirs | 3 + branches/WOF2-1/core/winverbs/kernel/SOURCES | 28 + branches/WOF2-1/core/winverbs/kernel/makefile | 7 + .../WOF2-1/core/winverbs/kernel/makefile.inc | 13 + .../WOF2-1/core/winverbs/kernel/winverbs.cdf | 11 + .../WOF2-1/core/winverbs/kernel/winverbs.inx | 108 + .../WOF2-1/core/winverbs/kernel/winverbs.rc | 44 + branches/WOF2-1/core/winverbs/kernel/wv_cq.c | 335 + branches/WOF2-1/core/winverbs/kernel/wv_cq.h | 72 + .../WOF2-1/core/winverbs/kernel/wv_device.c | 816 ++ .../WOF2-1/core/winverbs/kernel/wv_device.h | 87 + .../WOF2-1/core/winverbs/kernel/wv_driver.c | 593 + .../WOF2-1/core/winverbs/kernel/wv_driver.h | 84 + branches/WOF2-1/core/winverbs/kernel/wv_ep.c | 1297 ++ branches/WOF2-1/core/winverbs/kernel/wv_ep.h | 100 + branches/WOF2-1/core/winverbs/kernel/wv_pd.c | 629 + branches/WOF2-1/core/winverbs/kernel/wv_pd.h | 110 + .../WOF2-1/core/winverbs/kernel/wv_provider.c | 231 + .../WOF2-1/core/winverbs/kernel/wv_provider.h | 83 + branches/WOF2-1/core/winverbs/kernel/wv_qp.c | 763 ++ branches/WOF2-1/core/winverbs/kernel/wv_qp.h | 77 + branches/WOF2-1/core/winverbs/kernel/wv_srq.c | 378 + branches/WOF2-1/core/winverbs/kernel/wv_srq.h | 71 + branches/WOF2-1/core/winverbs/user/SOURCES | 39 + branches/WOF2-1/core/winverbs/user/makefile | 7 + .../WOF2-1/core/winverbs/user/winverbs.rc | 46 + .../WOF2-1/core/winverbs/user/wv_base.cpp | 106 + branches/WOF2-1/core/winverbs/user/wv_base.h | 85 + branches/WOF2-1/core/winverbs/user/wv_cq.cpp | 275 + branches/WOF2-1/core/winverbs/user/wv_cq.h | 103 + .../WOF2-1/core/winverbs/user/wv_device.cpp | 408 + .../WOF2-1/core/winverbs/user/wv_device.h | 111 + branches/WOF2-1/core/winverbs/user/wv_ep.cpp | 588 + branches/WOF2-1/core/winverbs/user/wv_ep.h | 184 + .../WOF2-1/core/winverbs/user/wv_exports.src | 9 + .../WOF2-1/core/winverbs/user/wv_main.cpp | 119 + .../WOF2-1/core/winverbs/user/wv_memory.h | 73 + branches/WOF2-1/core/winverbs/user/wv_pd.cpp | 471 + branches/WOF2-1/core/winverbs/user/wv_pd.h | 219 + .../WOF2-1/core/winverbs/user/wv_provider.cpp | 193 + .../WOF2-1/core/winverbs/user/wv_provider.h | 105 + branches/WOF2-1/core/winverbs/user/wv_qp.cpp | 796 ++ branches/WOF2-1/core/winverbs/user/wv_qp.h | 219 + branches/WOF2-1/core/winverbs/user/wv_srq.cpp | 306 + branches/WOF2-1/core/winverbs/user/wv_srq.h | 102 + .../WOF2-1/core/winverbs/user/wv_uverbs.cpp | 512 + branches/WOF2-1/core/winverbs/wv_ioctl.h | 752 ++ branches/WOF2-1/core/winverbs/wv_public.h | 32 + branches/WOF2-1/dirs | 6 + branches/WOF2-1/docs/Manual.htm | 4058 ++++++ branches/WOF2-1/docs/build.txt | 32 + .../WOF2-1/docs/complib/cl_async_proc_h.html | 309 + branches/WOF2-1/docs/complib/cl_atomic_h.html | 272 + .../WOF2-1/docs/complib/cl_byteswap_h.html | 500 + .../WOF2-1/docs/complib/cl_comppool_h.html | 604 + branches/WOF2-1/docs/complib/cl_debug_h.html | 534 + branches/WOF2-1/docs/complib/cl_event_h.html | 274 + .../WOF2-1/docs/complib/cl_fleximap_h.html | 948 ++ branches/WOF2-1/docs/complib/cl_ioctl_h.html | 609 + .../WOF2-1/docs/complib/cl_irqlock_h.html | 221 + branches/WOF2-1/docs/complib/cl_list_h.html | 1412 ++ branches/WOF2-1/docs/complib/cl_log_h.html | 117 + branches/WOF2-1/docs/complib/cl_map_h.html | 898 ++ branches/WOF2-1/docs/complib/cl_math_h.html | 103 + branches/WOF2-1/docs/complib/cl_memory_h.html | 629 + branches/WOF2-1/docs/complib/cl_mutex_h.html | 207 + branches/WOF2-1/docs/complib/cl_obj_h.html | 997 ++ .../WOF2-1/docs/complib/cl_passivelock_h.html | 417 + branches/WOF2-1/docs/complib/cl_perf_h.html | 583 + branches/WOF2-1/docs/complib/cl_pool_h.html | 581 + .../WOF2-1/docs/complib/cl_ptr_vector_h.html | 890 ++ .../WOF2-1/docs/complib/cl_qcomppool_h.html | 740 ++ branches/WOF2-1/docs/complib/cl_qlist_h.html | 1728 +++ .../WOF2-1/docs/complib/cl_qlockpool_h.html | 340 + branches/WOF2-1/docs/complib/cl_qmap_h.html | 998 ++ branches/WOF2-1/docs/complib/cl_qpool_h.html | 628 + branches/WOF2-1/docs/complib/cl_rbmap_h.html | 563 + branches/WOF2-1/docs/complib/cl_reqmgr_h.html | 463 + .../WOF2-1/docs/complib/cl_spinlock_h.html | 210 + .../WOF2-1/docs/complib/cl_syscallback_h.html | 243 + branches/WOF2-1/docs/complib/cl_thread_h.html | 164 + .../WOF2-1/docs/complib/cl_threadpool_h.html | 273 + branches/WOF2-1/docs/complib/cl_timer_h.html | 432 + branches/WOF2-1/docs/complib/cl_types_h.html | 410 + branches/WOF2-1/docs/complib/cl_vector_h.html | 984 ++ .../WOF2-1/docs/complib/cl_waitobj_h.html | 356 + branches/WOF2-1/docs/complib/comp_lib_h.html | 50 + branches/WOF2-1/docs/dontdiff.txt | 27 + branches/WOF2-1/docs/generate-patch.txt | 18 + branches/WOF2-1/docs/iba/ib_al_h.html | 10482 +++++++++++++++ branches/WOF2-1/docs/iba/ib_types_h.html | 10744 +++++++++++++++ branches/WOF2-1/docs/maintainers.txt | 61 + branches/WOF2-1/docs/masterindex.html | 2741 ++++ branches/WOF2-1/docs/openfabrics.gif | Bin 0 -> 3660 bytes branches/WOF2-1/docs/robo_definitions.html | 655 + branches/WOF2-1/docs/robo_functions.html | 1535 +++ branches/WOF2-1/docs/robo_modules.html | 116 + branches/WOF2-1/docs/robo_sourcefiles.html | 149 + branches/WOF2-1/docs/robo_strutures.html | 381 + branches/WOF2-1/docs/robodoc.css | 36 + branches/WOF2-1/etc/bldwo.bat | 100 + branches/WOF2-1/etc/bldwoall.bat | 19 + branches/WOF2-1/etc/clean-build.bat | 61 + branches/WOF2-1/etc/cpinst.bat | 84 + branches/WOF2-1/etc/kernel/index_list.c | 110 + branches/WOF2-1/etc/kernel/work_queue.c | 146 + branches/WOF2-1/etc/makebin.bat | 875 ++ branches/WOF2-1/etc/user/comp_channel.cpp | 324 + branches/WOF2-1/etc/user/getopt.c | 169 + branches/WOF2-1/etc/user/gtod.c | 138 + branches/WOF2-1/etc/user/inet.c | 216 + branches/WOF2-1/etc/wpp/ALTraceRt.cmd | 14 + branches/WOF2-1/etc/wpp/CreateTrace.cmd | 14 + branches/WOF2-1/etc/wpp/IPoIBTraceRt.cmd | 13 + branches/WOF2-1/etc/wpp/MTHCATraceRt.cmd | 14 + branches/WOF2-1/etc/wpp/SDPTraceRt.cmd | 10 + branches/WOF2-1/etc/wpp/StartSdpTrace.cmd | 7 + branches/WOF2-1/etc/wpp/StartTrace.cmd | 22 + branches/WOF2-1/etc/wpp/StopSdpTrace.cmd | 10 + branches/WOF2-1/etc/wpp/StopTrace.cmd | 8 + branches/WOF2-1/hw/dirs | 3 + branches/WOF2-1/hw/mlx4/dirs | 3 + branches/WOF2-1/hw/mlx4/inc/mx_abi.h | 180 + branches/WOF2-1/hw/mlx4/inc/public.h | 139 + branches/WOF2-1/hw/mlx4/inc/user.h | 94 + .../WOF2-1/hw/mlx4/kernel/bus/core/SOURCES | 51 + .../WOF2-1/hw/mlx4/kernel/bus/core/cache.c | 440 + .../WOF2-1/hw/mlx4/kernel/bus/core/core.def | 64 + .../WOF2-1/hw/mlx4/kernel/bus/core/core.h | 12 + .../WOF2-1/hw/mlx4/kernel/bus/core/core.rc | 48 + .../WOF2-1/hw/mlx4/kernel/bus/core/device.c | 762 ++ .../WOF2-1/hw/mlx4/kernel/bus/core/ev_log.mc | 56 + .../WOF2-1/hw/mlx4/kernel/bus/core/iobuf.c | 552 + branches/WOF2-1/hw/mlx4/kernel/bus/core/l2w.c | 504 + .../hw/mlx4/kernel/bus/core/l2w_debug.c | 234 + .../hw/mlx4/kernel/bus/core/l2w_memory.c | 119 + .../hw/mlx4/kernel/bus/core/l2w_radix.c | 74 + .../WOF2-1/hw/mlx4/kernel/bus/core/l2w_umem.c | 184 + .../WOF2-1/hw/mlx4/kernel/bus/core/makefile | 7 + .../WOF2-1/hw/mlx4/kernel/bus/core/pa_cash.c | 366 + .../WOF2-1/hw/mlx4/kernel/bus/core/pa_cash.h | 51 + .../WOF2-1/hw/mlx4/kernel/bus/core/packer.c | 203 + .../hw/mlx4/kernel/bus/core/ud_header.c | 281 + .../WOF2-1/hw/mlx4/kernel/bus/core/verbs.c | 338 + branches/WOF2-1/hw/mlx4/kernel/bus/dirs | 5 + .../WOF2-1/hw/mlx4/kernel/bus/drv/bus.mof | 27 + branches/WOF2-1/hw/mlx4/kernel/bus/drv/bus.rc | 16 + branches/WOF2-1/hw/mlx4/kernel/bus/drv/drv.c | 1325 ++ branches/WOF2-1/hw/mlx4/kernel/bus/drv/drv.h | 242 + .../WOF2-1/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 | 272 + .../hw/mlx4/kernel/bus/drv/mlx4_bus32.cdf | 9 + branches/WOF2-1/hw/mlx4/kernel/bus/drv/pci.c | 931 ++ branches/WOF2-1/hw/mlx4/kernel/bus/drv/pdo.c | 330 + .../WOF2-1/hw/mlx4/kernel/bus/drv/precomp.h | 15 + .../WOF2-1/hw/mlx4/kernel/bus/drv/sources | 60 + branches/WOF2-1/hw/mlx4/kernel/bus/drv/wmi.c | 240 + .../WOF2-1/hw/mlx4/kernel/bus/drv/wpptrace.h | 116 + branches/WOF2-1/hw/mlx4/kernel/bus/ib/Kconfig | 8 + .../WOF2-1/hw/mlx4/kernel/bus/ib/Makefile.lnx | 3 + branches/WOF2-1/hw/mlx4/kernel/bus/ib/SOURCES | 45 + branches/WOF2-1/hw/mlx4/kernel/bus/ib/ah.c | 139 + branches/WOF2-1/hw/mlx4/kernel/bus/ib/cq.c | 630 + .../WOF2-1/hw/mlx4/kernel/bus/ib/doorbell.c | 217 + branches/WOF2-1/hw/mlx4/kernel/bus/ib/ib.def | 11 + branches/WOF2-1/hw/mlx4/kernel/bus/ib/ib.rc | 47 + branches/WOF2-1/hw/mlx4/kernel/bus/ib/mad.c | 267 + branches/WOF2-1/hw/mlx4/kernel/bus/ib/main.c | 691 + .../WOF2-1/hw/mlx4/kernel/bus/ib/makefile | 7 + .../WOF2-1/hw/mlx4/kernel/bus/ib/mlx4_ib.h | 331 + branches/WOF2-1/hw/mlx4/kernel/bus/ib/mr.c | 288 + branches/WOF2-1/hw/mlx4/kernel/bus/ib/qp.c | 1879 +++ branches/WOF2-1/hw/mlx4/kernel/bus/ib/srq.c | 373 + .../WOF2-1/hw/mlx4/kernel/bus/inc/bus_intf.h | 193 + branches/WOF2-1/hw/mlx4/kernel/bus/inc/cmd.h | 188 + branches/WOF2-1/hw/mlx4/kernel/bus/inc/cq.h | 164 + .../WOF2-1/hw/mlx4/kernel/bus/inc/device.h | 523 + .../WOF2-1/hw/mlx4/kernel/bus/inc/doorbell.h | 83 + .../WOF2-1/hw/mlx4/kernel/bus/inc/driver.h | 59 + branches/WOF2-1/hw/mlx4/kernel/bus/inc/eq.h | 132 + .../WOF2-1/hw/mlx4/kernel/bus/inc/ib_cache.h | 116 + .../WOF2-1/hw/mlx4/kernel/bus/inc/ib_mad.h | 657 + .../WOF2-1/hw/mlx4/kernel/bus/inc/ib_pack.h | 245 + .../WOF2-1/hw/mlx4/kernel/bus/inc/ib_smi.h | 131 + .../WOF2-1/hw/mlx4/kernel/bus/inc/ib_verbs.h | 1876 +++ .../hw/mlx4/kernel/bus/inc/ib_verbs_ex.h | 94 + branches/WOF2-1/hw/mlx4/kernel/bus/inc/qp.h | 309 + branches/WOF2-1/hw/mlx4/kernel/bus/inc/srq.h | 42 + .../hw/mlx4/kernel/bus/net/Makefile.lnx | 4 + .../WOF2-1/hw/mlx4/kernel/bus/net/SOURCES | 54 + .../WOF2-1/hw/mlx4/kernel/bus/net/alloc.c | 448 + .../WOF2-1/hw/mlx4/kernel/bus/net/catas.c | 401 + branches/WOF2-1/hw/mlx4/kernel/bus/net/cmd.c | 595 + branches/WOF2-1/hw/mlx4/kernel/bus/net/cq.c | 289 + branches/WOF2-1/hw/mlx4/kernel/bus/net/eq.c | 989 ++ branches/WOF2-1/hw/mlx4/kernel/bus/net/fw.c | 899 ++ branches/WOF2-1/hw/mlx4/kernel/bus/net/fw.h | 172 + branches/WOF2-1/hw/mlx4/kernel/bus/net/icm.c | 460 + branches/WOF2-1/hw/mlx4/kernel/bus/net/icm.h | 132 + branches/WOF2-1/hw/mlx4/kernel/bus/net/intf.c | 186 + branches/WOF2-1/hw/mlx4/kernel/bus/net/main.c | 1099 ++ .../WOF2-1/hw/mlx4/kernel/bus/net/makefile | 7 + branches/WOF2-1/hw/mlx4/kernel/bus/net/mcg.c | 380 + branches/WOF2-1/hw/mlx4/kernel/bus/net/mlx4.h | 451 + branches/WOF2-1/hw/mlx4/kernel/bus/net/mr.c | 655 + .../WOF2-1/hw/mlx4/kernel/bus/net/net.def | 24 + branches/WOF2-1/hw/mlx4/kernel/bus/net/net.rc | 47 + branches/WOF2-1/hw/mlx4/kernel/bus/net/pd.c | 104 + branches/WOF2-1/hw/mlx4/kernel/bus/net/port.c | 293 + .../WOF2-1/hw/mlx4/kernel/bus/net/profile.c | 236 + branches/WOF2-1/hw/mlx4/kernel/bus/net/qp.c | 416 + .../WOF2-1/hw/mlx4/kernel/bus/net/reset.c | 0 branches/WOF2-1/hw/mlx4/kernel/bus/net/srq.c | 277 + branches/WOF2-1/hw/mlx4/kernel/dirs | 3 + branches/WOF2-1/hw/mlx4/kernel/hca/Makefile | 6 + branches/WOF2-1/hw/mlx4/kernel/hca/SOURCES | 63 + branches/WOF2-1/hw/mlx4/kernel/hca/av.c | 233 + branches/WOF2-1/hw/mlx4/kernel/hca/ca.c | 458 + branches/WOF2-1/hw/mlx4/kernel/hca/cq.c | 211 + branches/WOF2-1/hw/mlx4/kernel/hca/data.c | 1006 ++ branches/WOF2-1/hw/mlx4/kernel/hca/data.h | 338 + branches/WOF2-1/hw/mlx4/kernel/hca/debug.h | 132 + branches/WOF2-1/hw/mlx4/kernel/hca/direct.c | 285 + branches/WOF2-1/hw/mlx4/kernel/hca/drv.c | 1992 +++ branches/WOF2-1/hw/mlx4/kernel/hca/drv.h | 372 + branches/WOF2-1/hw/mlx4/kernel/hca/fw.c | 494 + branches/WOF2-1/hw/mlx4/kernel/hca/hca.mof | 59 + branches/WOF2-1/hw/mlx4/kernel/hca/hca.rc | 44 + branches/WOF2-1/hw/mlx4/kernel/hca/hverbs.c | 673 + branches/WOF2-1/hw/mlx4/kernel/hca/hverbs.h | 72 + .../WOF2-1/hw/mlx4/kernel/hca/makefile.inc | 24 + branches/WOF2-1/hw/mlx4/kernel/hca/mcast.c | 197 + .../WOF2-1/hw/mlx4/kernel/hca/mlx4_hca.cdf | 28 + .../WOF2-1/hw/mlx4/kernel/hca/mlx4_hca.inx | 470 + .../WOF2-1/hw/mlx4/kernel/hca/mlx4_hca32.cdf | 22 + branches/WOF2-1/hw/mlx4/kernel/hca/mr.c | 588 + branches/WOF2-1/hw/mlx4/kernel/hca/pd.c | 174 + branches/WOF2-1/hw/mlx4/kernel/hca/precomp.h | 48 + branches/WOF2-1/hw/mlx4/kernel/hca/qp.c | 398 + branches/WOF2-1/hw/mlx4/kernel/hca/srq.c | 183 + branches/WOF2-1/hw/mlx4/kernel/hca/vp.c | 326 + branches/WOF2-1/hw/mlx4/kernel/hca/wmi.c | 257 + branches/WOF2-1/hw/mlx4/kernel/inc/iobuf.h | 53 + branches/WOF2-1/hw/mlx4/kernel/inc/l2w.h | 350 + .../WOF2-1/hw/mlx4/kernel/inc/l2w_atomic.h | 47 + branches/WOF2-1/hw/mlx4/kernel/inc/l2w_bit.h | 192 + .../WOF2-1/hw/mlx4/kernel/inc/l2w_bitmap.h | 79 + .../WOF2-1/hw/mlx4/kernel/inc/l2w_debug.h | 45 + branches/WOF2-1/hw/mlx4/kernel/inc/l2w_list.h | 99 + .../WOF2-1/hw/mlx4/kernel/inc/l2w_memory.h | 334 + branches/WOF2-1/hw/mlx4/kernel/inc/l2w_pci.h | 112 + .../WOF2-1/hw/mlx4/kernel/inc/l2w_pcipool.h | 102 + .../WOF2-1/hw/mlx4/kernel/inc/l2w_radix.h | 25 + .../WOF2-1/hw/mlx4/kernel/inc/l2w_spinlock.h | 148 + branches/WOF2-1/hw/mlx4/kernel/inc/l2w_sync.h | 165 + branches/WOF2-1/hw/mlx4/kernel/inc/l2w_time.h | 17 + branches/WOF2-1/hw/mlx4/kernel/inc/l2w_umem.h | 34 + .../WOF2-1/hw/mlx4/kernel/inc/mlx4_debug.h | 200 + branches/WOF2-1/hw/mlx4/kernel/inc/shutter.h | 119 + branches/WOF2-1/hw/mlx4/kernel/inc/vc.h | 94 + branches/WOF2-1/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-1/hw/mlx4/todo.txt | 116 + branches/WOF2-1/hw/mlx4/user/dirs | 2 + branches/WOF2-1/hw/mlx4/user/hca/Makefile | 7 + branches/WOF2-1/hw/mlx4/user/hca/SOURCES | 70 + branches/WOF2-1/hw/mlx4/user/hca/buf.c | 47 + branches/WOF2-1/hw/mlx4/user/hca/cq.c | 529 + branches/WOF2-1/hw/mlx4/user/hca/dbrec.c | 147 + branches/WOF2-1/hw/mlx4/user/hca/doorbell.h | 55 + branches/WOF2-1/hw/mlx4/user/hca/l2w.h | 183 + branches/WOF2-1/hw/mlx4/user/hca/mlx4.c | 325 + branches/WOF2-1/hw/mlx4/user/hca/mlx4.def | 11 + branches/WOF2-1/hw/mlx4/user/hca/mlx4.h | 350 + branches/WOF2-1/hw/mlx4/user/hca/mlx4_debug.c | 88 + branches/WOF2-1/hw/mlx4/user/hca/mlx4_debug.h | 144 + branches/WOF2-1/hw/mlx4/user/hca/mlx4u.rc | 48 + branches/WOF2-1/hw/mlx4/user/hca/qp.c | 780 ++ branches/WOF2-1/hw/mlx4/user/hca/srq.c | 212 + branches/WOF2-1/hw/mlx4/user/hca/verbs.c | 1470 +++ branches/WOF2-1/hw/mlx4/user/hca/verbs.h | 436 + branches/WOF2-1/hw/mlx4/user/hca/wqe.h | 120 + branches/WOF2-1/hw/mthca/dirs | 3 + branches/WOF2-1/hw/mthca/hca_utils.c | 79 + branches/WOF2-1/hw/mthca/hca_utils.h | 49 + branches/WOF2-1/hw/mthca/kernel/Makefile | 6 + branches/WOF2-1/hw/mthca/kernel/SOURCES | 94 + branches/WOF2-1/hw/mthca/kernel/hca.rc | 45 + branches/WOF2-1/hw/mthca/kernel/hca_data.c | 964 ++ branches/WOF2-1/hw/mthca/kernel/hca_data.h | 395 + branches/WOF2-1/hw/mthca/kernel/hca_debug.h | 194 + branches/WOF2-1/hw/mthca/kernel/hca_direct.c | 308 + branches/WOF2-1/hw/mthca/kernel/hca_driver.c | 1049 ++ branches/WOF2-1/hw/mthca/kernel/hca_driver.h | 238 + branches/WOF2-1/hw/mthca/kernel/hca_mcast.c | 202 + branches/WOF2-1/hw/mthca/kernel/hca_memory.c | 601 + branches/WOF2-1/hw/mthca/kernel/hca_pci.c | 762 ++ branches/WOF2-1/hw/mthca/kernel/hca_pci.h | 24 + branches/WOF2-1/hw/mthca/kernel/hca_pnp.c | 1386 ++ branches/WOF2-1/hw/mthca/kernel/hca_pnp.h | 46 + branches/WOF2-1/hw/mthca/kernel/hca_verbs.c | 1720 +++ branches/WOF2-1/hw/mthca/kernel/ib_cache.h | 109 + branches/WOF2-1/hw/mthca/kernel/ib_mad.h | 579 + branches/WOF2-1/hw/mthca/kernel/ib_pack.h | 245 + branches/WOF2-1/hw/mthca/kernel/ib_smi.h | 95 + branches/WOF2-1/hw/mthca/kernel/ib_verbs.h | 1335 ++ branches/WOF2-1/hw/mthca/kernel/makefile.inc | 17 + branches/WOF2-1/hw/mthca/kernel/mt_atomic.h | 81 + branches/WOF2-1/hw/mthca/kernel/mt_bitmap.h | 74 + branches/WOF2-1/hw/mthca/kernel/mt_cache.c | 402 + branches/WOF2-1/hw/mthca/kernel/mt_device.c | 569 + branches/WOF2-1/hw/mthca/kernel/mt_l2w.c | 133 + branches/WOF2-1/hw/mthca/kernel/mt_l2w.h | 92 + branches/WOF2-1/hw/mthca/kernel/mt_list.h | 63 + branches/WOF2-1/hw/mthca/kernel/mt_memory.c | 762 ++ branches/WOF2-1/hw/mthca/kernel/mt_memory.h | 309 + branches/WOF2-1/hw/mthca/kernel/mt_pa_cash.c | 364 + branches/WOF2-1/hw/mthca/kernel/mt_pa_cash.h | 51 + branches/WOF2-1/hw/mthca/kernel/mt_packer.c | 205 + branches/WOF2-1/hw/mthca/kernel/mt_pci.h | 131 + branches/WOF2-1/hw/mthca/kernel/mt_pcipool.h | 103 + .../WOF2-1/hw/mthca/kernel/mt_reset_tavor.c | 485 + branches/WOF2-1/hw/mthca/kernel/mt_spinlock.h | 143 + branches/WOF2-1/hw/mthca/kernel/mt_sync.h | 109 + branches/WOF2-1/hw/mthca/kernel/mt_types.h | 60 + .../WOF2-1/hw/mthca/kernel/mt_ud_header.c | 280 + branches/WOF2-1/hw/mthca/kernel/mt_uverbs.c | 101 + branches/WOF2-1/hw/mthca/kernel/mt_verbs.c | 933 ++ branches/WOF2-1/hw/mthca/kernel/mthca.cdf | 29 + branches/WOF2-1/hw/mthca/kernel/mthca.h | 9 + branches/WOF2-1/hw/mthca/kernel/mthca.inx | 479 + branches/WOF2-1/hw/mthca/kernel/mthca32.cdf | 22 + .../WOF2-1/hw/mthca/kernel/mthca_allocator.c | 294 + branches/WOF2-1/hw/mthca/kernel/mthca_av.c | 293 + branches/WOF2-1/hw/mthca/kernel/mthca_catas.c | 166 + branches/WOF2-1/hw/mthca/kernel/mthca_cmd.c | 1844 +++ branches/WOF2-1/hw/mthca/kernel/mthca_cmd.h | 327 + .../WOF2-1/hw/mthca/kernel/mthca_config_reg.h | 50 + branches/WOF2-1/hw/mthca/kernel/mthca_cq.c | 989 ++ branches/WOF2-1/hw/mthca/kernel/mthca_dev.h | 618 + .../WOF2-1/hw/mthca/kernel/mthca_doorbell.h | 106 + branches/WOF2-1/hw/mthca/kernel/mthca_eq.c | 1249 ++ branches/WOF2-1/hw/mthca/kernel/mthca_log.c | 242 + branches/WOF2-1/hw/mthca/kernel/mthca_log.mc | 56 + branches/WOF2-1/hw/mthca/kernel/mthca_mad.c | 286 + branches/WOF2-1/hw/mthca/kernel/mthca_main.c | 1129 ++ branches/WOF2-1/hw/mthca/kernel/mthca_mcg.c | 403 + .../WOF2-1/hw/mthca/kernel/mthca_memfree.c | 729 + .../WOF2-1/hw/mthca/kernel/mthca_memfree.h | 177 + branches/WOF2-1/hw/mthca/kernel/mthca_mr.c | 976 ++ branches/WOF2-1/hw/mthca/kernel/mthca_pd.c | 83 + .../WOF2-1/hw/mthca/kernel/mthca_profile.c | 290 + .../WOF2-1/hw/mthca/kernel/mthca_profile.h | 61 + .../WOF2-1/hw/mthca/kernel/mthca_provider.c | 1340 ++ .../WOF2-1/hw/mthca/kernel/mthca_provider.h | 401 + branches/WOF2-1/hw/mthca/kernel/mthca_qp.c | 2542 ++++ branches/WOF2-1/hw/mthca/kernel/mthca_srq.c | 743 ++ branches/WOF2-1/hw/mthca/kernel/mthca_uar.c | 78 + branches/WOF2-1/hw/mthca/mt_utils.c | 50 + branches/WOF2-1/hw/mthca/mt_utils.h | 225 + branches/WOF2-1/hw/mthca/mthca_wqe.h | 139 + branches/WOF2-1/hw/mthca/mx_abi.h | 178 + branches/WOF2-1/hw/mthca/user/Makefile | 7 + branches/WOF2-1/hw/mthca/user/SOURCES | 87 + branches/WOF2-1/hw/mthca/user/arch.h | 53 + branches/WOF2-1/hw/mthca/user/mlnx_ual_av.c | 362 + branches/WOF2-1/hw/mthca/user/mlnx_ual_ca.c | 203 + branches/WOF2-1/hw/mthca/user/mlnx_ual_cq.c | 220 + branches/WOF2-1/hw/mthca/user/mlnx_ual_data.h | 52 + branches/WOF2-1/hw/mthca/user/mlnx_ual_main.c | 164 + branches/WOF2-1/hw/mthca/user/mlnx_ual_main.h | 134 + .../WOF2-1/hw/mthca/user/mlnx_ual_mcast.c | 122 + branches/WOF2-1/hw/mthca/user/mlnx_ual_mrw.c | 232 + .../WOF2-1/hw/mthca/user/mlnx_ual_osbypass.c | 254 + branches/WOF2-1/hw/mthca/user/mlnx_ual_pd.c | 182 + branches/WOF2-1/hw/mthca/user/mlnx_ual_qp.c | 386 + branches/WOF2-1/hw/mthca/user/mlnx_ual_srq.c | 262 + branches/WOF2-1/hw/mthca/user/mlnx_uvp.c | 238 + branches/WOF2-1/hw/mthca/user/mlnx_uvp.def | 10 + branches/WOF2-1/hw/mthca/user/mlnx_uvp.h | 338 + branches/WOF2-1/hw/mthca/user/mlnx_uvp.rc | 48 + branches/WOF2-1/hw/mthca/user/mlnx_uvp_ah.c | 190 + branches/WOF2-1/hw/mthca/user/mlnx_uvp_cq.c | 628 + .../WOF2-1/hw/mthca/user/mlnx_uvp_debug.c | 85 + .../WOF2-1/hw/mthca/user/mlnx_uvp_debug.h | 145 + .../WOF2-1/hw/mthca/user/mlnx_uvp_doorbell.h | 80 + .../WOF2-1/hw/mthca/user/mlnx_uvp_memfree.c | 207 + branches/WOF2-1/hw/mthca/user/mlnx_uvp_qp.c | 1088 ++ branches/WOF2-1/hw/mthca/user/mlnx_uvp_srq.c | 326 + .../WOF2-1/hw/mthca/user/mlnx_uvp_verbs.c | 512 + .../WOF2-1/hw/mthca/user/mlnx_uvp_verbs.h | 491 + branches/WOF2-1/hw/mthca/user/mt_l2w.h | 104 + branches/WOF2-1/hw/mthca/user/opcode.h | 149 + branches/WOF2-1/inc/complib/cl_async_proc.h | 342 + branches/WOF2-1/inc/complib/cl_atomic.h | 297 + branches/WOF2-1/inc/complib/cl_byteswap.h | 539 + branches/WOF2-1/inc/complib/cl_comppool.h | 619 + branches/WOF2-1/inc/complib/cl_debug.h | 599 + branches/WOF2-1/inc/complib/cl_event.h | 304 + branches/WOF2-1/inc/complib/cl_fleximap.h | 929 ++ branches/WOF2-1/inc/complib/cl_ioctl.h | 626 + branches/WOF2-1/inc/complib/cl_irqlock.h | 248 + branches/WOF2-1/inc/complib/cl_list.h | 1364 ++ branches/WOF2-1/inc/complib/cl_log.h | 245 + branches/WOF2-1/inc/complib/cl_map.h | 875 ++ branches/WOF2-1/inc/complib/cl_math.h | 138 + branches/WOF2-1/inc/complib/cl_memory.h | 963 ++ branches/WOF2-1/inc/complib/cl_mutex.h | 235 + branches/WOF2-1/inc/complib/cl_nodenamemap.h | 73 + branches/WOF2-1/inc/complib/cl_obj.h | 998 ++ branches/WOF2-1/inc/complib/cl_passivelock.h | 433 + branches/WOF2-1/inc/complib/cl_perf.h | 807 ++ branches/WOF2-1/inc/complib/cl_pool.h | 594 + branches/WOF2-1/inc/complib/cl_ptr_vector.h | 878 ++ branches/WOF2-1/inc/complib/cl_qcomppool.h | 785 ++ branches/WOF2-1/inc/complib/cl_qlist.h | 1756 +++ branches/WOF2-1/inc/complib/cl_qlockpool.h | 369 + branches/WOF2-1/inc/complib/cl_qmap.h | 973 ++ branches/WOF2-1/inc/complib/cl_qpool.h | 639 + branches/WOF2-1/inc/complib/cl_rbmap.h | 593 + branches/WOF2-1/inc/complib/cl_reqmgr.h | 481 + branches/WOF2-1/inc/complib/cl_spinlock.h | 238 + branches/WOF2-1/inc/complib/cl_syscallback.h | 368 + branches/WOF2-1/inc/complib/cl_thread.h | 396 + branches/WOF2-1/inc/complib/cl_threadpool.h | 304 + branches/WOF2-1/inc/complib/cl_timer.h | 446 + branches/WOF2-1/inc/complib/cl_types.h | 509 + branches/WOF2-1/inc/complib/cl_vector.h | 1004 ++ branches/WOF2-1/inc/complib/cl_waitobj.h | 377 + branches/WOF2-1/inc/complib/comp_lib.h | 115 + branches/WOF2-1/inc/iba/ib_al.h | 10095 ++++++++++++++ branches/WOF2-1/inc/iba/ib_al_ioctl.h | 3636 +++++ branches/WOF2-1/inc/iba/ib_at_ioctl.h | 171 + branches/WOF2-1/inc/iba/ib_ci.h | 3023 +++++ branches/WOF2-1/inc/iba/ib_types.h | 11021 ++++++++++++++++ .../WOF2-1/inc/kernel/complib/cl_atomic_osd.h | 107 + .../WOF2-1/inc/kernel/complib/cl_bus_ifc.h | 75 + .../inc/kernel/complib/cl_byteswap_osd.h | 67 + .../WOF2-1/inc/kernel/complib/cl_debug_osd.h | 122 + .../WOF2-1/inc/kernel/complib/cl_event_osd.h | 119 + branches/WOF2-1/inc/kernel/complib/cl_init.h | 59 + .../WOF2-1/inc/kernel/complib/cl_ioctl_osd.h | 203 + .../inc/kernel/complib/cl_irqlock_osd.h | 128 + .../WOF2-1/inc/kernel/complib/cl_memory_osd.h | 216 + .../WOF2-1/inc/kernel/complib/cl_mutex_osd.h | 106 + .../WOF2-1/inc/kernel/complib/cl_packoff.h | 36 + .../WOF2-1/inc/kernel/complib/cl_packon.h | 51 + .../WOF2-1/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-1/inc/kernel/complib/cl_thread_osd.h | 89 + .../WOF2-1/inc/kernel/complib/cl_timer_osd.h | 102 + .../WOF2-1/inc/kernel/complib/cl_types_osd.h | 154 + .../inc/kernel/complib/cl_waitobj_osd.h | 107 + branches/WOF2-1/inc/kernel/iba/ib_al_ifc.h | 774 ++ branches/WOF2-1/inc/kernel/iba/ib_ci_ifc.h | 136 + branches/WOF2-1/inc/kernel/iba/ib_cm_ifc.h | 296 + branches/WOF2-1/inc/kernel/iba/ib_rdma_cm.h | 65 + branches/WOF2-1/inc/kernel/iba/ioc_ifc.h | 96 + branches/WOF2-1/inc/kernel/iba/iou_ifc.h | 103 + branches/WOF2-1/inc/kernel/iba/ipoib_ifc.h | 112 + branches/WOF2-1/inc/kernel/index_list.h | 88 + branches/WOF2-1/inc/kernel/ip_packet.h | 535 + branches/WOF2-1/inc/kernel/rdma/verbs.h | 63 + branches/WOF2-1/inc/kernel/work_queue.h | 71 + branches/WOF2-1/inc/mod_ver.def | 20 + branches/WOF2-1/inc/mthca/mthca_vc.h | 101 + branches/WOF2-1/inc/oib_ver.h | 70 + branches/WOF2-1/inc/openib.def | 31 + branches/WOF2-1/inc/user/comp_channel.h | 98 + .../WOF2-1/inc/user/complib/cl_atomic_osd.h | 107 + .../WOF2-1/inc/user/complib/cl_byteswap_osd.h | 68 + .../WOF2-1/inc/user/complib/cl_debug_osd.h | 87 + .../WOF2-1/inc/user/complib/cl_event_osd.h | 120 + .../WOF2-1/inc/user/complib/cl_ioctl_osd.h | 118 + .../WOF2-1/inc/user/complib/cl_memory_osd.h | 101 + .../WOF2-1/inc/user/complib/cl_mutex_osd.h | 106 + branches/WOF2-1/inc/user/complib/cl_packoff.h | 36 + branches/WOF2-1/inc/user/complib/cl_packon.h | 51 + .../WOF2-1/inc/user/complib/cl_spinlock_osd.h | 127 + .../inc/user/complib/cl_syscallback_osd.h | 51 + .../WOF2-1/inc/user/complib/cl_thread_osd.h | 91 + .../WOF2-1/inc/user/complib/cl_timer_osd.h | 54 + .../WOF2-1/inc/user/complib/cl_types_osd.h | 157 + .../WOF2-1/inc/user/complib/cl_waitobj_osd.h | 120 + branches/WOF2-1/inc/user/dlist.h | 81 + branches/WOF2-1/inc/user/getopt.h | 67 + branches/WOF2-1/inc/user/iba/ib_uvp.h | 3492 +++++ branches/WOF2-1/inc/user/iba/ibat.h | 67 + branches/WOF2-1/inc/user/iba/winmad.h | 159 + branches/WOF2-1/inc/user/linux/_string.h | 45 + branches/WOF2-1/inc/user/linux/arpa/inet.h | 52 + branches/WOF2-1/inc/user/linux/inttypes.h | 37 + branches/WOF2-1/inc/user/linux/netinet/in.h | 42 + branches/WOF2-1/inc/user/linux/sys/time.h | 41 + branches/WOF2-1/inc/user/linux/unistd.h | 55 + branches/WOF2-1/inc/user/rdma/winverbs.h | 1530 +++ branches/WOF2-1/inc/user/rdma/wvstatus.h | 133 + branches/WOF2-1/inc/user/wsd/ibsp_regpath.h | 66 + branches/WOF2-1/tests/alts/allocdeallocpd.c | 116 + branches/WOF2-1/tests/alts/alts_common.h | 299 + branches/WOF2-1/tests/alts/alts_debug.h | 79 + branches/WOF2-1/tests/alts/alts_misc.c | 255 + branches/WOF2-1/tests/alts/alts_readme.txt | 119 + branches/WOF2-1/tests/alts/cmtests.c | 4258 ++++++ .../WOF2-1/tests/alts/createanddestroycq.c | 333 + .../WOF2-1/tests/alts/createanddestroyqp.c | 285 + branches/WOF2-1/tests/alts/createdestroyav.c | 334 + branches/WOF2-1/tests/alts/creatememwindow.c | 241 + branches/WOF2-1/tests/alts/dirs | 3 + branches/WOF2-1/tests/alts/ibquery.c | 583 + branches/WOF2-1/tests/alts/kernel/SOURCES | 38 + branches/WOF2-1/tests/alts/kernel/alts.inf | 169 + branches/WOF2-1/tests/alts/kernel/alts.rc | 47 + .../WOF2-1/tests/alts/kernel/alts_driver.c | 346 + .../WOF2-1/tests/alts/kernel/alts_driver.h | 23 + branches/WOF2-1/tests/alts/kernel/makefile | 7 + branches/WOF2-1/tests/alts/madtests.c | 3035 +++++ branches/WOF2-1/tests/alts/multisendrecv.c | 2369 ++++ branches/WOF2-1/tests/alts/openclose.c | 81 + branches/WOF2-1/tests/alts/querycaattr.c | 271 + .../WOF2-1/tests/alts/registermemregion.c | 724 + branches/WOF2-1/tests/alts/registerpnp.c | 208 + branches/WOF2-1/tests/alts/smatests.c | 439 + branches/WOF2-1/tests/alts/user/SOURCES | 35 + branches/WOF2-1/tests/alts/user/alts_main.c | 504 + branches/WOF2-1/tests/alts/user/makefile | 7 + branches/WOF2-1/tests/cmtest/dirs | 2 + branches/WOF2-1/tests/cmtest/user/SOURCES | 20 + branches/WOF2-1/tests/cmtest/user/cmtest.rc | 48 + .../WOF2-1/tests/cmtest/user/cmtest_main.c | 2036 +++ branches/WOF2-1/tests/cmtest/user/makefile | 7 + branches/WOF2-1/tests/dirs | 8 + branches/WOF2-1/tests/ibat/dirs | 2 + branches/WOF2-1/tests/ibat/user/PrintIp.c | 254 + branches/WOF2-1/tests/ibat/user/SOURCES | 18 + branches/WOF2-1/tests/ibat/user/makefile | 7 + branches/WOF2-1/tests/limits/dirs | 2 + branches/WOF2-1/tests/limits/user/SOURCES | 20 + .../WOF2-1/tests/limits/user/limits_main.c | 530 + branches/WOF2-1/tests/limits/user/makefile | 7 + branches/WOF2-1/tests/perftest/dirs | 9 + branches/WOF2-1/tests/perftest/perftest.c | 174 + branches/WOF2-1/tests/perftest/perftest.h | 50 + .../WOF2-1/tests/perftest/rdma_bw/SOURCES | 32 + .../WOF2-1/tests/perftest/rdma_bw/makefile | 7 + .../WOF2-1/tests/perftest/rdma_bw/rdma_bw.c | 1126 ++ .../WOF2-1/tests/perftest/rdma_bw/rdma_bw.rc | 47 + .../WOF2-1/tests/perftest/rdma_lat/SOURCES | 32 + .../WOF2-1/tests/perftest/rdma_lat/makefile | 7 + .../WOF2-1/tests/perftest/rdma_lat/rdma_lat.c | 1147 ++ .../tests/perftest/rdma_lat/rdma_lat.rc | 47 + .../WOF2-1/tests/perftest/read_bw/SOURCES | 29 + .../WOF2-1/tests/perftest/read_bw/makefile | 7 + .../WOF2-1/tests/perftest/read_bw/read_bw.c | 754 ++ .../WOF2-1/tests/perftest/read_bw/read_bw.rc | 47 + .../WOF2-1/tests/perftest/read_lat/SOURCES | 29 + .../WOF2-1/tests/perftest/read_lat/makefile | 7 + .../WOF2-1/tests/perftest/read_lat/read_lat.c | 808 ++ .../tests/perftest/read_lat/read_lat.rc | 47 + .../WOF2-1/tests/perftest/send_bw/SOURCES | 29 + .../WOF2-1/tests/perftest/send_bw/makefile | 7 + .../WOF2-1/tests/perftest/send_bw/send_bw.c | 1177 ++ .../WOF2-1/tests/perftest/send_bw/send_bw.rc | 47 + .../WOF2-1/tests/perftest/send_lat/SOURCES | 29 + .../WOF2-1/tests/perftest/send_lat/makefile | 7 + .../WOF2-1/tests/perftest/send_lat/send_lat.c | 1059 ++ .../tests/perftest/send_lat/send_lat.rc | 47 + .../WOF2-1/tests/perftest/write_bw/SOURCES | 29 + .../WOF2-1/tests/perftest/write_bw/makefile | 7 + .../WOF2-1/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-1/tests/perftest/write_lat/SOURCES | 29 + .../WOF2-1/tests/perftest/write_lat/makefile | 7 + .../tests/perftest/write_lat/write_lat.c | 798 ++ .../tests/perftest/write_lat/write_lat.rc | 47 + branches/WOF2-1/tests/wherebu/dirs | 2 + branches/WOF2-1/tests/wherebu/user/SOURCES | 20 + branches/WOF2-1/tests/wherebu/user/makefile | 7 + .../WOF2-1/tests/wherebu/user/wherebu.cpp | 121 + branches/WOF2-1/tests/wsd/dirs | 2 + .../WOF2-1/tests/wsd/user/contest/contest.c | 200 + .../WOF2-1/tests/wsd/user/contest/contest.h | 4 + branches/WOF2-1/tests/wsd/user/dirs | 2 + branches/WOF2-1/tests/wsd/user/test1/test1.c | 233 + branches/WOF2-1/tests/wsd/user/test2/ibwrap.c | 599 + branches/WOF2-1/tests/wsd/user/test2/ibwrap.h | 41 + branches/WOF2-1/tests/wsd/user/test2/test2.c | 64 + branches/WOF2-1/tests/wsd/user/test3/ibwrap.c | 610 + branches/WOF2-1/tests/wsd/user/test3/ibwrap.h | 44 + branches/WOF2-1/tests/wsd/user/test3/test3.c | 126 + branches/WOF2-1/tests/wsd/user/ttcp/SOURCES | 13 + branches/WOF2-1/tests/wsd/user/ttcp/makefile | 7 + branches/WOF2-1/tests/wsd/user/ttcp/ttcp.c | 860 ++ branches/WOF2-1/tools/dirs | 9 + branches/WOF2-1/tools/infiniband-diags/dirs | 1 + .../tools/infiniband-diags/include/grouping.h | 113 + .../infiniband-diags/include/ibdiag_common.h | 77 + .../infiniband-diags/include/ibnetdiscover.h | 107 + .../infiniband-diags/include/windows/config.h | 41 + .../include/windows/ibdiag_version.h | 41 + .../patches/ibping-cdecl.diff | 19 + .../WOF2-1/tools/infiniband-diags/src/dirs | 19 + .../tools/infiniband-diags/src/grouping.c | 785 ++ .../tools/infiniband-diags/src/ibaddr.c | 161 + .../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 | 326 + .../infiniband-diags/src/ibdiag_windows.c | 40 + .../tools/infiniband-diags/src/iblinkinfo.c | 414 + .../infiniband-diags/src/iblinkinfo/SOURCES | 36 + .../src/iblinkinfo/iblinkinfo.rc | 47 + .../infiniband-diags/src/iblinkinfo/makefile | 7 + .../infiniband-diags/src/ibnetdiscover.c | 697 + .../src/ibnetdiscover/SOURCES | 36 + .../src/ibnetdiscover/ibnetdiscover.rc | 47 + .../src/ibnetdiscover/makefile | 7 + .../tools/infiniband-diags/src/ibping.c | 263 + .../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 | 365 + .../infiniband-diags/src/ibportstate/SOURCES | 30 + .../src/ibportstate/ibportstate.rc | 47 + .../infiniband-diags/src/ibportstate/makefile | 7 + .../infiniband-diags/src/ibqueryerrors.c | 461 + .../src/ibqueryerrors/SOURCES | 35 + .../src/ibqueryerrors/ibqueryerrors.rc | 47 + .../src/ibqueryerrors/makefile | 7 + .../tools/infiniband-diags/src/ibroute.c | 432 + .../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 | 179 + .../infiniband-diags/src/ibsendtrap/SOURCES | 30 + .../src/ibsendtrap/ibsendtrap.rc | 47 + .../infiniband-diags/src/ibsendtrap/makefile | 7 + .../tools/infiniband-diags/src/ibstat.c | 259 + .../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 | 367 + .../infiniband-diags/src/ibsysstat/SOURCES | 31 + .../src/ibsysstat/ibsysstat.rc | 47 + .../infiniband-diags/src/ibsysstat/makefile | 7 + .../tools/infiniband-diags/src/ibtracert.c | 812 ++ .../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 | 540 + .../infiniband-diags/src/perfquery/SOURCES | 31 + .../infiniband-diags/src/perfquery/makefile | 7 + .../src/perfquery/perfquery.rc | 47 + .../tools/infiniband-diags/src/saquery.c | 1767 +++ .../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 | 157 + .../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 | 308 + .../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 | 481 + .../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 | 371 + .../infiniband-diags/src/vendstat/SOURCES | 31 + .../infiniband-diags/src/vendstat/makefile | 7 + .../infiniband-diags/src/vendstat/vendstat.rc | 47 + branches/WOF2-1/tools/ndinstall/dirs | 2 + branches/WOF2-1/tools/ndinstall/user/SOURCES | 23 + .../WOF2-1/tools/ndinstall/user/installsp.c | 332 + .../WOF2-1/tools/ndinstall/user/installsp.rc | 48 + branches/WOF2-1/tools/ndinstall/user/makefile | 17 + branches/WOF2-1/tools/nsc/SOURCES | 26 + branches/WOF2-1/tools/nsc/makefile | 8 + branches/WOF2-1/tools/nsc/nsc.c | 67 + branches/WOF2-1/tools/nsc/nsc.rc | 47 + branches/WOF2-1/tools/part_man/dirs | 2 + branches/WOF2-1/tools/part_man/user/SOURCES | 23 + branches/WOF2-1/tools/part_man/user/makefile | 7 + .../WOF2-1/tools/part_man/user/part_man.c | 587 + .../WOF2-1/tools/part_man/user/part_man.rc | 15 + branches/WOF2-1/tools/perftests/dirs | 2 + branches/WOF2-1/tools/perftests/user/README | 101 + branches/WOF2-1/tools/perftests/user/TODO | 1 + .../WOF2-1/tools/perftests/user/clock_test.c | 24 + branches/WOF2-1/tools/perftests/user/dirs | 9 + .../WOF2-1/tools/perftests/user/get_clock.c | 185 + .../WOF2-1/tools/perftests/user/get_clock.h | 79 + branches/WOF2-1/tools/perftests/user/getopt.c | 250 + branches/WOF2-1/tools/perftests/user/getopt.h | 117 + .../WOF2-1/tools/perftests/user/perf_defs.h | 157 + .../WOF2-1/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-1/tools/qlgcvnic_config/SOURCES | 20 + .../WOF2-1/tools/qlgcvnic_config/makefile | 7 + .../tools/qlgcvnic_config/qlgcvnic_config.rc | 47 + .../tools/qlgcvnic_config/vnic_child_config.c | 560 + branches/WOF2-1/tools/vstat/dirs | 2 + branches/WOF2-1/tools/vstat/user/SOURCES | 23 + branches/WOF2-1/tools/vstat/user/makefile | 7 + branches/WOF2-1/tools/vstat/user/vstat.rc | 47 + branches/WOF2-1/tools/vstat/user/vstat_main.c | 781 ++ branches/WOF2-1/tools/wsdinstall/dirs | 2 + .../tools/wsdinstall/user/InstallSP.sln | 21 + branches/WOF2-1/tools/wsdinstall/user/SOURCES | 23 + .../WOF2-1/tools/wsdinstall/user/installsp.c | 759 ++ .../wsdinstall/user/installsp.exe.manifest | 10 + .../WOF2-1/tools/wsdinstall/user/installsp.rc | 47 + .../WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cookie.c | 400 + .../WOF2-1/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-1/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-1/ulp/dapl/dapl/common/dapl_hash.c | 537 + .../WOF2-1/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-1/ulp/dapl/dapl/common/dapl_init.h | 56 + .../WOF2-1/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-1/ulp/dapl/dapl/dirs | 1 + .../WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_cm.c | 2004 +++ .../WOF2-1/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-1/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-1/ulp/dapl/dapl/include/dapl.h | 1042 ++ .../WOF2-1/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-1/ulp/dapl/dapl/udapl/Makefile.org | 200 + .../WOF2-1/ulp/dapl/dapl/udapl/Makefile.orig | 305 + branches/WOF2-1/ulp/dapl/dapl/udapl/SOURCES | 45 + .../WOF2-1/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-1/ulp/dapl/dapl/udapl/makefile | 7 + .../WOF2-1/ulp/dapl/dapl/udapl/makefile.wnd | 283 + branches/WOF2-1/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-1/ulp/dapl/dat/common/dat_dr.c | 381 + branches/WOF2-1/ulp/dapl/dat/common/dat_dr.h | 105 + .../WOF2-1/ulp/dapl/dat/common/dat_init.c | 161 + .../WOF2-1/ulp/dapl/dat/common/dat_init.h | 77 + branches/WOF2-1/ulp/dapl/dat/common/dat_sr.c | 412 + branches/WOF2-1/ulp/dapl/dat/common/dat_sr.h | 106 + .../WOF2-1/ulp/dapl/dat/common/dat_strerror.c | 600 + branches/WOF2-1/ulp/dapl/dat/dirs | 1 + .../WOF2-1/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-1/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-1/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-1/ulp/dapl/dat/kdat/Makefile | 113 + branches/WOF2-1/ulp/dapl/dat/kdat/dat_kdapl.c | 101 + .../WOF2-1/ulp/dapl/dat/kdat/dat_module.c | 104 + .../WOF2-1/ulp/dapl/dat/kdat/linux/dat_osd.c | 262 + .../WOF2-1/ulp/dapl/dat/kdat/linux/dat_osd.h | 258 + .../WOF2-1/ulp/dapl/dat/udat/Makefile.cygwin | 271 + .../WOF2-1/ulp/dapl/dat/udat/Makefile.org | 86 + .../WOF2-1/ulp/dapl/dat/udat/Makefile.orig | 114 + branches/WOF2-1/ulp/dapl/dat/udat/SOURCES | 31 + branches/WOF2-1/ulp/dapl/dat/udat/dat.conf | 7 + branches/WOF2-1/ulp/dapl/dat/udat/ibhosts | 7 + .../ulp/dapl/dat/udat/linux/dat-1.1.spec | 80 + .../WOF2-1/ulp/dapl/dat/udat/linux/dat_osd.c | 179 + .../WOF2-1/ulp/dapl/dat/udat/linux/dat_osd.h | 394 + branches/WOF2-1/ulp/dapl/dat/udat/makefile | 7 + .../WOF2-1/ulp/dapl/dat/udat/makefile.wnd | 144 + branches/WOF2-1/ulp/dapl/dat/udat/udat.c | 420 + branches/WOF2-1/ulp/dapl/dat/udat/udat.rc | 48 + .../WOF2-1/ulp/dapl/dat/udat/udat_exports.src | 15 + .../WOF2-1/ulp/dapl/dat/udat/udat_sources.c | 33 + .../WOF2-1/ulp/dapl/dat/udat/udat_sr_parser.c | 1551 +++ .../WOF2-1/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-1/ulp/dapl/dirs | 4 + .../WOF2-1/ulp/dapl/doc/dapl_coding_style.txt | 264 + .../ulp/dapl/doc/dapl_end_point_design.txt | 908 ++ branches/WOF2-1/ulp/dapl/doc/dapl_environ.txt | 42 + .../WOF2-1/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-1/ulp/dapl/doc/dat.conf | 11 + branches/WOF2-1/ulp/dapl/doc/dat_environ.txt | 45 + branches/WOF2-1/ulp/dapl/doc/ibhosts | 3 + .../WOF2-1/ulp/dapl/doc/mv_dapl_readme.txt | 226 + .../WOF2-1/ulp/dapl/doc/mv_dapl_relnotes.txt | 167 + branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/bw.sh | 22 + .../WOF2-1/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-1/ulp/dapl/test/udapl/dirs | 1 + branches/WOF2-1/ulp/dapl2/AUTHORS | 17 + branches/WOF2-1/ulp/dapl2/COPYING | 36 + branches/WOF2-1/ulp/dapl2/ChangeLog | 3275 +++++ branches/WOF2-1/ulp/dapl2/LICENSE.txt | 235 + branches/WOF2-1/ulp/dapl2/LICENSE2.txt | 30 + branches/WOF2-1/ulp/dapl2/LICENSE3.txt | 340 + branches/WOF2-1/ulp/dapl2/Makefile.am | 439 + branches/WOF2-1/ulp/dapl2/README | 434 + branches/WOF2-1/ulp/dapl2/README.windows | 190 + branches/WOF2-1/ulp/dapl2/autogen.sh | 10 + branches/WOF2-1/ulp/dapl2/configure.in | 101 + branches/WOF2-1/ulp/dapl2/dapl.spec.in | 200 + .../ulp/dapl2/dapl/common/dapl_adapter_util.h | 302 + .../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 | 549 + .../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 | 58 + .../WOF2-1/ulp/dapl2/dapl/common/dapl_csp.c | 102 + .../WOF2-1/ulp/dapl2/dapl/common/dapl_debug.c | 243 + .../ulp/dapl2/dapl/common/dapl_ep_connect.c | 416 + .../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 | 204 + .../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 | 585 + .../ulp/dapl2/dapl/common/dapl_ep_util.h | 87 + .../dapl/common/dapl_evd_connection_callb.c | 244 + .../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 | 164 + .../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 | 1535 +++ .../ulp/dapl2/dapl/common/dapl_evd_util.h | 174 + .../dapl/common/dapl_get_consumer_context.c | 98 + .../dapl2/dapl/common/dapl_get_handle_type.c | 87 + .../WOF2-1/ulp/dapl2/dapl/common/dapl_hash.c | 478 + .../WOF2-1/ulp/dapl2/dapl/common/dapl_hash.h | 109 + .../ulp/dapl2/dapl/common/dapl_hca_util.c | 176 + .../ulp/dapl2/dapl/common/dapl_hca_util.h | 60 + .../ulp/dapl2/dapl/common/dapl_ia_close.c | 87 + .../WOF2-1/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 | 233 + .../ulp/dapl2/dapl/common/dapl_ia_util.c | 1140 ++ .../ulp/dapl2/dapl/common/dapl_ia_util.h | 158 + .../WOF2-1/ulp/dapl2/dapl/common/dapl_init.h | 57 + .../WOF2-1/ulp/dapl2/dapl/common/dapl_llist.c | 343 + .../ulp/dapl2/dapl/common/dapl_lmr_free.c | 135 + .../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 | 319 + .../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 | 280 + .../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 | 319 + .../ulp/dapl2/dapl/common/dapl_timer_util.h | 47 + .../WOF2-1/ulp/dapl2/dapl/dapl_common_src.c | 112 + .../WOF2-1/ulp/dapl2/dapl/dapl_udapl_src.c | 45 + branches/WOF2-1/ulp/dapl2/dapl/dirs | 1 + branches/WOF2-1/ulp/dapl2/dapl/ibal/SOURCES | 56 + .../WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_cm.c | 1798 +++ .../WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_cq.c | 492 + .../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-1/ulp/dapl2/dapl/ibal/dapl_ibal_qp.c | 695 + .../ulp/dapl2/dapl/ibal/dapl_ibal_util.c | 2380 ++++ .../ulp/dapl2/dapl/ibal/dapl_ibal_util.h | 584 + branches/WOF2-1/ulp/dapl2/dapl/ibal/makefile | 7 + branches/WOF2-1/ulp/dapl2/dapl/ibal/udapl.rc | 48 + .../ulp/dapl2/dapl/ibal/udapl_exports.src | 14 + branches/WOF2-1/ulp/dapl2/dapl/include/dapl.h | 1275 ++ .../ulp/dapl2/dapl/include/dapl_debug.h | 114 + .../ulp/dapl2/dapl/include/dapl_ipoib_names.h | 262 + .../ulp/dapl2/dapl/include/dapl_vendor.h | 116 + .../WOF2-1/ulp/dapl2/dapl/openib_cma/README | 40 + .../WOF2-1/ulp/dapl2/dapl/openib_cma/SOURCES | 55 + .../WOF2-1/ulp/dapl2/dapl/openib_cma/cm.c | 1340 ++ .../ulp/dapl2/dapl/openib_cma/dapl_ib_util.h | 134 + .../WOF2-1/ulp/dapl2/dapl/openib_cma/device.c | 847 ++ .../ulp/dapl2/dapl/openib_cma/libdaplcma.map | 7 + .../dapl2/dapl/openib_cma/linux/openib_osd.h | 15 + .../WOF2-1/ulp/dapl2/dapl/openib_cma/makefile | 7 + .../WOF2-1/ulp/dapl2/dapl/openib_cma/udapl.rc | 48 + .../dapl/openib_cma/udapl_ofa_cma_exports.src | 14 + .../dapl/openib_cma/windows/openib_osd.h | 5 + .../WOF2-1/ulp/dapl2/dapl/openib_common.c | 6 + .../WOF2-1/ulp/dapl2/dapl/openib_common/cq.c | 491 + .../dapl2/dapl/openib_common/dapl_ib_common.h | 299 + .../dapl2/dapl/openib_common/dapl_ib_dto.h | 504 + .../dapl2/dapl/openib_common/ib_extensions.c | 360 + .../WOF2-1/ulp/dapl2/dapl/openib_common/mem.c | 370 + .../WOF2-1/ulp/dapl2/dapl/openib_common/qp.c | 515 + .../ulp/dapl2/dapl/openib_common/util.c | 375 + .../WOF2-1/ulp/dapl2/dapl/openib_scm/SOURCES | 50 + .../WOF2-1/ulp/dapl2/dapl/openib_scm/cm.c | 1865 +++ .../ulp/dapl2/dapl/openib_scm/dapl_ib_util.h | 125 + .../WOF2-1/ulp/dapl2/dapl/openib_scm/device.c | 412 + .../ulp/dapl2/dapl/openib_scm/libdaplscm.map | 6 + .../dapl2/dapl/openib_scm/linux/openib_osd.h | 21 + .../WOF2-1/ulp/dapl2/dapl/openib_scm/makefile | 7 + .../WOF2-1/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 + .../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 | 123 + .../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 | 101 + .../ulp/dapl2/dapl/udapl/dapl_evd_wait.c | 277 + .../WOF2-1/ulp/dapl2/dapl/udapl/dapl_init.c | 306 + .../ulp/dapl2/dapl/udapl/dapl_lmr_create.c | 506 + .../ulp/dapl2/dapl/udapl/libdaplofa.map | 7 + .../ulp/dapl2/dapl/udapl/libdaploscm.map | 7 + .../ulp/dapl2/dapl/udapl/libdaplscm.map | 6 + .../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 | 268 + .../ulp/dapl2/dapl/udapl/windows/dapl_osd.h | 525 + .../WOF2-1/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-1/ulp/dapl2/dat/common/dat_dr.c | 327 + branches/WOF2-1/ulp/dapl2/dat/common/dat_dr.h | 103 + .../WOF2-1/ulp/dapl2/dat/common/dat_init.c | 152 + .../WOF2-1/ulp/dapl2/dat/common/dat_init.h | 106 + branches/WOF2-1/ulp/dapl2/dat/common/dat_sr.c | 447 + branches/WOF2-1/ulp/dapl2/dat/common/dat_sr.h | 104 + .../ulp/dapl2/dat/common/dat_strerror.c | 611 + branches/WOF2-1/ulp/dapl2/dat/dirs | 1 + .../WOF2-1/ulp/dapl2/dat/include/dat2/dat.h | 1379 ++ .../ulp/dapl2/dat/include/dat2/dat_error.h | 380 + .../dat/include/dat2/dat_ib_extensions.h | 506 + .../dat/include/dat2/dat_iw_extensions.h | 167 + .../dat/include/dat2/dat_platform_specific.h | 271 + .../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-1/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-1/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-1/ulp/dapl2/dat/udat/SOURCES | 36 + .../WOF2-1/ulp/dapl2/dat/udat/libdat2.map | 78 + .../dat/udat/linux/dat-registry-1.1.spec | 106 + .../WOF2-1/ulp/dapl2/dat/udat/linux/dat_osd.c | 183 + .../WOF2-1/ulp/dapl2/dat/udat/linux/dat_osd.h | 415 + branches/WOF2-1/ulp/dapl2/dat/udat/makefile | 7 + branches/WOF2-1/ulp/dapl2/dat/udat/udat.c | 409 + branches/WOF2-1/ulp/dapl2/dat/udat/udat.rc | 48 + branches/WOF2-1/ulp/dapl2/dat/udat/udat_api.c | 260 + .../ulp/dapl2/dat/udat/udat_exports.src | 59 + .../WOF2-1/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 | 203 + .../ulp/dapl2/dat/udat/windows/dat_osd.h | 426 + .../ulp/dapl2/dat/udat/windows/dat_osd_sr.h | 43 + branches/WOF2-1/ulp/dapl2/dirs | 4 + .../ulp/dapl2/doc/dapl_coding_style.txt | 264 + .../ulp/dapl2/doc/dapl_end_point_design.txt | 1129 ++ .../WOF2-1/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-1/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-1/ulp/dapl2/doc/dat_environ.txt | 45 + .../ulp/dapl2/doc/uDAPL_release_notes.txt | 926 ++ branches/WOF2-1/ulp/dapl2/man/dapltest.1 | 390 + branches/WOF2-1/ulp/dapl2/man/dat.conf.5 | 62 + branches/WOF2-1/ulp/dapl2/man/dtest.1 | 78 + .../ulp/dapl2/test/dapltest/Makefile.am | 67 + .../WOF2-1/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-1/ulp/dapl2/test/dapltest/dirs | 1 + .../WOF2-1/ulp/dapl2/test/dapltest/dt_cmd.c | 12 + .../ulp/dapl2/test/dapltest/dt_common.c | 5 + .../WOF2-1/ulp/dapl2/test/dapltest/dt_mdep.c | 2 + .../WOF2-1/ulp/dapl2/test/dapltest/dt_test.c | 32 + .../WOF2-1/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 | 203 + .../dapltest/mdep/solaris/dapl_mdep_user.c | 466 + .../dapltest/mdep/solaris/dapl_mdep_user.h | 151 + .../dapltest/mdep/windows/dapl_mdep_user.c | 436 + .../dapltest/mdep/windows/dapl_mdep_user.h | 185 + .../ulp/dapl2/test/dapltest/scripts/cl.sh | 58 + .../dapl2/test/dapltest/scripts/dt-cli.bat | 372 + .../dapl2/test/dapltest/scripts/dt-svr.bat | 68 + .../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-1/ulp/dapl2/test/dirs | 1 + .../WOF2-1/ulp/dapl2/test/dtest/Makefile.am | 18 + branches/WOF2-1/ulp/dapl2/test/dtest/README | 19 + .../WOF2-1/ulp/dapl2/test/dtest/configure.in | 21 + branches/WOF2-1/ulp/dapl2/test/dtest/dirs | 1 + branches/WOF2-1/ulp/dapl2/test/dtest/dtc.bat | 42 + branches/WOF2-1/ulp/dapl2/test/dtest/dtest.c | 2148 +++ .../WOF2-1/ulp/dapl2/test/dtest/dtestcm.c | 1112 ++ branches/WOF2-1/ulp/dapl2/test/dtest/dtestx.c | 1299 ++ branches/WOF2-1/ulp/dapl2/test/dtest/dts.bat | 47 + .../WOF2-1/ulp/dapl2/test/dtest/windows/dirs | 1 + .../dapl2/test/dtest/windows/dtest/SOURCES | 33 + .../dapl2/test/dtest/windows/dtest/dtest.c | 3 + .../dapl2/test/dtest/windows/dtest/dtest.rc | 48 + .../dapl2/test/dtest/windows/dtest/makefile | 7 + .../dapl2/test/dtest/windows/dtestcm/SOURCES | 33 + .../test/dtest/windows/dtestcm/dtestcm.c | 3 + .../test/dtest/windows/dtestcm/dtestcm.rc | 48 + .../dapl2/test/dtest/windows/dtestcm/makefile | 7 + .../dapl2/test/dtest/windows/dtestx/SOURCES | 31 + .../dapl2/test/dtest/windows/dtestx/dtestx.c | 1 + .../dapl2/test/dtest/windows/dtestx/dtestx.rc | 48 + .../dapl2/test/dtest/windows/dtestx/makefile | 7 + branches/WOF2-1/ulp/dirs | 14 + branches/WOF2-1/ulp/ipoib/dirs | 2 + branches/WOF2-1/ulp/ipoib/ip_stats.h | 150 + branches/WOF2-1/ulp/ipoib/kernel/SOURCES | 58 + branches/WOF2-1/ulp/ipoib/kernel/ipoib.cdf | 13 + branches/WOF2-1/ulp/ipoib/kernel/ipoib.rc | 48 + .../WOF2-1/ulp/ipoib/kernel/ipoib32-xp.cdf | 10 + branches/WOF2-1/ulp/ipoib/kernel/ipoib32.cdf | 11 + .../WOF2-1/ulp/ipoib/kernel/ipoib_adapter.c | 1455 ++ .../WOF2-1/ulp/ipoib/kernel/ipoib_adapter.h | 436 + .../WOF2-1/ulp/ipoib/kernel/ipoib_debug.h | 300 + .../WOF2-1/ulp/ipoib/kernel/ipoib_driver.c | 2581 ++++ .../WOF2-1/ulp/ipoib/kernel/ipoib_driver.h | 146 + .../WOF2-1/ulp/ipoib/kernel/ipoib_endpoint.c | 358 + .../WOF2-1/ulp/ipoib/kernel/ipoib_endpoint.h | 158 + branches/WOF2-1/ulp/ipoib/kernel/ipoib_ibat.c | 670 + branches/WOF2-1/ulp/ipoib/kernel/ipoib_ibat.h | 45 + branches/WOF2-1/ulp/ipoib/kernel/ipoib_log.mc | 318 + branches/WOF2-1/ulp/ipoib/kernel/ipoib_port.c | 6480 +++++++++ branches/WOF2-1/ulp/ipoib/kernel/ipoib_port.h | 652 + .../WOF2-1/ulp/ipoib/kernel/ipoib_xfr_mgr.c | 52 + .../WOF2-1/ulp/ipoib/kernel/ipoib_xfr_mgr.h | 504 + branches/WOF2-1/ulp/ipoib/kernel/makefile | 7 + branches/WOF2-1/ulp/ipoib/kernel/makefile.inc | 17 + .../WOF2-1/ulp/ipoib/kernel/netipoib-xp32.inf | 269 + branches/WOF2-1/ulp/ipoib/kernel/netipoib.inx | 271 + branches/WOF2-1/ulp/ipoib/kernel/offload.h | 47 + branches/WOF2-1/ulp/ipoib/kernel6/SOURCES | 59 + branches/WOF2-1/ulp/ipoib/kernel6/ipoib.cdf | 13 + branches/WOF2-1/ulp/ipoib/kernel6/ipoib.rc | 48 + .../WOF2-1/ulp/ipoib/kernel6/ipoib32-xp.cdf | 10 + branches/WOF2-1/ulp/ipoib/kernel6/ipoib32.cdf | 11 + .../WOF2-1/ulp/ipoib/kernel6/ipoib_adapter.c | 1632 +++ .../WOF2-1/ulp/ipoib/kernel6/ipoib_adapter.h | 483 + branches/WOF2-1/ulp/ipoib/kernel6/ipoib_cm.c | 0 .../WOF2-1/ulp/ipoib/kernel6/ipoib_debug.h | 303 + .../WOF2-1/ulp/ipoib/kernel6/ipoib_driver.c | 4057 ++++++ .../WOF2-1/ulp/ipoib/kernel6/ipoib_driver.h | 162 + .../WOF2-1/ulp/ipoib/kernel6/ipoib_endpoint.c | 1170 ++ .../WOF2-1/ulp/ipoib/kernel6/ipoib_endpoint.h | 257 + .../WOF2-1/ulp/ipoib/kernel6/ipoib_ibat.c | 666 + .../WOF2-1/ulp/ipoib/kernel6/ipoib_ibat.h | 45 + .../WOF2-1/ulp/ipoib/kernel6/ipoib_log.mc | 334 + .../WOF2-1/ulp/ipoib/kernel6/ipoib_port.c | 8098 ++++++++++++ .../WOF2-1/ulp/ipoib/kernel6/ipoib_port.h | 827 ++ .../WOF2-1/ulp/ipoib/kernel6/ipoib_xfr_mgr.c | 74 + .../WOF2-1/ulp/ipoib/kernel6/ipoib_xfr_mgr.h | 513 + branches/WOF2-1/ulp/ipoib/kernel6/makefile | 7 + .../WOF2-1/ulp/ipoib/kernel6/makefile.inc | 17 + .../ulp/ipoib/kernel6/netipoib-xp32.inf | 280 + .../WOF2-1/ulp/ipoib/kernel6/netipoib.inx | 295 + branches/WOF2-1/ulp/ipoib/kernel6/offload.h | 47 + branches/WOF2-1/ulp/ipoib_NDIS6_CM/dirs | 2 + branches/WOF2-1/ulp/ipoib_NDIS6_CM/ip_stats.h | 150 + .../WOF2-1/ulp/ipoib_NDIS6_CM/kernel/SOURCES | 59 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib.cdf | 13 + .../WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib.rc | 48 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib32.cdf | 11 + .../ipoib_NDIS6_CM/kernel/ipoib_adapter.cpp | 1639 +++ .../ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h | 482 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h | 303 + .../ipoib_NDIS6_CM/kernel/ipoib_driver.cpp | 4570 +++++++ .../ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.h | 166 + .../ipoib_NDIS6_CM/kernel/ipoib_endpoint.cpp | 1170 ++ .../ipoib_NDIS6_CM/kernel/ipoib_endpoint.h | 257 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.cpp | 693 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.h | 45 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc | 334 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp | 8119 ++++++++++++ .../ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h | 829 ++ .../ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.cpp | 74 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.h | 513 + .../WOF2-1/ulp/ipoib_NDIS6_CM/kernel/makefile | 7 + .../ulp/ipoib_NDIS6_CM/kernel/makefile.inc | 17 + .../ulp/ipoib_NDIS6_CM/kernel/netipoib.inx | 295 + .../ulp/ipoib_NDIS6_CM/kernel/offload.h | 47 + branches/WOF2-1/ulp/libibmad/README.txt | 19 + branches/WOF2-1/ulp/libibmad/dirs | 2 + .../ulp/libibmad/include/infiniband/mad.h | 986 ++ .../ulp/libibmad/include/infiniband/mad_osd.h | 69 + branches/WOF2-1/ulp/libibmad/src/Sources | 54 + branches/WOF2-1/ulp/libibmad/src/bm.c | 105 + branches/WOF2-1/ulp/libibmad/src/dump.c | 746 ++ branches/WOF2-1/ulp/libibmad/src/fields.c | 697 + branches/WOF2-1/ulp/libibmad/src/gs.c | 117 + branches/WOF2-1/ulp/libibmad/src/ibmad.rc | 46 + .../WOF2-1/ulp/libibmad/src/ibmad_export.def | 34 + .../WOF2-1/ulp/libibmad/src/ibmad_exports.src | 47 + .../WOF2-1/ulp/libibmad/src/ibmad_main.cpp | 43 + branches/WOF2-1/ulp/libibmad/src/libibmad.map | 107 + branches/WOF2-1/ulp/libibmad/src/mad.c | 172 + .../WOF2-1/ulp/libibmad/src/mad_internal.h | 47 + branches/WOF2-1/ulp/libibmad/src/makefile | 7 + branches/WOF2-1/ulp/libibmad/src/portid.c | 118 + branches/WOF2-1/ulp/libibmad/src/register.c | 178 + branches/WOF2-1/ulp/libibmad/src/resolve.c | 185 + branches/WOF2-1/ulp/libibmad/src/rpc.c | 388 + branches/WOF2-1/ulp/libibmad/src/sa.c | 147 + branches/WOF2-1/ulp/libibmad/src/serv.c | 195 + branches/WOF2-1/ulp/libibmad/src/smp.c | 112 + branches/WOF2-1/ulp/libibmad/src/vendor.c | 104 + branches/WOF2-1/ulp/libibnetdisc/README.txt | 19 + branches/WOF2-1/ulp/libibnetdisc/dirs | 2 + .../include/infiniband/ibnetdisc.h | 188 + branches/WOF2-1/ulp/libibnetdisc/src/Sources | 45 + .../WOF2-1/ulp/libibnetdisc/src/chassis.c | 832 ++ .../WOF2-1/ulp/libibnetdisc/src/chassis.h | 85 + .../WOF2-1/ulp/libibnetdisc/src/ibnetdisc.c | 714 + .../ulp/libibnetdisc/src/ibnetdisc_export.def | 34 + .../libibnetdisc/src/ibnetdisc_exports.src | 24 + .../ulp/libibnetdisc/src/ibnetdisc_main.cpp | 39 + .../WOF2-1/ulp/libibnetdisc/src/internal.h | 95 + branches/WOF2-1/ulp/libibnetdisc/src/makefile | 7 + branches/WOF2-1/ulp/libibumad/AUTHORS | 4 + branches/WOF2-1/ulp/libibumad/COPYING | 27 + branches/WOF2-1/ulp/libibumad/dirs | 2 + .../ulp/libibumad/include/infiniband/umad.h | 219 + branches/WOF2-1/ulp/libibumad/src/Sources | 38 + .../WOF2-1/ulp/libibumad/src/ibum_export.def | 34 + .../WOF2-1/ulp/libibumad/src/ibum_exports.src | 39 + .../WOF2-1/ulp/libibumad/src/ibum_main.cpp | 39 + branches/WOF2-1/ulp/libibumad/src/ibumad.h | 44 + branches/WOF2-1/ulp/libibumad/src/ibumad.rc | 46 + branches/WOF2-1/ulp/libibumad/src/makefile | 7 + branches/WOF2-1/ulp/libibumad/src/umad.cpp | 700 + branches/WOF2-1/ulp/libibverbs/AUTHORS | 4 + branches/WOF2-1/ulp/libibverbs/COPYING | 29 + branches/WOF2-1/ulp/libibverbs/dirs | 3 + .../libibverbs/examples/asyncwatch/SOURCES | 30 + .../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-1/ulp/libibverbs/examples/dirs | 6 + .../WOF2-1/ulp/libibverbs/examples/pingpong.c | 52 + .../WOF2-1/ulp/libibverbs/examples/pingpong.h | 38 + .../libibverbs/examples/rc_pingpong/SOURCES | 30 + .../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 | 30 + .../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 | 30 + .../libibverbs/examples/ud_pingpong/makefile | 7 + .../examples/ud_pingpong/ud_pingpong.c | 738 ++ .../examples/ud_pingpong/ud_pingpong.rc | 47 + .../ulp/libibverbs/include/infiniband/verbs.h | 1138 ++ branches/WOF2-1/ulp/libibverbs/src/Sources | 38 + branches/WOF2-1/ulp/libibverbs/src/device.cpp | 370 + .../WOF2-1/ulp/libibverbs/src/enum_strs.cpp | 130 + .../WOF2-1/ulp/libibverbs/src/ibv_export.def | 34 + .../WOF2-1/ulp/libibverbs/src/ibv_exports.src | 56 + .../WOF2-1/ulp/libibverbs/src/ibv_main.cpp | 42 + branches/WOF2-1/ulp/libibverbs/src/ibverbs.h | 45 + branches/WOF2-1/ulp/libibverbs/src/ibverbs.rc | 46 + branches/WOF2-1/ulp/libibverbs/src/makefile | 7 + branches/WOF2-1/ulp/libibverbs/src/verbs.cpp | 882 ++ branches/WOF2-1/ulp/librdmacm/AUTHORS | 1 + branches/WOF2-1/ulp/librdmacm/COPYING | 26 + branches/WOF2-1/ulp/librdmacm/dirs | 3 + .../ulp/librdmacm/examples/cmatose/SOURCES | 30 + .../ulp/librdmacm/examples/cmatose/cmatose.c | 815 ++ .../ulp/librdmacm/examples/cmatose/makefile | 7 + branches/WOF2-1/ulp/librdmacm/examples/dirs | 2 + .../ulp/librdmacm/examples/mckey/mckey.c | 579 + .../ulp/librdmacm/examples/rping/rping.c | 1122 ++ .../ulp/librdmacm/examples/udaddy/udaddy.c | 701 + .../ulp/librdmacm/include/rdma/rdma_cma.h | 636 + branches/WOF2-1/ulp/librdmacm/src/Sources | 40 + branches/WOF2-1/ulp/librdmacm/src/cma.cpp | 1073 ++ branches/WOF2-1/ulp/librdmacm/src/cma.h | 46 + branches/WOF2-1/ulp/librdmacm/src/cma.rc | 46 + .../WOF2-1/ulp/librdmacm/src/cma_export.def | 34 + .../WOF2-1/ulp/librdmacm/src/cma_exports.src | 33 + .../WOF2-1/ulp/librdmacm/src/cma_main.cpp | 44 + branches/WOF2-1/ulp/librdmacm/src/makefile | 7 + branches/WOF2-1/ulp/nd/dirs | 2 + branches/WOF2-1/ulp/nd/user/NdAdapter.cpp | 950 ++ branches/WOF2-1/ulp/nd/user/NdAdapter.h | 210 + branches/WOF2-1/ulp/nd/user/NdConnector.cpp | 935 ++ branches/WOF2-1/ulp/nd/user/NdConnector.h | 172 + branches/WOF2-1/ulp/nd/user/NdCq.cpp | 487 + branches/WOF2-1/ulp/nd/user/NdCq.h | 113 + branches/WOF2-1/ulp/nd/user/NdEndpoint.cpp | 944 ++ branches/WOF2-1/ulp/nd/user/NdEndpoint.h | 202 + branches/WOF2-1/ulp/nd/user/NdListen.cpp | 385 + branches/WOF2-1/ulp/nd/user/NdListen.h | 115 + branches/WOF2-1/ulp/nd/user/NdMr.cpp | 48 + branches/WOF2-1/ulp/nd/user/NdMr.h | 55 + branches/WOF2-1/ulp/nd/user/NdMw.cpp | 110 + branches/WOF2-1/ulp/nd/user/NdMw.h | 75 + branches/WOF2-1/ulp/nd/user/NdProv.cpp | 570 + branches/WOF2-1/ulp/nd/user/NdProv.def | 6 + branches/WOF2-1/ulp/nd/user/NdProv.h | 110 + branches/WOF2-1/ulp/nd/user/NdProv.rc | 49 + branches/WOF2-1/ulp/nd/user/README.txt | 18 + branches/WOF2-1/ulp/nd/user/SOURCES | 64 + branches/WOF2-1/ulp/nd/user/fake.c | 2 + .../user/fre_svr-03_amd64/amd64/ibndprov.dll | Bin 0 -> 43520 bytes .../user/fre_svr-03_amd64/amd64/ndinstall.exe | Bin 0 -> 11776 bytes .../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-03_x86/i386/ibndprov.dll | Bin 0 -> 37376 bytes .../nd/user/fre_svr-03_x86/i386/ndinstall.exe | Bin 0 -> 11264 bytes .../user/fre_svr-08_amd64/amd64/ibndprov.dll | Bin 0 -> 43520 bytes .../user/fre_svr-08_amd64/amd64/ndinstall.exe | Bin 0 -> 10752 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 .../nd/user/fre_svr-08_x86/i386/ibndprov.dll | Bin 0 -> 37376 bytes .../nd/user/fre_svr-08_x86/i386/ndinstall.exe | Bin 0 -> 9216 bytes .../ulp/nd/user/fre_xp_x86/i386/ibndprov.dll | Bin 0 -> 37376 bytes .../ulp/nd/user/fre_xp_x86/i386/ndinstall.exe | Bin 0 -> 11264 bytes branches/WOF2-1/ulp/nd/user/makefile | 17 + branches/WOF2-1/ulp/nd/user/makefile.inc | 41 + branches/WOF2-1/ulp/nd/user/nddebug.h | 160 + branches/WOF2-1/ulp/netdirect/dirs | 1 + branches/WOF2-1/ulp/netdirect/user/SOURCES | 42 + branches/WOF2-1/ulp/netdirect/user/makefile | 14 + .../WOF2-1/ulp/netdirect/user/nd_adapter.cpp | 301 + .../WOF2-1/ulp/netdirect/user/nd_adapter.h | 127 + .../WOF2-1/ulp/netdirect/user/nd_base.cpp | 53 + branches/WOF2-1/ulp/netdirect/user/nd_base.h | 63 + .../WOF2-1/ulp/netdirect/user/nd_connect.cpp | 259 + .../WOF2-1/ulp/netdirect/user/nd_connect.h | 119 + branches/WOF2-1/ulp/netdirect/user/nd_cq.cpp | 124 + branches/WOF2-1/ulp/netdirect/user/nd_cq.h | 95 + branches/WOF2-1/ulp/netdirect/user/nd_ep.cpp | 282 + branches/WOF2-1/ulp/netdirect/user/nd_ep.h | 130 + .../WOF2-1/ulp/netdirect/user/nd_export.def | 35 + .../WOF2-1/ulp/netdirect/user/nd_exports.src | 12 + .../WOF2-1/ulp/netdirect/user/nd_listen.cpp | 145 + .../WOF2-1/ulp/netdirect/user/nd_listen.h | 98 + .../WOF2-1/ulp/netdirect/user/nd_main.cpp | 88 + branches/WOF2-1/ulp/netdirect/user/nd_main.h | 37 + branches/WOF2-1/ulp/netdirect/user/nd_mw.cpp | 76 + branches/WOF2-1/ulp/netdirect/user/nd_mw.h | 85 + .../WOF2-1/ulp/netdirect/user/nd_provider.cpp | 180 + .../WOF2-1/ulp/netdirect/user/nd_provider.h | 76 + .../WOF2-1/ulp/netdirect/user/netdirect.rc | 46 + branches/WOF2-1/ulp/opensm/dirs | 2 + .../ulp/opensm/user/README.opensm-build | 24 + branches/WOF2-1/ulp/opensm/user/TODO | 16 + branches/WOF2-1/ulp/opensm/user/config.h | 71 + branches/WOF2-1/ulp/opensm/user/dirs | 7 + .../ulp/opensm/user/doc/OpenSM_PKey_Mgr.txt | 79 + .../ulp/opensm/user/doc/OpenSM_RN_0_3_1.pdf | Bin 0 -> 83938 bytes .../ulp/opensm/user/doc/OpenSM_UM_0_3.pdf | Bin 0 -> 223001 bytes .../ulp/opensm/user/doc/current-routing.txt | 202 + .../ulp/opensm/user/doc/modular-routing.txt | 78 + .../doc/opensm_release_notes_openib-2.0.5.txt | 487 + .../WOF2-1/ulp/opensm/user/doc/qos-config.txt | 45 + .../WOF2-1/ulp/opensm/user/ibtrapgen/Makefile | 7 + .../WOF2-1/ulp/opensm/user/ibtrapgen/SOURCES | 64 + .../ulp/opensm/user/ibtrapgen/ibtrapgen.c | 442 + .../ulp/opensm/user/ibtrapgen/ibtrapgen.h | 313 + .../WOF2-1/ulp/opensm/user/ibtrapgen/main.c | 465 + .../opensm/user/include/complib/cl_byteswap.h | 547 + .../user/include/complib/cl_dispatcher.h | 660 + .../user/include/complib/cl_event_wheel.h | 493 + .../user/include/complib/cl_signal_osd.h | 127 + .../ulp/opensm/user/include/iba/ib_types.h | 10684 +++++++++++++++ .../user/include/iba/ib_types_extended.h | 2809 ++++ .../user/include/opensm/cl_dispatcher.h | 673 + .../user/include/opensm/cl_event_wheel.h | 497 + .../user/include/opensm/osm_attrib_req.h | 119 + .../ulp/opensm/user/include/opensm/osm_base.h | 823 ++ .../opensm/user/include/opensm/osm_console.h | 58 + .../ulp/opensm/user/include/opensm/osm_db.h | 455 + .../opensm/user/include/opensm/osm_db_pack.h | 255 + .../opensm/user/include/opensm/osm_drop_mgr.h | 259 + .../opensm/user/include/opensm/osm_errors.h | 181 + .../opensm/user/include/opensm/osm_fwd_tbl.h | 388 + .../opensm/user/include/opensm/osm_helper.h | 620 + .../opensm/user/include/opensm/osm_inform.h | 305 + .../opensm/user/include/opensm/osm_lid_mgr.h | 322 + .../user/include/opensm/osm_lin_fwd_rcv.h | 255 + .../include/opensm/osm_lin_fwd_rcv_ctrl.h | 233 + .../user/include/opensm/osm_lin_fwd_tbl.h | 379 + .../opensm/user/include/opensm/osm_link_mgr.h | 271 + .../ulp/opensm/user/include/opensm/osm_log.h | 474 + .../opensm/user/include/opensm/osm_mad_pool.h | 405 + .../ulp/opensm/user/include/opensm/osm_madw.h | 1160 ++ .../opensm/user/include/opensm/osm_matrix.h | 454 + .../user/include/opensm/osm_mcast_fwd_rcv.h | 259 + .../include/opensm/osm_mcast_fwd_rcv_ctrl.h | 235 + .../user/include/opensm/osm_mcast_mgr.h | 339 + .../user/include/opensm/osm_mcast_tbl.h | 484 + .../opensm/user/include/opensm/osm_mcm_info.h | 237 + .../opensm/user/include/opensm/osm_mcm_port.h | 269 + .../opensm/user/include/opensm/osm_msgdef.h | 208 + .../opensm/user/include/opensm/osm_mtl_bind.h | 144 + .../opensm/user/include/opensm/osm_mtree.h | 378 + .../user/include/opensm/osm_multicast.h | 769 ++ .../ulp/opensm/user/include/opensm/osm_node.h | 957 ++ .../user/include/opensm/osm_node_desc_rcv.h | 256 + .../include/opensm/osm_node_desc_rcv_ctrl.h | 232 + .../user/include/opensm/osm_node_info_rcv.h | 305 + .../include/opensm/osm_node_info_rcv_ctrl.h | 261 + .../opensm/user/include/opensm/osm_opensm.h | 440 + .../user/include/opensm/osm_partition.h | 256 + .../ulp/opensm/user/include/opensm/osm_path.h | 267 + .../ulp/opensm/user/include/opensm/osm_pkey.h | 755 ++ .../opensm/user/include/opensm/osm_pkey_mgr.h | 90 + .../opensm/user/include/opensm/osm_pkey_rcv.h | 253 + .../user/include/opensm/osm_pkey_rcv_ctrl.h | 248 + .../ulp/opensm/user/include/opensm/osm_port.h | 2122 +++ .../user/include/opensm/osm_port_info_rcv.h | 274 + .../include/opensm/osm_port_info_rcv_ctrl.h | 261 + .../user/include/opensm/osm_port_profile.h | 291 + .../user/include/opensm/osm_rand_fwd_tbl.h | 354 + .../user/include/opensm/osm_remote_sm.h | 212 + .../ulp/opensm/user/include/opensm/osm_req.h | 354 + .../opensm/user/include/opensm/osm_req_ctrl.h | 228 + .../ulp/opensm/user/include/opensm/osm_resp.h | 279 + .../opensm/user/include/opensm/osm_router.h | 323 + .../ulp/opensm/user/include/opensm/osm_sa.h | 500 + .../include/opensm/osm_sa_class_port_info.h | 269 + .../opensm/osm_sa_class_port_info_ctrl.h | 261 + .../include/opensm/osm_sa_guidinfo_record.h | 279 + .../opensm/osm_sa_guidinfo_record_ctrl.h | 230 + .../user/include/opensm/osm_sa_informinfo.h | 299 + .../include/opensm/osm_sa_informinfo_ctrl.h | 261 + .../user/include/opensm/osm_sa_lft_record.h | 281 + .../include/opensm/osm_sa_lft_record_ctrl.h | 233 + .../user/include/opensm/osm_sa_link_record.h | 276 + .../include/opensm/osm_sa_link_record_ctrl.h | 261 + .../user/include/opensm/osm_sa_mad_ctrl.h | 352 + .../include/opensm/osm_sa_mcmember_record.h | 420 + .../opensm/osm_sa_mcmember_record_ctrl.h | 262 + .../user/include/opensm/osm_sa_mft_record.h | 280 + .../include/opensm/osm_sa_mft_record_ctrl.h | 231 + .../include/opensm/osm_sa_multipath_record.h | 273 + .../opensm/osm_sa_multipath_record_ctrl.h | 260 + .../user/include/opensm/osm_sa_node_record.h | 275 + .../include/opensm/osm_sa_node_record_ctrl.h | 231 + .../user/include/opensm/osm_sa_path_record.h | 274 + .../include/opensm/osm_sa_path_record_ctrl.h | 261 + .../user/include/opensm/osm_sa_pkey_record.h | 268 + .../include/opensm/osm_sa_pkey_record_ctrl.h | 218 + .../include/opensm/osm_sa_portinfo_record.h | 280 + .../opensm/osm_sa_portinfo_record_ctrl.h | 231 + .../user/include/opensm/osm_sa_response.h | 255 + .../include/opensm/osm_sa_service_record.h | 298 + .../opensm/osm_sa_service_record_ctrl.h | 230 + .../user/include/opensm/osm_sa_slvl_record.h | 281 + .../include/opensm/osm_sa_slvl_record_ctrl.h | 231 + .../include/opensm/osm_sa_sminfo_record.h | 262 + .../opensm/osm_sa_sminfo_record_ctrl.h | 231 + .../include/opensm/osm_sa_sw_info_record.h | 306 + .../opensm/osm_sa_sw_info_record_ctrl.h | 259 + .../user/include/opensm/osm_sa_vlarb_record.h | 280 + .../include/opensm/osm_sa_vlarb_record_ctrl.h | 231 + .../opensm/user/include/opensm/osm_service.h | 241 + .../user/include/opensm/osm_slvl_map_rcv.h | 265 + .../include/opensm/osm_slvl_map_rcv_ctrl.h | 261 + .../ulp/opensm/user/include/opensm/osm_sm.h | 566 + .../user/include/opensm/osm_sm_mad_ctrl.h | 339 + .../user/include/opensm/osm_sm_state_mgr.h | 353 + .../user/include/opensm/osm_sminfo_rcv.h | 291 + .../user/include/opensm/osm_sminfo_rcv_ctrl.h | 232 + .../user/include/opensm/osm_state_mgr.h | 518 + .../user/include/opensm/osm_state_mgr_ctrl.h | 233 + .../opensm/user/include/opensm/osm_stats.h | 125 + .../opensm/user/include/opensm/osm_subnet.h | 1161 ++ .../user/include/opensm/osm_sw_info_rcv.h | 304 + .../include/opensm/osm_sw_info_rcv_ctrl.h | 261 + .../user/include/opensm/osm_sweep_fail_ctrl.h | 239 + .../opensm/user/include/opensm/osm_switch.h | 1552 +++ .../opensm/user/include/opensm/osm_trap_rcv.h | 326 + .../user/include/opensm/osm_trap_rcv_ctrl.h | 232 + .../user/include/opensm/osm_ts_useraccess.h | 54 + .../user/include/opensm/osm_ucast_mgr.h | 328 + .../opensm/user/include/opensm/osm_umadt.h | 143 + .../opensm/user/include/opensm/osm_version.h | 63 + .../opensm/user/include/opensm/osm_vl15intf.h | 417 + .../user/include/opensm/osm_vl_arb_rcv.h | 265 + .../user/include/opensm/osm_vl_arb_rcv_ctrl.h | 261 + .../ulp/opensm/user/include/opensm/st.h | 107 + .../WOF2-1/ulp/opensm/user/include/unistd.h | 38 + .../opensm/user/include/vendor/osm_vendor.h | 78 + .../user/include/vendor/osm_vendor_al.h | 372 + .../user/include/vendor/osm_vendor_api.h | 519 + .../user/include/vendor/osm_vendor_sa_api.h | 879 ++ .../user/include/vendor/osm_vendor_select.h | 76 + .../user/include/vendor/winosm_common.h | 251 + .../WOF2-1/ulp/opensm/user/libopensm/Makefile | 7 + .../WOF2-1/ulp/opensm/user/libopensm/SOURCES | 62 + .../ulp/opensm/user/libopensm/osm_helper.c | 2534 ++++ .../ulp/opensm/user/libopensm/osm_log.c | 327 + .../ulp/opensm/user/libopensm/osm_mad_pool.c | 302 + .../WOF2-1/ulp/opensm/user/libvendor/Makefile | 7 + .../WOF2-1/ulp/opensm/user/libvendor/SOURCES | 60 + .../ulp/opensm/user/libvendor/osm_vendor_al.c | 1533 +++ .../opensm/user/libvendor/osm_vendor_mlx_sa.c | 879 ++ .../ulp/opensm/user/libvendor/winosm_common.c | 249 + .../WOF2-1/ulp/opensm/user/opensm/Makefile | 7 + .../WOF2-1/ulp/opensm/user/opensm/SOURCES | 62 + .../ulp/opensm/user/opensm/cl_dispatcher.c | 405 + .../ulp/opensm/user/opensm/cl_event_wheel.c | 663 + branches/WOF2-1/ulp/opensm/user/opensm/main.c | 1158 ++ .../WOF2-1/ulp/opensm/user/opensm/opensm.opts | 139 + .../WOF2-1/ulp/opensm/user/opensm/opensm.rc | 46 + branches/WOF2-1/ulp/opensm/user/opensm/osm.mc | 29 + .../ulp/opensm/user/opensm/osm_console.c | 226 + .../ulp/opensm/user/opensm/osm_db_files.c | 796 ++ .../ulp/opensm/user/opensm/osm_db_pack.c | 172 + .../ulp/opensm/user/opensm/osm_drop_mgr.c | 721 + .../WOF2-1/ulp/opensm/user/opensm/osm_files.c | 99 + .../ulp/opensm/user/opensm/osm_fwd_tbl.c | 115 + .../ulp/opensm/user/opensm/osm_inform.c | 763 ++ .../ulp/opensm/user/opensm/osm_lid_mgr.c | 1494 +++ .../ulp/opensm/user/opensm/osm_lin_fwd_rcv.c | 160 + .../opensm/user/opensm/osm_lin_fwd_rcv_ctrl.c | 125 + .../ulp/opensm/user/opensm/osm_lin_fwd_tbl.c | 102 + .../ulp/opensm/user/opensm/osm_link_mgr.c | 514 + .../ulp/opensm/user/opensm/osm_matrix.c | 156 + .../opensm/user/opensm/osm_mcast_fwd_rcv.c | 181 + .../user/opensm/osm_mcast_fwd_rcv_ctrl.c | 125 + .../ulp/opensm/user/opensm/osm_mcast_mgr.c | 1726 +++ .../ulp/opensm/user/opensm/osm_mcast_tbl.c | 302 + .../ulp/opensm/user/opensm/osm_mcm_info.c | 102 + .../ulp/opensm/user/opensm/osm_mcm_port.c | 127 + .../WOF2-1/ulp/opensm/user/opensm/osm_mtree.c | 137 + .../ulp/opensm/user/opensm/osm_multicast.c | 403 + .../WOF2-1/ulp/opensm/user/opensm/osm_node.c | 335 + .../opensm/user/opensm/osm_node_desc_rcv.c | 182 + .../user/opensm/osm_node_desc_rcv_ctrl.c | 127 + .../opensm/user/opensm/osm_node_info_rcv.c | 1090 ++ .../user/opensm/osm_node_info_rcv_ctrl.c | 127 + .../ulp/opensm/user/opensm/osm_opensm.c | 320 + .../WOF2-1/ulp/opensm/user/opensm/osm_pkey.c | 547 + .../ulp/opensm/user/opensm/osm_pkey_mgr.c | 596 + .../ulp/opensm/user/opensm/osm_pkey_rcv.c | 220 + .../opensm/user/opensm/osm_pkey_rcv_ctrl.c | 116 + .../WOF2-1/ulp/opensm/user/opensm/osm_port.c | 936 ++ .../opensm/user/opensm/osm_port_info_rcv.c | 870 ++ .../user/opensm/osm_port_info_rcv_ctrl.c | 128 + .../WOF2-1/ulp/opensm/user/opensm/osm_prtn.c | 399 + .../ulp/opensm/user/opensm/osm_prtn_config.c | 447 + .../WOF2-1/ulp/opensm/user/opensm/osm_qos.c | 451 + .../ulp/opensm/user/opensm/osm_remote_sm.c | 90 + .../WOF2-1/ulp/opensm/user/opensm/osm_req.c | 298 + .../ulp/opensm/user/opensm/osm_req_ctrl.c | 136 + .../WOF2-1/ulp/opensm/user/opensm/osm_resp.c | 227 + .../ulp/opensm/user/opensm/osm_router.c | 124 + .../WOF2-1/ulp/opensm/user/opensm/osm_sa.c | 1207 ++ .../user/opensm/osm_sa_class_port_info.c | 280 + .../user/opensm/osm_sa_class_port_info_ctrl.c | 126 + .../user/opensm/osm_sa_guidinfo_record.c | 611 + .../user/opensm/osm_sa_guidinfo_record_ctrl.c | 124 + .../opensm/user/opensm/osm_sa_informinfo.c | 922 ++ .../user/opensm/osm_sa_informinfo_ctrl.c | 154 + .../opensm/user/opensm/osm_sa_lft_record.c | 515 + .../user/opensm/osm_sa_lft_record_ctrl.c | 124 + .../opensm/user/opensm/osm_sa_link_record.c | 777 ++ .../user/opensm/osm_sa_link_record_ctrl.c | 128 + .../ulp/opensm/user/opensm/osm_sa_mad_ctrl.c | 651 + .../user/opensm/osm_sa_mcmember_record.c | 2383 ++++ .../user/opensm/osm_sa_mcmember_record_ctrl.c | 132 + .../opensm/user/opensm/osm_sa_mft_record.c | 547 + .../user/opensm/osm_sa_mft_record_ctrl.c | 123 + .../user/opensm/osm_sa_multipath_record.c | 1652 +++ .../opensm/osm_sa_multipath_record_ctrl.c | 128 + .../opensm/user/opensm/osm_sa_node_record.c | 600 + .../user/opensm/osm_sa_node_record_ctrl.c | 125 + .../opensm/user/opensm/osm_sa_path_record.c | 2006 +++ .../user/opensm/osm_sa_path_record_ctrl.c | 126 + .../opensm/user/opensm/osm_sa_pkey_record.c | 590 + .../user/opensm/osm_sa_pkey_record_ctrl.c | 113 + .../user/opensm/osm_sa_portinfo_record.c | 878 ++ .../user/opensm/osm_sa_portinfo_record_ctrl.c | 125 + .../ulp/opensm/user/opensm/osm_sa_response.c | 175 + .../user/opensm/osm_sa_service_record.c | 1204 ++ .../user/opensm/osm_sa_service_record_ctrl.c | 125 + .../opensm/user/opensm/osm_sa_slvl_record.c | 557 + .../user/opensm/osm_sa_slvl_record_ctrl.c | 126 + .../opensm/user/opensm/osm_sa_sminfo_record.c | 583 + .../user/opensm/osm_sa_sminfo_record_ctrl.c | 125 + .../user/opensm/osm_sa_sw_info_record.c | 535 + .../user/opensm/osm_sa_sw_info_record_ctrl.c | 123 + .../opensm/user/opensm/osm_sa_vlarb_record.c | 577 + .../user/opensm/osm_sa_vlarb_record_ctrl.c | 126 + .../ulp/opensm/user/opensm/osm_service.c | 202 + .../ulp/opensm/user/opensm/osm_slvl_map_rcv.c | 232 + .../user/opensm/osm_slvl_map_rcv_ctrl.c | 127 + .../WOF2-1/ulp/opensm/user/opensm/osm_sm.c | 824 ++ .../ulp/opensm/user/opensm/osm_sm_mad_ctrl.c | 1049 ++ .../ulp/opensm/user/opensm/osm_sm_state_mgr.c | 872 ++ .../ulp/opensm/user/opensm/osm_sminfo_rcv.c | 768 ++ .../opensm/user/opensm/osm_sminfo_rcv_ctrl.c | 127 + .../ulp/opensm/user/opensm/osm_state_mgr.c | 2986 +++++ .../opensm/user/opensm/osm_state_mgr_ctrl.c | 127 + .../ulp/opensm/user/opensm/osm_subnet.c | 1272 ++ .../ulp/opensm/user/opensm/osm_sw_info_rcv.c | 681 + .../opensm/user/opensm/osm_sw_info_rcv_ctrl.c | 126 + .../opensm/user/opensm/osm_sweep_fail_ctrl.c | 133 + .../ulp/opensm/user/opensm/osm_switch.c | 550 + .../ulp/opensm/user/opensm/osm_trap_rcv.c | 771 ++ .../opensm/user/opensm/osm_trap_rcv_ctrl.c | 126 + .../ulp/opensm/user/opensm/osm_ucast_file.c | 413 + .../ulp/opensm/user/opensm/osm_ucast_ftree.c | 3141 +++++ .../ulp/opensm/user/opensm/osm_ucast_mgr.c | 1277 ++ .../ulp/opensm/user/opensm/osm_ucast_updn.c | 1281 ++ .../ulp/opensm/user/opensm/osm_vl15intf.c | 544 + .../ulp/opensm/user/opensm/osm_vl_arb_rcv.c | 240 + .../opensm/user/opensm/osm_vl_arb_rcv_ctrl.c | 127 + branches/WOF2-1/ulp/opensm/user/opensm/st.c | 625 + .../WOF2-1/ulp/opensm/user/osmtest/Makefile | 7 + .../WOF2-1/ulp/opensm/user/osmtest/SOURCES | 71 + .../ulp/opensm/user/osmtest/include/error.h | 57 + .../opensm/user/osmtest/include/osmt_inform.h | 88 + .../osmtest/include/osmt_mtl_regular_qp.h | 187 + .../ulp/opensm/user/osmtest/include/osmtest.h | 517 + .../user/osmtest/include/osmtest_base.h | 72 + .../user/osmtest/include/osmtest_subnet.h | 349 + .../WOF2-1/ulp/opensm/user/osmtest/main.c | 678 + .../ulp/opensm/user/osmtest/osmt_inform.c | 961 ++ .../opensm/user/osmtest/osmt_mtl_regular_qp.c | 447 + .../ulp/opensm/user/osmtest/osmt_multicast.c | 3500 +++++ .../ulp/opensm/user/osmtest/osmt_service.c | 1833 +++ .../opensm/user/osmtest/osmt_slvl_vl_arb.c | 570 + .../WOF2-1/ulp/opensm/user/osmtest/osmtest.c | 7489 +++++++++++ branches/WOF2-1/ulp/qlgcvnic/dirs | 2 + branches/WOF2-1/ulp/qlgcvnic/kernel/SOURCES | 90 + branches/WOF2-1/ulp/qlgcvnic/kernel/inic.rc | 47 + branches/WOF2-1/ulp/qlgcvnic/kernel/makefile | 7 + .../WOF2-1/ulp/qlgcvnic/kernel/makefile.inc | 17 + .../WOF2-1/ulp/qlgcvnic/kernel/netvnic.cdf | 8 + .../WOF2-1/ulp/qlgcvnic/kernel/netvnic.inx | 198 + .../WOF2-1/ulp/qlgcvnic/kernel/vnic_adapter.c | 1845 +++ .../WOF2-1/ulp/qlgcvnic/kernel/vnic_adapter.h | 242 + .../WOF2-1/ulp/qlgcvnic/kernel/vnic_config.h | 302 + .../WOF2-1/ulp/qlgcvnic/kernel/vnic_control.c | 2091 +++ .../WOF2-1/ulp/qlgcvnic/kernel/vnic_control.h | 123 + .../ulp/qlgcvnic/kernel/vnic_controlpkt.h | 287 + .../WOF2-1/ulp/qlgcvnic/kernel/vnic_data.c | 1459 ++ .../WOF2-1/ulp/qlgcvnic/kernel/vnic_data.h | 206 + .../WOF2-1/ulp/qlgcvnic/kernel/vnic_debug.h | 132 + .../WOF2-1/ulp/qlgcvnic/kernel/vnic_driver.c | 2152 +++ .../WOF2-1/ulp/qlgcvnic/kernel/vnic_driver.h | 192 + branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_ib.c | 921 ++ branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_ib.h | 239 + .../WOF2-1/ulp/qlgcvnic/kernel/vnic_netpath.c | 345 + .../WOF2-1/ulp/qlgcvnic/kernel/vnic_trailer.h | 107 + .../WOF2-1/ulp/qlgcvnic/kernel/vnic_util.h | 60 + .../WOF2-1/ulp/qlgcvnic/kernel/vnic_viport.c | 1232 ++ .../WOF2-1/ulp/qlgcvnic/kernel/vnic_viport.h | 396 + branches/WOF2-1/ulp/srp/dirs | 2 + branches/WOF2-1/ulp/srp/kernel/SOURCES | 64 + branches/WOF2-1/ulp/srp/kernel/ib_srp.cdf | 10 + branches/WOF2-1/ulp/srp/kernel/ib_srp.inx | 136 + branches/WOF2-1/ulp/srp/kernel/ibsrp.rc | 47 + branches/WOF2-1/ulp/srp/kernel/makefile | 7 + branches/WOF2-1/ulp/srp/kernel/makefile.inc | 17 + branches/WOF2-1/ulp/srp/kernel/srp.h | 370 + branches/WOF2-1/ulp/srp/kernel/srp_aer_req.h | 295 + branches/WOF2-1/ulp/srp/kernel/srp_aer_rsp.h | 163 + branches/WOF2-1/ulp/srp/kernel/srp_cmd.h | 648 + .../WOF2-1/ulp/srp/kernel/srp_connection.c | 874 ++ .../WOF2-1/ulp/srp/kernel/srp_connection.h | 127 + branches/WOF2-1/ulp/srp/kernel/srp_cred_req.h | 201 + branches/WOF2-1/ulp/srp/kernel/srp_cred_rsp.h | 163 + branches/WOF2-1/ulp/srp/kernel/srp_data.h | 80 + .../WOF2-1/ulp/srp/kernel/srp_data_path.c | 1627 +++ .../WOF2-1/ulp/srp/kernel/srp_data_path.h | 86 + branches/WOF2-1/ulp/srp/kernel/srp_debug.h | 149 + .../WOF2-1/ulp/srp/kernel/srp_descriptors.c | 687 + .../WOF2-1/ulp/srp/kernel/srp_descriptors.h | 144 + branches/WOF2-1/ulp/srp/kernel/srp_driver.c | 941 ++ branches/WOF2-1/ulp/srp/kernel/srp_event.c | 83 + branches/WOF2-1/ulp/srp/kernel/srp_event.h | 42 + branches/WOF2-1/ulp/srp/kernel/srp_hba.c | 1044 ++ branches/WOF2-1/ulp/srp/kernel/srp_hba.h | 100 + branches/WOF2-1/ulp/srp/kernel/srp_hca.c | 263 + branches/WOF2-1/ulp/srp/kernel/srp_hca.h | 76 + branches/WOF2-1/ulp/srp/kernel/srp_i_logout.h | 163 + .../ulp/srp/kernel/srp_information_unit.h | 106 + .../WOF2-1/ulp/srp/kernel/srp_iu_buffer.h | 142 + .../WOF2-1/ulp/srp/kernel/srp_login_rej.h | 262 + .../WOF2-1/ulp/srp/kernel/srp_login_req.h | 364 + .../WOF2-1/ulp/srp/kernel/srp_login_rsp.h | 382 + branches/WOF2-1/ulp/srp/kernel/srp_rsp.h | 726 + branches/WOF2-1/ulp/srp/kernel/srp_session.c | 597 + branches/WOF2-1/ulp/srp/kernel/srp_session.h | 132 + branches/WOF2-1/ulp/srp/kernel/srp_t_logout.h | 200 + branches/WOF2-1/ulp/srp/kernel/srp_tsk_mgmt.h | 276 + branches/WOF2-1/ulp/wsd/dirs | 2 + branches/WOF2-1/ulp/wsd/user/README | 38 + branches/WOF2-1/ulp/wsd/user/SOURCES | 63 + branches/WOF2-1/ulp/wsd/user/extensions.c | 651 + branches/WOF2-1/ulp/wsd/user/ib_cm.c | 960 ++ branches/WOF2-1/ulp/wsd/user/ibsp_duplicate.c | 327 + branches/WOF2-1/ulp/wsd/user/ibsp_iblow.c | 1328 ++ branches/WOF2-1/ulp/wsd/user/ibsp_ip.c | 566 + branches/WOF2-1/ulp/wsd/user/ibsp_mem.c | 400 + branches/WOF2-1/ulp/wsd/user/ibsp_mem.h | 30 + branches/WOF2-1/ulp/wsd/user/ibsp_mngt.c | 289 + branches/WOF2-1/ulp/wsd/user/ibsp_perfmon.c | 562 + branches/WOF2-1/ulp/wsd/user/ibsp_perfmon.h | 116 + branches/WOF2-1/ulp/wsd/user/ibsp_pnp.c | 443 + branches/WOF2-1/ulp/wsd/user/ibspdebug.c | 291 + branches/WOF2-1/ulp/wsd/user/ibspdebug.h | 267 + branches/WOF2-1/ulp/wsd/user/ibspdefines.h | 90 + branches/WOF2-1/ulp/wsd/user/ibspdll.c | 2329 ++++ branches/WOF2-1/ulp/wsd/user/ibspdll.def | 6 + branches/WOF2-1/ulp/wsd/user/ibspdll.h | 72 + branches/WOF2-1/ulp/wsd/user/ibspdll.rc | 47 + branches/WOF2-1/ulp/wsd/user/ibspproto.h | 298 + branches/WOF2-1/ulp/wsd/user/ibspstruct.h | 469 + branches/WOF2-1/ulp/wsd/user/makefile | 8 + branches/WOF2-1/ulp/wsd/user/misc.c | 134 + branches/WOF2-1/ulp/wsd/user/sockinfo.c | 176 + 2319 files changed, 783663 insertions(+) create mode 100644 branches/WOF2-1/WinOF/BuildRelease.bat create mode 100644 branches/WOF2-1/WinOF/WIX/CustomActions.vbs create mode 100644 branches/WOF2-1/WinOF/WIX/License.rtf create mode 100644 branches/WOF2-1/WinOF/WIX/README.txt create mode 100644 branches/WOF2-1/WinOF/WIX/README_checked.txt create mode 100644 branches/WOF2-1/WinOF/WIX/README_release.txt create mode 100644 branches/WOF2-1/WinOF/WIX/Release_notes.htm create mode 100644 branches/WOF2-1/WinOF/WIX/SDK_Samples/DDK/README.txt create mode 100644 branches/WOF2-1/WinOF/WIX/SDK_Samples/DDK/SOURCES create mode 100644 branches/WOF2-1/WinOF/WIX/SDK_Samples/DDK/cmtest.rc create mode 100644 branches/WOF2-1/WinOF/WIX/SDK_Samples/DDK/makefile create mode 100644 branches/WOF2-1/WinOF/WIX/SDK_Samples/VS/Makefile.x64 create mode 100644 branches/WOF2-1/WinOF/WIX/SDK_Samples/VS/Makefile.x86 create mode 100644 branches/WOF2-1/WinOF/WIX/SDK_Samples/VS/README.txt create mode 100644 branches/WOF2-1/WinOF/WIX/SDK_Samples/VS/cmtest.rc create mode 100644 branches/WOF2-1/WinOF/WIX/WIX_tools/README.txt create mode 100644 branches/WOF2-1/WinOF/WIX/build-OFA-dist.bat create mode 100644 branches/WOF2-1/WinOF/WIX/build-all-MSI.bat create mode 100644 branches/WOF2-1/WinOF/WIX/common/DAT_config.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/Docs.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/IBcore.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/InstallExecuteSeq.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/OpenSM_service.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/WinOF_cfg.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/arp.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/checked.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/dapl_rt.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/hca_filters.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/ib_sdk.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/iou.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/ipoib.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/mlnx_drivers.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/qlgc_vnic.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/requirements.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/srp.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/std_features.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/tools.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/winverbs_OFED.inc create mode 100644 branches/WOF2-1/WinOF/WIX/common/winverbs_drivers.inc create mode 100644 branches/WOF2-1/WinOF/WIX/dat.conf create mode 100644 branches/WOF2-1/WinOF/WIX/dpinst.xml create mode 100644 branches/WOF2-1/WinOF/WIX/ia64/Command Window.lnk create mode 100644 branches/WOF2-1/WinOF/WIX/ia64/devman.exe create mode 100644 branches/WOF2-1/WinOF/WIX/openfabrics.gif create mode 100644 branches/WOF2-1/WinOF/WIX/openfabrics.ico create mode 100644 branches/WOF2-1/WinOF/WIX/sign-all-drivers.bat create mode 100644 branches/WOF2-1/WinOF/WIX/win7/build-MSI.bat create mode 100644 branches/WOF2-1/WinOF/WIX/win7/ia64/Makefile create mode 100644 branches/WOF2-1/WinOF/WIX/win7/ia64/wof.wxs create mode 100644 branches/WOF2-1/WinOF/WIX/win7/signDrivers.bat create mode 100644 branches/WOF2-1/WinOF/WIX/win7/x64/Makefile create mode 100644 branches/WOF2-1/WinOF/WIX/win7/x64/wof.wxs create mode 100644 branches/WOF2-1/WinOF/WIX/win7/x86/Makefile create mode 100644 branches/WOF2-1/WinOF/WIX/win7/x86/wof.wxs create mode 100644 branches/WOF2-1/WinOF/WIX/wlh/build-MSI.bat create mode 100644 branches/WOF2-1/WinOF/WIX/wlh/ia64/Makefile create mode 100644 branches/WOF2-1/WinOF/WIX/wlh/ia64/wof.wxs create mode 100644 branches/WOF2-1/WinOF/WIX/wlh/signDrivers.bat create mode 100644 branches/WOF2-1/WinOF/WIX/wlh/x64/Makefile create mode 100644 branches/WOF2-1/WinOF/WIX/wlh/x64/cert-add.bat create mode 100644 branches/WOF2-1/WinOF/WIX/wlh/x64/rem-cert-ADD.bat create mode 100644 branches/WOF2-1/WinOF/WIX/wlh/x64/wof.wxs create mode 100644 branches/WOF2-1/WinOF/WIX/wlh/x86/Makefile create mode 100644 branches/WOF2-1/WinOF/WIX/wlh/x86/wof.wxs create mode 100644 branches/WOF2-1/WinOF/WIX/wnet/build-MSI.bat create mode 100644 branches/WOF2-1/WinOF/WIX/wnet/ia64/Makefile create mode 100644 branches/WOF2-1/WinOF/WIX/wnet/ia64/wof.wxs create mode 100644 branches/WOF2-1/WinOF/WIX/wnet/signDrivers.bat create mode 100644 branches/WOF2-1/WinOF/WIX/wnet/x64/Makefile create mode 100644 branches/WOF2-1/WinOF/WIX/wnet/x64/wof.wxs create mode 100644 branches/WOF2-1/WinOF/WIX/wnet/x86/Makefile create mode 100644 branches/WOF2-1/WinOF/WIX/wnet/x86/wof.wxs create mode 100644 branches/WOF2-1/WinOF/WIX/wxp/build-MSI.bat create mode 100644 branches/WOF2-1/WinOF/WIX/wxp/signDrivers.bat create mode 100644 branches/WOF2-1/WinOF/WIX/wxp/x86/Makefile create mode 100644 branches/WOF2-1/WinOF/WIX/wxp/x86/wof.wxs create mode 100644 branches/WOF2-1/WinOF/WIX/x64/Command Window.lnk create mode 100644 branches/WOF2-1/WinOF/WIX/x64/devman.exe create mode 100644 branches/WOF2-1/WinOF/WIX/x86/Command Window.lnk create mode 100644 branches/WOF2-1/WinOF/WIX/x86/devman.exe create mode 100644 branches/WOF2-1/WinOF/WIX/zip-OFA-dist.bat create mode 100644 branches/WOF2-1/core/al/al.c create mode 100644 branches/WOF2-1/core/al/al.h create mode 100644 branches/WOF2-1/core/al/al_av.c create mode 100644 branches/WOF2-1/core/al/al_av.h create mode 100644 branches/WOF2-1/core/al/al_ca.c create mode 100644 branches/WOF2-1/core/al/al_ca.h create mode 100644 branches/WOF2-1/core/al/al_ci_ca.h create mode 100644 branches/WOF2-1/core/al/al_ci_ca_shared.c create mode 100644 branches/WOF2-1/core/al/al_cm_cep.h create mode 100644 branches/WOF2-1/core/al/al_cm_conn.h create mode 100644 branches/WOF2-1/core/al/al_cm_qp.c create mode 100644 branches/WOF2-1/core/al/al_cm_sidr.h create mode 100644 branches/WOF2-1/core/al/al_common.c create mode 100644 branches/WOF2-1/core/al/al_common.h create mode 100644 branches/WOF2-1/core/al/al_cq.c create mode 100644 branches/WOF2-1/core/al/al_cq.h create mode 100644 branches/WOF2-1/core/al/al_debug.h create mode 100644 branches/WOF2-1/core/al/al_dev.h create mode 100644 branches/WOF2-1/core/al/al_dm.c create mode 100644 branches/WOF2-1/core/al/al_dm.h create mode 100644 branches/WOF2-1/core/al/al_init.c create mode 100644 branches/WOF2-1/core/al/al_init.h create mode 100644 branches/WOF2-1/core/al/al_ioc_pnp.h create mode 100644 branches/WOF2-1/core/al/al_mad.c create mode 100644 branches/WOF2-1/core/al/al_mad.h create mode 100644 branches/WOF2-1/core/al/al_mad_pool.h create mode 100644 branches/WOF2-1/core/al/al_mcast.c create mode 100644 branches/WOF2-1/core/al/al_mcast.h create mode 100644 branches/WOF2-1/core/al/al_mgr.h create mode 100644 branches/WOF2-1/core/al/al_mgr_shared.c create mode 100644 branches/WOF2-1/core/al/al_mr.h create mode 100644 branches/WOF2-1/core/al/al_mr_shared.c create mode 100644 branches/WOF2-1/core/al/al_mw.c create mode 100644 branches/WOF2-1/core/al/al_mw.h create mode 100644 branches/WOF2-1/core/al/al_pd.c create mode 100644 branches/WOF2-1/core/al/al_pd.h create mode 100644 branches/WOF2-1/core/al/al_pnp.h create mode 100644 branches/WOF2-1/core/al/al_proxy.h create mode 100644 branches/WOF2-1/core/al/al_proxy_ioctl.h create mode 100644 branches/WOF2-1/core/al/al_proxy_ndi.h create mode 100644 branches/WOF2-1/core/al/al_qp.c create mode 100644 branches/WOF2-1/core/al/al_qp.h create mode 100644 branches/WOF2-1/core/al/al_query.c create mode 100644 branches/WOF2-1/core/al/al_query.h create mode 100644 branches/WOF2-1/core/al/al_reg_svc.c create mode 100644 branches/WOF2-1/core/al/al_reg_svc.h create mode 100644 branches/WOF2-1/core/al/al_res_mgr.c create mode 100644 branches/WOF2-1/core/al/al_res_mgr.h create mode 100644 branches/WOF2-1/core/al/al_srq.c create mode 100644 branches/WOF2-1/core/al/al_srq.h create mode 100644 branches/WOF2-1/core/al/al_sub.c create mode 100644 branches/WOF2-1/core/al/al_verbs.h create mode 100644 branches/WOF2-1/core/al/dirs create mode 100644 branches/WOF2-1/core/al/ib_common.c create mode 100644 branches/WOF2-1/core/al/ib_common.h create mode 100644 branches/WOF2-1/core/al/ib_statustext.c create mode 100644 branches/WOF2-1/core/al/kernel/SOURCES create mode 100644 branches/WOF2-1/core/al/kernel/al_ci_ca.c create mode 100644 branches/WOF2-1/core/al/kernel/al_cm.c create mode 100644 branches/WOF2-1/core/al/kernel/al_cm_cep.c create mode 100644 branches/WOF2-1/core/al/kernel/al_dev.c create mode 100644 branches/WOF2-1/core/al/kernel/al_exports.def create mode 100644 branches/WOF2-1/core/al/kernel/al_fmr_pool.c create mode 100644 branches/WOF2-1/core/al/kernel/al_fmr_pool.h create mode 100644 branches/WOF2-1/core/al/kernel/al_ioc_pnp.c create mode 100644 branches/WOF2-1/core/al/kernel/al_mad_pool.c create mode 100644 branches/WOF2-1/core/al/kernel/al_mgr.c create mode 100644 branches/WOF2-1/core/al/kernel/al_mr.c create mode 100644 branches/WOF2-1/core/al/kernel/al_ndi_cm.c create mode 100644 branches/WOF2-1/core/al/kernel/al_ndi_cm.h create mode 100644 branches/WOF2-1/core/al/kernel/al_ndi_cq.c create mode 100644 branches/WOF2-1/core/al/kernel/al_ndi_cq.h create mode 100644 branches/WOF2-1/core/al/kernel/al_pnp.c create mode 100644 branches/WOF2-1/core/al/kernel/al_proxy.c create mode 100644 branches/WOF2-1/core/al/kernel/al_proxy_cep.c create mode 100644 branches/WOF2-1/core/al/kernel/al_proxy_ioc.c create mode 100644 branches/WOF2-1/core/al/kernel/al_proxy_ndi.c create mode 100644 branches/WOF2-1/core/al/kernel/al_proxy_subnet.c create mode 100644 branches/WOF2-1/core/al/kernel/al_proxy_verbs.c create mode 100644 branches/WOF2-1/core/al/kernel/al_sa_req.c create mode 100644 branches/WOF2-1/core/al/kernel/al_smi.c create mode 100644 branches/WOF2-1/core/al/kernel/al_smi.h create mode 100644 branches/WOF2-1/core/al/kernel/ibal.rc create mode 100644 branches/WOF2-1/core/al/kernel/makefile create mode 100644 branches/WOF2-1/core/al/user/SOURCES create mode 100644 branches/WOF2-1/core/al/user/al_dll.c create mode 100644 branches/WOF2-1/core/al/user/al_exports.src create mode 100644 branches/WOF2-1/core/al/user/al_mad_pool.c create mode 100644 branches/WOF2-1/core/al/user/ibal.rc create mode 100644 branches/WOF2-1/core/al/user/makefile create mode 100644 branches/WOF2-1/core/al/user/ual_av.c create mode 100644 branches/WOF2-1/core/al/user/ual_ca.c create mode 100644 branches/WOF2-1/core/al/user/ual_ca.h create mode 100644 branches/WOF2-1/core/al/user/ual_ci_ca.c create mode 100644 branches/WOF2-1/core/al/user/ual_ci_ca.h create mode 100644 branches/WOF2-1/core/al/user/ual_cm_cep.c create mode 100644 branches/WOF2-1/core/al/user/ual_cq.c create mode 100644 branches/WOF2-1/core/al/user/ual_mad.c create mode 100644 branches/WOF2-1/core/al/user/ual_mad.h create mode 100644 branches/WOF2-1/core/al/user/ual_mad_pool.c create mode 100644 branches/WOF2-1/core/al/user/ual_mcast.c create mode 100644 branches/WOF2-1/core/al/user/ual_mcast.h create mode 100644 branches/WOF2-1/core/al/user/ual_mgr.c create mode 100644 branches/WOF2-1/core/al/user/ual_mgr.h create mode 100644 branches/WOF2-1/core/al/user/ual_mr.c create mode 100644 branches/WOF2-1/core/al/user/ual_mw.c create mode 100644 branches/WOF2-1/core/al/user/ual_pd.c create mode 100644 branches/WOF2-1/core/al/user/ual_pnp.c create mode 100644 branches/WOF2-1/core/al/user/ual_qp.c create mode 100644 branches/WOF2-1/core/al/user/ual_qp.h create mode 100644 branches/WOF2-1/core/al/user/ual_res_mgr.h create mode 100644 branches/WOF2-1/core/al/user/ual_sa_req.c create mode 100644 branches/WOF2-1/core/al/user/ual_srq.c create mode 100644 branches/WOF2-1/core/al/user/ual_support.h create mode 100644 branches/WOF2-1/core/bus/dirs create mode 100644 branches/WOF2-1/core/bus/kernel/SOURCES create mode 100644 branches/WOF2-1/core/bus/kernel/bus_driver.c create mode 100644 branches/WOF2-1/core/bus/kernel/bus_driver.h create mode 100644 branches/WOF2-1/core/bus/kernel/bus_ev_log.mc create mode 100644 branches/WOF2-1/core/bus/kernel/bus_iou_mgr.c create mode 100644 branches/WOF2-1/core/bus/kernel/bus_iou_mgr.h create mode 100644 branches/WOF2-1/core/bus/kernel/bus_pnp.c create mode 100644 branches/WOF2-1/core/bus/kernel/bus_pnp.h create mode 100644 branches/WOF2-1/core/bus/kernel/bus_port_mgr.c create mode 100644 branches/WOF2-1/core/bus/kernel/bus_port_mgr.h create mode 100644 branches/WOF2-1/core/bus/kernel/ibbus.rc create mode 100644 branches/WOF2-1/core/bus/kernel/makefile create mode 100644 branches/WOF2-1/core/complib/cl_async_proc.c create mode 100644 branches/WOF2-1/core/complib/cl_list.c create mode 100644 branches/WOF2-1/core/complib/cl_map.c create mode 100644 branches/WOF2-1/core/complib/cl_memory.c create mode 100644 branches/WOF2-1/core/complib/cl_memtrack.h create mode 100644 branches/WOF2-1/core/complib/cl_obj.c create mode 100644 branches/WOF2-1/core/complib/cl_perf.c create mode 100644 branches/WOF2-1/core/complib/cl_pool.c create mode 100644 branches/WOF2-1/core/complib/cl_ptr_vector.c create mode 100644 branches/WOF2-1/core/complib/cl_reqmgr.c create mode 100644 branches/WOF2-1/core/complib/cl_statustext.c create mode 100644 branches/WOF2-1/core/complib/cl_threadpool.c create mode 100644 branches/WOF2-1/core/complib/cl_vector.c create mode 100644 branches/WOF2-1/core/complib/dirs create mode 100644 branches/WOF2-1/core/complib/kernel/SOURCES create mode 100644 branches/WOF2-1/core/complib/kernel/cl_bus_ifc.c create mode 100644 branches/WOF2-1/core/complib/kernel/cl_driver.c create mode 100644 branches/WOF2-1/core/complib/kernel/cl_event.c create mode 100644 branches/WOF2-1/core/complib/kernel/cl_exports.def create mode 100644 branches/WOF2-1/core/complib/kernel/cl_log.c create mode 100644 branches/WOF2-1/core/complib/kernel/cl_memory_osd.c create mode 100644 branches/WOF2-1/core/complib/kernel/cl_pnp_po.c create mode 100644 branches/WOF2-1/core/complib/kernel/cl_syscallback.c create mode 100644 branches/WOF2-1/core/complib/kernel/cl_thread.c create mode 100644 branches/WOF2-1/core/complib/kernel/cl_timer.c create mode 100644 branches/WOF2-1/core/complib/kernel/makefile create mode 100644 branches/WOF2-1/core/complib/user/SOURCES create mode 100644 branches/WOF2-1/core/complib/user/cl_debug.c create mode 100644 branches/WOF2-1/core/complib/user/cl_dll.c create mode 100644 branches/WOF2-1/core/complib/user/cl_event.c create mode 100644 branches/WOF2-1/core/complib/user/cl_log.c create mode 100644 branches/WOF2-1/core/complib/user/cl_memory_osd.c create mode 100644 branches/WOF2-1/core/complib/user/cl_nodenamemap.c create mode 100644 branches/WOF2-1/core/complib/user/cl_syscallback.c create mode 100644 branches/WOF2-1/core/complib/user/cl_thread.c create mode 100644 branches/WOF2-1/core/complib/user/cl_timer.c create mode 100644 branches/WOF2-1/core/complib/user/complib.rc create mode 100644 branches/WOF2-1/core/complib/user/complib.src create mode 100644 branches/WOF2-1/core/complib/user/makefile create mode 100644 branches/WOF2-1/core/dirs create mode 100644 branches/WOF2-1/core/ibat/dirs create mode 100644 branches/WOF2-1/core/ibat/user/SOURCES create mode 100644 branches/WOF2-1/core/ibat/user/ibat.cpp create mode 100644 branches/WOF2-1/core/ibat/user/makefile create mode 100644 branches/WOF2-1/core/iou/dirs create mode 100644 branches/WOF2-1/core/iou/kernel/SOURCES create mode 100644 branches/WOF2-1/core/iou/kernel/ib_iou.cdf create mode 100644 branches/WOF2-1/core/iou/kernel/ib_iou.inx create mode 100644 branches/WOF2-1/core/iou/kernel/ibiou.rc create mode 100644 branches/WOF2-1/core/iou/kernel/iou_driver.c create mode 100644 branches/WOF2-1/core/iou/kernel/iou_driver.h create mode 100644 branches/WOF2-1/core/iou/kernel/iou_ioc_mgr.c create mode 100644 branches/WOF2-1/core/iou/kernel/iou_ioc_mgr.h create mode 100644 branches/WOF2-1/core/iou/kernel/iou_pnp.c create mode 100644 branches/WOF2-1/core/iou/kernel/iou_pnp.h create mode 100644 branches/WOF2-1/core/iou/kernel/makefile create mode 100644 branches/WOF2-1/core/iou/kernel/makefile.inc create mode 100644 branches/WOF2-1/core/winmad/dirs create mode 100644 branches/WOF2-1/core/winmad/kernel/SOURCES create mode 100644 branches/WOF2-1/core/winmad/kernel/makefile create mode 100644 branches/WOF2-1/core/winmad/kernel/makefile.inc create mode 100644 branches/WOF2-1/core/winmad/kernel/winmad.inx create mode 100644 branches/WOF2-1/core/winmad/kernel/winmad.rc create mode 100644 branches/WOF2-1/core/winmad/kernel/wm_driver.c create mode 100644 branches/WOF2-1/core/winmad/kernel/wm_driver.h create mode 100644 branches/WOF2-1/core/winmad/kernel/wm_provider.c create mode 100644 branches/WOF2-1/core/winmad/kernel/wm_provider.h create mode 100644 branches/WOF2-1/core/winmad/kernel/wm_reg.c create mode 100644 branches/WOF2-1/core/winmad/kernel/wm_reg.h create mode 100644 branches/WOF2-1/core/winmad/user/SOURCES create mode 100644 branches/WOF2-1/core/winmad/user/makefile create mode 100644 branches/WOF2-1/core/winmad/user/winmad.rc create mode 100644 branches/WOF2-1/core/winmad/user/wm_exports.src create mode 100644 branches/WOF2-1/core/winmad/user/wm_main.cpp create mode 100644 branches/WOF2-1/core/winmad/user/wm_memory.h create mode 100644 branches/WOF2-1/core/winmad/user/wm_provider.cpp create mode 100644 branches/WOF2-1/core/winmad/user/wm_provider.h create mode 100644 branches/WOF2-1/core/winmad/wm_ioctl.h create mode 100644 branches/WOF2-1/core/winverbs/dirs create mode 100644 branches/WOF2-1/core/winverbs/kernel/SOURCES create mode 100644 branches/WOF2-1/core/winverbs/kernel/makefile create mode 100644 branches/WOF2-1/core/winverbs/kernel/makefile.inc create mode 100644 branches/WOF2-1/core/winverbs/kernel/winverbs.cdf create mode 100644 branches/WOF2-1/core/winverbs/kernel/winverbs.inx create mode 100644 branches/WOF2-1/core/winverbs/kernel/winverbs.rc create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_cq.c create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_cq.h create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_device.c create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_device.h create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_driver.c create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_driver.h create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_ep.c create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_ep.h create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_pd.c create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_pd.h create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_provider.c create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_provider.h create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_qp.c create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_qp.h create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_srq.c create mode 100644 branches/WOF2-1/core/winverbs/kernel/wv_srq.h create mode 100644 branches/WOF2-1/core/winverbs/user/SOURCES create mode 100644 branches/WOF2-1/core/winverbs/user/makefile create mode 100644 branches/WOF2-1/core/winverbs/user/winverbs.rc create mode 100644 branches/WOF2-1/core/winverbs/user/wv_base.cpp create mode 100644 branches/WOF2-1/core/winverbs/user/wv_base.h create mode 100644 branches/WOF2-1/core/winverbs/user/wv_cq.cpp create mode 100644 branches/WOF2-1/core/winverbs/user/wv_cq.h create mode 100644 branches/WOF2-1/core/winverbs/user/wv_device.cpp create mode 100644 branches/WOF2-1/core/winverbs/user/wv_device.h create mode 100644 branches/WOF2-1/core/winverbs/user/wv_ep.cpp create mode 100644 branches/WOF2-1/core/winverbs/user/wv_ep.h create mode 100644 branches/WOF2-1/core/winverbs/user/wv_exports.src create mode 100644 branches/WOF2-1/core/winverbs/user/wv_main.cpp create mode 100644 branches/WOF2-1/core/winverbs/user/wv_memory.h create mode 100644 branches/WOF2-1/core/winverbs/user/wv_pd.cpp create mode 100644 branches/WOF2-1/core/winverbs/user/wv_pd.h create mode 100644 branches/WOF2-1/core/winverbs/user/wv_provider.cpp create mode 100644 branches/WOF2-1/core/winverbs/user/wv_provider.h create mode 100644 branches/WOF2-1/core/winverbs/user/wv_qp.cpp create mode 100644 branches/WOF2-1/core/winverbs/user/wv_qp.h create mode 100644 branches/WOF2-1/core/winverbs/user/wv_srq.cpp create mode 100644 branches/WOF2-1/core/winverbs/user/wv_srq.h create mode 100644 branches/WOF2-1/core/winverbs/user/wv_uverbs.cpp create mode 100644 branches/WOF2-1/core/winverbs/wv_ioctl.h create mode 100644 branches/WOF2-1/core/winverbs/wv_public.h create mode 100644 branches/WOF2-1/dirs create mode 100644 branches/WOF2-1/docs/Manual.htm create mode 100644 branches/WOF2-1/docs/build.txt create mode 100644 branches/WOF2-1/docs/complib/cl_async_proc_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_atomic_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_byteswap_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_comppool_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_debug_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_event_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_fleximap_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_ioctl_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_irqlock_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_list_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_log_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_map_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_math_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_memory_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_mutex_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_obj_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_passivelock_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_perf_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_pool_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_ptr_vector_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_qcomppool_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_qlist_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_qlockpool_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_qmap_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_qpool_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_rbmap_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_reqmgr_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_spinlock_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_syscallback_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_thread_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_threadpool_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_timer_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_types_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_vector_h.html create mode 100644 branches/WOF2-1/docs/complib/cl_waitobj_h.html create mode 100644 branches/WOF2-1/docs/complib/comp_lib_h.html create mode 100644 branches/WOF2-1/docs/dontdiff.txt create mode 100644 branches/WOF2-1/docs/generate-patch.txt create mode 100644 branches/WOF2-1/docs/iba/ib_al_h.html create mode 100644 branches/WOF2-1/docs/iba/ib_types_h.html create mode 100644 branches/WOF2-1/docs/maintainers.txt create mode 100644 branches/WOF2-1/docs/masterindex.html create mode 100644 branches/WOF2-1/docs/openfabrics.gif create mode 100644 branches/WOF2-1/docs/robo_definitions.html create mode 100644 branches/WOF2-1/docs/robo_functions.html create mode 100644 branches/WOF2-1/docs/robo_modules.html create mode 100644 branches/WOF2-1/docs/robo_sourcefiles.html create mode 100644 branches/WOF2-1/docs/robo_strutures.html create mode 100644 branches/WOF2-1/docs/robodoc.css create mode 100644 branches/WOF2-1/etc/bldwo.bat create mode 100644 branches/WOF2-1/etc/bldwoall.bat create mode 100644 branches/WOF2-1/etc/clean-build.bat create mode 100644 branches/WOF2-1/etc/cpinst.bat create mode 100644 branches/WOF2-1/etc/kernel/index_list.c create mode 100644 branches/WOF2-1/etc/kernel/work_queue.c create mode 100644 branches/WOF2-1/etc/makebin.bat create mode 100644 branches/WOF2-1/etc/user/comp_channel.cpp create mode 100644 branches/WOF2-1/etc/user/getopt.c create mode 100644 branches/WOF2-1/etc/user/gtod.c create mode 100644 branches/WOF2-1/etc/user/inet.c create mode 100644 branches/WOF2-1/etc/wpp/ALTraceRt.cmd create mode 100644 branches/WOF2-1/etc/wpp/CreateTrace.cmd create mode 100644 branches/WOF2-1/etc/wpp/IPoIBTraceRt.cmd create mode 100644 branches/WOF2-1/etc/wpp/MTHCATraceRt.cmd create mode 100644 branches/WOF2-1/etc/wpp/SDPTraceRt.cmd create mode 100644 branches/WOF2-1/etc/wpp/StartSdpTrace.cmd create mode 100644 branches/WOF2-1/etc/wpp/StartTrace.cmd create mode 100644 branches/WOF2-1/etc/wpp/StopSdpTrace.cmd create mode 100644 branches/WOF2-1/etc/wpp/StopTrace.cmd create mode 100644 branches/WOF2-1/hw/dirs create mode 100644 branches/WOF2-1/hw/mlx4/dirs create mode 100644 branches/WOF2-1/hw/mlx4/inc/mx_abi.h create mode 100644 branches/WOF2-1/hw/mlx4/inc/public.h create mode 100644 branches/WOF2-1/hw/mlx4/inc/user.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/SOURCES create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/cache.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/core.def create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/core.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/core.rc create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/device.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/ev_log.mc create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/iobuf.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/l2w.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/l2w_debug.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/l2w_memory.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/l2w_radix.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/l2w_umem.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/makefile create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/pa_cash.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/pa_cash.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/packer.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/ud_header.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/core/verbs.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/dirs create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/bus.mof create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/bus.rc create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/drv.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/drv.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/makefile create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/makefile.inc create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/mlx4_bus.cdf create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/mlx4_bus.inx create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/mlx4_bus32.cdf create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/pci.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/pdo.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/precomp.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/sources create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/wmi.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/drv/wpptrace.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/Kconfig create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/Makefile.lnx create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/SOURCES create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/ah.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/cq.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/doorbell.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/ib.def create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/ib.rc create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/mad.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/main.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/makefile create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/mlx4_ib.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/mr.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/qp.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/ib/srq.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/bus_intf.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/cmd.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/cq.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/device.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/doorbell.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/driver.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/eq.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/ib_cache.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/ib_mad.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/ib_pack.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/ib_smi.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/ib_verbs.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/ib_verbs_ex.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/qp.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/inc/srq.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/Makefile.lnx create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/SOURCES create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/alloc.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/catas.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/cmd.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/cq.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/eq.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/fw.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/fw.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/icm.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/icm.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/intf.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/main.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/makefile create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/mcg.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/mlx4.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/mr.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/net.def create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/net.rc create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/pd.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/port.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/profile.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/qp.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/reset.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/bus/net/srq.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/dirs create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/Makefile create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/SOURCES create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/av.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/ca.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/cq.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/data.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/data.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/debug.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/direct.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/drv.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/drv.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/fw.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/hca.mof create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/hca.rc create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/hverbs.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/hverbs.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/makefile.inc create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/mcast.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/mlx4_hca.cdf create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/mlx4_hca.inx create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/mlx4_hca32.cdf create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/mr.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/pd.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/precomp.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/qp.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/srq.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/vp.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/hca/wmi.c create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/iobuf.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w_atomic.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w_bit.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w_bitmap.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w_debug.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w_list.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w_memory.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w_pci.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w_pcipool.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w_radix.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w_spinlock.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w_sync.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w_time.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/l2w_umem.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/mlx4_debug.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/shutter.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/vc.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel/inc/vip_dev.h create mode 100644 branches/WOF2-1/hw/mlx4/kernel_patches/core_0020_csum.patch create mode 100644 branches/WOF2-1/hw/mlx4/kernel_patches/core_0025_qp_create_flags.patch create mode 100644 branches/WOF2-1/hw/mlx4/kernel_patches/core_0030_lso.patch create mode 100644 branches/WOF2-1/hw/mlx4/kernel_patches/mlx4_0010_add_wc.patch create mode 100644 branches/WOF2-1/hw/mlx4/kernel_patches/mlx4_0030_checksum_offload.patch create mode 100644 branches/WOF2-1/hw/mlx4/kernel_patches/mlx4_0045_qp_flags.patch create mode 100644 branches/WOF2-1/hw/mlx4/kernel_patches/mlx4_0050_lso.patch create mode 100644 branches/WOF2-1/hw/mlx4/kernel_patches/mlx4_0170_shrinking_wqe.patch create mode 100644 branches/WOF2-1/hw/mlx4/todo.txt create mode 100644 branches/WOF2-1/hw/mlx4/user/dirs create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/Makefile create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/SOURCES create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/buf.c create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/cq.c create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/dbrec.c create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/doorbell.h create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/l2w.h create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/mlx4.c create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/mlx4.def create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/mlx4.h create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/mlx4_debug.c create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/mlx4_debug.h create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/mlx4u.rc create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/qp.c create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/srq.c create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/verbs.c create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/verbs.h create mode 100644 branches/WOF2-1/hw/mlx4/user/hca/wqe.h create mode 100644 branches/WOF2-1/hw/mthca/dirs create mode 100644 branches/WOF2-1/hw/mthca/hca_utils.c create mode 100644 branches/WOF2-1/hw/mthca/hca_utils.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/Makefile create mode 100644 branches/WOF2-1/hw/mthca/kernel/SOURCES create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca.rc create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca_data.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca_data.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca_debug.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca_direct.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca_driver.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca_driver.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca_mcast.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca_memory.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca_pci.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca_pci.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca_pnp.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca_pnp.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/hca_verbs.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/ib_cache.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/ib_mad.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/ib_pack.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/ib_smi.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/ib_verbs.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/makefile.inc create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_atomic.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_bitmap.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_cache.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_device.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_l2w.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_l2w.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_list.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_memory.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_memory.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_pa_cash.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_pa_cash.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_packer.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_pci.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_pcipool.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_reset_tavor.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_spinlock.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_sync.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_types.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_ud_header.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_uverbs.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mt_verbs.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca.cdf create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca.inx create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca32.cdf create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_allocator.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_av.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_catas.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_cmd.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_cmd.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_config_reg.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_cq.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_dev.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_doorbell.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_eq.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_log.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_log.mc create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_mad.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_main.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_mcg.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_memfree.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_memfree.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_mr.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_pd.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_profile.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_profile.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_provider.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_provider.h create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_qp.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_srq.c create mode 100644 branches/WOF2-1/hw/mthca/kernel/mthca_uar.c create mode 100644 branches/WOF2-1/hw/mthca/mt_utils.c create mode 100644 branches/WOF2-1/hw/mthca/mt_utils.h create mode 100644 branches/WOF2-1/hw/mthca/mthca_wqe.h create mode 100644 branches/WOF2-1/hw/mthca/mx_abi.h create mode 100644 branches/WOF2-1/hw/mthca/user/Makefile create mode 100644 branches/WOF2-1/hw/mthca/user/SOURCES create mode 100644 branches/WOF2-1/hw/mthca/user/arch.h create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_ual_av.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_ual_ca.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_ual_cq.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_ual_data.h create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_ual_main.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_ual_main.h create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_ual_mcast.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_ual_mrw.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_ual_osbypass.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_ual_pd.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_ual_qp.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_ual_srq.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp.def create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp.h create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp.rc create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp_ah.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp_cq.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp_debug.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp_debug.h create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp_doorbell.h create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp_memfree.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp_qp.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp_srq.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp_verbs.c create mode 100644 branches/WOF2-1/hw/mthca/user/mlnx_uvp_verbs.h create mode 100644 branches/WOF2-1/hw/mthca/user/mt_l2w.h create mode 100644 branches/WOF2-1/hw/mthca/user/opcode.h create mode 100644 branches/WOF2-1/inc/complib/cl_async_proc.h create mode 100644 branches/WOF2-1/inc/complib/cl_atomic.h create mode 100644 branches/WOF2-1/inc/complib/cl_byteswap.h create mode 100644 branches/WOF2-1/inc/complib/cl_comppool.h create mode 100644 branches/WOF2-1/inc/complib/cl_debug.h create mode 100644 branches/WOF2-1/inc/complib/cl_event.h create mode 100644 branches/WOF2-1/inc/complib/cl_fleximap.h create mode 100644 branches/WOF2-1/inc/complib/cl_ioctl.h create mode 100644 branches/WOF2-1/inc/complib/cl_irqlock.h create mode 100644 branches/WOF2-1/inc/complib/cl_list.h create mode 100644 branches/WOF2-1/inc/complib/cl_log.h create mode 100644 branches/WOF2-1/inc/complib/cl_map.h create mode 100644 branches/WOF2-1/inc/complib/cl_math.h create mode 100644 branches/WOF2-1/inc/complib/cl_memory.h create mode 100644 branches/WOF2-1/inc/complib/cl_mutex.h create mode 100644 branches/WOF2-1/inc/complib/cl_nodenamemap.h create mode 100644 branches/WOF2-1/inc/complib/cl_obj.h create mode 100644 branches/WOF2-1/inc/complib/cl_passivelock.h create mode 100644 branches/WOF2-1/inc/complib/cl_perf.h create mode 100644 branches/WOF2-1/inc/complib/cl_pool.h create mode 100644 branches/WOF2-1/inc/complib/cl_ptr_vector.h create mode 100644 branches/WOF2-1/inc/complib/cl_qcomppool.h create mode 100644 branches/WOF2-1/inc/complib/cl_qlist.h create mode 100644 branches/WOF2-1/inc/complib/cl_qlockpool.h create mode 100644 branches/WOF2-1/inc/complib/cl_qmap.h create mode 100644 branches/WOF2-1/inc/complib/cl_qpool.h create mode 100644 branches/WOF2-1/inc/complib/cl_rbmap.h create mode 100644 branches/WOF2-1/inc/complib/cl_reqmgr.h create mode 100644 branches/WOF2-1/inc/complib/cl_spinlock.h create mode 100644 branches/WOF2-1/inc/complib/cl_syscallback.h create mode 100644 branches/WOF2-1/inc/complib/cl_thread.h create mode 100644 branches/WOF2-1/inc/complib/cl_threadpool.h create mode 100644 branches/WOF2-1/inc/complib/cl_timer.h create mode 100644 branches/WOF2-1/inc/complib/cl_types.h create mode 100644 branches/WOF2-1/inc/complib/cl_vector.h create mode 100644 branches/WOF2-1/inc/complib/cl_waitobj.h create mode 100644 branches/WOF2-1/inc/complib/comp_lib.h create mode 100644 branches/WOF2-1/inc/iba/ib_al.h create mode 100644 branches/WOF2-1/inc/iba/ib_al_ioctl.h create mode 100644 branches/WOF2-1/inc/iba/ib_at_ioctl.h create mode 100644 branches/WOF2-1/inc/iba/ib_ci.h create mode 100644 branches/WOF2-1/inc/iba/ib_types.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_atomic_osd.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_bus_ifc.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_byteswap_osd.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_debug_osd.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_event_osd.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_init.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_ioctl_osd.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_irqlock_osd.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_memory_osd.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_mutex_osd.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_packoff.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_packon.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_pnp_po.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_spinlock_osd.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_syscallback_osd.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_thread_osd.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_timer_osd.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_types_osd.h create mode 100644 branches/WOF2-1/inc/kernel/complib/cl_waitobj_osd.h create mode 100644 branches/WOF2-1/inc/kernel/iba/ib_al_ifc.h create mode 100644 branches/WOF2-1/inc/kernel/iba/ib_ci_ifc.h create mode 100644 branches/WOF2-1/inc/kernel/iba/ib_cm_ifc.h create mode 100644 branches/WOF2-1/inc/kernel/iba/ib_rdma_cm.h create mode 100644 branches/WOF2-1/inc/kernel/iba/ioc_ifc.h create mode 100644 branches/WOF2-1/inc/kernel/iba/iou_ifc.h create mode 100644 branches/WOF2-1/inc/kernel/iba/ipoib_ifc.h create mode 100644 branches/WOF2-1/inc/kernel/index_list.h create mode 100644 branches/WOF2-1/inc/kernel/ip_packet.h create mode 100644 branches/WOF2-1/inc/kernel/rdma/verbs.h create mode 100644 branches/WOF2-1/inc/kernel/work_queue.h create mode 100644 branches/WOF2-1/inc/mod_ver.def create mode 100644 branches/WOF2-1/inc/mthca/mthca_vc.h create mode 100644 branches/WOF2-1/inc/oib_ver.h create mode 100644 branches/WOF2-1/inc/openib.def create mode 100644 branches/WOF2-1/inc/user/comp_channel.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_atomic_osd.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_byteswap_osd.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_debug_osd.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_event_osd.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_ioctl_osd.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_memory_osd.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_mutex_osd.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_packoff.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_packon.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_spinlock_osd.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_syscallback_osd.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_thread_osd.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_timer_osd.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_types_osd.h create mode 100644 branches/WOF2-1/inc/user/complib/cl_waitobj_osd.h create mode 100644 branches/WOF2-1/inc/user/dlist.h create mode 100644 branches/WOF2-1/inc/user/getopt.h create mode 100644 branches/WOF2-1/inc/user/iba/ib_uvp.h create mode 100644 branches/WOF2-1/inc/user/iba/ibat.h create mode 100644 branches/WOF2-1/inc/user/iba/winmad.h create mode 100644 branches/WOF2-1/inc/user/linux/_string.h create mode 100644 branches/WOF2-1/inc/user/linux/arpa/inet.h create mode 100644 branches/WOF2-1/inc/user/linux/inttypes.h create mode 100644 branches/WOF2-1/inc/user/linux/netinet/in.h create mode 100644 branches/WOF2-1/inc/user/linux/sys/time.h create mode 100644 branches/WOF2-1/inc/user/linux/unistd.h create mode 100644 branches/WOF2-1/inc/user/rdma/winverbs.h create mode 100644 branches/WOF2-1/inc/user/rdma/wvstatus.h create mode 100644 branches/WOF2-1/inc/user/wsd/ibsp_regpath.h create mode 100644 branches/WOF2-1/tests/alts/allocdeallocpd.c create mode 100644 branches/WOF2-1/tests/alts/alts_common.h create mode 100644 branches/WOF2-1/tests/alts/alts_debug.h create mode 100644 branches/WOF2-1/tests/alts/alts_misc.c create mode 100644 branches/WOF2-1/tests/alts/alts_readme.txt create mode 100644 branches/WOF2-1/tests/alts/cmtests.c create mode 100644 branches/WOF2-1/tests/alts/createanddestroycq.c create mode 100644 branches/WOF2-1/tests/alts/createanddestroyqp.c create mode 100644 branches/WOF2-1/tests/alts/createdestroyav.c create mode 100644 branches/WOF2-1/tests/alts/creatememwindow.c create mode 100644 branches/WOF2-1/tests/alts/dirs create mode 100644 branches/WOF2-1/tests/alts/ibquery.c create mode 100644 branches/WOF2-1/tests/alts/kernel/SOURCES create mode 100644 branches/WOF2-1/tests/alts/kernel/alts.inf create mode 100644 branches/WOF2-1/tests/alts/kernel/alts.rc create mode 100644 branches/WOF2-1/tests/alts/kernel/alts_driver.c create mode 100644 branches/WOF2-1/tests/alts/kernel/alts_driver.h create mode 100644 branches/WOF2-1/tests/alts/kernel/makefile create mode 100644 branches/WOF2-1/tests/alts/madtests.c create mode 100644 branches/WOF2-1/tests/alts/multisendrecv.c create mode 100644 branches/WOF2-1/tests/alts/openclose.c create mode 100644 branches/WOF2-1/tests/alts/querycaattr.c create mode 100644 branches/WOF2-1/tests/alts/registermemregion.c create mode 100644 branches/WOF2-1/tests/alts/registerpnp.c create mode 100644 branches/WOF2-1/tests/alts/smatests.c create mode 100644 branches/WOF2-1/tests/alts/user/SOURCES create mode 100644 branches/WOF2-1/tests/alts/user/alts_main.c create mode 100644 branches/WOF2-1/tests/alts/user/makefile create mode 100644 branches/WOF2-1/tests/cmtest/dirs create mode 100644 branches/WOF2-1/tests/cmtest/user/SOURCES create mode 100644 branches/WOF2-1/tests/cmtest/user/cmtest.rc create mode 100644 branches/WOF2-1/tests/cmtest/user/cmtest_main.c create mode 100644 branches/WOF2-1/tests/cmtest/user/makefile create mode 100644 branches/WOF2-1/tests/dirs create mode 100644 branches/WOF2-1/tests/ibat/dirs create mode 100644 branches/WOF2-1/tests/ibat/user/PrintIp.c create mode 100644 branches/WOF2-1/tests/ibat/user/SOURCES create mode 100644 branches/WOF2-1/tests/ibat/user/makefile create mode 100644 branches/WOF2-1/tests/limits/dirs create mode 100644 branches/WOF2-1/tests/limits/user/SOURCES create mode 100644 branches/WOF2-1/tests/limits/user/limits_main.c create mode 100644 branches/WOF2-1/tests/limits/user/makefile create mode 100644 branches/WOF2-1/tests/perftest/dirs create mode 100644 branches/WOF2-1/tests/perftest/perftest.c create mode 100644 branches/WOF2-1/tests/perftest/perftest.h create mode 100644 branches/WOF2-1/tests/perftest/rdma_bw/SOURCES create mode 100644 branches/WOF2-1/tests/perftest/rdma_bw/makefile create mode 100644 branches/WOF2-1/tests/perftest/rdma_bw/rdma_bw.c create mode 100644 branches/WOF2-1/tests/perftest/rdma_bw/rdma_bw.rc create mode 100644 branches/WOF2-1/tests/perftest/rdma_lat/SOURCES create mode 100644 branches/WOF2-1/tests/perftest/rdma_lat/makefile create mode 100644 branches/WOF2-1/tests/perftest/rdma_lat/rdma_lat.c create mode 100644 branches/WOF2-1/tests/perftest/rdma_lat/rdma_lat.rc create mode 100644 branches/WOF2-1/tests/perftest/read_bw/SOURCES create mode 100644 branches/WOF2-1/tests/perftest/read_bw/makefile create mode 100644 branches/WOF2-1/tests/perftest/read_bw/read_bw.c create mode 100644 branches/WOF2-1/tests/perftest/read_bw/read_bw.rc create mode 100644 branches/WOF2-1/tests/perftest/read_lat/SOURCES create mode 100644 branches/WOF2-1/tests/perftest/read_lat/makefile create mode 100644 branches/WOF2-1/tests/perftest/read_lat/read_lat.c create mode 100644 branches/WOF2-1/tests/perftest/read_lat/read_lat.rc create mode 100644 branches/WOF2-1/tests/perftest/send_bw/SOURCES create mode 100644 branches/WOF2-1/tests/perftest/send_bw/makefile create mode 100644 branches/WOF2-1/tests/perftest/send_bw/send_bw.c create mode 100644 branches/WOF2-1/tests/perftest/send_bw/send_bw.rc create mode 100644 branches/WOF2-1/tests/perftest/send_lat/SOURCES create mode 100644 branches/WOF2-1/tests/perftest/send_lat/makefile create mode 100644 branches/WOF2-1/tests/perftest/send_lat/send_lat.c create mode 100644 branches/WOF2-1/tests/perftest/send_lat/send_lat.rc create mode 100644 branches/WOF2-1/tests/perftest/write_bw/SOURCES create mode 100644 branches/WOF2-1/tests/perftest/write_bw/makefile create mode 100644 branches/WOF2-1/tests/perftest/write_bw/write_bw.c create mode 100644 branches/WOF2-1/tests/perftest/write_bw/write_bw.rc create mode 100644 branches/WOF2-1/tests/perftest/write_bw_postlist/SOURCES create mode 100644 branches/WOF2-1/tests/perftest/write_bw_postlist/makefile create mode 100644 branches/WOF2-1/tests/perftest/write_bw_postlist/write_bw_postlist.c create mode 100644 branches/WOF2-1/tests/perftest/write_bw_postlist/write_bw_postlist.rc create mode 100644 branches/WOF2-1/tests/perftest/write_lat/SOURCES create mode 100644 branches/WOF2-1/tests/perftest/write_lat/makefile create mode 100644 branches/WOF2-1/tests/perftest/write_lat/write_lat.c create mode 100644 branches/WOF2-1/tests/perftest/write_lat/write_lat.rc create mode 100644 branches/WOF2-1/tests/wherebu/dirs create mode 100644 branches/WOF2-1/tests/wherebu/user/SOURCES create mode 100644 branches/WOF2-1/tests/wherebu/user/makefile create mode 100644 branches/WOF2-1/tests/wherebu/user/wherebu.cpp create mode 100644 branches/WOF2-1/tests/wsd/dirs create mode 100644 branches/WOF2-1/tests/wsd/user/contest/contest.c create mode 100644 branches/WOF2-1/tests/wsd/user/contest/contest.h create mode 100644 branches/WOF2-1/tests/wsd/user/dirs create mode 100644 branches/WOF2-1/tests/wsd/user/test1/test1.c create mode 100644 branches/WOF2-1/tests/wsd/user/test2/ibwrap.c create mode 100644 branches/WOF2-1/tests/wsd/user/test2/ibwrap.h create mode 100644 branches/WOF2-1/tests/wsd/user/test2/test2.c create mode 100644 branches/WOF2-1/tests/wsd/user/test3/ibwrap.c create mode 100644 branches/WOF2-1/tests/wsd/user/test3/ibwrap.h create mode 100644 branches/WOF2-1/tests/wsd/user/test3/test3.c create mode 100644 branches/WOF2-1/tests/wsd/user/ttcp/SOURCES create mode 100644 branches/WOF2-1/tests/wsd/user/ttcp/makefile create mode 100644 branches/WOF2-1/tests/wsd/user/ttcp/ttcp.c create mode 100644 branches/WOF2-1/tools/dirs create mode 100644 branches/WOF2-1/tools/infiniband-diags/dirs create mode 100644 branches/WOF2-1/tools/infiniband-diags/include/grouping.h create mode 100644 branches/WOF2-1/tools/infiniband-diags/include/ibdiag_common.h create mode 100644 branches/WOF2-1/tools/infiniband-diags/include/ibnetdiscover.h create mode 100644 branches/WOF2-1/tools/infiniband-diags/include/windows/config.h create mode 100644 branches/WOF2-1/tools/infiniband-diags/include/windows/ibdiag_version.h create mode 100644 branches/WOF2-1/tools/infiniband-diags/patches/ibping-cdecl.diff create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/dirs create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/grouping.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibaddr.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibaddr/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibaddr/ibaddr.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibaddr/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibdiag_common.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibdiag_windows.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/iblinkinfo.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/iblinkinfo/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/iblinkinfo/iblinkinfo.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/iblinkinfo/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibnetdiscover.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibnetdiscover/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibnetdiscover/ibnetdiscover.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibnetdiscover/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibping.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibping/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibping/ibping.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibping/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibportstate.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibportstate/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibportstate/ibportstate.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibportstate/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibqueryerrors.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibqueryerrors/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibqueryerrors/ibqueryerrors.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibqueryerrors/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibroute.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibroute/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibroute/ibroute.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibroute/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibsendtrap.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibsendtrap/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibsendtrap/ibsendtrap.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibsendtrap/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibstat.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibstat/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibstat/ibstat.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibstat/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibsysstat.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibsysstat/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibsysstat/ibsysstat.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibsysstat/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibtracert.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibtracert/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibtracert/ibtracert.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/ibtracert/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/mcm_rereg_test.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/mcm_rereg_test/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/mcm_rereg_test/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/mcm_rereg_test/mcm_rereg_test.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/perfquery.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/perfquery/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/perfquery/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/perfquery/perfquery.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/saquery.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/saquery/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/saquery/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/saquery/saquery.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/sminfo.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/sminfo/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/sminfo/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/sminfo/sminfo.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/smpdump.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/smpdump/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/smpdump/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/smpdump/smpdump.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/smpquery.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/smpquery/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/smpquery/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/smpquery/smpquery.rc create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/vendstat.c create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/vendstat/SOURCES create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/vendstat/makefile create mode 100644 branches/WOF2-1/tools/infiniband-diags/src/vendstat/vendstat.rc create mode 100644 branches/WOF2-1/tools/ndinstall/dirs create mode 100644 branches/WOF2-1/tools/ndinstall/user/SOURCES create mode 100644 branches/WOF2-1/tools/ndinstall/user/installsp.c create mode 100644 branches/WOF2-1/tools/ndinstall/user/installsp.rc create mode 100644 branches/WOF2-1/tools/ndinstall/user/makefile create mode 100644 branches/WOF2-1/tools/nsc/SOURCES create mode 100644 branches/WOF2-1/tools/nsc/makefile create mode 100644 branches/WOF2-1/tools/nsc/nsc.c create mode 100644 branches/WOF2-1/tools/nsc/nsc.rc create mode 100644 branches/WOF2-1/tools/part_man/dirs create mode 100644 branches/WOF2-1/tools/part_man/user/SOURCES create mode 100644 branches/WOF2-1/tools/part_man/user/makefile create mode 100644 branches/WOF2-1/tools/part_man/user/part_man.c create mode 100644 branches/WOF2-1/tools/part_man/user/part_man.rc create mode 100644 branches/WOF2-1/tools/perftests/dirs create mode 100644 branches/WOF2-1/tools/perftests/user/README create mode 100644 branches/WOF2-1/tools/perftests/user/TODO create mode 100644 branches/WOF2-1/tools/perftests/user/clock_test.c create mode 100644 branches/WOF2-1/tools/perftests/user/dirs create mode 100644 branches/WOF2-1/tools/perftests/user/get_clock.c create mode 100644 branches/WOF2-1/tools/perftests/user/get_clock.h create mode 100644 branches/WOF2-1/tools/perftests/user/getopt.c create mode 100644 branches/WOF2-1/tools/perftests/user/getopt.h create mode 100644 branches/WOF2-1/tools/perftests/user/perf_defs.h create mode 100644 branches/WOF2-1/tools/perftests/user/perf_utils.c create mode 100644 branches/WOF2-1/tools/perftests/user/read_bw/SOURCES create mode 100644 branches/WOF2-1/tools/perftests/user/read_bw/makefile create mode 100644 branches/WOF2-1/tools/perftests/user/read_bw/read_bw.c create mode 100644 branches/WOF2-1/tools/perftests/user/read_bw/read_bw.rc create mode 100644 branches/WOF2-1/tools/perftests/user/read_lat/SOURCES create mode 100644 branches/WOF2-1/tools/perftests/user/read_lat/makefile create mode 100644 branches/WOF2-1/tools/perftests/user/read_lat/read_lat.c create mode 100644 branches/WOF2-1/tools/perftests/user/read_lat/read_lat.rc create mode 100644 branches/WOF2-1/tools/perftests/user/send_bw/SOURCES create mode 100644 branches/WOF2-1/tools/perftests/user/send_bw/makefile create mode 100644 branches/WOF2-1/tools/perftests/user/send_bw/send_bw.c create mode 100644 branches/WOF2-1/tools/perftests/user/send_bw/send_bw.rc create mode 100644 branches/WOF2-1/tools/perftests/user/send_lat/SOURCES create mode 100644 branches/WOF2-1/tools/perftests/user/send_lat/makefile create mode 100644 branches/WOF2-1/tools/perftests/user/send_lat/send_lat.c create mode 100644 branches/WOF2-1/tools/perftests/user/send_lat/send_lat.rc create mode 100644 branches/WOF2-1/tools/perftests/user/write_bw/SOURCES create mode 100644 branches/WOF2-1/tools/perftests/user/write_bw/makefile create mode 100644 branches/WOF2-1/tools/perftests/user/write_bw/write_bw.c create mode 100644 branches/WOF2-1/tools/perftests/user/write_bw/write_bw.rc create mode 100644 branches/WOF2-1/tools/perftests/user/write_lat/SOURCES create mode 100644 branches/WOF2-1/tools/perftests/user/write_lat/makefile create mode 100644 branches/WOF2-1/tools/perftests/user/write_lat/write_lat.c create mode 100644 branches/WOF2-1/tools/perftests/user/write_lat/write_lat.rc create mode 100644 branches/WOF2-1/tools/qlgcvnic_config/SOURCES create mode 100644 branches/WOF2-1/tools/qlgcvnic_config/makefile create mode 100644 branches/WOF2-1/tools/qlgcvnic_config/qlgcvnic_config.rc create mode 100644 branches/WOF2-1/tools/qlgcvnic_config/vnic_child_config.c create mode 100644 branches/WOF2-1/tools/vstat/dirs create mode 100644 branches/WOF2-1/tools/vstat/user/SOURCES create mode 100644 branches/WOF2-1/tools/vstat/user/makefile create mode 100644 branches/WOF2-1/tools/vstat/user/vstat.rc create mode 100644 branches/WOF2-1/tools/vstat/user/vstat_main.c create mode 100644 branches/WOF2-1/tools/wsdinstall/dirs create mode 100644 branches/WOF2-1/tools/wsdinstall/user/InstallSP.sln create mode 100644 branches/WOF2-1/tools/wsdinstall/user/SOURCES create mode 100644 branches/WOF2-1/tools/wsdinstall/user/installsp.c create mode 100644 branches/WOF2-1/tools/wsdinstall/user/installsp.exe.manifest create mode 100644 branches/WOF2-1/tools/wsdinstall/user/installsp.rc create mode 100644 branches/WOF2-1/tools/wsdinstall/user/makefile create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_adapter_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_create.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_free.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_modify_agent.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_query.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_wait.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cookie.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cookie.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_accept.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_callback.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_handoff.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_query.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_reject.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_debug.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_connect.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_create.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_disconnect.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_dup_connect.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_free.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_get_status.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_modify.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_post_rdma_read.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_post_rdma_write.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_post_recv.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_post_send.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_query.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_reset.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_clear_unwaitable.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_connection_callb.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_cq_async_error_callb.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_create.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_dequeue.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_disable.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_dto_callb.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_enable.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_free.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_modify_cno.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_post_se.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_qp_async_error_callb.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_query.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_resize.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_set_unwaitable.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_un_async_error_callb.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_wait.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_get_consumer_context.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_get_handle_type.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_hash.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_hash.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_hca_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_hca_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ia_close.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ia_open.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ia_query.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ia_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ia_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_init.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_llist.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_lmr_create.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_lmr_free.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_lmr_query.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_lmr_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_lmr_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_mr_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_mr_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_provider.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_provider.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_psp_create.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_psp_create_any.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_psp_free.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_psp_query.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_pz_create.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_pz_free.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_pz_query.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_pz_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_pz_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ring_buffer_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_ring_buffer_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_rmr_bind.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_rmr_create.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_rmr_free.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_rmr_query.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_rmr_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_rmr_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_rsp_create.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_rsp_free.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_rsp_query.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_set_consumer_context.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_sp_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/common/dapl_sp_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/dirs create mode 100644 branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_cm.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_dto.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_kmod.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_qp.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/include/dapl.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/include/dapl_debug.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/include/dapl_ipoib_names.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/include/dapl_vendor.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/Makefile.cygwin create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/Makefile.org create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/Makefile.orig create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/SOURCES create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/dapl_init.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/dapl_name_service.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/dapl_name_service.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/dapl_timer_util.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/dapl_timer_util.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/linux/dapl_osd.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/linux/dapl_osd.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/makefile create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/makefile.wnd create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/udapl.rc create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/udapl_exports.src create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/udapl_sources.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/windows/dapl_osd.c create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/windows/dapl_osd.h create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/windows/dapl_win.def create mode 100644 branches/WOF2-1/ulp/dapl/dapl/udapl/windows/dapllib.rc create mode 100644 branches/WOF2-1/ulp/dapl/dat/common/dat_dictionary.c create mode 100644 branches/WOF2-1/ulp/dapl/dat/common/dat_dictionary.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/common/dat_dr.c create mode 100644 branches/WOF2-1/ulp/dapl/dat/common/dat_dr.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/common/dat_init.c create mode 100644 branches/WOF2-1/ulp/dapl/dat/common/dat_init.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/common/dat_sr.c create mode 100644 branches/WOF2-1/ulp/dapl/dat/common/dat_sr.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/common/dat_strerror.c create mode 100644 branches/WOF2-1/ulp/dapl/dat/dirs create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/dat.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/dat_error.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/dat_platform_specific.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/dat_redirection.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/dat_registry.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/dat_vendor_specific.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/kdat.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/kdat_config.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/kdat_redirection.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/kdat_vendor_specific.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/udat.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/udat_config.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/udat_redirection.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/include/dat/udat_vendor_specific.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/kdat/Makefile create mode 100644 branches/WOF2-1/ulp/dapl/dat/kdat/dat_kdapl.c create mode 100644 branches/WOF2-1/ulp/dapl/dat/kdat/dat_module.c create mode 100644 branches/WOF2-1/ulp/dapl/dat/kdat/linux/dat_osd.c create mode 100644 branches/WOF2-1/ulp/dapl/dat/kdat/linux/dat_osd.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/Makefile.cygwin create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/Makefile.org create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/Makefile.orig create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/SOURCES create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/dat.conf create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/ibhosts create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/linux/dat-1.1.spec create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/linux/dat_osd.c create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/linux/dat_osd.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/makefile create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/makefile.wnd create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/udat.c create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/udat.rc create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/udat_exports.src create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/udat_sources.c create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/udat_sr_parser.c create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/udat_sr_parser.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/windows/dat_osd.c create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/windows/dat_osd.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/windows/dat_osd_sr.h create mode 100644 branches/WOF2-1/ulp/dapl/dat/udat/windows/dat_win.def create mode 100644 branches/WOF2-1/ulp/dapl/dirs create mode 100644 branches/WOF2-1/ulp/dapl/doc/dapl_coding_style.txt create mode 100644 branches/WOF2-1/ulp/dapl/doc/dapl_end_point_design.txt create mode 100644 branches/WOF2-1/ulp/dapl/doc/dapl_environ.txt create mode 100644 branches/WOF2-1/ulp/dapl/doc/dapl_event_design.txt create mode 100644 branches/WOF2-1/ulp/dapl/doc/dapl_memory_management_design.txt create mode 100644 branches/WOF2-1/ulp/dapl/doc/dapl_registry_design.txt create mode 100644 branches/WOF2-1/ulp/dapl/doc/dapl_shared_memory_design.txt create mode 100644 branches/WOF2-1/ulp/dapl/doc/dapl_vendor_specific_changes.txt create mode 100644 branches/WOF2-1/ulp/dapl/doc/dat.conf create mode 100644 branches/WOF2-1/ulp/dapl/doc/dat_environ.txt create mode 100644 branches/WOF2-1/ulp/dapl/doc/ibhosts create mode 100644 branches/WOF2-1/ulp/dapl/doc/mv_dapl_readme.txt create mode 100644 branches/WOF2-1/ulp/dapl/doc/mv_dapl_relnotes.txt create mode 100644 branches/WOF2-1/ulp/dapl/test/dirs create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/.DT_defaults create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/.DT_onetest create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/.DT_perf.csh create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/DaplTest_how_2.txt create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/Makefile.cygwin create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/Makefile.org create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/Makefile.orig create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/SOURCES create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/bw.sh create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/cl.sh create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_bpool.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_bpool.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_client.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_client_info.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_client_info.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_cnxn.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_cnxn.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_common.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_endian.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_connmgt.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer_client.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_endpoint.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_hwconn.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_mem.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_pz.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_queryinfo.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_test.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_util.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_util.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_funcs.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_getopt.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_getopt.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_limit.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_main.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_mdep.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_mdep.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_memlist.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_memlist.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_netaddr.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_params.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_params.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_client.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_server.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_test.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_util.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_proto.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_server.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_server_info.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_server_info.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_test_data.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_test_data.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_test_util.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_thread.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_util.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_util.c create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_version.h create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapltest.rc create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/lat_block.sh create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/lat_poll.sh create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/lim.sh create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/makefile create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/makefile.wnd create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/quit.sh create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/regress.sh create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dapltest/srv.sh create mode 100644 branches/WOF2-1/ulp/dapl/test/udapl/dirs create mode 100644 branches/WOF2-1/ulp/dapl2/AUTHORS create mode 100644 branches/WOF2-1/ulp/dapl2/COPYING create mode 100644 branches/WOF2-1/ulp/dapl2/ChangeLog create mode 100644 branches/WOF2-1/ulp/dapl2/LICENSE.txt create mode 100644 branches/WOF2-1/ulp/dapl2/LICENSE2.txt create mode 100644 branches/WOF2-1/ulp/dapl2/LICENSE3.txt create mode 100644 branches/WOF2-1/ulp/dapl2/Makefile.am create mode 100644 branches/WOF2-1/ulp/dapl2/README create mode 100644 branches/WOF2-1/ulp/dapl2/README.windows create mode 100644 branches/WOF2-1/ulp/dapl2/autogen.sh create mode 100644 branches/WOF2-1/ulp/dapl2/configure.in create mode 100644 branches/WOF2-1/ulp/dapl2/dapl.spec.in create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_adapter_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cno_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cno_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cookie.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cookie.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_accept.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_callback.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_handoff.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_query.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_reject.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_csp.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_debug.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_connect.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_create.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_create_with_srq.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_disconnect.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_dup_connect.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_free.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_get_status.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_modify.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read_to_rmr.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_post_rdma_write.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_post_recv.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_post_send.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_post_send_invalidate.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_query.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_recv_query.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_reset.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_set_watermark.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_connection_callb.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_cq_async_error_callb.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_dequeue.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_dto_callb.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_free.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_post_se.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_qp_async_error_callb.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_resize.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_un_async_error_callb.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_get_consumer_context.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_get_handle_type.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_hash.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_hash.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_hca_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_hca_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ia_close.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ia_ha.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ia_open.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ia_query.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ia_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ia_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_init.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_llist.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_lmr_free.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_lmr_query.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_read.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_write.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_lmr_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_lmr_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_mr_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_mr_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_name_service.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_name_service.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_provider.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_provider.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_psp_create.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_psp_create_any.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_psp_free.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_psp_query.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_pz_create.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_pz_free.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_pz_query.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_pz_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_pz_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ring_buffer_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ring_buffer_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rmr_bind.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rmr_create.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rmr_free.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rmr_query.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rmr_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rmr_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rsp_create.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rsp_free.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rsp_query.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_set_consumer_context.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_sp_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_sp_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_create.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_free.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_post_recv.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_query.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_resize.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_set_lw.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_timer_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/common/dapl_timer_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/dapl_common_src.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/dapl_udapl_src.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/dirs create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/SOURCES create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_cm.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_cq.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_dto.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_extensions.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_kmod.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_qp.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/makefile create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/udapl.rc create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/ibal/udapl_exports.src create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/include/dapl.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/include/dapl_debug.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/include/dapl_ipoib_names.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/include/dapl_vendor.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_cma/README create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_cma/SOURCES create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_cma/cm.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_cma/dapl_ib_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_cma/device.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_cma/libdaplcma.map create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_cma/linux/openib_osd.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_cma/makefile create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_cma/udapl.rc create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_cma/udapl_ofa_cma_exports.src create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_cma/windows/openib_osd.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_common.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_common/cq.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_common/dapl_ib_common.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_common/dapl_ib_dto.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_common/ib_extensions.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_common/mem.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_common/qp.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_common/util.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_scm/SOURCES create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_scm/cm.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_scm/dapl_ib_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_scm/device.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_scm/libdaplscm.map create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_scm/linux/openib_osd.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_scm/makefile create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_scm/udapl.rc create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_scm/udapl_ofa_scm_exports.src create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/openib_scm/windows/openib_osd.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_cno_create.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_cno_free.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_cno_modify_agent.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_cno_query.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_cno_wait.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_clear_unwaitable.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_create.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_disable.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_enable.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_modify_cno.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_query.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_set_unwaitable.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_wait.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_init.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_lmr_create.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/libdaplofa.map create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/libdaploscm.map create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/libdaplscm.map create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/linux/dapl_osd.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/linux/dapl_osd.h create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/windows/dapl_osd.c create mode 100644 branches/WOF2-1/ulp/dapl2/dapl/udapl/windows/dapl_osd.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/common/dat_api.c create mode 100644 branches/WOF2-1/ulp/dapl2/dat/common/dat_dictionary.c create mode 100644 branches/WOF2-1/ulp/dapl2/dat/common/dat_dictionary.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/common/dat_dr.c create mode 100644 branches/WOF2-1/ulp/dapl2/dat/common/dat_dr.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/common/dat_init.c create mode 100644 branches/WOF2-1/ulp/dapl2/dat/common/dat_init.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/common/dat_sr.c create mode 100644 branches/WOF2-1/ulp/dapl2/dat/common/dat_sr.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/common/dat_strerror.c create mode 100644 branches/WOF2-1/ulp/dapl2/dat/dirs create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_error.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_ib_extensions.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_iw_extensions.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_platform_specific.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_redirection.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_registry.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_vendor_specific.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/kdat.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/kdat_config.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/kdat_redirection.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/kdat_vendor_specific.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/udat.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/udat_config.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/udat_redirection.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/include/dat2/udat_vendor_specific.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/SOURCES create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/libdat2.map create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/linux/dat-registry-1.1.spec create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/linux/dat_osd.c create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/linux/dat_osd.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/makefile create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/udat.c create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/udat.rc create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/udat_api.c create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/udat_exports.src create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/udat_sources.c create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/udat_sr_parser.c create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/udat_sr_parser.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/windows/dat_osd.c create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/windows/dat_osd.h create mode 100644 branches/WOF2-1/ulp/dapl2/dat/udat/windows/dat_osd_sr.h create mode 100644 branches/WOF2-1/ulp/dapl2/dirs create mode 100644 branches/WOF2-1/ulp/dapl2/doc/dapl_coding_style.txt create mode 100644 branches/WOF2-1/ulp/dapl2/doc/dapl_end_point_design.txt create mode 100644 branches/WOF2-1/ulp/dapl2/doc/dapl_environ.txt create mode 100644 branches/WOF2-1/ulp/dapl2/doc/dapl_event_design.txt create mode 100644 branches/WOF2-1/ulp/dapl2/doc/dapl_ibm_api_variations.txt create mode 100644 branches/WOF2-1/ulp/dapl2/doc/dapl_memory_management_design.txt create mode 100644 branches/WOF2-1/ulp/dapl2/doc/dapl_patch.txt create mode 100644 branches/WOF2-1/ulp/dapl2/doc/dapl_registry_design.txt create mode 100644 branches/WOF2-1/ulp/dapl2/doc/dapl_shared_memory_design.txt create mode 100644 branches/WOF2-1/ulp/dapl2/doc/dapl_vendor_specific_changes.txt create mode 100644 branches/WOF2-1/ulp/dapl2/doc/dat_environ.txt create mode 100644 branches/WOF2-1/ulp/dapl2/doc/uDAPL_release_notes.txt create mode 100644 branches/WOF2-1/ulp/dapl2/man/dapltest.1 create mode 100644 branches/WOF2-1/ulp/dapl2/man/dat.conf.5 create mode 100644 branches/WOF2-1/ulp/dapl2/man/dtest.1 create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/Makefile.am create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/README create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_fft_cmd.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_getopt.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_limit_cmd.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_main.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_netaddr.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_params.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_performance_cmd.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_qos_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_quit_cmd.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_server_cmd.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_test_data.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_transaction_cmd.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/common/dapl_endian.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/common/dapl_global.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/common/dapl_performance_cmd_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/common/dapl_quit_cmd_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/common/dapl_transaction_cmd_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/configure.in create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/dirs create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/dt_cmd.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/dt_common.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/dt_mdep.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/dt_test.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/dt_udapl.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_bpool.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_client_info.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_common.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_execute.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_fft_cmd.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_fft_util.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_getopt.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_global.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_limit_cmd.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_mdep.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_memlist.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_params.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_performance_cmd.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_performance_stats.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_performance_test.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_proto.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_quit_cmd.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_server_cmd.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_server_info.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_tdep.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_tdep_print.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_test_data.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_transaction_cmd.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_transaction_stats.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_transaction_test.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_version.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.h create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/cl.sh create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/dt-cli.bat create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/dt-svr.bat create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/kregress.sh create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/ksrv.sh create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/lim.sh create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/regress.sh create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/srv.sh create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_bpool.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_client.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_client_info.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_cnxn.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_execute.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_connmgt.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer_client.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_endpoint.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_hwconn.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_mem.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_pz.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_queryinfo.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_test.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_limit.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_memlist.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_performance_client.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_performance_server.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_performance_stats.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_performance_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_quit_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_server.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_server_info.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_test_data.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_test_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_thread.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_transaction_stats.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_transaction_test.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_transaction_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_util.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/udapl/udapl_tdep.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/windows/SOURCES create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/windows/dapltest.rc create mode 100644 branches/WOF2-1/ulp/dapl2/test/dapltest/windows/makefile create mode 100644 branches/WOF2-1/ulp/dapl2/test/dirs create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/Makefile.am create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/README create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/configure.in create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/dirs create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/dtc.bat create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/dtest.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/dtestcm.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/dtestx.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/dts.bat create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/windows/dirs create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtest/SOURCES create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtest/dtest.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtest/dtest.rc create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtest/makefile create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestcm/SOURCES create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.rc create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestcm/makefile create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestx/SOURCES create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestx/dtestx.c create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestx/dtestx.rc create mode 100644 branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestx/makefile create mode 100644 branches/WOF2-1/ulp/dirs create mode 100644 branches/WOF2-1/ulp/ipoib/dirs create mode 100644 branches/WOF2-1/ulp/ipoib/ip_stats.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/SOURCES create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib.cdf create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib.rc create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib32-xp.cdf create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib32.cdf create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_adapter.c create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_adapter.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_debug.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_driver.c create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_driver.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_endpoint.c create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_endpoint.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_ibat.c create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_ibat.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_log.mc create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_port.c create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_port.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_xfr_mgr.c create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/ipoib_xfr_mgr.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/makefile create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/makefile.inc create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/netipoib-xp32.inf create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/netipoib.inx create mode 100644 branches/WOF2-1/ulp/ipoib/kernel/offload.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/SOURCES create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib.cdf create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib.rc create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib32-xp.cdf create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib32.cdf create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_adapter.c create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_adapter.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_cm.c create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_debug.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_driver.c create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_driver.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_endpoint.c create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_endpoint.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_ibat.c create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_ibat.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_log.mc create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_port.c create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_port.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_xfr_mgr.c create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/ipoib_xfr_mgr.h create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/makefile create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/makefile.inc create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/netipoib-xp32.inf create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/netipoib.inx create mode 100644 branches/WOF2-1/ulp/ipoib/kernel6/offload.h create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/dirs create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/ip_stats.h create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/SOURCES create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib.cdf create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib.rc create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib32.cdf create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.cpp create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.cpp create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.h create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.cpp create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.h create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.cpp create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.h create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.cpp create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.h create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/makefile create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/makefile.inc create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/netipoib.inx create mode 100644 branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/offload.h create mode 100644 branches/WOF2-1/ulp/libibmad/README.txt create mode 100644 branches/WOF2-1/ulp/libibmad/dirs create mode 100644 branches/WOF2-1/ulp/libibmad/include/infiniband/mad.h create mode 100644 branches/WOF2-1/ulp/libibmad/include/infiniband/mad_osd.h create mode 100644 branches/WOF2-1/ulp/libibmad/src/Sources create mode 100644 branches/WOF2-1/ulp/libibmad/src/bm.c create mode 100644 branches/WOF2-1/ulp/libibmad/src/dump.c create mode 100644 branches/WOF2-1/ulp/libibmad/src/fields.c create mode 100644 branches/WOF2-1/ulp/libibmad/src/gs.c create mode 100644 branches/WOF2-1/ulp/libibmad/src/ibmad.rc create mode 100644 branches/WOF2-1/ulp/libibmad/src/ibmad_export.def create mode 100644 branches/WOF2-1/ulp/libibmad/src/ibmad_exports.src create mode 100644 branches/WOF2-1/ulp/libibmad/src/ibmad_main.cpp create mode 100644 branches/WOF2-1/ulp/libibmad/src/libibmad.map create mode 100644 branches/WOF2-1/ulp/libibmad/src/mad.c create mode 100644 branches/WOF2-1/ulp/libibmad/src/mad_internal.h create mode 100644 branches/WOF2-1/ulp/libibmad/src/makefile create mode 100644 branches/WOF2-1/ulp/libibmad/src/portid.c create mode 100644 branches/WOF2-1/ulp/libibmad/src/register.c create mode 100644 branches/WOF2-1/ulp/libibmad/src/resolve.c create mode 100644 branches/WOF2-1/ulp/libibmad/src/rpc.c create mode 100644 branches/WOF2-1/ulp/libibmad/src/sa.c create mode 100644 branches/WOF2-1/ulp/libibmad/src/serv.c create mode 100644 branches/WOF2-1/ulp/libibmad/src/smp.c create mode 100644 branches/WOF2-1/ulp/libibmad/src/vendor.c create mode 100644 branches/WOF2-1/ulp/libibnetdisc/README.txt create mode 100644 branches/WOF2-1/ulp/libibnetdisc/dirs create mode 100644 branches/WOF2-1/ulp/libibnetdisc/include/infiniband/ibnetdisc.h create mode 100644 branches/WOF2-1/ulp/libibnetdisc/src/Sources create mode 100644 branches/WOF2-1/ulp/libibnetdisc/src/chassis.c create mode 100644 branches/WOF2-1/ulp/libibnetdisc/src/chassis.h create mode 100644 branches/WOF2-1/ulp/libibnetdisc/src/ibnetdisc.c create mode 100644 branches/WOF2-1/ulp/libibnetdisc/src/ibnetdisc_export.def create mode 100644 branches/WOF2-1/ulp/libibnetdisc/src/ibnetdisc_exports.src create mode 100644 branches/WOF2-1/ulp/libibnetdisc/src/ibnetdisc_main.cpp create mode 100644 branches/WOF2-1/ulp/libibnetdisc/src/internal.h create mode 100644 branches/WOF2-1/ulp/libibnetdisc/src/makefile create mode 100644 branches/WOF2-1/ulp/libibumad/AUTHORS create mode 100644 branches/WOF2-1/ulp/libibumad/COPYING create mode 100644 branches/WOF2-1/ulp/libibumad/dirs create mode 100644 branches/WOF2-1/ulp/libibumad/include/infiniband/umad.h create mode 100644 branches/WOF2-1/ulp/libibumad/src/Sources create mode 100644 branches/WOF2-1/ulp/libibumad/src/ibum_export.def create mode 100644 branches/WOF2-1/ulp/libibumad/src/ibum_exports.src create mode 100644 branches/WOF2-1/ulp/libibumad/src/ibum_main.cpp create mode 100644 branches/WOF2-1/ulp/libibumad/src/ibumad.h create mode 100644 branches/WOF2-1/ulp/libibumad/src/ibumad.rc create mode 100644 branches/WOF2-1/ulp/libibumad/src/makefile create mode 100644 branches/WOF2-1/ulp/libibumad/src/umad.cpp create mode 100644 branches/WOF2-1/ulp/libibverbs/AUTHORS create mode 100644 branches/WOF2-1/ulp/libibverbs/COPYING create mode 100644 branches/WOF2-1/ulp/libibverbs/dirs create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/asyncwatch/SOURCES create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/asyncwatch/asyncwatch.c create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/asyncwatch/asyncwatch.rc create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/asyncwatch/makefile create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/device_list.c create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/devinfo/SOURCES create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/devinfo/devinfo.c create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/devinfo/devinfo.rc create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/devinfo/makefile create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/dirs create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/pingpong.c create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/pingpong.h create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/rc_pingpong/SOURCES create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/rc_pingpong/makefile create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.c create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.rc create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/srq_pingpong/SOURCES create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/srq_pingpong/makefile create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.c create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.rc create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/uc_pingpong/SOURCES create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/uc_pingpong/makefile create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.c create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.rc create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/ud_pingpong/SOURCES create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/ud_pingpong/makefile create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.c create mode 100644 branches/WOF2-1/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.rc create mode 100644 branches/WOF2-1/ulp/libibverbs/include/infiniband/verbs.h create mode 100644 branches/WOF2-1/ulp/libibverbs/src/Sources create mode 100644 branches/WOF2-1/ulp/libibverbs/src/device.cpp create mode 100644 branches/WOF2-1/ulp/libibverbs/src/enum_strs.cpp create mode 100644 branches/WOF2-1/ulp/libibverbs/src/ibv_export.def create mode 100644 branches/WOF2-1/ulp/libibverbs/src/ibv_exports.src create mode 100644 branches/WOF2-1/ulp/libibverbs/src/ibv_main.cpp create mode 100644 branches/WOF2-1/ulp/libibverbs/src/ibverbs.h create mode 100644 branches/WOF2-1/ulp/libibverbs/src/ibverbs.rc create mode 100644 branches/WOF2-1/ulp/libibverbs/src/makefile create mode 100644 branches/WOF2-1/ulp/libibverbs/src/verbs.cpp create mode 100644 branches/WOF2-1/ulp/librdmacm/AUTHORS create mode 100644 branches/WOF2-1/ulp/librdmacm/COPYING create mode 100644 branches/WOF2-1/ulp/librdmacm/dirs create mode 100644 branches/WOF2-1/ulp/librdmacm/examples/cmatose/SOURCES create mode 100644 branches/WOF2-1/ulp/librdmacm/examples/cmatose/cmatose.c create mode 100644 branches/WOF2-1/ulp/librdmacm/examples/cmatose/makefile create mode 100644 branches/WOF2-1/ulp/librdmacm/examples/dirs create mode 100644 branches/WOF2-1/ulp/librdmacm/examples/mckey/mckey.c create mode 100644 branches/WOF2-1/ulp/librdmacm/examples/rping/rping.c create mode 100644 branches/WOF2-1/ulp/librdmacm/examples/udaddy/udaddy.c create mode 100644 branches/WOF2-1/ulp/librdmacm/include/rdma/rdma_cma.h create mode 100644 branches/WOF2-1/ulp/librdmacm/src/Sources create mode 100644 branches/WOF2-1/ulp/librdmacm/src/cma.cpp create mode 100644 branches/WOF2-1/ulp/librdmacm/src/cma.h create mode 100644 branches/WOF2-1/ulp/librdmacm/src/cma.rc create mode 100644 branches/WOF2-1/ulp/librdmacm/src/cma_export.def create mode 100644 branches/WOF2-1/ulp/librdmacm/src/cma_exports.src create mode 100644 branches/WOF2-1/ulp/librdmacm/src/cma_main.cpp create mode 100644 branches/WOF2-1/ulp/librdmacm/src/makefile create mode 100644 branches/WOF2-1/ulp/nd/dirs create mode 100644 branches/WOF2-1/ulp/nd/user/NdAdapter.cpp create mode 100644 branches/WOF2-1/ulp/nd/user/NdAdapter.h create mode 100644 branches/WOF2-1/ulp/nd/user/NdConnector.cpp create mode 100644 branches/WOF2-1/ulp/nd/user/NdConnector.h create mode 100644 branches/WOF2-1/ulp/nd/user/NdCq.cpp create mode 100644 branches/WOF2-1/ulp/nd/user/NdCq.h create mode 100644 branches/WOF2-1/ulp/nd/user/NdEndpoint.cpp create mode 100644 branches/WOF2-1/ulp/nd/user/NdEndpoint.h create mode 100644 branches/WOF2-1/ulp/nd/user/NdListen.cpp create mode 100644 branches/WOF2-1/ulp/nd/user/NdListen.h create mode 100644 branches/WOF2-1/ulp/nd/user/NdMr.cpp create mode 100644 branches/WOF2-1/ulp/nd/user/NdMr.h create mode 100644 branches/WOF2-1/ulp/nd/user/NdMw.cpp create mode 100644 branches/WOF2-1/ulp/nd/user/NdMw.h create mode 100644 branches/WOF2-1/ulp/nd/user/NdProv.cpp create mode 100644 branches/WOF2-1/ulp/nd/user/NdProv.def create mode 100644 branches/WOF2-1/ulp/nd/user/NdProv.h create mode 100644 branches/WOF2-1/ulp/nd/user/NdProv.rc create mode 100644 branches/WOF2-1/ulp/nd/user/README.txt create mode 100644 branches/WOF2-1/ulp/nd/user/SOURCES create mode 100644 branches/WOF2-1/ulp/nd/user/fake.c create mode 100644 branches/WOF2-1/ulp/nd/user/fre_svr-03_amd64/amd64/ibndprov.dll create mode 100644 branches/WOF2-1/ulp/nd/user/fre_svr-03_amd64/amd64/ndinstall.exe create mode 100644 branches/WOF2-1/ulp/nd/user/fre_svr-03_ia64/ia64/ibndprov.dll create mode 100644 branches/WOF2-1/ulp/nd/user/fre_svr-03_ia64/ia64/ndinstall.exe create mode 100644 branches/WOF2-1/ulp/nd/user/fre_svr-03_x86/i386/ibndprov.dll create mode 100644 branches/WOF2-1/ulp/nd/user/fre_svr-03_x86/i386/ndinstall.exe create mode 100644 branches/WOF2-1/ulp/nd/user/fre_svr-08_amd64/amd64/ibndprov.dll create mode 100644 branches/WOF2-1/ulp/nd/user/fre_svr-08_amd64/amd64/ndinstall.exe create mode 100644 branches/WOF2-1/ulp/nd/user/fre_svr-08_ia64/ia64/ibndprov.dll create mode 100644 branches/WOF2-1/ulp/nd/user/fre_svr-08_ia64/ia64/ndinstall.exe create mode 100644 branches/WOF2-1/ulp/nd/user/fre_svr-08_x86/i386/ibndprov.dll create mode 100644 branches/WOF2-1/ulp/nd/user/fre_svr-08_x86/i386/ndinstall.exe create mode 100644 branches/WOF2-1/ulp/nd/user/fre_xp_x86/i386/ibndprov.dll create mode 100644 branches/WOF2-1/ulp/nd/user/fre_xp_x86/i386/ndinstall.exe create mode 100644 branches/WOF2-1/ulp/nd/user/makefile create mode 100644 branches/WOF2-1/ulp/nd/user/makefile.inc create mode 100644 branches/WOF2-1/ulp/nd/user/nddebug.h create mode 100644 branches/WOF2-1/ulp/netdirect/dirs create mode 100644 branches/WOF2-1/ulp/netdirect/user/SOURCES create mode 100644 branches/WOF2-1/ulp/netdirect/user/makefile create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_adapter.cpp create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_adapter.h create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_base.cpp create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_base.h create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_connect.cpp create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_connect.h create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_cq.cpp create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_cq.h create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_ep.cpp create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_ep.h create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_export.def create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_exports.src create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_listen.cpp create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_listen.h create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_main.cpp create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_main.h create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_mw.cpp create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_mw.h create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_provider.cpp create mode 100644 branches/WOF2-1/ulp/netdirect/user/nd_provider.h create mode 100644 branches/WOF2-1/ulp/netdirect/user/netdirect.rc create mode 100644 branches/WOF2-1/ulp/opensm/dirs create mode 100644 branches/WOF2-1/ulp/opensm/user/README.opensm-build create mode 100644 branches/WOF2-1/ulp/opensm/user/TODO create mode 100644 branches/WOF2-1/ulp/opensm/user/config.h create mode 100644 branches/WOF2-1/ulp/opensm/user/dirs create mode 100644 branches/WOF2-1/ulp/opensm/user/doc/OpenSM_PKey_Mgr.txt create mode 100644 branches/WOF2-1/ulp/opensm/user/doc/OpenSM_RN_0_3_1.pdf create mode 100644 branches/WOF2-1/ulp/opensm/user/doc/OpenSM_UM_0_3.pdf create mode 100644 branches/WOF2-1/ulp/opensm/user/doc/current-routing.txt create mode 100644 branches/WOF2-1/ulp/opensm/user/doc/modular-routing.txt create mode 100644 branches/WOF2-1/ulp/opensm/user/doc/opensm_release_notes_openib-2.0.5.txt create mode 100644 branches/WOF2-1/ulp/opensm/user/doc/qos-config.txt create mode 100644 branches/WOF2-1/ulp/opensm/user/ibtrapgen/Makefile create mode 100644 branches/WOF2-1/ulp/opensm/user/ibtrapgen/SOURCES create mode 100644 branches/WOF2-1/ulp/opensm/user/ibtrapgen/ibtrapgen.c create mode 100644 branches/WOF2-1/ulp/opensm/user/ibtrapgen/ibtrapgen.h create mode 100644 branches/WOF2-1/ulp/opensm/user/ibtrapgen/main.c create mode 100644 branches/WOF2-1/ulp/opensm/user/include/complib/cl_byteswap.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/complib/cl_dispatcher.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/complib/cl_event_wheel.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/complib/cl_signal_osd.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/iba/ib_types.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/iba/ib_types_extended.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/cl_dispatcher.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/cl_event_wheel.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_attrib_req.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_base.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_console.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_db.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_db_pack.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_drop_mgr.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_errors.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_fwd_tbl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_helper.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_inform.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lid_mgr.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lin_fwd_rcv.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lin_fwd_rcv_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lin_fwd_tbl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_link_mgr.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_log.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mad_pool.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_madw.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_matrix.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_fwd_rcv.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_fwd_rcv_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_mgr.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_tbl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcm_info.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcm_port.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_msgdef.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mtl_bind.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mtree.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_multicast.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_desc_rcv.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_desc_rcv_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_info_rcv.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_info_rcv_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_opensm.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_partition.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_path.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey_mgr.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey_rcv.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey_rcv_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port_info_rcv.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port_info_rcv_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port_profile.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_rand_fwd_tbl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_remote_sm.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_req.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_req_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_resp.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_router.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_class_port_info.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_class_port_info_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_guidinfo_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_guidinfo_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_informinfo.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_informinfo_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_lft_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_lft_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_link_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_link_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mad_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mcmember_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mcmember_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mft_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mft_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_multipath_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_multipath_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_node_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_node_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_path_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_path_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_pkey_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_pkey_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_portinfo_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_portinfo_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_response.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_service_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_service_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_slvl_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_slvl_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sminfo_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sminfo_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sw_info_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sw_info_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_vlarb_record.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_vlarb_record_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_service.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_slvl_map_rcv.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_slvl_map_rcv_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sm.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sm_mad_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sm_state_mgr.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sminfo_rcv.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sminfo_rcv_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_state_mgr.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_state_mgr_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_stats.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_subnet.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sw_info_rcv.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sw_info_rcv_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sweep_fail_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_switch.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_trap_rcv.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_trap_rcv_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_ts_useraccess.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_ucast_mgr.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_umadt.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_version.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_vl15intf.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_vl_arb_rcv.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/osm_vl_arb_rcv_ctrl.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/opensm/st.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/unistd.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_al.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_api.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_sa_api.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_select.h create mode 100644 branches/WOF2-1/ulp/opensm/user/include/vendor/winosm_common.h create mode 100755 branches/WOF2-1/ulp/opensm/user/libopensm/Makefile create mode 100644 branches/WOF2-1/ulp/opensm/user/libopensm/SOURCES create mode 100644 branches/WOF2-1/ulp/opensm/user/libopensm/osm_helper.c create mode 100644 branches/WOF2-1/ulp/opensm/user/libopensm/osm_log.c create mode 100644 branches/WOF2-1/ulp/opensm/user/libopensm/osm_mad_pool.c create mode 100644 branches/WOF2-1/ulp/opensm/user/libvendor/Makefile create mode 100644 branches/WOF2-1/ulp/opensm/user/libvendor/SOURCES create mode 100644 branches/WOF2-1/ulp/opensm/user/libvendor/osm_vendor_al.c create mode 100644 branches/WOF2-1/ulp/opensm/user/libvendor/osm_vendor_mlx_sa.c create mode 100644 branches/WOF2-1/ulp/opensm/user/libvendor/winosm_common.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/Makefile create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/SOURCES create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/cl_dispatcher.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/cl_event_wheel.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/main.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/opensm.opts create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/opensm.rc create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm.mc create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_console.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_db_files.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_db_pack.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_drop_mgr.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_files.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_fwd_tbl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_inform.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_lid_mgr.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_lin_fwd_rcv.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_lin_fwd_rcv_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_lin_fwd_tbl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_link_mgr.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_matrix.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_fwd_rcv.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_fwd_rcv_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_mgr.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_tbl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_mcm_info.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_mcm_port.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_mtree.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_multicast.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_node.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_node_desc_rcv.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_node_desc_rcv_ctrl.c create mode 100755 branches/WOF2-1/ulp/opensm/user/opensm/osm_node_info_rcv.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_node_info_rcv_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_opensm.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey_mgr.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey_rcv.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey_rcv_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_port.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_port_info_rcv.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_port_info_rcv_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_prtn.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_prtn_config.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_qos.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_remote_sm.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_req.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_req_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_resp.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_router.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_class_port_info.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_class_port_info_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_guidinfo_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_guidinfo_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_informinfo.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_informinfo_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_lft_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_lft_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_link_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_link_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mad_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mcmember_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mcmember_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mft_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mft_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_multipath_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_multipath_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_node_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_node_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_path_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_path_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_pkey_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_pkey_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_portinfo_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_portinfo_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_response.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_service_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_service_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_slvl_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_slvl_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sminfo_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sminfo_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sw_info_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sw_info_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_vlarb_record.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_vlarb_record_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_service.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_slvl_map_rcv.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_slvl_map_rcv_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sm.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sm_mad_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sm_state_mgr.c create mode 100755 branches/WOF2-1/ulp/opensm/user/opensm/osm_sminfo_rcv.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sminfo_rcv_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_state_mgr.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_state_mgr_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_subnet.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sw_info_rcv.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sw_info_rcv_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_sweep_fail_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_switch.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_trap_rcv.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_trap_rcv_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_file.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_ftree.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_mgr.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_updn.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_vl15intf.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_vl_arb_rcv.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/osm_vl_arb_rcv_ctrl.c create mode 100644 branches/WOF2-1/ulp/opensm/user/opensm/st.c create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/Makefile create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/SOURCES create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/include/error.h create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/include/osmt_inform.h create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/include/osmt_mtl_regular_qp.h create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/include/osmtest.h create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/include/osmtest_base.h create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/include/osmtest_subnet.h create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/main.c create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/osmt_inform.c create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/osmt_mtl_regular_qp.c create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/osmt_multicast.c create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/osmt_service.c create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/osmt_slvl_vl_arb.c create mode 100644 branches/WOF2-1/ulp/opensm/user/osmtest/osmtest.c create mode 100644 branches/WOF2-1/ulp/qlgcvnic/dirs create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/SOURCES create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/inic.rc create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/makefile create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/makefile.inc create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/netvnic.cdf create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/netvnic.inx create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_adapter.c create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_adapter.h create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_config.h create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_control.c create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_control.h create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_controlpkt.h create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_data.c create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_data.h create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_debug.h create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_driver.c create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_driver.h create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_ib.c create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_ib.h create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_netpath.c create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_trailer.h create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_util.h create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_viport.c create mode 100644 branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_viport.h create mode 100644 branches/WOF2-1/ulp/srp/dirs create mode 100644 branches/WOF2-1/ulp/srp/kernel/SOURCES create mode 100644 branches/WOF2-1/ulp/srp/kernel/ib_srp.cdf create mode 100644 branches/WOF2-1/ulp/srp/kernel/ib_srp.inx create mode 100644 branches/WOF2-1/ulp/srp/kernel/ibsrp.rc create mode 100644 branches/WOF2-1/ulp/srp/kernel/makefile create mode 100644 branches/WOF2-1/ulp/srp/kernel/makefile.inc create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_aer_req.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_aer_rsp.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_cmd.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_connection.c create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_connection.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_cred_req.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_cred_rsp.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_data.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_data_path.c create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_data_path.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_debug.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_descriptors.c create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_descriptors.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_driver.c create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_event.c create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_event.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_hba.c create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_hba.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_hca.c create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_hca.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_i_logout.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_information_unit.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_iu_buffer.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_login_rej.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_login_req.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_login_rsp.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_rsp.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_session.c create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_session.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_t_logout.h create mode 100644 branches/WOF2-1/ulp/srp/kernel/srp_tsk_mgmt.h create mode 100644 branches/WOF2-1/ulp/wsd/dirs create mode 100644 branches/WOF2-1/ulp/wsd/user/README create mode 100644 branches/WOF2-1/ulp/wsd/user/SOURCES create mode 100644 branches/WOF2-1/ulp/wsd/user/extensions.c create mode 100644 branches/WOF2-1/ulp/wsd/user/ib_cm.c create mode 100644 branches/WOF2-1/ulp/wsd/user/ibsp_duplicate.c create mode 100644 branches/WOF2-1/ulp/wsd/user/ibsp_iblow.c create mode 100644 branches/WOF2-1/ulp/wsd/user/ibsp_ip.c create mode 100644 branches/WOF2-1/ulp/wsd/user/ibsp_mem.c create mode 100644 branches/WOF2-1/ulp/wsd/user/ibsp_mem.h create mode 100644 branches/WOF2-1/ulp/wsd/user/ibsp_mngt.c create mode 100644 branches/WOF2-1/ulp/wsd/user/ibsp_perfmon.c create mode 100644 branches/WOF2-1/ulp/wsd/user/ibsp_perfmon.h create mode 100644 branches/WOF2-1/ulp/wsd/user/ibsp_pnp.c create mode 100644 branches/WOF2-1/ulp/wsd/user/ibspdebug.c create mode 100644 branches/WOF2-1/ulp/wsd/user/ibspdebug.h create mode 100644 branches/WOF2-1/ulp/wsd/user/ibspdefines.h create mode 100644 branches/WOF2-1/ulp/wsd/user/ibspdll.c create mode 100644 branches/WOF2-1/ulp/wsd/user/ibspdll.def create mode 100644 branches/WOF2-1/ulp/wsd/user/ibspdll.h create mode 100644 branches/WOF2-1/ulp/wsd/user/ibspdll.rc create mode 100644 branches/WOF2-1/ulp/wsd/user/ibspproto.h create mode 100644 branches/WOF2-1/ulp/wsd/user/ibspstruct.h create mode 100644 branches/WOF2-1/ulp/wsd/user/makefile create mode 100644 branches/WOF2-1/ulp/wsd/user/misc.c create mode 100644 branches/WOF2-1/ulp/wsd/user/sockinfo.c diff --git a/branches/WOF2-1/WinOF/BuildRelease.bat b/branches/WOF2-1/WinOF/BuildRelease.bat new file mode 100644 index 00000000..1b97fee1 --- /dev/null +++ b/branches/WOF2-1/WinOF/BuildRelease.bat @@ -0,0 +1,581 @@ +@echo off +setlocal +rem tabstop=4 +rem +rem EXAMPLE - Build entire openIB-windows release & WIX installers (.msi) files. +rem Binary release is constructed in WinOF\Wix\OS\bin. +rem Processor architecture specific WIX installers are constructed +rem in %IDIR% +rem +rem BuildRelease option +rem option: all | allnoforce | allf | compile | compilenoforce | compf path | +rem makebin | msi |sign | wix | clean | msi-label | msi-del | +rem 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 WinOF releases. +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 + +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" ( + if "%2" == "" goto usage + if exist "%2" goto OK + echo %0 Err - path .\%2 does not exist? + exit /B 1 +) +if "%1" == "compile" goto OK +if "%1" == "compilenoforce" goto OK +if "%1" == "compf" ( + if "%2" == "" goto usage + if exist "%2" goto OK + echo %0 Err - path .\%2 does not exist? + exit /B 1 +) +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 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 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%\WinOF\WIX + +rem Use Wix V2 binaries. +rem set WIX_BIN=wix-2.0.5325.0-binaries +set WIX_BIN=wix-2.0.5805.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" == "msi" goto chk_cert +if "%1" == "sign" goto chk_cert + +goto cert_OK + +:chk_cert + if "%CERTFILE%" == "noCert" set /P CERTFILE=[Enter Certificate FileName] + if "%CERTFILE%" == "" ( + echo %0 + echo %0: Err - driver signing certificate filename required. + echo %0: see certmgr.exe + exit /B 1 + ) +) + +:cert_OK + +set WIN7=no + +rem Use this WDK + +if "%WIN7%" == "yes" ( + rem Windows 7 WDK + set _DDK_VER=7100.0.0 + set _COIN_VER=01009 +) else ( + rem Server 2008 WDK & WdfCoInstaller version + set _DDK_VER=6001.18001 + set _COIN_VER=01007 +) + +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 "%1" == "allf" ( + set FPATH=%2 + goto svn +) +if "%1" == "compf" ( + set FPATH=%2 + goto svn +) + +rem setup value for OPENIB_REV assignment; AND supported by if would be nice. +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=\gen1\trunk\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 +) + +if NOT EXIST etc\makebin.bat ( + echo %0 - Missing etc\makebin.bat, script must run from gen1\trunk + 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 "%WIN7%" == "yes" ( + 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" == "compf" ( + rem Force Compile everything + set OPS=-wgcfPM 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 | allf +if EXIST "%FPATH%" pushd %FPATH% + +rem ********* Compile for win7 - Windows 7 + +if "%WIN7%" == "yes" ( + rem win7 x64 + echo %0 - Build win7 x64 Checked + %COMSPEC% /C "call %BSE%\etc\bldwo.bat chk x64 win7 %OPS%" + if ERRORLEVEL 1 exit /B 1 + echo %0 - Build win7 x64 Free + %COMSPEC% /C "call %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 "call %BSE%\etc\bldwo.bat chk x86 win7 %OPS%" + if ERRORLEVEL 1 exit /B 1 + echo %0 - Build win7 x86 Free + %COMSPEC% /C "call %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 "call %BSE%\etc\bldwo.bat chk ia64 win7 %OPS%" + if ERRORLEVEL 1 exit /B 1 + echo %0 - Build win7 ia64 Free + %COMSPEC% /C "call %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 "call %BSE%\etc\bldwo.bat chk x64 2008 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build WLH x64 Free +%COMSPEC% /C "call %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 "call %BSE%\etc\bldwo.bat chk x86 2008 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build WLH x86 Free +%COMSPEC% /C "call %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 "call %BSE%\etc\bldwo.bat chk ia64 2008 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build WLH ia64 Free +%COMSPEC% /C "call %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 "call %BSE%\etc\bldwo.bat chk x86 xp %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build XP x86 Free +%COMSPEC% /C "call %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 "call %BSE%\etc\bldwo.bat chk x64 2003 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build WNET x64 Free +%COMSPEC% /C "call %BSE%\etc\bldwo.bat fre x64 2003 %OPS%" +if ERRORLEVEL 1 exit /B 1 + +echo %0 - Build WNET x86 Checked +%COMSPEC% /C "call %BSE%\etc\bldwo.bat chk x86 2003 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build WNET x86 Free +%COMSPEC% /C "call %BSE%\etc\bldwo.bat fre x86 2003 %OPS%" +if ERRORLEVEL 1 exit /B 1 + +echo %0 - Build WNET ia64 Checked +%COMSPEC% /C "call %BSE%\etc\bldwo.bat chk ia64 2003 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build WNET ia64 Free +%COMSPEC% /C "call %BSE%\etc\bldwo.bat fre ia64 2003 %OPS%" +if ERRORLEVEL 1 exit /B 1 + +rem compf | allf +if EXIST "%FPATH%" popd + +if "%1" == "compf" 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 WinOF-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%) + +if "%WIN7%" == "yes" mkdir %RBIN_W7% +mkdir %RBIN_WLH% +mkdir %RBIN_WNET% +mkdir %RBIN_WXP% + +if EXIST "%BSE%\etc\makebin.bat" ( + if "%WIN7%" == "yes" ( + call %BSE%\etc\makebin.bat %BSE% %RBIN_W7% win7 %_DDK% %_COIN_VER% + if ERRORLEVEL 1 ( + echo %0: Err in makebin.bat %BSE% %RBIN_W7% wlh %_DDK% %_COIN_VER% + exit /B 1 + ) + ) + call %BSE%\etc\makebin.bat %BSE% %RBIN_WLH% wlh %_DDK% %_COIN_VER% + if ERRORLEVEL 1 ( + echo %0: Err in makebin.bat %BSE% %RBIN_WLH% wlh %_DDK% %_COIN_VER% + exit /B 1 + ) + call %BSE%\etc\makebin.bat %BSE% %RBIN_WNET% wnet %_DDK% %_COIN_VER% + if ERRORLEVEL 1 ( + echo %0: Err in makebin.bat %BSE% %RBIN_WNET% wnet %_DDK% %_COIN_VER% + exit /B 1 + ) + call %BSE%\etc\makebin.bat %BSE% %RBIN_WXP% wxp %_DDK% %_COIN_VER% + if ERRORLEVEL 1 ( + echo %0: Err in makebin.bat %BSE% %RBIN_WXP% wxp %_DDK% %_COIN_VER% + exit /B 1 + ) +) + +if "%1" == "makebin" goto finito + +:mk_msi + +echo %0 - Drivers Signed with %CERTFILE% +echo Binary releases created in +if "%WIN7%" == "yes" echo %RBIN_W7% +echo %RBIN_WLH% +echo %RBIN_WNET% +echo %RBIN_WXP% + +rem build WIX installers --> see WinOF\WIX + +%COMSPEC% /V:on /E:on /C "%_DDK%\bin\setenv.bat %_DDK% fre X64 WNET & 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-1/WinOF/WIX/CustomActions.vbs b/branches/WOF2-1/WinOF/WIX/CustomActions.vbs new file mode 100644 index 00000000..5ffbac0c --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/CustomActions.vbs @@ -0,0 +1,1806 @@ +'/* +' * 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. +' */ + +' WIX CustomActions used in the WinOF (Windows OpenFabrics) Release. +' File is based on the installer src contributed by Mellanox Technologies. +' +' TabStops == 4 +' +' $Id$ + +' 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 + +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 DriverInstall(). +' A CA can only see Installer properties through pre-loaded 'CustomActionData' + +Sub WinOF_setup + dim VersionNT,Installed,AddLocal,use_this_HCA + + 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,hca_mthca,fIPoIB,fWSD,fDAPL,fDatBASIC1,fDatBASIC2" + 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("DriverInstall") = _ + 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 + + +'Waiting to delete a file until it's free + +Function FileDeleteUntilFree(filename) + Set objFSO=CreateObject("Scripting.FileSystemObject") + Set WshShell = CreateObject("WScript.Shell") + dim too_much + too_much = 0 + Do While objFSO.FileExists(filename) + On Error Resume Next + objFSO.DeleteFile(filename) + WScript.Sleep 100 ' milliseconds + ' Do not wait to long to delete the file, bail and don't delete it if too + ' long of a wait. + too_much = too_much + 1 + if too_much > 50 then + msgbox "delete Timeout(5) " & filename + exit Do + End If + err.clear + Loop +End Function + +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,VersionNT) + 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", 0, 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,VersionNT) + + 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",VersionNT + DriverFileDelete fso,WshShell,sDRIVERS & "mthca.sys",VersionNT + FileDeleteQ fso,sDRIVERS & "mthca.sy1" + DriverFileDelete fso,WshShell,sDRIVERS & "mlx4_bus.sys",VersionNT + DriverFileDelete fso,WshShell,sDRIVERS & "mlx4_hca.sys",VersionNT + DriverFileDelete fso,WshShell,sDRIVERS & "winverbs.sys",VersionNT + DriverFileDelete fso,WshShell,sDRIVERS & "winverbsd.sys",VersionNT + DriverFileDelete fso,WshShell,sDRIVERS & "winmad.sys",VersionNT + DriverFileDelete fso,WshShell,sDRIVERS & "winmadd.sys",VersionNT + DriverFileDelete fso,WshShell,sDRIVERS & "ipoib.sys",VersionNT + DriverFileDelete fso,WshShell,sDRIVERS & "ibiou.sys",VersionNT + DriverFileDelete fso,WshShell,sDRIVERS & "ibsrp.sys",VersionNT + DriverFileDelete fso,WshShell,sDRIVERS & "vnic.sys",VersionNT + DriverFileDelete fso,WshShell,sDRIVERS & "qlgcvnic.sys",VersionNT + + DriverFileDelete fso,WshShell,sSYS32 & "libibverbs.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "libibverbsd.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "winmad.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "winmadd.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "winverbs.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "winverbsd.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "ibal.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "ibald.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "ibal32.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "ibal32d.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "complib.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "complibd.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "cl32.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "cl32d.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "mthcau.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "mthcaud.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "mthca32.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "mthca32d.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "mlx4u.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "mlx4ud.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "mlx4u32.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "mlx4u32d.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "ibsrp.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "ibsrpd.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "IbInstaller.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "ibwsd.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "ibndprov.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "ibndprov32.dll",VersionNT + DriverFileDelete fso,WshShell,sSYS32 & "ndinstall.exe",VersionNT + + If fso.FolderExists(sSYSWOW64) Then + DriverFileDelete fso,WshShell,sSYSWOW64 & "ibal.dll",VersionNT + DriverFileDelete fso,WshShell,sSYSWOW64 & "ibald.dll",VersionNT + DriverFileDelete fso,WshShell,sSYSWOW64 & "complib.dll",VersionNT + DriverFileDelete fso,WshShell,sSYSWOW64 & "complibd.dll",VersionNT + DriverFileDelete fso,WshShell,sSYSWOW64 & "mthcau.dll",VersionNT + DriverFileDelete fso,WshShell,sSYSWOW64 & "mthcaud.dll",VersionNT + DriverFileDelete fso,WshShell,sSYSWOW64 & "mlx4u.dll",VersionNT + DriverFileDelete fso,WshShell,sSYSWOW64 & "mlx4ud.dll",VersionNT + DriverFileDelete fso,WshShell,sSYSWOW64 & "ibsrp.dll",VersionNT + DriverFileDelete fso,WshShell,sSYSWOW64 & "ibsrpd.dll",VersionNT + DriverFileDelete fso,WshShell,sSYSWOW64 & "IbInstaller.dll",VersionNT + DriverFileDelete fso,WshShell,sSYSWOW64 & "ibwsd.dll",VersionNT + DriverFileDelete fso,WshShell,sSYSWOW64 & "ibndprov.dll",VersionNT + 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\ndinstall.exe" + FileDeleteQ fso,Win & "lastgood\system32\ibwsd.dll" + + FileDeleteQ fso,Win & "lastgood\SysWOW64\ibndprov.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,0,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,0,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 + + + +''''''''''' Device Driver Install '''''''''''' + +Function DriverInstall() + 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 Not 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.",,_ + "DriverInstall" + End If + End If + + DriverInstall = 0 + +End Function + + + +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +' Find IBA devices using devman.exe + +Function Find_IBA_Devices(WshShell,sInstalldir) + Dim dev + + Set ibaDevicesExec = WshShell.Exec ("cmd.exe /c cd " & sInstalldir & "Drivers & devman.exe findall * | FIND ""IBA""") + + 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 + 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 + 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, 0, true) + if use_dpinst then + ' use devman.exe to delete all .inf referenced files + Return = WshShell.Run (cmdDM, 0, 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, 0, true) + if use_dpinst then + ' use devman.exe to delete all .inf referenced files + Return = WshShell.Run (cmdDM, 0, 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,VersionNT,devInfo) + + Dim i,Flist,udfCnt + + If IsNull(devInfo) Then + msgbox "cleanup_driver_files devInfo?" + Exit Sub + End If + + If sDBG >= "1" Then + DisplayDevInfo devInfo,"WinOF 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),VersionNT + 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,"WinOF Device Info" + + GetDeviceInstallInfo = ibaDev + +End Function + + + +' remove IB I/O Unit driver + +Sub Uninstall_IOU(fso,WshShell,devList,sInstalldir,VersionNT) + Dim tool + + RemoveDevice fso,WshShell,sInstalldir,devList,"InfiniBand I/O Unit",VersionNT + + tool = "cmd.exe /c cd /d " & sInstalldir & "Drivers & dpinst.exe " + + ' dpinst (loads the driver store) not load the driver (no srp/vnic) + + find_remove_INF_file WshShell,tool,"ib_iou.cat" + +End Sub + + + +' Remove QLogic VNIC instances + +Sub Uninstall_VNIC(fso,WshShell,devices,sInstalldir,VersionNT) + + 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 & """", 0, true) + ' Removing the Qlogic Vnic I/O Unit + Return = WshShell.Run (devman & "remove ""@" & dt & """", 0, true) + End if + Next + + ' use dpinst.exe instead of devman.exe for Windows LongHorn++ + tool = replace(devman,"devman","dpinst") + + If IsNull(devInfo) Then + find_remove_INF_file WshShell,tool,"netvnic.cat" + Exit Sub + End If + + cleanup_driver_files fso,WshShell,sInstalldir,tool,VersionNT,devInfo + +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,VersionNT) + + 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, 0, true) + ' Removing SRP device + Return = WshShell.Run (devmanRMAT & dt, 0, true) + ' msgbox "Uninstall_SRP() " & devmanRMAT & dt & " rc " & Return + End if + Next + Next + + ' use dpinst.exe instead of devman.exe for Windows LongHorn++ + tool = replace(devman,"devman","dpinst") + + 'No SRP device - check/clear to be safe. + If IsNull(devInfo) Then + find_remove_INF_file WshShell,tool,"ibsrp.cat" + Exit Sub + End If + + cleanup_driver_files fso,WshShell,sInstalldir,tool,VersionNT,devInfo + +End Sub + + +Sub RemoveDevice(fso,WshShell,sInstalldir,devList,DeviceTag,VersionNT) + + 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 & """", 0, true) + Return = WshShell.Run (devmanRMAT & dt & """", 0, true) + End if + Next + + ' Only if a device was found + If IsNull(devInfo) Then + Exit Sub + End If + + ' use dpinst.exe instead of devman.exe for Windows LongHorn++ + tool = replace(devman,"devman","dpinst") + + cleanup_driver_files fso,WshShell,sInstalldir,tool,VersionNT,devInfo + +End Sub + + + +Sub remove_all_HCA_devices(fso,WshShell,sInstalldir,VersionNT) + + Dim devman,tool + + devman = "cmd.exe /c cd /d " & sInstalldir & "Drivers & devman.exe " + + ' Old (CoInstaller version) ibbus GUID - just in case. + Return = WshShell.Run (devman & "remove {94F41CED-78EB-407C-B5DF-958040AF0FD8",0,true) + + RemoveDevice fso,WshShell,sInstalldir,Null,"MLX4\CONNECTX_HCA",VersionNT + + ' VEN_15B3 covers devices: mthca & mlx4_bus + RemoveDevice fso,WshShell,sInstalldir,Null,"PCI\VEN_15B3",VersionNT + + ' 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" + +End Sub + + +Sub Uninstall_IB_Devices(fso,WshShell,sInstalldir,VersionNT) + + Dim devList + + If (fso.FileExists(sInstalldir & "Drivers\dpinst.exe") = False) Then + 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(devices) Then + + Uninstall_SRP fso,WshShell,devList,sInstalldir,VersionNT + + Uninstall_VNIC fso,WshShell,devList,sInstalldir,VersionNT + + ' remove I/O Unit driver + Uninstall_IOU fso,WshShell,devList,sInstalldir,VersionNT + + ' remove IPoIB devices + RemoveDevice fso,WshShell,sInstalldir,devList,"IBA\IPOIB",VersionNT + + End If + + ' stop the openSM service in case it was started. + Return = WshShell.Run ("cmd.exe /c sc.exe stop opensm", 0, true) + + ' delete opensm service from registry + Return = WshShell.Run ("cmd.exe /c sc.exe delete opensm", 0, true) + + remove_all_HCA_devices fso,WshShell,sInstalldir,VersionNT + +End Sub + + + +''''''''''' Driver Uninstall '''''''''''' + +Sub DriverUninstall() + Dim sInstalldir, WshShell, fso, sVersionNT + + 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") + sVersionNT = Session.Property("VersionNT") + + sRemove = Session.Property("REMOVE") + If sRemove = "" Then + sRemove = "ALL" + End If + + If fso.FileExists(sInstalldir & "Drivers\net\ndinstall.exe") Then + Return = WshShell.Run ("cmd.exe /c cd /d " & sInstalldir & _ + "Drivers\net & ndinstall.exe -r", 0, true) + End If + + ' WSD is not supported on XP and should NOT have been installed. + ' otherwise, remove the service: ND (Network Direct) then WinSock Direct. + + If sVersionNT <> WindowsXP AND fso.FileExists(sInstalldir & "installsp.exe") Then + Return = WshShell.Run ("cmd.exe /c cd /d " & sInstalldir & _ + " & installsp.exe -r", 0, true) + End If + + Uninstall_IB_Devices fso,WshShell,sInstalldir,sVersionNT + + ' 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" ) + + 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", 0, true) + End if + Next + + ' Cleanup KMDF CoInstaller Driver entries. + Return = WshShell.Run (base & "Control\Wdf\Kmdf\kmdflibrary\versions\1\driverservices /v mlx4_bus /f", 0, true) + Return = WshShell.Run (base & "Control\Wdf\Kmdf\kmdflibrary\versions\1\driverservices /v winverbs /f", 0, true) + Return = WshShell.Run (base & "Control\Wdf\Kmdf\kmdflibrary\versions\1\driverservices /v winmad /f", 0, true) + +' Not yet +' Return = WshShell.Run ("reg.exe delete HKLM\Software\Microsoft\Windows\currentVersion\DIFx\DriverStore\WinVerbs_* /f", 0, true) +' Return = WshShell.Run ("reg.exe delete HKLM\Software\Microsoft\Windows\currentVersion\DIFx\DriverStore\ipoib_* /f", 0, true) +' + + ' Remove all Local Area Connection registry entries which were constructed + ' for IPoIB. Next WinOF 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", 0, true) + If Err Then ShowErr + End if + Next + + ' remove driver installed files + RemoveDriverFiles fso,WshShell,sVersionNT + + Session.Property("REBOOT") = "FORCE" + err.clear +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", 0, true) + End If + If Err Then ShowError + +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 sInstalldir, WshShell, fso + + sInstalldir = Session.Property("INSTALLDIR") + + Set WshShell = CreateObject("WScript.Shell") + Set fso = CreateObject("Scripting.FileSystemObject") + + ' Start the Network Direct Service if installed + + If fso.FileExists(sInstalldir & "Drivers\net\ndinstall.exe") Then + Return = WshShell.Run ("cmd.exe /c cd /d " & sInstalldir _ + & " & Drivers\net\ndinstall.exe -i", 0, true) + If Err Then ShowErr2("ND service install failed") + End If + +End Sub + + +Sub ShowError() + If Err.Number = 0 Then + Exit Sub + End if + strMsg = vbCrLf & "Error # " & Err.Number & vbCrLf & _ + Err.Description & vbCrLf & vbCrLf + msgbox 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 + + +' 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 DriverInstall 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) + Dim opensmPath + + opensmPath = sInstalldir & "opensm.exe" + + Return = WshShell.Run ("cmd.exe /c sc.exe config opensm start= auto",0,true) + Return = WshShell.Run ("cmd.exe /c sc.exe start opensm", 0, 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,"WinOF" + +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 ChkInstallAndReboot() + + 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 + + VersionNT = Session.Property("VersionNT") + + ' remove any lingering driver installed files + RemoveDriverFiles fso,WshShell,VersionNT + + ChkInstallAndReboot = 0 + +End Function + + + +' Not Used - idea was to run %SystemRoot%\temp\WinOFcleanup.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 = "RunOnceWinOFcleanup.bat" + src = sInstalldir & "Drivers\" & script + + If Not fso.FileExists(src) Then + msgbox "Missing " & src + Exit Sub + End if + + ' copy WinOFclean.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 "WinOF", cmd + ' 2nd cmd to remove previous script. +' XXX cmd = "cmd.exe /C del /F/Q " & sTemp +' RunAtReboot "WinOF2", 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", 0, 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,0,true) + End if + + RemoveFolder "C:\IBSDK" + +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") + + VersionNT = Session.Property("VersionNT") + + 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,VersionNT + NeedReboot = NeedReboot + 1 + End If + + If Instr(sRemove,"fVNIC") Then + Uninstall_VNIC fso,WshShell,Null,sInstalldir,VersionNT + 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-1/WinOF/WIX/License.rtf b/branches/WOF2-1/WinOF/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-1/WinOF/WIX/README.txt b/branches/WOF2-1/WinOF/WIX/README.txt new file mode 100644 index 00000000..30057875 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/README.txt @@ -0,0 +1,165 @@ +[04-10-09] + +How to generate a Windows OpenFabrics Release (WinOF) using the WIX 2.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-wix2/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 + + + +Creating a binary release tree +------------------------------ + +As of WinOF 2.0 release [Aug'08] the build environment has been switched over to +Microsoft's WDK (Windows Driver Kit) version 6001.180001. + +See gen1\trunk\WinOF\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 asembly 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 v2 (stable) tool set (http://sourceforge.net/projects/wix/) +to ‘WinOF\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-2.0.5325.0-binaries.zip into wix-2.0.5325.0-binaries\. +You would now have the following structure: + WinOF\WIX\WIX_tools\wix-2.0.5325.0-binaries\{candle.exe, light.exe,...} +Point being Trunk\WinOF\buildRelease.bat needs the path to the WIX tool set. + + + +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; WinOF\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\WinOF\WIX\wlh\x86 & nmake + Results in a .\WOF_wlh_x86.msi installer image. + +cd gen1\trunk\WinOF\WIX\wlh\x64 & nmake + Results in a WOF_wlh_x64.msi installer image. + +cd gen1\trunk\WinOF\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 "WOF_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-1/WinOF/WIX/README_checked.txt b/branches/WOF2-1/WinOF/WIX/README_checked.txt new file mode 100644 index 00000000..3b8813e7 --- /dev/null +++ b/branches/WOF2-1/WinOF/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 WinOF\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-1/WinOF/WIX/README_release.txt b/branches/WOF2-1/WinOF/WIX/README_release.txt new file mode 100644 index 00000000..89afa5e1 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/README_release.txt @@ -0,0 +1,141 @@ + +[6-23-09] WinOF 2.1 (pre-RC0) release + +Downloads available at http://www.openfabrics.org/downloads/WinOF/v2.1_rc0 + + +WinOF 2.1 Summary Changes +------------------------- + +1) The WinOF 2.1 release is based on openib-windows source svn revision + (branches\WOF2-1 svn.2272). + + Last WinOF release (2.0.2) based on svn.1975. + +2) Bug fixes in + + IB Core + IPoIB + WSD + SRP + DAT/DAPL + WinVerbs + WinMAD + OFED (Open Fabrics Enterprise Distribution [Linux]) verbs API + OFED Diagnostic utilities + WinOF Installer + +3) Integrated Functionality + + - OFED Compatibility layers allow for easy porting of OFED applications + into the WinOF environment. + libibverbs - OFED verbs API library. + libmad - InfiniBand MAD (Management Datagram) library. + libumad - IB MAD exported user-mode interface library. + librdmacm - OFED RDMA CM (Comunications Manager). + + - OFED Fabric Diagnostics available ( for usage info, see --help ). + ibaddr - query InfiniBand address(es) + ibnetdiscover - generate a fabric topology. + iblinkinfo - report link info for all links in the fabric + ibping - ping an InfiniBand address + ibportstate - manage IB port (physical) state and link speed + ibqueryerrors - query and report non-zero IB port counters + ibroute - query InfiniBand switch forwarding tables + ibstat - display HCA information. + ibsysstat - system status for an InfiniBand address + ibtracert - trace InfiniBand path + 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 + + - Connected mode IPoIB ensures higher performance IPoIB transfers in + addition to OFED (Linux) IPoIB connectivity. + + - All WinOF installs now utilize the Windows Driver Store along with the + Plug-n-Play (PNP) subsystem to install the correct HCA driver(s). + Selection of a specific Mellanox HCA type is no longer required. + + - Server 2008-HPC install support has been enhanced to provide a no-drivers + installed mode to ease WinOF installation when drivers have been previously + installed with WDM (Windows Deployment Manager) node templates. + From an msiexec.exe command line when NODRV=1, device driver '.inf' files + are not processed during the WinOF install. + The base assumption is the WDM node provisioning template (see cluster + Manager) will install WinOF drivers. All other WinOF files are installed + to the standard WinOF location '%ProgramFiles(x86)%\WinOF'. + When uninstalling a WinOF install which was done with NODRV=1, you MUST + include NODRV=1 on the msiexec.exe uninstall command line or the uninstall + will uninstall WinOF drivers installed via WDM templates. + + Examples + + unattended install (for use with clusrun.bat) + start/wait msiexec /I WOF.msi /quiet NODRV=1 + + console based non-interactive install: + start/wait msiexec /I WOF.msi /passive NODRV=1 + + Install selectable features (No drivers): + start/wait msiexec /I WOF.msi NODRV=1 + + Extract WinOF install files (aka driver files for WDM install) + start/wait msiexec /A WinOF_wlh_x64.msi TARGETDIR=%TEMP% + + The folder %TEMP%\PFiles\WinOF will be created. + + console based unattended uninstall with auto-reboot: + start/wait msiexec /X WOF.msi /passive + + clusrun unattended uninstall with auto-reboot + start/wait msiexec /X WOF.msi /quiet /forcereboot + + - Subnet Management started as a local Windows Service from a command line: + start/wait msiexec /I WOF.msi /passive OSMS=1 + + - HCA drivers now load WinVerbs and WinMad filter drivers by default. + + + +Note on Vista installs Only: + + Vista installs must be performed from an Administrator priviledged command + window. Right-clicking the .msi installer file for a Vista installation + will fail due to insufficent privileges to install the HCA driver! + From the Administrator privileged cmd-window (Interactive install) say + + start/wait msiexec /I WinOF_wlh_xxx.msi + -or- + a quiet, default install: start/wait msiexec /I WinOF_wlh_xxx.msi /passive + + +**** WARNING **** + +After the WinOF.msi file has started installation execution, an errant +"Welcome to the Found New Hardware Wizard" window 'may' popup. + +Just ignore or 'cancel' the errant FNHW popup window in order to proceed with +the installation. XP requires a cancel, for WLH & WNET, the notifiers will +disappear on their own. + +You do need to answer 'Yes' or 'Continue' to those popup windows which refer to +non-WHQL'ed drivers. + +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. + +thank you, + +WinOF Developers. + diff --git a/branches/WOF2-1/WinOF/WIX/Release_notes.htm b/branches/WOF2-1/WinOF/WIX/Release_notes.htm new file mode 100644 index 00000000..42a907a6 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/Release_notes.htm @@ -0,0 +1,1358 @@ + + + + + + + + + +WinOF Release Notes + + + + + +
+ +

+ +

Windows OpenFabrics

+ +

2.1 Release Notes

+ +

+07/13/2009

+ + + +

+Unattended Install

+

HCA Device Driver +Installation

+

+Server 2008 HPC Install Notes

+

+Setting the IPoIB Interface IP Address

+

+Uninstall

+

+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-1 svn revision 1835) +are packaged into a WIX 2.0 +(Windows Installer Xml) single file install package referred to as the +Windows OpenFabrics (WinOF) release 2.1.

+

+This WinOF 2.1 is a full release as it contains WHQL fixes +to numerous components along with full Winverbs and OFED integration modules:

+ +
+
    +
  • +

    Windows Server + 2008, HPC and Vista are supported.

  • +
  • +

    Network Direct + supported on Server 2008/HPC.

  • +
  • +

    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.

    +
  • +
  • +

    QLogic has + enhanced VNIC & SRP for increased performance and stability.

    +
  • +
  • +

    uDAT/DAPL is now a + common code base with OFED uDAT/DAPL; supported DAPL providers: IBAL, + socket-cm and rdma-cm.

  • +
  • +

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

    +
  • +
+
+ +

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

+
    +
  • +

    HCA + Drivers - +  Mellanox + + + + InfiniHost & ConnectX low level drivers; See list of +supported devices below

  • +
  • +

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

    +
  • +
+ +

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

    +
  • +
  • +

    Windows + Server 2008 R2

    +
  • +
  • +

    + Vista

  • +
  • +

    + Windows Server 2008 HPC Edition

  • +
  • +

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

+ +

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 (x86)\WinOF'.  Although device driver modules initially reside in +'%SystemDrive%\Program Files (x86)\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 to 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 (x86)\WinOF' is appended to the system wide search +path environment variable 'PATH'; new 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_Enabled' install feature, an 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: from an administrator command window, execute 'msiexec /I + WinOF_2-1_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, 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 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 public key digital + 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 WDM 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(x86)%\WinOF
    • +
    • Otherwise unpack, not install, the WinOF files to + gain access to cert-add.bat file by executing the following commands:
        +
      • msiexec /A WinOF_2-1_wlh.msi TARGETDIR=%TEMP%
      • +
      • cd /d %TEMP%\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
    • +
    • example:  cert-add + \\orion-hn\winof cn01 cn02 cn03 cn04 + cn05
    • +
  • +
  • If remote nodes are not yet provisioned (not + running Windows), then do the following:
      +
    • From the head node, extract OFA certificate to a + file:
      + certutil -store TRUSTEDPUBLISHER 71175fca6b85d5c2e0864df16349ad84 OFA-TP.cer
    • +
    • Place OFA-TP.cer in a remote node accessible share.
    • +
    • As part of the node provisioning template process + before loading WinOF drivers, execute the certutil command on the remote + node:
      + certutil -addstore TRUSTEDPUBLISHER + \\share\OFA-TP.cer
    • +
  • +
  • Run the cluster manager tool to create compute node + templates using WinOF drivers in %ProgramFiles(x86)%\Winof\IDrivers.
  • +
  • Use 'cluster manager' to provision all compute nodes.
  • +
  • Set IPoIB interface IPv4 address on all compute + nodes.
  • +
  • At this juncture, the WinOF drivers are installed and + operational, although additional WInOF components are not; IB diags, DAPL & + docs.
  • +
  • To install remaining WinOF components without + installing device drivers, use the + unattended install process with NO Drivers:
      +
    • Place WinOF_wlh_x64.msi in a remote node accessible + share
    • +
    •  Use the Cluster Manager tool to execute the + misexec command on all remote nodes to perform the WinOF install:
      + 'msiexec /I \\share-name\WinOF_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.
     
  • +
+

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 driver files accessible to WDM provisioning; the other +approach is to install WinOF on the head-node and point Cluster Manager node +template creation at the WinOF device driver .inf files located in +the folder %ProgramFiles(x86)%\WinOF\Drivers.

+

msiexec /A WinOF_2-1_wlh_x64.msi TARGETDIR=dev:\path-to-extracted-files

+

example:  msiexec /A WinOF_2-1_wlh_x64.msi TARGETDIR=%TEMP%   +(note: TARGETDIR is case sensitive)

+

The above command creates the following folder structure:
+
+%TEMP%\PFiles\WinOF\
    +Drivers\mthca\mthca.inf                 Mellanox InfiniHost HCA driver
    +Drivers\mlx4_bus\mlx4_bus.inf     Mellanox ConnectX bus driver
    +Drivers\mlx4_hca\mlx4_hca.inf     Mellanox ConnectX HCA driver (both ConnectX drivers required).
    +Drivers\net\netipoib.inf                   IPoIB + Network Direct IB provider + WSD (Winsock Direct) provider.
+    Drivers\srp\ibsrp.inf                        SCSI over IB.
+    Drivers\qlgcvnic\qlgcvnic.inf          QLogic VNIC (Virtual Ethernet controller over InfiniBand)

+

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 can be +identified as the 'Application' network. In this case, a few minutes after a +compute node is installed, the local 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>

+

 

+ +
+

Trouble Shooting

+

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

+
    +
  • To start the Device Manager:  devmgmt.msc
  • +
  • To start the Services Manager:  services.msc
  • +
+

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. Add/Remove Programs entry identifies the WinOF release version.
  2. +
  3. Start->Programs->Windows OpenFabrics->Release Notes  +(2nd Line)
  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(x86)\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.2210 branches\WOF2-1)
  • +
+

<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 dat.dll and dapl.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 (x86)\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%\dapl.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 (x86)\\WinOF\\dapl.dll").

+

DAT/DAPL version 2.0 runtime +libraries are identified as dat2.dll and dapl2.dll, both in %SystemRoot%; see +manual for further details.

+

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

+

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
 

+ +
    +
  • +

    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-1/WinOF/WIX/SDK_Samples/DDK/README.txt b/branches/WOF2-1/WinOF/WIX/SDK_Samples/DDK/README.txt new file mode 100644 index 00000000..d3f55fee --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/SDK_Samples/DDK/README.txt @@ -0,0 +1,99 @@ + +DDK (Driver Development Kit) Build Environment Example [12-06-07] +----------------------------------------------------------------- + +Install the Windows Server 2003 (SP1) DDK see +http://www.microsoft.com/whdc/devtools/ddk/default.mspx . + +Why use the DDK? Windows Server 2003 DDK (SP1) is what's used to build the WinOF +distribution. +Installing the DDK first requires burning a CD of the downloaded DDK - sigh... + +Due to the problematic nature of spaces in path names, Windows Server 2003 DDK +does not allow spaces in pathnames; this is why IBSDK is not installed under +WinOF. + + +Building CM test example +------------------------ + +Start a 'Free/Release' type DDK command prompt for you respective architecture [x86,amd64,ia64]. + +cd to C:\IBAL\Sampes\DDK + +Set the 'OPENIB_REV' env variable to the svn version number. +Hold the mouse-point over the file 'C:\Program Files (x86)\WinOF\opensm.exe'. +The last field of the 'File Version' field is the svn revision number. + +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_wnet_x86\i386\cmtest.exe'. + +build -wg + +The executable will be created in a processor specific directory: + + x64 (Release/Free) example: + C:\IBAL\Sampes\DDK\objfre_wnet_amd64\amd64\cmtest.exe + + x64 (Checked/Debug)) example: + C:\IBAL\Sampes\DDK\objchk_wnet_amd64\amd64\cmtest.exe + + x86 (Release/Free) example: + C:\IBAL\Sampes\DDK\objfre_wnet_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-1/WinOF/WIX/SDK_Samples/DDK/SOURCES b/branches/WOF2-1/WinOF/WIX/SDK_Samples/DDK/SOURCES new file mode 100644 index 00000000..99254f96 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/SDK_Samples/DDK/SOURCES @@ -0,0 +1,21 @@ +TARGETNAME=cmtest +TARGETPATH=obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_CRTDLL=1 +_LIBS=..\..\Lib + +SOURCES=cmtest.c cmtest.rc + +INCLUDES=..\..\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-1/WinOF/WIX/SDK_Samples/DDK/cmtest.rc b/branches/WOF2-1/WinOF/WIX/SDK_Samples/DDK/cmtest.rc new file mode 100644 index 00000000..3c02ca9b --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/SDK_Samples/DDK/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-1/WinOF/WIX/SDK_Samples/DDK/makefile b/branches/WOF2-1/WinOF/WIX/SDK_Samples/DDK/makefile new file mode 100644 index 00000000..f86adf81 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/SDK_Samples/DDK/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:\IBSDK\Inc\openib.def diff --git a/branches/WOF2-1/WinOF/WIX/SDK_Samples/VS/Makefile.x64 b/branches/WOF2-1/WinOF/WIX/SDK_Samples/VS/Makefile.x64 new file mode 100644 index 00000000..0bc70cc0 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/SDK_Samples/VS/Makefile.x64 @@ -0,0 +1,97 @@ +# +#********************************************************************* +# +# NMAKE Options (passed as macro) +# +# Select a Visual Studio 2005 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:\IBSDK\Lib +INC_PATH=C:\IBSDK\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 bufferoverflowU.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-1/WinOF/WIX/SDK_Samples/VS/Makefile.x86 b/branches/WOF2-1/WinOF/WIX/SDK_Samples/VS/Makefile.x86 new file mode 100644 index 00000000..64070763 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/SDK_Samples/VS/Makefile.x86 @@ -0,0 +1,97 @@ +# +#********************************************************************* +# +# 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:\IBSDK\Lib +INC_PATH=C:\IBSDK\Inc + +IB_LIBS=ibal.lib complib.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 bufferoverflowU.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-1/WinOF/WIX/SDK_Samples/VS/README.txt b/branches/WOF2-1/WinOF/WIX/SDK_Samples/VS/README.txt new file mode 100644 index 00000000..99d41736 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/SDK_Samples/VS/README.txt @@ -0,0 +1,111 @@ + +Visual Studio 8/5.0 (C++) Build Environment [12-06-07] +----------------------------------------------------------------- + +Install Microsoft Visual Studio 8/5.0 (C++ env) + + +**** WARNING - win32 application building **** + +The Visual Studio default 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 +------------------------ + + +cd to C:\IBAL\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:\IBSDK\Inc + set additional Resource Include path as C:\IBSDK\Inc + Set additional Library path as C:\IBSDK\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-1/WinOF/WIX/SDK_Samples/VS/cmtest.rc b/branches/WOF2-1/WinOF/WIX/SDK_Samples/VS/cmtest.rc new file mode 100644 index 00000000..b0a596b0 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/SDK_Samples/VS/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-1/WinOF/WIX/WIX_tools/README.txt b/branches/WOF2-1/WinOF/WIX/WIX_tools/README.txt new file mode 100644 index 00000000..c50670ac --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/WIX_tools/README.txt @@ -0,0 +1,23 @@ + +[1-29-09] + +Creating the WIX tool set +------------------------- + +Download the WIX v2 (stable) tool set to ‘WinOF\WIX\WIX_tools\’. + +http://sourceforge.net/project/showfiles.php?group_id=105970&package_id=114109&release_id=574429 + +Download WIX binaries wix-2.0.5805.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-2.0.5805.0-binaries.zip into wix-2.0.5805.0-binaries\. + +You should now have the following structure: + trunk\WinOF\WIX\WIX_tools\wix-2.0.5805.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-1/WinOF/WIX/build-OFA-dist.bat b/branches/WOF2-1/WinOF/WIX/build-OFA-dist.bat new file mode 100644 index 00000000..939a85a6 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/build-OFA-dist.bat @@ -0,0 +1,245 @@ +@echo off +setlocal + +rem TabStop=4 + +rem Mfg. a ZIP file of a WinOF distribution, such that the zip file can be +rem pushed to the OFA WinOF download site and unzipped for distribution. + +rem populate arch specific distribution folders, zip'em, populate symbols +rem folder and zip the entire package for transmission to OFA download website. +rem calls .\zip-OFA-dist.bat script. + +rem Operating assumptions: +rem 1) current arch specific installers are in %systemroot%\temp\*.msi +rem resultant from trunk\buildrelease.bat execution. +rem +rem ASSUMES %CD% == gen1\branches\WinOF\Wix +rem +rem build-OFA-dist release_ID {target_path} +rem +rem example build-OFA-dist 1-1 %windir%\temp +rem # if target_path is null then default %SystemRoot%\temp\v%1 +rem # otherwise %2\v%1 + +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 +) + +if "%1" == "" ( + echo "Missing release ID, example %0 1-1" + echo "usage: %0 release_ID {target_path, default: %SystemRoot%\temp} + exit /B 1 +) + +set ID=%1 + +rem Final zip archive name +set ZIP=WinOF_dist_v%ID%.zip + +rem where gen1\trunk\buildRelease.bat created the .msi installer files. +set MSI=%SystemRoot%\temp +set MSI_DST=%MSI%\v%ID% + +rem start fresh +if exist %MSI_DST% rmdir /S /Q %MSI_DST% +mkdir %MSI_DST% +if ERRORLEVEL 1 ( + echo Err - unable to create %MSI_DST% ? + exit /B 1 +) + +set WZ="C:\Program Files (x86)\WinZip\WZZIP.EXE" +if not exist %WZ% ( + echo "Missing WinZip pro [cmd-line interface]" + echo "Please manually create the archives." + exit /B 1 +) +set SYMST="C:\Program Files\Debugging Tools for Windows (x64)"\symstore.exe +if not exist %SYMST% ( + echo %0 - Missing installation of MS Debug tools @ + echo %SYMST% + echo www.microsoft.com/whdc/devtools/debugging/install64bit.mspx + exit /B 1 +) + +FOR %%s IN ( win7 wxp wlh wnet ) DO ( + if exist %CD%\%%s\bin\Misc\Manual.htm ( + set OSF=%%s !OSF! + ) +) +echo Packaging installers for !OSF! + +if "!OSF!" == "" ( + echo "Missing components?" + echo "Must execute from gen1\branches\WinOF\WIX -- and --" + echo " .\win7,wnet,wxp,wlh\bin\ must be populated." + echo " run gen1\trunk\buildRelease.bat -or- gen1\trunk\etc\makebin" + exit /B 1 +) + +FOR %%s IN ( !OSF! ) DO ( + echo Building %%s installers. + + rem create target structure + mkdir %MSI_DST%\%%s + mkdir %MSI_DST%\%%s\Installers + mkdir %MSI_DST%\%%s\SymStor + if ERRORLEVEL 1 ( + echo Err - unable to create %MSI_DST%\%%s\... ? + exit /B 1 + ) + + set DSTx86=WinOF_%ID%_%%s_x86 + set DSTx64=WinOF_%ID%_%%s_x64 + set DSTia64=WinOF_%ID%_%%s_ia64 + + echo Building target !DSTx86! + + if exist !DSTx86! rmdir /S /Q !DSTx86! + mkdir !DSTx86! + + IF NOT EXIST !DSTx86! ( + echo Unable to create !DSTx86! ? + exit /B 1 + ) + + copy README_release.txt !DSTX86!\README.txt + if ERRORLEVEL 1 ( + echo Err - missing file README_release.txt ? + exit /B 1 + ) + + copy /B openfabrics.gif !DSTX86!\openfabrics.gif + copy release_notes.htm !DSTX86!\release_notes.htm + + rem would like to use a goto although the target label destroys the + rem scope for %%s ... sigh. + rem Scope is preserved by if not + + if not "%%s" == "wxp" ( + + echo Building target !DSTx64! + if exist !DSTx64!\. rmdir /S /Q !DSTx64! + mkdir !DSTx64! + + if NOT EXIST !DSTx64! ( + echo Unable to create !DSTx64! ? + exit /B 1 + ) + + copy README_release.txt !DSTX64!\README.txt + copy /B openfabrics.gif !DSTX64!\openfabrics.gif + copy release_notes.htm !DSTX64!\release_notes.htm + + echo Building target !DSTia64! + if exist !DSTia64!\. rmdir /S /Q !DSTia64! + mkdir !DSTia64! + if NOT EXIST !DSTia64! ( + echo Unable to create !DSTia64! ? + exit /B 1 + ) + + copy README_release.txt !DSTia64!\README.txt + copy /B openfabrics.gif !DSTia64!\openfabrics.gif + copy release_notes.htm !DSTia64!\release_notes.htm + ) + + echo Copying installers for %%s + + copy /B /Y %MSI%\WOF_%%s_x86.msi !DSTx86!\WinOF_%ID%_%%s_x86.msi + if ERRORLEVEL 1 ( + echo Err - unable to copy %MSI%\WOF_%%s_x86.msi + exit /B 1 + ) + + if not "%%s" == "wxp" ( + + copy /B /Y %MSI%\WOF_%%s_x64.msi !DSTx64!\WinOF_%ID%_%%s_x64.msi + if ERRORLEVEL 1 ( + echo Err - unable to copy %MSI%\WOF_%%s_x64.msi + exit /B 1 + ) + + copy /B /Y %MSI%\WOF_%%s_ia64.msi !DSTia64!\WinOF_%ID%_%%s_ia64.msi + if ERRORLEVEL 1 ( + echo Err - unable to copy %MSI%\WOF_%%s_ia64.msi + exit /B 1 + ) + ) + + echo Building ZIP archives of the architecture specific folders + + if EXIST !DSTx86!.zip del /F /Q !DSTx86!.zip + if EXIST !DSTx64!.zip del /F /Q !DSTx64!.zip + if EXIST !DSTia64!.zip del /F /Q !DSTia64!.zip + + %WZ% -P -r %MSI_DST%\%%s\Installers\!DSTx86!.zip !DSTx86! + if ERRORLEVEL 1 ( + echo Err - unable to create %MSI_DST%\%%s\Installers\!DSTx86!.zip + exit /B 1 + ) + + if not "%%s" == "wxp" ( + + %WZ% -P -r %MSI_DST%\%%s\Installers\!DSTx64!.zip !DSTx64! + if ERRORLEVEL 1 ( + echo Err - unable to create %MSI_DST%\%%s\Installers\!DSTx64!.zip + exit /B 1 + ) + + %WZ% -P -r %MSI_DST%\%%s\Installers\!DSTia64!.zip !DSTia64! + if ERRORLEVEL 1 ( + echo Err - unable to create %MSI_DST%\%%s\Installers\!DSTia64!.zip + exit /B 1 + ) + ) + + rem create the symbol store for the OS flavor + echo Generating %MSI_DST%\%%s\SymStor Symbol store + + %SYMST% add /r /f %CD%\%%s\bin\bin /s %MSI_DST%\%%s\SymStor /t "WinOF" /v "version %ID%" + if ERRORLEVEL 1 ( + echo %%s symstore.exe failure rc %ERRORLEVEL% + exit /B 1 + ) + rem OS flavor cleanup + + if exist !DSTx86!\. rmdir /S /Q !DSTx86! + if exist !DSTx64!\. rmdir /S /Q !DSTx64! + if exist !DSTia64!\. rmdir /S /Q !DSTia64! +) + +rem create a ZIP file of the entire distribution + +echo WinOF v%ID% distribution @ %ZIP% + +pushd %MSI% + +rem rename MS Operating System code-names to common Retail names +pushd v%ID% +rename wlh Server_2008-Vista-HPC +rename wnet Server_2003-XP64 +rename wxp XP32 +if exist win7 rename win7 Windows7 +popd + +IF EXIST %ZIP% del /F/Q %ZIP% + +%WZ% -P -r %ZIP% v%ID% + +rmdir /Q /S v%ID% + +popd + +echo ----- +echo ----- +echo WinOF v%ID% distribution @ %MSI%\%ZIP% +echo ----- + +endlocal + diff --git a/branches/WOF2-1/WinOF/WIX/build-all-MSI.bat b/branches/WOF2-1/WinOF/WIX/build-all-MSI.bat new file mode 100644 index 00000000..9623500f --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/build-all-MSI.bat @@ -0,0 +1,141 @@ +@echo off +setlocal +rem Build WIX installers (.msi) for 'all' architectures & Operating environments +rem +rem usage: +rem %0 cmd Cross-CertFileName SPCSubjectName {msi-dest-path} +rem cmd - if 'msi' then assume drivers already signed, only sign .msi +rem otherwise sign all drivers and installers (.msi files) + +rem Cross-CertFilename is a filename only, must prefix '...\WIX' before +rem passing it down. +rem SW_PUB - Software Publisher name in 'MY' Cert Store, see signtool /n switch + +rem *** REQUIRES nmake, common invocation from Visual C or WDK command window +rem *** Assumes current folder is WIX\ + +set USE=usage %0 all/msi Certificate-FileName SW_Publisher[see signtool /n] {msi-dest-path} + +if "%1" == "" ( + echo %0: %USE% + exit /B 1 +) + +if "%1" == "all" ( + goto ok +) +if "%1" == "msi" ( + goto ok +) +if "%1" == "sign" ( + goto ok +) +echo %0 - Unknown command '%1' - 'all' or 'msi' +echo %0: %USE% +exit /B 1 + +:ok + +if NOT EXIST %2 ( + echo %0: Certificate-Filename not found? + echo %0 - %2 + exit /B 1 +) + +rem need a Cert subject name string - name is passed-in quoted! +if %3 == "" ( + echo %0: %USE% + exit /B 1 +) + +if "%4" == "" ( + set DST=%windir%\temp +) else ( + set DST=%4 +) + +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 + +if "%1" == "msi" goto mk_msi + +rem Sign drivers for all OSes & arches. Convert CertFilename to full path. +call sign-all-drivers %CD%\%2 %3 + +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 Windows 7 x86, x64 & ia64 installers +if exist win7\bin\HCA ( + pushd win7 + call build-MSI %DST% + if ERRORLEVEL 1 exit /B + popd +) + +rem build Windows Server 2008 / Vista (LongHorn versions) x86, x64 & ia64 + +pushd wlh +call build-MSI %DST% +if ERRORLEVEL 1 exit /B +popd + +:: build Windows Server 2003 versions: x86, x64 & ia64 +pushd wnet +call build-MSI %DST% +if ERRORLEVEL 1 exit /B +popd + +:: build Windows XP (32-bit) versions: x86 only +pushd wxp +call build-MSI %DST% +if ERRORLEVEL 1 exit /B +popd + +rem Digitally Sign the installer .msi files + +set TS=/t http://timestamp.verisign.com/scripts/timstamp.dll +echo %0 - Signing Installer .msi files +for %%o in ( win7 wlh wnet wxp ) do ( + for %%a in ( x86 x64 ia64 ) do ( + if exist %DST%\WOF_%%o_%%a.msi ( + + echo Signing installer %DST%\WOF_%%o_%%a.msi + signtool sign /ac %CD%\%2 /n %3 %TS% %DST%\WOF_%%o_%%a.msi + if ERRORLEVEL 1 ( + echo %0 signtool sign %DST%\WOF_%%o_%%a.msi failed? + exit /B 1 + ) + signtool verify /pa %DST%\WOF_%%o_%%a.msi + if ERRORLEVEL 1 ( + echo %0 signtool verify %DST%\WOF_%%o_%%a.msi failed? + exit /B 1 + ) + ) + ) +) + +dir %DST%\*.msi + +echo '' +echo Done - WIX installers in %DST% + +@endlocal diff --git a/branches/WOF2-1/WinOF/WIX/common/DAT_config.inc b/branches/WOF2-1/WinOF/WIX/common/DAT_config.inc new file mode 100644 index 00000000..a80eeff9 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/DAT_config.inc @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/Docs.inc b/branches/WOF2-1/WinOF/WIX/common/Docs.inc new file mode 100644 index 00000000..b741ee66 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/Docs.inc @@ -0,0 +1,57 @@ + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/IBcore.inc b/branches/WOF2-1/WinOF/WIX/common/IBcore.inc new file mode 100644 index 00000000..18a8fbe2 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/IBcore.inc @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/InstallExecuteSeq.inc b/branches/WOF2-1/WinOF/WIX/common/InstallExecuteSeq.inc new file mode 100644 index 00000000..f8bb552f --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/InstallExecuteSeq.inc @@ -0,0 +1,69 @@ + + + File where Custom Actions are defined --> + + + + + + + + + + + + + + + + + + + + + + + + + + Install ONLY + + NOT Installed AND Not NODRV + + + REBOOT="FORCE" + + + 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" + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/OpenSM_service.inc b/branches/WOF2-1/WinOF/WIX/common/OpenSM_service.inc new file mode 100644 index 00000000..9717c558 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/OpenSM_service.inc @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/WinOF_cfg.inc b/branches/WOF2-1/WinOF/WIX/common/WinOF_cfg.inc new file mode 100644 index 00000000..75d99842 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/WinOF_cfg.inc @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/arp.inc b/branches/WOF2-1/WinOF/WIX/common/arp.inc new file mode 100644 index 00000000..3de2e993 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/arp.inc @@ -0,0 +1,15 @@ + + + + + + OpenFabrics Windows InfiniBand + 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/ + + diff --git a/branches/WOF2-1/WinOF/WIX/common/checked.inc b/branches/WOF2-1/WinOF/WIX/common/checked.inc new file mode 100644 index 00000000..2b1eba5e --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/checked.inc @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/dapl_rt.inc b/branches/WOF2-1/WinOF/WIX/common/dapl_rt.inc new file mode 100644 index 00000000..31da5caf --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/dapl_rt.inc @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/hca_filters.inc b/branches/WOF2-1/WinOF/WIX/common/hca_filters.inc new file mode 100644 index 00000000..eeaa49ed --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/hca_filters.inc @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/ib_sdk.inc b/branches/WOF2-1/WinOF/WIX/common/ib_sdk.inc new file mode 100644 index 00000000..ec855edb --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/ib_sdk.inc @@ -0,0 +1,354 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/iou.inc b/branches/WOF2-1/WinOF/WIX/common/iou.inc new file mode 100644 index 00000000..21c4f56f --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/iou.inc @@ -0,0 +1,27 @@ + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/ipoib.inc b/branches/WOF2-1/WinOF/WIX/common/ipoib.inc new file mode 100644 index 00000000..7d11e9ef --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/ipoib.inc @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/mlnx_drivers.inc b/branches/WOF2-1/WinOF/WIX/common/mlnx_drivers.inc new file mode 100644 index 00000000..9335a608 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/mlnx_drivers.inc @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/qlgc_vnic.inc b/branches/WOF2-1/WinOF/WIX/common/qlgc_vnic.inc new file mode 100644 index 00000000..f8a92399 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/qlgc_vnic.inc @@ -0,0 +1,28 @@ + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/requirements.inc b/branches/WOF2-1/WinOF/WIX/common/requirements.inc new file mode 100644 index 00000000..3b40e478 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/requirements.inc @@ -0,0 +1,57 @@ + + + + Value="1" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + REG_EXISTS + + + + SC_EXISTS + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/srp.inc b/branches/WOF2-1/WinOF/WIX/common/srp.inc new file mode 100644 index 00000000..2c3ac4d8 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/srp.inc @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/std_features.inc b/branches/WOF2-1/WinOF/WIX/common/std_features.inc new file mode 100644 index 00000000..70602e3a --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/std_features.inc @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IPOIB_EXISTS + + + + + + + + + + + IPOIB_EXISTS + + + + + + + + + + IPOIB_EXISTS + + + DAT_CONF_EXISTS AND Not Installed + + + + + + + + + DAT1_INSTALLED + + + + + + + + + + + DAT2_INSTALLED + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/tools.inc b/branches/WOF2-1/WinOF/WIX/common/tools.inc new file mode 100644 index 00000000..cb1a8e07 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/tools.inc @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/winverbs_OFED.inc b/branches/WOF2-1/WinOF/WIX/common/winverbs_OFED.inc new file mode 100644 index 00000000..955f94e2 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/winverbs_OFED.inc @@ -0,0 +1,314 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/common/winverbs_drivers.inc b/branches/WOF2-1/WinOF/WIX/common/winverbs_drivers.inc new file mode 100644 index 00000000..7f58e5cc --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/common/winverbs_drivers.inc @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/dat.conf b/branches/WOF2-1/WinOF/WIX/dat.conf new file mode 100644 index 00000000..3dfce3a9 --- /dev/null +++ b/branches/WOF2-1/WinOF/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 v1.1 dapl provider configuration for HCA0 port 1 +ibnic0 u1.1 threadsafe default C:\Windows\dapl.dll ri.1.1 "IbalHca0 1" "" +IbalHca0 u1.1 threadsafe default C:\Windows\dapl.dll ri.1.1 "IbalHca0 1" "" +# +# DAT 1.1 debug +ibnic0d u1.1 threadsafe default "C:\\Program Files (x86)\\WinOF\\dapld.dll" ri.1.1 "IbalHca0 1" "" +# +# DAT 2.0 +ibnic0v2 u2.0 nonthreadsafe default C:\Windows\dapl2.dll ri.2.0 "IbalHca0 1" "" +ibnic1v2 u2.0 nonthreadsafe default C:\Windows\dapl2.dll ri.2.0 "IbalHca1 1" "" +IbalHca0v2 u2.0 nonthreadsafe default C:\Windows\dapl2.dll ri.2.0 "IbalHca0 1" "" +# +# DAT 2.0 (debug) +ibnic0v2d u2.0 nonthreadsafe default "C:\\Program Files (x86)\\WinOF\\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\dapl2-ofa-scm.dll ri.2.0 "ibv_device0 1" "" +# +# Socket-CM (debug) +ibnic0v2-scmd u2.0 nonthreadsafe default "C:\\Program Files (x86)\\WinOF\\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\dapl2-ofa-cma.dll ri.2.0 "rdma_dev0 1" "" +# +# DAT 2.0 RDMA-CM (debug) +ibnic0v2-cmad u2.0 nonthreadsafe default "C:\\Program Files (x86)\\WinOF\\dapl2-ofa-cmad.dll" ri.2.0 "rdma_dev0 1" "" diff --git a/branches/WOF2-1/WinOF/WIX/dpinst.xml b/branches/WOF2-1/WinOF/WIX/dpinst.xml new file mode 100644 index 00000000..653066c3 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/dpinst.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/ia64/Command Window.lnk b/branches/WOF2-1/WinOF/WIX/ia64/Command Window.lnk new file mode 100644 index 0000000000000000000000000000000000000000..51cf55050a5ac4a90efd92bf6aeb8d4624ce0973 GIT binary patch literal 1350 zcmdT@QAkr^6#nL&p-^Bn!qLjTERtZ(j5UVYC>aUj#1%JW4~uQobZgdKIN>VdULpu4 zLP->iURoG|^pFr#NIH6{h#(;dp-7XcAS@)KzW;7_GkxeS=!f&4bN=(4^PT_P`?muy zm@2pfkF*`$F}hY^XJ>nYL$iiHb8h)9- zufuWOjD{obKp9oCn$f7)GtSf58pv%Otv=b0-H>3!=LZL!tNs~hG;1P8MjJZN3Lh;$ z{q69Sa`Vhp29#tZ-n0+c^G9}G%T_P|1xZ8@M-vD_Et-YqHSX<4(27tzY>%WOC2ny# z;~dnoL(B@p&g>LLa0ACF7K#{v&@PHt$0)*=C|6eQT&tlj^kxl5m0oZT#cKximIFFB z%&?&o=a9fD?k7p>MHDfTD!f*TBu>;56W|b{IKyFhVImWo$lCnc1iBK5q-|sAwU-ZI z{e{@$f4_3?Wy!{0qx_+}IL8D(x|rAcA7JAQVhgequN+m~`Xks@Vf?2=&(p7)8ZPBdeJSJ_`J?1M7Hm;RtP4L^ zq{qacpMBZyijF^Am3HuP0IAKu9M3%hR9tSj(at_aOt+0ovg8{4*6*QMKFCt@qAWez z)uP$2s70#a*rFFfH5|lD92iyel&VeDm@-b3qA|wm8`5ecWzwEj`?}vqI~f%iy@ud8 znpu_t5cRxyM)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-1/WinOF/WIX/openfabrics.gif b/branches/WOF2-1/WinOF/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-1/WinOF/WIX/sign-all-drivers.bat b/branches/WOF2-1/WinOF/WIX/sign-all-drivers.bat new file mode 100644 index 00000000..90e1ef13 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/sign-all-drivers.bat @@ -0,0 +1,79 @@ +@echo off +setlocal +rem +rem Digitally sign all drivers for all OSes & architectures. +rem +rem example - sign-all-drivers CertFilename CertSubjName {noTimeStamp} +rem see TS below. +rem + +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 +) + +if %2 == "" ( + echo %0 - Missing Cert Subject name? + exit /B 1 +) + +rem XXX defeat TimeStamping until net access resolved. +rem set TS=noTimeStamp + +for %%p in ( win7 wlh wnet wxp ) do ( + if exist %%p\bin\HCA ( + echo %0 - Signing %%p drivers + pushd %%p + if ERRORLEVEL 1 ( + echo %0 - Error Bad cd to %%p folder ? + exit /B 1 + ) + rem Sign free HCA drivers + call signDrivers %1 %2 bin\HCA %TS% + if ERRORLEVEL 1 ( + echo %0 - Error signing %%p\bin\HCA drivers? + exit /B 1 + ) + rem Sign checked HCA drivers + call signDrivers %1 %2 bin\Chk\HCA %TS% + if ERRORLEVEL 1 ( + echo %0 - Error signing %%p\bin\Chk\HCA drivers? + exit /B 1 + ) + + rem Sign free: IPoIB & VNIC drivers + call signDrivers %1 %2 bin\net %TS% + if ERRORLEVEL 1 ( + echo %0 - Error signing %%p\bin\net drivers? + exit /B 1 + ) + rem Sign checked: IPoIB & VNIC drivers + call signDrivers %1 %2 bin\Chk\net %TS% + if ERRORLEVEL 1 ( + echo %0 - Error signing %%p\bin\Chk\net drivers? + exit /B 1 + ) + + rem Sign free SRP drivers + call signDrivers %1 %2 bin\storage %TS% + if ERRORLEVEL 1 ( + echo %0 - Error signing %%p\bin\storage drivers? + exit /B 1 + ) + rem Sign checked SRP drivers + call signDrivers %1 %2 bin\Chk\storage %TS% + if ERRORLEVEL 1 ( + echo %0 - Error signing %%p\bin\Chk\storage drivers? + exit /B 1 + ) + popd + ) +) +endlocal +echo Done %0 %1 diff --git a/branches/WOF2-1/WinOF/WIX/win7/build-MSI.bat b/branches/WOF2-1/WinOF/WIX/win7/build-MSI.bat new file mode 100644 index 00000000..90e4f033 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/win7/build-MSI.bat @@ -0,0 +1,69 @@ +@echo off +setlocal +rem Build Windows 7 WIX installer (.msi) for all architectures +rem +rem usage: %0 {dest-path-for-msi-files} + +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 NOT EXIST %DST% ( + echo %0: Installer output path %DST% not found? + exit /B +) +nmake /NOLOGO /? > %DST%\jnk.txt +if ERRORLEVEL 1 ( + echo %0 missing nmake.exe in PATH? + exit /B +) +del /Q /F %DST%\jnk.txt + +if NOT EXIST %CD%\bin\HCA\amd64 ( + echo %0 - %CD%\bin not populated correctly? see trunk\etc\makebin.bat + exit /B +) + +if EXIST ia64\WOF_%OS%_ia64.msi del /Q /F ia64\WOF_%OS%_ia64.msi +if EXIST x64\WOF_%OS%_x64.msi del /Q /F x64\WOF_%OS%_x64.msi +if EXIST x86\WOF_%OS%_x86.msi del /Q /F x86\WOF_%OS%_x86.msi + +if EXIST %DST%\WOF_%OS%_ia64.msi del /Q /F %DST%\WOF_%OS%_ia64.msi +if EXIST %DST%\WOF_%OS%_x64.msi del /Q /F %DST%\WOF_%OS%_x64.msi +if EXIST %DST%\WOF_%OS%_x86.msi del /Q /F %DST%\WOF_%OS%_x86.msi + +pushd ia64 +nmake /NOLOGO full +if ERRORLEVEL 1 exit /B +echo move /Y WOF_%OS%_ia64.msi %DST% +move /Y WOF_%OS%_ia64.msi %DST% +popd + +pushd x64 +nmake /NOLOGO full +if ERRORLEVEL 1 exit /B +echo move /Y WOF_%OS%_x64.msi %DST% +move /Y WOF_%OS%_x64.msi %DST% +popd + +pushd x86 +nmake /NOLOGO full +if ERRORLEVEL 1 exit /B +echo move /Y WOF_%OS%_x86.msi %DST% +move /Y WOF_%OS%_x86.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-1/WinOF/WIX/win7/ia64/Makefile b/branches/WOF2-1/WinOF/WIX/win7/ia64/Makefile new file mode 100644 index 00000000..2ce9b004 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/win7/ia64/Makefile @@ -0,0 +1,57 @@ +################### +# IA64/IPF Itanium makefile targets +# +S=WOF +P=$(S)_win7_ia64 + +#WIX 2.0 +# L=..\..\WIX_tools\wix-2.0.5325.0-binaries +L=..\..\WIX_tools\wix-2.0.5805.0-binaries + +# WIX 3.0 L=..\WIX_tools\wix-3.0.2925.0-binaries + +WIX_UI="$(L)\wixui.wixlib" -loc "$(L)\WixUI_en-us.wxl" + +DFX=DIFxApp.wixlib +# Since makebin.bat knows correct WDK version, it copies the DIFX APP files +# to the bin\ tree; eliminates Makefiles having to know about WDK versions. +DFXP=..\bin\Misc\ia64 + +full: clean $(P).msi + +clean: + @del /q $(S).wixobj 2>nul + @del /q $(P).msi 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + +MySetup: $(P).msi + +license.rtf: ..\..\license.rtf + @copy ..\..\license.rtf .\license.rtf + +# .dlls need to be in the current folder +$(DFX) : $(DFXP)\$(DFX) $(DFXP)\DIFxApp.dll $(DFXP)\DIFxAppA.dll + @copy /B/Y $(DFXP)\DIFxApp.dll . + @copy /B/Y $(DFXP)\DIFxAppA.dll . + @copy /B/Y $(DFXP)\$(DFX) . + +$(S).wixobj: $(S).wxs + +$(P).msi: $(S).wixobj license.rtf $(DFX) + @echo -- + @echo Building $(P).msi + $(L)\light.exe /nologo -out $(P).msi $(S).wixobj $(DFX) $(WIX_UI) + @del /q $(S).wixobj 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + + +################### +# makefile inference rules +# +.SUFFIXES: .wxs .wixobj + +.wxs.wixobj:: + @$(L)\candle.exe /nologo -trace -v $< + diff --git a/branches/WOF2-1/WinOF/WIX/win7/ia64/wof.wxs b/branches/WOF2-1/WinOF/WIX/win7/ia64/wof.wxs new file mode 100644 index 00000000..886ed36c --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/win7/ia64/wof.wxs @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + AdminUser + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/win7/signDrivers.bat b/branches/WOF2-1/WinOF/WIX/win7/signDrivers.bat new file mode 100644 index 00000000..8cb87228 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/win7/signDrivers.bat @@ -0,0 +1,160 @@ +@echo off +setlocal + +rem Sign device drivers for architectures specified + +rem usage: +rem signDrivers CrossCertFilename CertStoreName path-2-drivers {noTimeStamp} +rem CrossCertFilename - fully qualified path\filename of cross cert. +rem CertStoreName - name of certificate in 'MY' Cert store (certmgr). + +rem example: signDrivers %CD%\Cross-Cert SWPublisher bin\hca + +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 +) + +rem Timestamp the signed file unless instructed not to. +if "%4" == "" ( + 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 (amd64 x86 ia64) 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 1 ( + 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-1/WinOF/WIX/win7/x64/Makefile b/branches/WOF2-1/WinOF/WIX/win7/x64/Makefile new file mode 100644 index 00000000..acba40e1 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/win7/x64/Makefile @@ -0,0 +1,57 @@ +################### +# makefile targets +# +S=WOF +P=$(S)_win7_x64 + +#WIX 2.0 +# L=..\..\WIX_tools\wix-2.0.5325.0-binaries +L=..\..\WIX_tools\wix-2.0.5805.0-binaries + +# WIX 3.0 L=..\WIX_tools\wix-3.0.2925.0-binaries + +WIX_UI="$(L)\wixui.wixlib" -loc "$(L)\WixUI_en-us.wxl" + +DFX=DIFxApp.wixlib +# Since makebin.bat knows correct WDK version, it copies the DIFX APP files +# to the bin\ tree; eliminates Makefiles having to know about WDK versions. +DFXP=..\bin\Misc\amd64 + +full: clean $(P).msi + +clean: + @del /q $(S).wixobj 2>nul + @del /q $(P).msi 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + +MySetup: $(P).msi + +license.rtf: ..\..\license.rtf + @copy ..\..\license.rtf .\license.rtf + +# .dlls need to be in the current folder +$(DFX) : $(DFXP)\$(DFX) $(DFXP)\DIFxApp.dll $(DFXP)\DIFxAppA.dll + @copy /B/Y $(DFXP)\DIFxApp.dll . + @copy /B/Y $(DFXP)\DIFxAppA.dll . + @copy /B/Y $(DFXP)\$(DFX) . + +$(S).wixobj: $(S).wxs + +$(P).msi: $(S).wixobj license.rtf $(DFX) + @echo -- + @echo Building $(P).msi + $(L)\light.exe /nologo -out $(P).msi $(S).wixobj $(DFX) $(WIX_UI) + @del /q $(S).wixobj 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + + +################### +# makefile inference rules +# +.SUFFIXES: .wxs .wixobj + +.wxs.wixobj:: + @$(L)\candle.exe /nologo -trace -v $< + diff --git a/branches/WOF2-1/WinOF/WIX/win7/x64/wof.wxs b/branches/WOF2-1/WinOF/WIX/win7/x64/wof.wxs new file mode 100644 index 00000000..5fb61d87 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/win7/x64/wof.wxs @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/win7/x86/Makefile b/branches/WOF2-1/WinOF/WIX/win7/x86/Makefile new file mode 100644 index 00000000..f53d575d --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/win7/x86/Makefile @@ -0,0 +1,57 @@ +################### +# makefile targets +# +S=WOF +P=$(S)_win7_x86 + +#WIX 2.0 +# L=..\..\WIX_tools\wix-2.0.5325.0-binaries +L=..\..\WIX_tools\wix-2.0.5805.0-binaries + +# WIX 3.0 L=..\WIX_tools\wix-3.0.2925.0-binaries + +WIX_UI="$(L)\wixui.wixlib" -loc "$(L)\WixUI_en-us.wxl" + +DFX=DIFxApp.wixlib +# Since makebin.bat knows correct WDK version, it copies the DIFX APP files +# to the bin\ tree; eliminates Makefiles having to know about WDK versions. +DFXP=..\bin\Misc\x86 + +full: clean $(P).msi + +clean: + @del /q $(S).wixobj 2>nul + @del /q $(P).msi 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + +MySetup: $(P).msi + +license.rtf: ..\..\license.rtf + @copy ..\..\license.rtf .\license.rtf + +# .dlls need to be in the current folder +$(DFX) : $(DFXP)\$(DFX) $(DFXP)\DIFxApp.dll $(DFXP)\DIFxAppA.dll + @copy /B/Y $(DFXP)\DIFxApp.dll . + @copy /B/Y $(DFXP)\DIFxAppA.dll . + @copy /B/Y $(DFXP)\$(DFX) . + +$(S).wixobj: $(S).wxs + +$(P).msi: $(S).wixobj license.rtf $(DFX) + @echo -- + @echo Building $(P).msi + $(L)\light.exe /nologo -out $(P).msi $(S).wixobj $(DFX) $(WIX_UI) + @del /q $(S).wixobj 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + + +################### +# makefile inference rules +# +.SUFFIXES: .wxs .wixobj + +.wxs.wixobj:: + @$(L)\candle.exe /nologo -trace -v $< + diff --git a/branches/WOF2-1/WinOF/WIX/win7/x86/wof.wxs b/branches/WOF2-1/WinOF/WIX/win7/x86/wof.wxs new file mode 100644 index 00000000..0bf3c949 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/win7/x86/wof.wxs @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/wlh/build-MSI.bat b/branches/WOF2-1/WinOF/WIX/wlh/build-MSI.bat new file mode 100644 index 00000000..d197c55b --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wlh/build-MSI.bat @@ -0,0 +1,69 @@ +@echo off +setlocal +rem Build WNET WIX installer (.msi) for all architectures +rem +rem usage: %0 {dest-path-for-msi-files} + +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 NOT EXIST %DST% ( + echo %0: Installer output path %DST% not found? + exit /B +) +nmake /NOLOGO /? > %DST%\jnk.txt +if ERRORLEVEL 1 ( + echo %0 missing nmake.exe in PATH? + exit /B +) +del /Q /F %DST%\jnk.txt + +if NOT EXIST %CD%\bin\HCA\amd64 ( + echo %0 - %CD%\bin not populated correctly? see trunk\etc\makebin.bat + exit /B +) + +if EXIST ia64\WOF_%OS%_ia64.msi del /Q /F ia64\WOF_%OS%_ia64.msi +if EXIST x64\WOF_%OS%_x64.msi del /Q /F x64\WOF_%OS%_x64.msi +if EXIST x86\WOF_%OS%_x86.msi del /Q /F x86\WOF_%OS%_x86.msi + +if EXIST %DST%\WOF_%OS%_ia64.msi del /Q /F %DST%\WOF_%OS%_ia64.msi +if EXIST %DST%\WOF_%OS%_x64.msi del /Q /F %DST%\WOF_%OS%_x64.msi +if EXIST %DST%\WOF_%OS%_x86.msi del /Q /F %DST%\WOF_%OS%_x86.msi + +pushd ia64 +nmake /NOLOGO full +if ERRORLEVEL 1 exit /B +echo move /Y WOF_%OS%_ia64.msi %DST% +move /Y WOF_%OS%_ia64.msi %DST% +popd + +pushd x64 +nmake /NOLOGO full +if ERRORLEVEL 1 exit /B +echo move /Y WOF_%OS%_x64.msi %DST% +move /Y WOF_%OS%_x64.msi %DST% +popd + +pushd x86 +nmake /NOLOGO full +if ERRORLEVEL 1 exit /B +echo move /Y WOF_%OS%_x86.msi %DST% +move /Y WOF_%OS%_x86.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-1/WinOF/WIX/wlh/ia64/Makefile b/branches/WOF2-1/WinOF/WIX/wlh/ia64/Makefile new file mode 100644 index 00000000..21537cd5 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wlh/ia64/Makefile @@ -0,0 +1,57 @@ +################### +# IA64/IPF Itanium makefile targets +# +S=WOF +P=$(S)_wlh_ia64 + +#WIX 2.0 +# L=..\..\WIX_tools\wix-2.0.5325.0-binaries +L=..\..\WIX_tools\wix-2.0.5805.0-binaries + +# WIX 3.0 L=..\WIX_tools\wix-3.0.2925.0-binaries + +WIX_UI="$(L)\wixui.wixlib" -loc "$(L)\WixUI_en-us.wxl" + +DFX=DIFxApp.wixlib +# Since makebin.bat knows correct WDK version, it copies the DIFX APP files +# to the bin\ tree; eliminates Makefiles having to know about WDK versions. +DFXP=..\bin\Misc\ia64 + +full: clean $(P).msi + +clean: + @del /q $(S).wixobj 2>nul + @del /q $(P).msi 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + +MySetup: $(P).msi + +license.rtf: ..\..\license.rtf + @copy ..\..\license.rtf .\license.rtf + +# .dlls need to be in the current folder +$(DFX) : $(DFXP)\$(DFX) $(DFXP)\DIFxApp.dll $(DFXP)\DIFxAppA.dll + @copy /B/Y $(DFXP)\DIFxApp.dll . + @copy /B/Y $(DFXP)\DIFxAppA.dll . + @copy /B/Y $(DFXP)\$(DFX) . + +$(S).wixobj: $(S).wxs + +$(P).msi: $(S).wixobj license.rtf $(DFX) + @echo -- + @echo Building $(P).msi + $(L)\light.exe /nologo -out $(P).msi $(S).wixobj $(DFX) $(WIX_UI) + @del /q $(S).wixobj 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + + +################### +# makefile inference rules +# +.SUFFIXES: .wxs .wixobj + +.wxs.wixobj:: + @$(L)\candle.exe /nologo -trace -v $< + diff --git a/branches/WOF2-1/WinOF/WIX/wlh/ia64/wof.wxs b/branches/WOF2-1/WinOF/WIX/wlh/ia64/wof.wxs new file mode 100644 index 00000000..3089a99c --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wlh/ia64/wof.wxs @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + AdminUser + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/wlh/signDrivers.bat b/branches/WOF2-1/WinOF/WIX/wlh/signDrivers.bat new file mode 100644 index 00000000..8927b3b2 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wlh/signDrivers.bat @@ -0,0 +1,159 @@ +@echo off +setlocal + +rem Sign device drivers for architectures specified + +rem usage: +rem signDrivers CrossCertFilename CertStoreName path-2-drivers {noTimeStamp} +rem CrossCertFilename - fully qualified path\filename of cross cert. +rem CertStoreName - name of certificate in 'MY' Cert store (certmgr). + +rem example: signDrivers %CD%\Cross-Cert SWPublisher bin\hca + +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 +) + +rem Timestamp the signed file unless instructed not to. +if "%4" == "" ( + 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 (amd64 x86 ia64) 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,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 1 ( + 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-1/WinOF/WIX/wlh/x64/Makefile b/branches/WOF2-1/WinOF/WIX/wlh/x64/Makefile new file mode 100644 index 00000000..2d4d3082 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wlh/x64/Makefile @@ -0,0 +1,57 @@ +################### +# makefile targets +# +S=WOF +P=$(S)_wlh_x64 + +#WIX 2.0 +# L=..\..\WIX_tools\wix-2.0.5325.0-binaries +L=..\..\WIX_tools\wix-2.0.5805.0-binaries + +# WIX 3.0 L=..\WIX_tools\wix-3.0.2925.0-binaries + +WIX_UI="$(L)\wixui.wixlib" -loc "$(L)\WixUI_en-us.wxl" + +DFX=DIFxApp.wixlib +# Since makebin.bat knows correct WDK version, it copies the DIFX APP files +# to the bin\ tree; eliminates Makefiles having to know about WDK versions. +DFXP=..\bin\Misc\amd64 + +full: clean $(P).msi + +clean: + @del /q $(S).wixobj 2>nul + @del /q $(P).msi 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + +MySetup: $(P).msi + +license.rtf: ..\..\license.rtf + @copy ..\..\license.rtf .\license.rtf + +# .dlls need to be in the current folder +$(DFX) : $(DFXP)\$(DFX) $(DFXP)\DIFxApp.dll $(DFXP)\DIFxAppA.dll + @copy /B/Y $(DFXP)\DIFxApp.dll . + @copy /B/Y $(DFXP)\DIFxAppA.dll . + @copy /B/Y $(DFXP)\$(DFX) . + +$(S).wixobj: $(S).wxs + +$(P).msi: $(S).wixobj license.rtf $(DFX) + @echo -- + @echo Building $(P).msi + $(L)\light.exe /nologo -out $(P).msi $(S).wixobj $(DFX) $(WIX_UI) + @del /q $(S).wixobj 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + + +################### +# makefile inference rules +# +.SUFFIXES: .wxs .wixobj + +.wxs.wixobj:: + @$(L)\candle.exe /nologo -trace -v $< + diff --git a/branches/WOF2-1/WinOF/WIX/wlh/x64/cert-add.bat b/branches/WOF2-1/WinOF/WIX/wlh/x64/cert-add.bat new file mode 100644 index 00000000..b4380612 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wlh/x64/cert-add.bat @@ -0,0 +1,127 @@ +@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: %0 \\head-node\remShar cn1 cn2 cn3 cn4 + exit /B 1 +) + +if "%2" == "" goto usage + +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(x86)%\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 + +set OfaWinOfCertID=71175fca6b85d5c2e0864df16349ad84 + +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 %OfaWinOfCertID% 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 %OfaWinOfCertID% %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 using clusrun. + +:again + +if "%2" == "" goto xit +rem echo call clusrun /node:%1 %1\%CISF% %OfaWinOfCertID% %1\%CERTNAME% + clusrun /nodes:%2 %1\%CISF% %OfaWinOfCertID% %1\%CERTNAME% + shift /2 + if not "%2" == "" timeout /T 5 + goto again + +:xit + +if not "%CPY_CERT%" == "" del /F/Q %1\%CERTNAME% +if not "%CPY_CISF%" == "" del /F/Q %1\%CISF% +if not "%EXTRACTED%" == "" del /F/Q %CERTNAME% + +endlocal diff --git a/branches/WOF2-1/WinOF/WIX/wlh/x64/rem-cert-ADD.bat b/branches/WOF2-1/WinOF/WIX/wlh/x64/rem-cert-ADD.bat new file mode 100644 index 00000000..0c441ea6 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wlh/x64/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. + +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 OFA cert in TrustedPublisher cert store +certutil -store TRUSTEDPUBLISHER %1 1> Nul +IF %ERRORLEVEL% NEQ 0 ( +rem echo Installing %2 Cert on %computername% + echo. + certutil -addstore TRUSTEDPUBLISHER "%2" 1> Nul + IF ERRORLEVEL 0 ( + echo %computername% SUCCESS: OFA TrustedPublisher cert installed + ) ELSE ( + echo %computername% FAILURE: OFA TrustedPublisher cert failed to install err %ERRORLEVEL% + ) + echo. +) else ( + echo. + echo %computername% OFA TrustedPublisher Cert already installed. + echo. +) + +endlocal diff --git a/branches/WOF2-1/WinOF/WIX/wlh/x64/wof.wxs b/branches/WOF2-1/WinOF/WIX/wlh/x64/wof.wxs new file mode 100644 index 00000000..ff172aeb --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wlh/x64/wof.wxs @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/wlh/x86/Makefile b/branches/WOF2-1/WinOF/WIX/wlh/x86/Makefile new file mode 100644 index 00000000..880cdb53 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wlh/x86/Makefile @@ -0,0 +1,57 @@ +################### +# makefile targets +# +S=WOF +P=$(S)_wlh_x86 + +#WIX 2.0 +# L=..\..\WIX_tools\wix-2.0.5325.0-binaries +L=..\..\WIX_tools\wix-2.0.5805.0-binaries + +# WIX 3.0 L=..\WIX_tools\wix-3.0.2925.0-binaries + +WIX_UI="$(L)\wixui.wixlib" -loc "$(L)\WixUI_en-us.wxl" + +DFX=DIFxApp.wixlib +# Since makebin.bat knows correct WDK version, it copies the DIFX APP files +# to the bin\ tree; eliminates Makefiles having to know about WDK versions. +DFXP=..\bin\Misc\x86 + +full: clean $(P).msi + +clean: + @del /q $(S).wixobj 2>nul + @del /q $(P).msi 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + +MySetup: $(P).msi + +license.rtf: ..\..\license.rtf + @copy ..\..\license.rtf .\license.rtf + +# .dlls need to be in the current folder +$(DFX) : $(DFXP)\$(DFX) $(DFXP)\DIFxApp.dll $(DFXP)\DIFxAppA.dll + @copy /B/Y $(DFXP)\DIFxApp.dll . + @copy /B/Y $(DFXP)\DIFxAppA.dll . + @copy /B/Y $(DFXP)\$(DFX) . + +$(S).wixobj: $(S).wxs + +$(P).msi: $(S).wixobj license.rtf $(DFX) + @echo -- + @echo Building $(P).msi + $(L)\light.exe /nologo -out $(P).msi $(S).wixobj $(DFX) $(WIX_UI) + @del /q $(S).wixobj 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + + +################### +# makefile inference rules +# +.SUFFIXES: .wxs .wixobj + +.wxs.wixobj:: + @$(L)\candle.exe /nologo -trace -v $< + diff --git a/branches/WOF2-1/WinOF/WIX/wlh/x86/wof.wxs b/branches/WOF2-1/WinOF/WIX/wlh/x86/wof.wxs new file mode 100644 index 00000000..c9aa20c8 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wlh/x86/wof.wxs @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/wnet/build-MSI.bat b/branches/WOF2-1/WinOF/WIX/wnet/build-MSI.bat new file mode 100644 index 00000000..8025c2ca --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wnet/build-MSI.bat @@ -0,0 +1,66 @@ +@echo off +setlocal +rem Build WNET WIX installer (.msi) for all architectures +rem +rem usage: %0 {dest-path-for-msi-files} + +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 NOT EXIST %DST% ( + echo %0: Installer output path %DST% not found? + exit /B +) +nmake /NOLOGO /? > %DST%\jnk.txt +if ERRORLEVEL 1 ( + echo %0 missing nmake.exe in PATH? + exit /B +) +del /Q /F %DST%\jnk.txt + +if NOT EXIST %CD%\bin\HCA\amd64 ( + echo %0 - %CD%\bin not populated correctly? see trunk\etc\makebin.bat + exit /B +) + + +if EXIST ia64\WOF_%OS%_ia64.msi del /Q /F ia64\WOF_%OS%_ia64.msi +if EXIST x64\WOF_%OS%_x64.msi del /Q /F x64\WOF_%OS%_x64.msi +if EXIST x86\WOF_%OS%_x86.msi del /Q /F x86\WOF_%OS%_x86.msi + +if EXIST %DST%\WOF_%OS%_ia64.msi del /Q /F %DST%\WOF_%OS%_ia64.msi +if EXIST %DST%\WOF_%OS%_x64.msi del /Q /F %DST%\WOF_%OS%_x64.msi +if EXIST %DST%\WOF_%OS%_x86.msi del /Q /F %DST%\WOF_%OS%_x86.msi + +pushd ia64 +nmake /NOLOGO full +if ERRORLEVEL 1 exit /B +echo move /Y WOF_%OS%_ia64.msi %DST% +move /Y WOF_%OS%_ia64.msi %DST% +popd +pushd x64 +nmake /NOLOGO full +if ERRORLEVEL 1 exit /B +echo move /Y WOF_%OS%_x64.msi %DST% +move /Y WOF_%OS%_x64.msi %DST% +popd +pushd x86 +nmake /NOLOGO full +if ERRORLEVEL 1 exit /B +echo move /Y WOF_%OS%_x86.msi %DST% +move /Y WOF_%OS%_x86.msi %DST% +popd + +if "%1" == "" dir %DST%\*.msi + +echo ---- +echo Done - %OS% WIX installers in %DST% +echo ---- + +endlocal diff --git a/branches/WOF2-1/WinOF/WIX/wnet/ia64/Makefile b/branches/WOF2-1/WinOF/WIX/wnet/ia64/Makefile new file mode 100644 index 00000000..73b34097 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wnet/ia64/Makefile @@ -0,0 +1,57 @@ +################### +# IA64/IPF Itanium makefile targets +# +S=WOF +P=$(S)_wnet_ia64 + +#WIX 2.0 +# L=..\..\WIX_tools\wix-2.0.5325.0-binaries +L=..\..\WIX_tools\wix-2.0.5805.0-binaries + +# WIX 3.0 L=..\WIX_tools\wix-3.0.2925.0-binaries + +WIX_UI="$(L)\wixui.wixlib" -loc "$(L)\WixUI_en-us.wxl" + +DFX=DIFxApp.wixlib +# Since makebin.bat knows correct WDK version, it copies the DIFX APP files +# to the bin\ tree; eliminates Makefiles having to know about WDK versions. +DFXP=..\bin\Misc\ia64 + +full: clean $(P).msi + +clean: + @del /q $(S).wixobj 2>nul + @del /q $(P).msi 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + +MySetup: $(P).msi + +license.rtf: ..\..\license.rtf + @copy ..\..\license.rtf .\license.rtf + +# .dlls need to be in the current folder +$(DFX) : $(DFXP)\$(DFX) $(DFXP)\DIFxApp.dll $(DFXP)\DIFxAppA.dll + @copy /B/Y $(DFXP)\DIFxApp.dll . + @copy /B/Y $(DFXP)\DIFxAppA.dll . + @copy /B/Y $(DFXP)\$(DFX) . + +$(S).wixobj: $(S).wxs + +$(P).msi: $(S).wixobj license.rtf $(DFX) + @echo -- + @echo Building $(P).msi + $(L)\light.exe /nologo -out $(P).msi $(S).wixobj $(DFX) $(WIX_UI) + @del /q $(S).wixobj 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + + +################### +# makefile inference rules +# +.SUFFIXES: .wxs .wixobj + +.wxs.wixobj:: + @$(L)\candle.exe /nologo -trace -v $< + diff --git a/branches/WOF2-1/WinOF/WIX/wnet/ia64/wof.wxs b/branches/WOF2-1/WinOF/WIX/wnet/ia64/wof.wxs new file mode 100644 index 00000000..f51da3d1 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wnet/ia64/wof.wxs @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/wnet/signDrivers.bat b/branches/WOF2-1/WinOF/WIX/wnet/signDrivers.bat new file mode 100644 index 00000000..13b00cf7 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wnet/signDrivers.bat @@ -0,0 +1,159 @@ +@echo off +setlocal + +rem Sign device drivers for architectures specified + +rem usage: +rem signDrivers CrossCertFilename CertStoreName path-2-drivers {noTimeStamp} +rem CrossCertFilename - fully qualified path\filename of cross cert. +rem CertStoreName - name of certificate in 'MY' Cert store (certmgr). + +rem example: signDrivers %CD%\Cross-Cert SWPublisher bin\hca + +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 +) + +rem Timestamp the signed file unless instructed not to. +if "%4" == "" ( + 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 (amd64 x86 ia64) 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 1 ( + 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-1/WinOF/WIX/wnet/x64/Makefile b/branches/WOF2-1/WinOF/WIX/wnet/x64/Makefile new file mode 100644 index 00000000..97e97989 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wnet/x64/Makefile @@ -0,0 +1,57 @@ +################### +# makefile targets +# +S=WOF +P=$(S)_wnet_x64 + +#WIX 2.0 +# L=..\..\WIX_tools\wix-2.0.5325.0-binaries +L=..\..\WIX_tools\wix-2.0.5805.0-binaries + +# WIX 3.0 L=..\WIX_tools\wix-3.0.2925.0-binaries + +WIX_UI="$(L)\wixui.wixlib" -loc "$(L)\WixUI_en-us.wxl" + +DFX=DIFxApp.wixlib +# Since makebin.bat knows correct WDK version, it copies the DIFX APP files +# to the bin\ tree; eliminates Makefiles having to know about WDK versions. +DFXP=..\bin\Misc\amd64 + +full: clean $(P).msi + +clean: + @del /q $(S).wixobj 2>nul + @del /q $(P).msi 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + +MySetup: $(P).msi + +license.rtf: ..\..\license.rtf + @copy ..\..\license.rtf .\license.rtf + +# .dlls need to be in the current folder +$(DFX) : $(DFXP)\$(DFX) $(DFXP)\DIFxApp.dll $(DFXP)\DIFxAppA.dll + @copy /B/Y $(DFXP)\DIFxApp.dll . + @copy /B/Y $(DFXP)\DIFxAppA.dll . + @copy /B/Y $(DFXP)\$(DFX) . + +$(S).wixobj: $(S).wxs + +$(P).msi: $(S).wixobj license.rtf $(DFX) + @echo -- + @echo Building $(P).msi + $(L)\light.exe /nologo -out $(P).msi $(S).wixobj $(DFX) $(WIX_UI) + @del /q $(S).wixobj 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + + +################### +# makefile inference rules +# +.SUFFIXES: .wxs .wixobj + +.wxs.wixobj:: + @$(L)\candle.exe /nologo -trace -v $< + diff --git a/branches/WOF2-1/WinOF/WIX/wnet/x64/wof.wxs b/branches/WOF2-1/WinOF/WIX/wnet/x64/wof.wxs new file mode 100644 index 00000000..093773ca --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wnet/x64/wof.wxs @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/wnet/x86/Makefile b/branches/WOF2-1/WinOF/WIX/wnet/x86/Makefile new file mode 100644 index 00000000..5a09a4d4 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wnet/x86/Makefile @@ -0,0 +1,57 @@ +################### +# makefile targets +# +S=WOF +P=$(S)_wnet_x86 + +#WIX 2.0 +# L=..\..\WIX_tools\wix-2.0.5325.0-binaries +L=..\..\WIX_tools\wix-2.0.5805.0-binaries + +# WIX 3.0 L=..\WIX_tools\wix-3.0.2925.0-binaries + +WIX_UI="$(L)\wixui.wixlib" -loc "$(L)\WixUI_en-us.wxl" + +DFX=DIFxApp.wixlib +# Since makebin.bat knows correct WDK version, it copies the DIFX APP files +# to the bin\ tree; eliminates Makefiles having to know about WDK versions. +DFXP=..\bin\Misc\x86 + +full: clean $(P).msi + +clean: + @del /q $(S).wixobj 2>nul + @del /q $(P).msi 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + +MySetup: $(P).msi + +license.rtf: ..\..\license.rtf + @copy ..\..\license.rtf .\license.rtf + +# .dlls need to be in the current folder +$(DFX) : $(DFXP)\$(DFX) $(DFXP)\DIFxApp.dll $(DFXP)\DIFxAppA.dll + @copy /B/Y $(DFXP)\DIFxApp.dll . + @copy /B/Y $(DFXP)\DIFxAppA.dll . + @copy /B/Y $(DFXP)\$(DFX) . + +$(S).wixobj: $(S).wxs + +$(P).msi: $(S).wixobj license.rtf $(DFX) + @echo -- + @echo Building $(P).msi + $(L)\light.exe /nologo -out $(P).msi $(S).wixobj $(DFX) $(WIX_UI) + @del /q $(S).wixobj 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + + +################### +# makefile inference rules +# +.SUFFIXES: .wxs .wixobj + +.wxs.wixobj:: + @$(L)\candle.exe /nologo -trace -v $< + diff --git a/branches/WOF2-1/WinOF/WIX/wnet/x86/wof.wxs b/branches/WOF2-1/WinOF/WIX/wnet/x86/wof.wxs new file mode 100644 index 00000000..02b69928 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wnet/x86/wof.wxs @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/wxp/build-MSI.bat b/branches/WOF2-1/WinOF/WIX/wxp/build-MSI.bat new file mode 100644 index 00000000..04096c06 --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wxp/build-MSI.bat @@ -0,0 +1,68 @@ +@echo off +setlocal +rem Build WNET WIX installer (.msi) for all architectures +rem +rem usage: %0 {dest-path-for-msi-files} + +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 NOT EXIST %DST% ( + echo %0: Installer output path %DST% not found? + exit /B +) +nmake /NOLOGO /? > %DST%\jnk.txt +if ERRORLEVEL 1 ( + echo %0 missing nmake.exe in PATH? + exit /B +) +del /Q /F %DST%\jnk.txt + +if NOT EXIST %CD%\bin\HCA\x86 ( + echo %0 - %CD%\bin not populated correctly? see trunk\etc\makebin.bat + exit /B +) + + +rem if EXIST ia64\WOF_%OS%_ia64.msi del /Q /F ia64\WOF_%OS%_ia64.msi +rem if EXIST x64\WOF_%OS%_x64.msi del /Q /F x64\WOF_%OS%_x64.msi +if EXIST x86\WOF_%OS%_x86.msi del /Q /F x86\WOF_%OS%_x86.msi + +rem if EXIST %DST%\WOF_%OS%_ia64.msi del /Q /F %DST%\WOF_%OS%_ia64.msi +rem if EXIST %DST%\WOF_%OS%_x64.msi del /Q /F %DST%\WOF_%OS%_x64.msi +if EXIST %DST%\WOF_%OS%_x86.msi del /Q /F %DST%\WOF_%OS%_x86.msi + +rem pushd ia64 +rem nmake /NOLOGO full +rem if ERRORLEVEL 1 exit /B +rem echo move /Y WOF_%OS%_ia64.msi %DST% +rem move /Y WOF_%OS%_ia64.msi %DST% +rem popd + +rem pushd x64 +rem nmake /NOLOGO full +rem if ERRORLEVEL 1 exit /B +rem echo move /Y WOF_%OS%_x64.msi %DST% +rem move /Y WOF_%OS%_x64.msi %DST% +rem popd + +pushd x86 +nmake /NOLOGO full +if ERRORLEVEL 1 exit /B +echo move /Y WOF_%OS%_x86.msi %DST% +move /Y WOF_%OS%_x86.msi %DST% +popd + +if "%1" == "" dir %DST%\*.msi + +echo ---- +echo Done - %OS% WIX installers in %DST% +echo ---- + +endlocal diff --git a/branches/WOF2-1/WinOF/WIX/wxp/signDrivers.bat b/branches/WOF2-1/WinOF/WIX/wxp/signDrivers.bat new file mode 100644 index 00000000..3311a0be --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wxp/signDrivers.bat @@ -0,0 +1,159 @@ +@echo off +setlocal + +rem Sign device drivers for architectures specified + +rem usage: +rem signDrivers CrossCertFilename CertStoreName path-2-drivers {noTimeStamp} +rem CrossCertFilename - fully qualified path\filename of cross cert. +rem CertStoreName - name of certificate in 'MY' Cert store (certmgr). + +rem example: signDrivers %CD%\Cross-Cert SWPublisher bin\hca + +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 +) + +rem Timestamp the signed file unless instructed not to. +if "%4" == "" ( + 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 ( x86 ) 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 1 ( + 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-1/WinOF/WIX/wxp/x86/Makefile b/branches/WOF2-1/WinOF/WIX/wxp/x86/Makefile new file mode 100644 index 00000000..67bff5aa --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wxp/x86/Makefile @@ -0,0 +1,57 @@ +################### +# makefile targets +# +S=WOF +P=$(S)_wxp_x86 + +#WIX 2.0 +# L=..\..\WIX_tools\wix-2.0.5325.0-binaries +L=..\..\WIX_tools\wix-2.0.5805.0-binaries + +# WIX 3.0 L=..\WIX_tools\wix-3.0.2925.0-binaries + +WIX_UI="$(L)\wixui.wixlib" -loc "$(L)\WixUI_en-us.wxl" + +DFX=DIFxApp.wixlib +# Since makebin.bat knows correct WDK version, it copies the DIFX APP files +# to the bin\ tree; eliminates Makefiles having to know about WDK versions. +DFXP=..\bin\Misc\x86 + +full: clean $(P).msi + +clean: + @del /q $(S).wixobj 2>nul + @del /q $(P).msi 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + +MySetup: $(P).msi + +license.rtf: ..\..\license.rtf + @copy ..\..\license.rtf .\license.rtf + +# .dlls need to be in the current folder +$(DFX) : $(DFXP)\$(DFX) $(DFXP)\DIFxApp.dll $(DFXP)\DIFxAppA.dll + @copy /B/Y $(DFXP)\DIFxApp.dll . + @copy /B/Y $(DFXP)\DIFxAppA.dll . + @copy /B/Y $(DFXP)\$(DFX) . + +$(S).wixobj: $(S).wxs + +$(P).msi: $(S).wixobj license.rtf $(DFX) + @echo -- + @echo Building $(P).msi + $(L)\light.exe /nologo -out $(P).msi $(S).wixobj $(DFX) $(WIX_UI) + @del /q $(S).wixobj 2>nul + @del /q license.rtf 2>nul + @del /q/f DIFxA*.* 2>nul + + +################### +# makefile inference rules +# +.SUFFIXES: .wxs .wixobj + +.wxs.wixobj:: + @$(L)\candle.exe /nologo -trace -v $< + diff --git a/branches/WOF2-1/WinOF/WIX/wxp/x86/wof.wxs b/branches/WOF2-1/WinOF/WIX/wxp/x86/wof.wxs new file mode 100644 index 00000000..82a3b1ed --- /dev/null +++ b/branches/WOF2-1/WinOF/WIX/wxp/x86/wof.wxs @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-1/WinOF/WIX/x64/Command Window.lnk b/branches/WOF2-1/WinOF/WIX/x64/Command Window.lnk new file mode 100644 index 0000000000000000000000000000000000000000..51cf55050a5ac4a90efd92bf6aeb8d4624ce0973 GIT binary patch literal 1350 zcmdT@QAkr^6#nL&p-^Bn!qLjTERtZ(j5UVYC>aUj#1%JW4~uQobZgdKIN>VdULpu4 zLP->iURoG|^pFr#NIH6{h#(;dp-7XcAS@)KzW;7_GkxeS=!f&4bN=(4^PT_P`?muy zm@2pfkF*`$F}hY^XJ>nYL$iiHb8h)9- zufuWOjD{obKp9oCn$f7)GtSf58pv%Otv=b0-H>3!=LZL!tNs~hG;1P8MjJZN3Lh;$ z{q69Sa`Vhp29#tZ-n0+c^G9}G%T_P|1xZ8@M-vD_Et-YqHSX<4(27tzY>%WOC2ny# z;~dnoL(B@p&g>LLa0ACF7K#{v&@PHt$0)*=C|6eQT&tlj^kxl5m0oZT#cKximIFFB z%&?&o=a9fD?k7p>MHDfTD!f*TBu>;56W|b{IKyFhVImWo$lCnc1iBK5q-|sAwU-ZI z{e{@$f4_3?Wy!{0qx_+}IL8D(x|rAcA7JAQVhgequN+m~`Xks@Vf?2=&(p7)8ZPBdeJSJ_`J?1M7Hm;RtP4L^ zq{qacpMBZyijF^Am3HuP0IAKu9M3%hR9tSj(at_aOt+0ovg8{4*6*QMKFCt@qAWez z)uP$2s70#a*rFFfH5|lD92iyel&VeDm@-b3qA|wm8`5ecWzwEj`?}vqI~f%iy@ud8 znpu_t=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-1/WinOF/WIX/x86/Command Window.lnk b/branches/WOF2-1/WinOF/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-1/core/al/al.h b/branches/WOF2-1/core/al/al.h new file mode 100644 index 00000000..07e402d9 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_av.c b/branches/WOF2-1/core/al/al_av.c new file mode 100644 index 00000000..b94162e4 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_av.h b/branches/WOF2-1/core/al/al_av.h new file mode 100644 index 00000000..ffbff2f1 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_ca.c b/branches/WOF2-1/core/al/al_ca.c new file mode 100644 index 00000000..e056cf30 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_ca.h b/branches/WOF2-1/core/al/al_ca.h new file mode 100644 index 00000000..403a0a08 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_ci_ca.h b/branches/WOF2-1/core/al/al_ci_ca.h new file mode 100644 index 00000000..8d654143 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_ci_ca_shared.c b/branches/WOF2-1/core/al/al_ci_ca_shared.c new file mode 100644 index 00000000..ae992d77 --- /dev/null +++ b/branches/WOF2-1/core/al/al_ci_ca_shared.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 "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 ); + } + 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-1/core/al/al_cm_cep.h b/branches/WOF2-1/core/al/al_cm_cep.h new file mode 100644 index 00000000..07a838b1 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_cm_conn.h b/branches/WOF2-1/core/al/al_cm_conn.h new file mode 100644 index 00000000..d11ab34f --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_cm_qp.c b/branches/WOF2-1/core/al/al_cm_qp.c new file mode 100644 index 00000000..dc1aeade --- /dev/null +++ b/branches/WOF2-1/core/al/al_cm_qp.c @@ -0,0 +1,1953 @@ +/* + * 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_req 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 ); + + 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-1/core/al/al_cm_sidr.h b/branches/WOF2-1/core/al/al_cm_sidr.h new file mode 100644 index 00000000..2d37bbbc --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_common.c b/branches/WOF2-1/core/al/al_common.c new file mode 100644 index 00000000..d9dbd50c --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_common.h b/branches/WOF2-1/core/al/al_common.h new file mode 100644 index 00000000..14288694 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_cq.c b/branches/WOF2-1/core/al/al_cq.c new file mode 100644 index 00000000..ef5f8002 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_cq.h b/branches/WOF2-1/core/al/al_cq.h new file mode 100644 index 00000000..39a4b24c --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_debug.h b/branches/WOF2-1/core/al/al_debug.h new file mode 100644 index 00000000..b7f9c30c --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_dev.h b/branches/WOF2-1/core/al/al_dev.h new file mode 100644 index 00000000..6d26e34f --- /dev/null +++ b/branches/WOF2-1/core/al/al_dev.h @@ -0,0 +1,572 @@ +/* + * 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 ); + +void +al_dev_cancel_ioctl( + IN cl_ioctl_handle_t h_ioctl ); + +void +al_dev_cancel_io( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ); + +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-1/core/al/al_dm.c b/branches/WOF2-1/core/al/al_dm.c new file mode 100644 index 00000000..29815a5d --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_dm.h b/branches/WOF2-1/core/al/al_dm.h new file mode 100644 index 00000000..ebd30bdc --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_init.c b/branches/WOF2-1/core/al/al_init.c new file mode 100644 index 00000000..2b2aca5e --- /dev/null +++ b/branches/WOF2-1/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, "Althread" ); + 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-1/core/al/al_init.h b/branches/WOF2-1/core/al/al_init.h new file mode 100644 index 00000000..4f100474 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_ioc_pnp.h b/branches/WOF2-1/core/al/al_ioc_pnp.h new file mode 100644 index 00000000..5758ff46 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_mad.c b/branches/WOF2-1/core/al/al_mad.c new file mode 100644 index 00000000..4576fa8a --- /dev/null +++ b/branches/WOF2-1/core/al/al_mad.c @@ -0,0 +1,3267 @@ +/* + * 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 */ + +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_t *p_wc ); + +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; + } + + 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 ) ) + { + /* 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_t *p_wc ) +{ + AL_ENTER( AL_DBG_MAD_SVC ); + + /* Complete the send if the request failed. */ + if( p_wc->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-1/core/al/al_mad.h b/branches/WOF2-1/core/al/al_mad.h new file mode 100644 index 00000000..ff6cb9cc --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_mad_pool.h b/branches/WOF2-1/core/al/al_mad_pool.h new file mode 100644 index 00000000..cc08888f --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_mcast.c b/branches/WOF2-1/core/al/al_mcast.c new file mode 100644 index 00000000..fe6fde5d --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_mcast.h b/branches/WOF2-1/core/al/al_mcast.h new file mode 100644 index 00000000..4c3c0a25 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_mgr.h b/branches/WOF2-1/core/al/al_mgr.h new file mode 100644 index 00000000..583374c6 --- /dev/null +++ b/branches/WOF2-1/core/al/al_mgr.h @@ -0,0 +1,123 @@ +/* + * 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; + + +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-1/core/al/al_mgr_shared.c b/branches/WOF2-1/core/al/al_mgr_shared.c new file mode 100644 index 00000000..02bd4727 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_mr.h b/branches/WOF2-1/core/al/al_mr.h new file mode 100644 index 00000000..07b5880e --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_mr_shared.c b/branches/WOF2-1/core/al/al_mr_shared.c new file mode 100644 index 00000000..ef5192d8 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_mw.c b/branches/WOF2-1/core/al/al_mw.c new file mode 100644 index 00000000..10b92cef --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_mw.h b/branches/WOF2-1/core/al/al_mw.h new file mode 100644 index 00000000..cdaa97b0 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_pd.c b/branches/WOF2-1/core/al/al_pd.c new file mode 100644 index 00000000..436fc017 --- /dev/null +++ b/branches/WOF2-1/core/al/al_pd.c @@ -0,0 +1,486 @@ +/* + * 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: + CL_ASSERT( h_pd->type == IB_PDT_ALIAS || h_pd->type == IB_PDT_NORMAL ); + 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-1/core/al/al_pd.h b/branches/WOF2-1/core/al/al_pd.h new file mode 100644 index 00000000..4d55867b --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_pnp.h b/branches/WOF2-1/core/al/al_pnp.h new file mode 100644 index 00000000..fdd6c85e --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_proxy.h b/branches/WOF2-1/core/al/al_proxy.h new file mode 100644 index 00000000..5bc853cb --- /dev/null +++ b/branches/WOF2-1/core/al/al_proxy.h @@ -0,0 +1,263 @@ +/* + * 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 _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; + + + +/********************************************************** + * + * 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. */ + cl_ioctl_handle_t h_cm_ioctl; + cl_ioctl_handle_t h_comp_ioctl; + cl_ioctl_handle_t h_misc_ioctl; + + /* 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; + + +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-1/core/al/al_proxy_ioctl.h b/branches/WOF2-1/core/al/al_proxy_ioctl.h new file mode 100644 index 00000000..07b27b47 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_proxy_ndi.h b/branches/WOF2-1/core/al/al_proxy_ndi.h new file mode 100644 index 00000000..ff589629 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_qp.c b/branches/WOF2-1/core/al/al_qp.c new file mode 100644 index 00000000..e785a6fa --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_qp.h b/branches/WOF2-1/core/al/al_qp.h new file mode 100644 index 00000000..f2deaf46 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_query.c b/branches/WOF2-1/core/al/al_query.c new file mode 100644 index 00000000..d382e065 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_query.h b/branches/WOF2-1/core/al/al_query.h new file mode 100644 index 00000000..e32dfb2e --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_reg_svc.c b/branches/WOF2-1/core/al/al_reg_svc.c new file mode 100644 index 00000000..09c0dd0f --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_reg_svc.h b/branches/WOF2-1/core/al/al_reg_svc.h new file mode 100644 index 00000000..56f6dbc5 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_res_mgr.c b/branches/WOF2-1/core/al/al_res_mgr.c new file mode 100644 index 00000000..4e4746cd --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_res_mgr.h b/branches/WOF2-1/core/al/al_res_mgr.h new file mode 100644 index 00000000..65eb54aa --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_srq.c b/branches/WOF2-1/core/al/al_srq.c new file mode 100644 index 00000000..97802408 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_srq.h b/branches/WOF2-1/core/al/al_srq.h new file mode 100644 index 00000000..1c50176a --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_sub.c b/branches/WOF2-1/core/al/al_sub.c new file mode 100644 index 00000000..664e833b --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/al_verbs.h b/branches/WOF2-1/core/al/al_verbs.h new file mode 100644 index 00000000..98c1e677 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/dirs b/branches/WOF2-1/core/al/dirs new file mode 100644 index 00000000..ddf0ed7d --- /dev/null +++ b/branches/WOF2-1/core/al/dirs @@ -0,0 +1,3 @@ +DIRS=\ + user \ + kernel diff --git a/branches/WOF2-1/core/al/ib_common.c b/branches/WOF2-1/core/al/ib_common.c new file mode 100644 index 00000000..9fa149ac --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/ib_common.h b/branches/WOF2-1/core/al/ib_common.h new file mode 100644 index 00000000..456217b1 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/ib_statustext.c b/branches/WOF2-1/core/al/ib_statustext.c new file mode 100644 index 00000000..43e0ae51 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/SOURCES b/branches/WOF2-1/core/al/kernel/SOURCES new file mode 100644 index 00000000..23bfebc9 --- /dev/null +++ b/branches/WOF2-1/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\$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-1/core/al/kernel/al_ci_ca.c b/branches/WOF2-1/core/al/kernel/al_ci_ca.c new file mode 100644 index 00000000..8f62030b --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_cm.c b/branches/WOF2-1/core/al/kernel/al_cm.c new file mode 100644 index 00000000..48b0cb56 --- /dev/null +++ b/branches/WOF2-1/core/al/kernel/al_cm.c @@ -0,0 +1,362 @@ +/* + * 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, *listen_id; + iba_cm_event event; + NTSTATUS status; + + while (al_cep_poll(h_al, cid, &context, &new_cid, &mad) == IB_SUCCESS) { + + if (new_cid == AL_INVALID_CID) { + id = (iba_cm_id *) context; + } else { + listen_id = (iba_cm_id *) context; + + id = cm_alloc_id(listen_id->callback, listen_id); + if (id == NULL) { + kal_cep_destroy(h_al, new_cid, STATUS_NO_MORE_ENTRIES); + ib_put_mad(mad); + continue; + } + + kal_cep_config(h_al, new_cid, cm_cep_handler, id, cm_destroy_handler); + id->cid = new_cid; + } + + 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 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; + + 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->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-1/core/al/kernel/al_cm_cep.c b/branches/WOF2-1/core/al/kernel/al_cm_cep.c new file mode 100644 index 00000000..be0a0045 --- /dev/null +++ b/branches/WOF2-1/core/al/kernel/al_cm_cep.c @@ -0,0 +1,6696 @@ +/* + * 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_REQ_RCVD: + 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_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, + ("al_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 connection context is not set when performing immediate responses, + * such as repeating MADS. + */ + if( !p_cep ) + { + ib_put_mad( p_mad ); + AL_EXIT( AL_DBG_CM ); + return; + } + + p_mad->context1 = NULL; + + KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl ); + /* Clear the sent MAD pointer so that we don't try cancelling again. */ + if( p_cep->p_send_mad == p_mad ) + p_cep->p_send_mad = NULL; + + switch( p_mad->status ) + { + case IB_WCS_SUCCESS: + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + ib_put_mad( p_mad ); + break; + + case IB_WCS_CANCELED: + if( p_cep->state != CEP_STATE_REQ_SENT && + p_cep->state != CEP_STATE_REQ_MRA_RCVD && + p_cep->state != CEP_STATE_REP_SENT && + p_cep->state != CEP_STATE_REP_MRA_RCVD && + p_cep->state != CEP_STATE_LAP_SENT && + p_cep->state != CEP_STATE_LAP_MRA_RCVD && + p_cep->state != CEP_STATE_DREQ_SENT && + p_cep->state != CEP_STATE_SREQ_SENT ) + { + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + ib_put_mad( p_mad ); + break; + } + /* Treat as a timeout so we don't stall the state machine. */ + p_mad->status = IB_WCS_TIMEOUT_RETRY_ERR; + + /* Fall through. */ + case IB_WCS_TIMEOUT_RETRY_ERR: + default: + /* Timeout. Reject the connection. */ + 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 ); + + 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 ); + break; + } + +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. */ + if( p_cep->state == CEP_STATE_DESTROY || + p_cep->state == CEP_STATE_DREQ_DESTROY ) + { + AL_EXIT( AL_DBG_CM ); + return -1; + } + + /* 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] ); + + 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; + p_path->resv1 = 0; + p_path->resv2 = 0; +} + +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->req.service_id = p_mad->sid; + + p_req->req.qpn = conn_req_get_lcl_qpn(p_mad); + p_req->req.qp_type = conn_req_get_qp_type(p_mad); + p_req->req.starting_psn = conn_req_get_starting_psn(p_mad); + + p_req->req.p_pdata = p_mad->pdata; + p_req->req.pdata_len = IB_REQ_PDATA_SIZE; + + p_req->req.max_cm_retries = conn_req_get_max_cm_retries(p_mad); + p_req->req.resp_res = conn_req_get_init_depth(p_mad); + p_req->req.init_depth = conn_req_get_resp_res(p_mad); + p_req->req.remote_resp_timeout = conn_req_get_resp_timeout(p_mad); + p_req->req.flow_ctrl = (uint8_t) conn_req_get_flow_ctrl(p_mad); + p_req->req.local_resp_timeout = conn_req_get_lcl_resp_timeout(p_mad); + p_req->req.rnr_retry_cnt = conn_req_get_rnr_retry_cnt(p_mad); + p_req->req.retry_cnt = conn_req_get_retry_cnt(p_mad); + p_req->req.srq = 0; // TODO: fix mad_cm_req_t + + // We can re-use the MAD buffer if we're careful to read out the data + // that we need before it's overwritten. + p_req->req.p_primary_path = (ib_path_rec_t *) p_mad; + __format_path(p_req->req.p_primary_path, &p_mad->primary_path, + p_mad->pkey, conn_req_get_mtu(p_mad)); + + if (p_mad->alternate_path.remote_lid != 0) { + p_req->req.p_alt_path = p_req->req.p_primary_path + 1; + __format_path(p_req->req.p_alt_path, &p_mad->alternate_path, + p_req->req.p_primary_path->pkey, + p_req->req.p_primary_path->mtu); + } else { + p_req->req.p_alt_path = NULL; + } +} + +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; + if ( p_cep->resp_res ) + { + p_init->state.init.access_ctrl |= IB_AC_RDMA_READ | + IB_AC_RDMA_WRITE | + 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 ); + CL_ASSERT( pfn_addref ); + + 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( 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( 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-1/core/al/kernel/al_dev.c b/branches/WOF2-1/core/al/kernel/al_dev.c new file mode 100644 index 00000000..a0283701 --- /dev/null +++ b/branches/WOF2-1/core/al/kernel/al_dev.c @@ -0,0 +1,566 @@ +/* + * 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; + + 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; + + 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 ); + 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_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. */ + 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. */ + if( p_context->h_cm_ioctl ) + al_dev_cancel_ioctl( p_context->h_cm_ioctl ); + if( p_context->h_comp_ioctl ) + al_dev_cancel_ioctl( p_context->h_comp_ioctl ); + if( p_context->h_misc_ioctl ) + al_dev_cancel_ioctl( p_context->h_misc_ioctl ); + + 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; +} + + + +/* + * Cancel any pending IOCTL calls for the specified type. + * This routine is also called when closing the device. + */ +void +al_dev_cancel_ioctl( + IN cl_ioctl_handle_t h_ioctl ) +{ + al_dev_open_context_t *p_context; + cl_ioctl_handle_t *ph_ioctl; + PIO_STACK_LOCATION p_io_stack; + + /* + * Search the ioctl buffer in the process specific queue + * Dequeue it, if found + */ + AL_ENTER( AL_DBG_DEV ); + + /* Get the stack location. */ + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + + p_context = (al_dev_open_context_t *)p_io_stack->FileObject->FsContext; + ASSERT( p_context ); + + /* Clear the IOCTL. */ + cl_spinlock_acquire( &p_context->cb_lock ); + switch( cl_ioctl_ctl_code( h_ioctl ) ) + { + case UAL_GET_COMP_CB_INFO: + ph_ioctl = &p_context->h_comp_ioctl; + break; + case UAL_GET_MISC_CB_INFO: + ph_ioctl = &p_context->h_misc_ioctl; + break; + default: + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid CB type\n") ); + ph_ioctl = NULL; + break; + } + + if( ph_ioctl && *ph_ioctl == h_ioctl ) + { + *ph_ioctl = NULL; +#pragma warning(push, 3) + IoSetCancelRoutine( h_ioctl, NULL ); +#pragma warning(pop) + + /* Complete the IOCTL. */ + cl_ioctl_complete( h_ioctl, CL_CANCELED, 0 ); + proxy_context_deref( p_context ); + } + cl_spinlock_release( &p_context->cb_lock ); + + AL_EXIT( AL_DBG_DEV ); +} + + +void +al_dev_cancel_io( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ) +{ + AL_ENTER( AL_DBG_DEV ); + + UNUSED_PARAM( p_dev_obj ); + + al_dev_cancel_ioctl( p_irp ); + + IoReleaseCancelSpinLock( p_irp->CancelIrql ); + + AL_EXIT( AL_DBG_DEV ); +} diff --git a/branches/WOF2-1/core/al/kernel/al_exports.def b/branches/WOF2-1/core/al/kernel/al_exports.def new file mode 100644 index 00000000..217e2fde --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_fmr_pool.c b/branches/WOF2-1/core/al/kernel/al_fmr_pool.c new file mode 100644 index 00000000..2525813e --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_fmr_pool.h b/branches/WOF2-1/core/al/kernel/al_fmr_pool.h new file mode 100644 index 00000000..2f7624a2 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_ioc_pnp.c b/branches/WOF2-1/core/al/kernel/al_ioc_pnp.c new file mode 100644 index 00000000..b283ea13 --- /dev/null +++ b/branches/WOF2-1/core/al/kernel/al_ioc_pnp.c @@ -0,0 +1,3330 @@ +/* + * 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 intn_t +__iou_cmp( + IN const void* const p_key1, + IN const void* const p_key2 ); + +static intn_t +__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. + */ + p_path->rec.resv1 = 0; + p_path->rec.resv2 = 0; + + 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 intn_t +__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 intn_t +__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-1/core/al/kernel/al_mad_pool.c b/branches/WOF2-1/core/al/kernel/al_mad_pool.c new file mode 100644 index 00000000..252f72b8 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_mgr.c b/branches/WOF2-1/core/al/kernel/al_mgr.c new file mode 100644 index 00000000..313a8404 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_mr.c b/branches/WOF2-1/core/al/kernel/al_mr.c new file mode 100644 index 00000000..8080c61c --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_ndi_cm.c b/branches/WOF2-1/core/al/kernel/al_ndi_cm.c new file mode 100644 index 00000000..8f3c95c1 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_ndi_cm.h b/branches/WOF2-1/core/al/kernel/al_ndi_cm.h new file mode 100644 index 00000000..554e3978 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_ndi_cq.c b/branches/WOF2-1/core/al/kernel/al_ndi_cq.c new file mode 100644 index 00000000..5ae46422 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_ndi_cq.h b/branches/WOF2-1/core/al/kernel/al_ndi_cq.h new file mode 100644 index 00000000..21b339a7 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_pnp.c b/branches/WOF2-1/core/al/kernel/al_pnp.c new file mode 100644 index 00000000..c3026f29 --- /dev/null +++ b/branches/WOF2-1/core/al/kernel/al_pnp.c @@ -0,0 +1,1813 @@ +/* + * 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 intn_t +__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 intn_t +__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_pzalloc( 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 ); +} + + + +/* + * Check for port attribute changes. + */ +static void +__pnp_check_ports( + IN al_ci_ca_t* const p_ci_ca, + IN const ib_ca_attr_t* const p_old_ca_attr ) +{ + uint16_t index; + al_pnp_ca_event_t event_rec; + ib_port_attr_t *p_old_port_attr, *p_new_port_attr; + + AL_ENTER( AL_DBG_PNP ); + + /* Store the event information. */ + event_rec.p_ci_ca = p_ci_ca; + + for( event_rec.port_index = 0; + event_rec.port_index < p_ci_ca->p_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 ); + } + } + + /* send asynchronous events */ + { + int ci, cnt, i; + 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 ); + + for (i=0; inum_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; + } + } + } + + /* 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-1/core/al/kernel/al_proxy.c b/branches/WOF2-1/core/al/kernel/al_proxy.c new file mode 100644 index 00000000..e89d3632 --- /dev/null +++ b/branches/WOF2-1/core/al/kernel/al_proxy.c @@ -0,0 +1,1284 @@ +/* + * 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; + cl_ioctl_handle_t *ph_ioctl; + 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; + ph_ioctl = &p_context->h_comp_ioctl; + /* 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; + ph_ioctl = &p_context->h_misc_ioctl; + /* 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. */ + CL_ASSERT( !(*ph_ioctl) ); + + /* 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; + } + + *ph_ioctl = h_ioctl; + /* Set the cancel routine for this IRP so the app can abort. */ +#pragma warning(push, 3) + IoSetCancelRoutine( h_ioctl, al_dev_cancel_io ); +#pragma warning(pop) + /* If returning pending, the IRP must be marked as such. */ + IoMarkIrpPending( h_ioctl ); + + /* 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-1/core/al/kernel/al_proxy_cep.c b/branches/WOF2-1/core/al/kernel/al_proxy_cep.c new file mode 100644 index 00000000..6602966a --- /dev/null +++ b/branches/WOF2-1/core/al/kernel/al_proxy_cep.c @@ -0,0 +1,999 @@ +/* + * 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; + + 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 ); + + 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) || + 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 ) ); + + 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-1/core/al/kernel/al_proxy_ioc.c b/branches/WOF2-1/core/al/kernel/al_proxy_ioc.c new file mode 100644 index 00000000..aa4a9a68 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_proxy_ndi.c b/branches/WOF2-1/core/al/kernel/al_proxy_ndi.c new file mode 100644 index 00000000..9d16ceb2 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_proxy_subnet.c b/branches/WOF2-1/core/al/kernel/al_proxy_subnet.c new file mode 100644 index 00000000..07ec17af --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_proxy_verbs.c b/branches/WOF2-1/core/al/kernel/al_proxy_verbs.c new file mode 100644 index 00000000..0169b089 --- /dev/null +++ b/branches/WOF2-1/core/al/kernel/al_proxy_verbs.c @@ -0,0 +1,3916 @@ +/* + * 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 *ph_ioctl, h_ioctl; + 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; + ph_ioctl = &p_context->h_comp_ioctl; + ioctl_size = sizeof( comp_cb_ioctl_info_t ); + break; + + case UAL_GET_MISC_CB_INFO: + p_cb_list = &p_context->misc_cb_list; + ph_ioctl = &p_context->h_misc_ioctl; + 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 ); + + /* See if there is a pending IOCTL ready to receive the callback. */ + if( *ph_ioctl ) + { + h_ioctl = *ph_ioctl; + *ph_ioctl = NULL; +#pragma warning(push, 3) + IoSetCancelRoutine( h_ioctl, NULL ); +#pragma warning(pop) + + 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-1/core/al/kernel/al_sa_req.c b/branches/WOF2-1/core/al/kernel/al_sa_req.c new file mode 100644 index 00000000..05418d76 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/al_smi.c b/branches/WOF2-1/core/al/kernel/al_smi.c new file mode 100644 index 00000000..7f5abee9 --- /dev/null +++ b/branches/WOF2-1/core/al/kernel/al_smi.c @@ -0,0 +1,3757 @@ +/* + * 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 ); + +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; + + 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 ); + + 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 ); + /* 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: + local = ( h_av && + ( h_av->av_attr.dlid == + ( h_av->av_attr.path_bits | p_spl_qp_svc->base_lid ) ) ); + break; + + default: + /* Route vendor specific MADs to the HCA provider. */ + if( ib_class_is_vendor_specific( p_mad->mgmt_class ) ) + { + local = ( 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_LOCAL; + 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; +} + +/* + * 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 ); + CL_ASSERT( p_mad_response->send_context1 ); + + /* 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-1/core/al/kernel/al_smi.h b/branches/WOF2-1/core/al/kernel/al_smi.h new file mode 100644 index 00000000..62cb0fe2 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/ibal.rc b/branches/WOF2-1/core/al/kernel/ibal.rc new file mode 100644 index 00000000..608d6f38 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/kernel/makefile b/branches/WOF2-1/core/al/kernel/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/SOURCES b/branches/WOF2-1/core/al/user/SOURCES new file mode 100644 index 00000000..bc294a53 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/al_dll.c b/branches/WOF2-1/core/al/user/al_dll.c new file mode 100644 index 00000000..85aef032 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/al_exports.src b/branches/WOF2-1/core/al/user/al_exports.src new file mode 100644 index 00000000..02d80658 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/al_mad_pool.c b/branches/WOF2-1/core/al/user/al_mad_pool.c new file mode 100644 index 00000000..6b582342 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ibal.rc b/branches/WOF2-1/core/al/user/ibal.rc new file mode 100644 index 00000000..e2d86f5f --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/makefile b/branches/WOF2-1/core/al/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_av.c b/branches/WOF2-1/core/al/user/ual_av.c new file mode 100644 index 00000000..83ffcec9 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_ca.c b/branches/WOF2-1/core/al/user/ual_ca.c new file mode 100644 index 00000000..3e595c28 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_ca.h b/branches/WOF2-1/core/al/user/ual_ca.h new file mode 100644 index 00000000..671eaad1 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_ci_ca.c b/branches/WOF2-1/core/al/user/ual_ci_ca.c new file mode 100644 index 00000000..e2294e98 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_ci_ca.h b/branches/WOF2-1/core/al/user/ual_ci_ca.h new file mode 100644 index 00000000..6dd42670 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_cm_cep.c b/branches/WOF2-1/core/al/user/ual_cm_cep.c new file mode 100644 index 00000000..5cfc9c1b --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_cq.c b/branches/WOF2-1/core/al/user/ual_cq.c new file mode 100644 index 00000000..5e7116dc --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_mad.c b/branches/WOF2-1/core/al/user/ual_mad.c new file mode 100644 index 00000000..e175ee51 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_mad.h b/branches/WOF2-1/core/al/user/ual_mad.h new file mode 100644 index 00000000..ea090e13 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_mad_pool.c b/branches/WOF2-1/core/al/user/ual_mad_pool.c new file mode 100644 index 00000000..411dd7ee --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_mcast.c b/branches/WOF2-1/core/al/user/ual_mcast.c new file mode 100644 index 00000000..7c17f07f --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_mcast.h b/branches/WOF2-1/core/al/user/ual_mcast.h new file mode 100644 index 00000000..b74e6eeb --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_mgr.c b/branches/WOF2-1/core/al/user/ual_mgr.c new file mode 100644 index 00000000..e92ac6b6 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_mgr.h b/branches/WOF2-1/core/al/user/ual_mgr.h new file mode 100644 index 00000000..e1b37044 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_mr.c b/branches/WOF2-1/core/al/user/ual_mr.c new file mode 100644 index 00000000..6ed32168 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_mw.c b/branches/WOF2-1/core/al/user/ual_mw.c new file mode 100644 index 00000000..8e969d9a --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_pd.c b/branches/WOF2-1/core/al/user/ual_pd.c new file mode 100644 index 00000000..3d58cd09 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_pnp.c b/branches/WOF2-1/core/al/user/ual_pnp.c new file mode 100644 index 00000000..d0eb3972 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_qp.c b/branches/WOF2-1/core/al/user/ual_qp.c new file mode 100644 index 00000000..0b39de4a --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_qp.h b/branches/WOF2-1/core/al/user/ual_qp.h new file mode 100644 index 00000000..0d736efe --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_res_mgr.h b/branches/WOF2-1/core/al/user/ual_res_mgr.h new file mode 100644 index 00000000..84d848e4 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_sa_req.c b/branches/WOF2-1/core/al/user/ual_sa_req.c new file mode 100644 index 00000000..5f1363c7 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_srq.c b/branches/WOF2-1/core/al/user/ual_srq.c new file mode 100644 index 00000000..a9d0d1e4 --- /dev/null +++ b/branches/WOF2-1/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-1/core/al/user/ual_support.h b/branches/WOF2-1/core/al/user/ual_support.h new file mode 100644 index 00000000..04deb8be --- /dev/null +++ b/branches/WOF2-1/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-1/core/bus/dirs b/branches/WOF2-1/core/bus/dirs new file mode 100644 index 00000000..ed41dcf4 --- /dev/null +++ b/branches/WOF2-1/core/bus/dirs @@ -0,0 +1,2 @@ +DIRS=\ + kernel diff --git a/branches/WOF2-1/core/bus/kernel/SOURCES b/branches/WOF2-1/core/bus/kernel/SOURCES new file mode 100644 index 00000000..09d90f2d --- /dev/null +++ b/branches/WOF2-1/core/bus/kernel/SOURCES @@ -0,0 +1,41 @@ +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 + +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-1/core/bus/kernel/bus_driver.c b/branches/WOF2-1/core/bus/kernel/bus_driver.c new file mode 100644 index 00000000..79f9f87f --- /dev/null +++ b/branches/WOF2-1/core/bus/kernel/bus_driver.c @@ -0,0 +1,1083 @@ +/* + * 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_EXIT( BUS_DBG_DRV ); + +} + + +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; + + /* 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_EXIT( BUS_DBG_DRV ); + return STATUS_SUCCESS; +} diff --git a/branches/WOF2-1/core/bus/kernel/bus_driver.h b/branches/WOF2-1/core/bus/kernel/bus_driver.h new file mode 100644 index 00000000..08fc71f9 --- /dev/null +++ b/branches/WOF2-1/core/bus/kernel/bus_driver.h @@ -0,0 +1,303 @@ +/* + * 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 + +/* 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; + +} 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-1/core/bus/kernel/bus_ev_log.mc b/branches/WOF2-1/core/bus/kernel/bus_ev_log.mc new file mode 100644 index 00000000..e60869f1 --- /dev/null +++ b/branches/WOF2-1/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-1/core/bus/kernel/bus_iou_mgr.c b/branches/WOF2-1/core/bus/kernel/bus_iou_mgr.c new file mode 100644 index 00000000..d711ee6d --- /dev/null +++ b/branches/WOF2-1/core/bus/kernel/bus_iou_mgr.c @@ -0,0 +1,1696 @@ +/* + * 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( PagedPool, 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( PagedPool, 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( PagedPool, 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( PagedPool, 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( PagedPool, + 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( PagedPool, 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( PagedPool, 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 )) + { + 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-1/core/bus/kernel/bus_iou_mgr.h b/branches/WOF2-1/core/bus/kernel/bus_iou_mgr.h new file mode 100644 index 00000000..debca84a --- /dev/null +++ b/branches/WOF2-1/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-1/core/bus/kernel/bus_pnp.c b/branches/WOF2-1/core/bus/kernel/bus_pnp.c new file mode 100644 index 00000000..82ffddd8 --- /dev/null +++ b/branches/WOF2-1/core/bus/kernel/bus_pnp.c @@ -0,0 +1,1600 @@ +/* + * 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" + + +/* 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_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, + cl_irp_skip, + 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 ); + IoInitializeRemoveLock( &p_ext->cl_ext.stop_lock, 'dtci', 0, 1000 ); + + /* 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; + p_ext->n_al_ifc_ref = 0; + p_ext->n_ci_ifc_ref = 0; + + 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 +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; + + /* 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; + } + + 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")); + } + 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; + } + + 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 ) ); + } + + /* 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)) ); + return STATUS_UNSUCCESSFUL; + } + + BUS_TRACE_EXIT(BUS_DBG_PNP, ("%s bound to CA guid %I64x\n", + p_bfi->whoami,p_bfi->ca_guid)); + 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; +} + + +/* + * 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; + ib_api_status_t ib_status; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + ic = get_bfi_count(); + + p_bfi = p_ext->bus_filter; + CL_ASSERT( p_bfi ); + + //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_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 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; + } + + 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 )); + 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 ); + + /* 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; + } + + BUS_EXIT( BUS_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; + 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->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_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 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; +} + + +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; + + BUS_ENTER( BUS_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 ); + BUS_EXIT( BUS_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; + bus_fdo_ext_t *p_ext; + IO_STACK_LOCATION *p_io_stack; + + BUS_ENTER( BUS_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 ); + BUS_TRACE_EXIT( BUS_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( status != STATUS_PENDING ) + { + 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 ); + BUS_TRACE( BUS_DBG_ERROR, + ("PoRequestPowerIrp returned %08x.\n", status) ); + } + + BUS_EXIT( BUS_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; + 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 \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 )); + + switch( p_io_stack->Parameters.Power.Type ) + { + case SystemPowerState: +#if 0 + /* + * 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; +#endif + case DevicePowerState: + default: + /* Pass down and let the PDO driver handle it. */ + *p_action = IrpIgnore; + status = STATUS_SUCCESS; + break; + } + + 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-1/core/bus/kernel/bus_pnp.h b/branches/WOF2-1/core/bus/kernel/bus_pnp.h new file mode 100644 index 00000000..681d8449 --- /dev/null +++ b/branches/WOF2-1/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-1/core/bus/kernel/bus_port_mgr.c b/branches/WOF2-1/core/bus/kernel/bus_port_mgr.c new file mode 100644 index 00000000..a0d083ea --- /dev/null +++ b/branches/WOF2-1/core/bus/kernel/bus_port_mgr.c @@ -0,0 +1,2147 @@ +/* + * 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( PagedPool, 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( PagedPool, 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( PagedPool, 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( PagedPool, 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( PagedPool, 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; + } + + 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( PagedPool, 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( PagedPool, 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 )) + { + 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-1/core/bus/kernel/bus_port_mgr.h b/branches/WOF2-1/core/bus/kernel/bus_port_mgr.h new file mode 100644 index 00000000..c3cd60aa --- /dev/null +++ b/branches/WOF2-1/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-1/core/bus/kernel/ibbus.rc b/branches/WOF2-1/core/bus/kernel/ibbus.rc new file mode 100644 index 00000000..ba5e0b7a --- /dev/null +++ b/branches/WOF2-1/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-1/core/bus/kernel/makefile b/branches/WOF2-1/core/bus/kernel/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/cl_async_proc.c b/branches/WOF2-1/core/complib/cl_async_proc.c new file mode 100644 index 00000000..c8dbbe12 --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/cl_list.c b/branches/WOF2-1/core/complib/cl_list.c new file mode 100644 index 00000000..4866b125 --- /dev/null +++ b/branches/WOF2-1/core/complib/cl_list.c @@ -0,0 +1,650 @@ +/* + * 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; + + CL_ASSERT( p_list ); + CL_ASSERT( cl_is_qpool_inited( &p_list->list_item_pool ) ); + CL_ASSERT( p_array ); + CL_ASSERT( item_size ); + CL_ASSERT( item_count ); + + /* + * To add items from the array to the list in the same order as + * the elements appear in the array, we add them starting with + * the last one first. Locate the last item. + */ + p_object = ((uint8_t*)p_array + (item_size * (item_count - 1))); + + /* Continue to add all items to the list. */ + while( item_count-- ) + { + status = cl_list_insert_head( p_list, p_object ); + if( status != CL_SUCCESS ) + { + /* Remove all items that have been inserted. */ + while( item_count++ < item_count ) + cl_list_remove_head( p_list ); + return( status ); + } + + /* Get the next object to add to the list. */ + p_object = ((uint8_t*)p_object - item_size); + } + + return( CL_SUCCESS ); +} + + +cl_status_t +cl_list_insert_array_tail( + IN cl_list_t* const p_list, + IN const void* const p_array, + IN uint32_t item_count, + IN const uint32_t item_size ) +{ + cl_status_t status; + void *p_object; + + CL_ASSERT( p_list ); + CL_ASSERT( cl_is_qpool_inited( &p_list->list_item_pool ) ); + CL_ASSERT( p_array ); + CL_ASSERT( item_size ); + CL_ASSERT( item_count ); + + /* Set the first item to add to the list. */ + p_object = (void*)p_array; + + /* Continue to add all items to the list. */ + while( item_count-- ) + { + status = cl_list_insert_tail( p_list, p_object ); + if( status != CL_SUCCESS ) + { + /* Remove all items that have been inserted. */ + while( item_count++ < item_count ) + cl_list_remove_tail( p_list ); + return( status ); + } + + /* Get the next object to add to the list. */ + p_object = ((uint8_t*)p_object + item_size); + } + + return( CL_SUCCESS ); +} + + +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-1/core/complib/cl_map.c b/branches/WOF2-1/core/complib/cl_map.c new file mode 100644 index 00000000..9af2471c --- /dev/null +++ b/branches/WOF2-1/core/complib/cl_map.c @@ -0,0 +1,2218 @@ +/* + * 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_get( + IN const cl_fmap_t* const p_map, + IN const void* const p_key ) +{ + cl_fmap_item_t *p_item; + intn_t cmp; + + CL_ASSERT( p_map ); + CL_ASSERT( p_map->state == CL_INITIALIZED ); + + p_item = __cl_fmap_root( p_map ); + + while( p_item != &p_map->nil ) + { + cmp = p_map->pfn_compare( p_key, p_item->p_key ); + + if( !cmp ) + break; /* just right */ + + if( cmp < 0 ) + p_item = p_item->p_left; /* too small */ + else + p_item = p_item->p_right; /* too big */ + } + + return( p_item ); +} + + +void +cl_fmap_apply_func( + IN const cl_fmap_t* const p_map, + IN cl_pfn_fmap_apply_t pfn_func, + IN const void* const context ) +{ + cl_fmap_item_t* p_fmap_item; + + /* Note that context can have any arbitrary value. */ + CL_ASSERT( p_map ); + CL_ASSERT( p_map->state == CL_INITIALIZED ); + CL_ASSERT( pfn_func ); + + p_fmap_item = cl_fmap_head( p_map ); + while( p_fmap_item != cl_fmap_end( p_map ) ) + { + pfn_func( p_fmap_item, (void*)context ); + p_fmap_item = cl_fmap_next( p_fmap_item ); + } +} + + +/* + * Balance a tree starting at a given item back to the root. + */ +static void +__cl_fmap_ins_bal( + IN cl_fmap_t* const p_map, + IN cl_fmap_item_t* p_item ) +{ + cl_fmap_item_t* p_grand_uncle; + + CL_ASSERT( p_map ); + CL_ASSERT( p_item ); + CL_ASSERT( p_item != &p_map->root ); + + while( p_item->p_up->color == CL_MAP_RED ) + { + if( __cl_fmap_is_left_child( p_item->p_up ) ) + { + p_grand_uncle = p_item->p_up->p_up->p_right; + CL_ASSERT( p_grand_uncle ); + if( p_grand_uncle->color == CL_MAP_RED ) + { + p_grand_uncle->color = CL_MAP_BLACK; + p_item->p_up->color = CL_MAP_BLACK; + p_item->p_up->p_up->color = CL_MAP_RED; + p_item = p_item->p_up->p_up; + continue; + } + + if( !__cl_fmap_is_left_child( p_item ) ) + { + p_item = p_item->p_up; + __cl_fmap_rot_left( p_map, p_item ); + } + p_item->p_up->color = CL_MAP_BLACK; + p_item->p_up->p_up->color = CL_MAP_RED; + __cl_fmap_rot_right( p_map, p_item->p_up->p_up ); + } + else + { + p_grand_uncle = p_item->p_up->p_up->p_left; + CL_ASSERT( p_grand_uncle ); + if( p_grand_uncle->color == CL_MAP_RED ) + { + p_grand_uncle->color = CL_MAP_BLACK; + p_item->p_up->color = CL_MAP_BLACK; + p_item->p_up->p_up->color = CL_MAP_RED; + p_item = p_item->p_up->p_up; + continue; + } + + if( __cl_fmap_is_left_child( p_item ) ) + { + p_item = p_item->p_up; + __cl_fmap_rot_right( p_map, p_item ); + } + p_item->p_up->color = CL_MAP_BLACK; + p_item->p_up->p_up->color = CL_MAP_RED; + __cl_fmap_rot_left( p_map, p_item->p_up->p_up ); + } + } +} + + +cl_fmap_item_t* +cl_fmap_insert( + IN cl_fmap_t* const p_map, + IN const void* const p_key, + IN cl_fmap_item_t* const p_item ) +{ + cl_fmap_item_t *p_insert_at, *p_comp_item; + intn_t cmp = 0; + + CL_ASSERT( p_map ); + CL_ASSERT( p_map->state == CL_INITIALIZED ); + CL_ASSERT( p_item ); + CL_ASSERT( p_map->root.p_up == &p_map->root ); + CL_ASSERT( p_map->root.color != CL_MAP_RED ); + CL_ASSERT( p_map->nil.color != CL_MAP_RED ); + + p_item->p_left = &p_map->nil; + p_item->p_right = &p_map->nil; + p_item->p_key = p_key; + p_item->color = CL_MAP_RED; + + /* Find the insertion location. */ + p_insert_at = &p_map->root; + p_comp_item = __cl_fmap_root( p_map ); + + while( p_comp_item != &p_map->nil ) + { + p_insert_at = p_comp_item; + + cmp = p_map->pfn_compare( p_key, p_insert_at->p_key ); + + if( !cmp ) + return( p_insert_at ); + + /* Traverse the tree until the correct insertion point is found. */ + if( cmp < 0 ) + p_comp_item = p_insert_at->p_left; + else + p_comp_item = p_insert_at->p_right; + } + + CL_ASSERT( p_insert_at != &p_map->nil ); + CL_ASSERT( p_comp_item == &p_map->nil ); + /* Insert the item. */ + if( p_insert_at == &p_map->root ) + { + p_insert_at->p_left = p_item; + /* + * Primitive insert places the new item in front of + * the existing item. + */ + __cl_primitive_insert( &p_map->nil.pool_item.list_item, + &p_item->pool_item.list_item ); + } + else if( cmp < 0 ) + { + p_insert_at->p_left = p_item; + /* + * Primitive insert places the new item in front of + * the existing item. + */ + __cl_primitive_insert( &p_insert_at->pool_item.list_item, + &p_item->pool_item.list_item ); + } + else + { + p_insert_at->p_right = p_item; + /* + * Primitive insert places the new item in front of + * the existing item. + */ + __cl_primitive_insert( p_insert_at->pool_item.list_item.p_next, + &p_item->pool_item.list_item ); + } + /* Increase the count. */ + p_map->count++; + + p_item->p_up = p_insert_at; + + /* + * We have added depth to this section of the tree. + * Rebalance as necessary as we retrace our path through the tree + * and update colors. + */ + __cl_fmap_ins_bal( p_map, p_item ); + + __cl_fmap_root( p_map )->color = CL_MAP_BLACK; + + /* + * Note that it is not necessary to re-color the nil node black because all + * red color assignments are made via the p_up pointer, and nil is never + * set as the value of a p_up pointer. + */ + +#ifdef _DEBUG_ + /* Set the pointer to the map in the map item for consistency checking. */ + p_item->p_map = p_map; +#endif + + return( p_item ); +} + + +static void +__cl_fmap_del_bal( + IN cl_fmap_t* const p_map, + IN cl_fmap_item_t* p_item ) +{ + cl_fmap_item_t *p_uncle; + + while( (p_item->color != CL_MAP_RED) && (p_item->p_up != &p_map->root) ) + { + if( __cl_fmap_is_left_child( p_item ) ) + { + p_uncle = p_item->p_up->p_right; + + if( p_uncle->color == CL_MAP_RED ) + { + p_uncle->color = CL_MAP_BLACK; + p_item->p_up->color = CL_MAP_RED; + __cl_fmap_rot_left( p_map, p_item->p_up ); + p_uncle = p_item->p_up->p_right; + } + + if( p_uncle->p_right->color != CL_MAP_RED ) + { + if( p_uncle->p_left->color != CL_MAP_RED ) + { + p_uncle->color = CL_MAP_RED; + p_item = p_item->p_up; + continue; + } + + p_uncle->p_left->color = CL_MAP_BLACK; + p_uncle->color = CL_MAP_RED; + __cl_fmap_rot_right( p_map, p_uncle ); + p_uncle = p_item->p_up->p_right; + } + p_uncle->color = p_item->p_up->color; + p_item->p_up->color = CL_MAP_BLACK; + p_uncle->p_right->color = CL_MAP_BLACK; + __cl_fmap_rot_left( p_map, p_item->p_up ); + break; + } + else + { + p_uncle = p_item->p_up->p_left; + + if( p_uncle->color == CL_MAP_RED ) + { + p_uncle->color = CL_MAP_BLACK; + p_item->p_up->color = CL_MAP_RED; + __cl_fmap_rot_right( p_map, p_item->p_up ); + p_uncle = p_item->p_up->p_left; + } + + if( p_uncle->p_left->color != CL_MAP_RED ) + { + if( p_uncle->p_right->color != CL_MAP_RED ) + { + p_uncle->color = CL_MAP_RED; + p_item = p_item->p_up; + continue; + } + + p_uncle->p_right->color = CL_MAP_BLACK; + p_uncle->color = CL_MAP_RED; + __cl_fmap_rot_left( p_map, p_uncle ); + p_uncle = p_item->p_up->p_left; + } + p_uncle->color = p_item->p_up->color; + p_item->p_up->color = CL_MAP_BLACK; + p_uncle->p_left->color = CL_MAP_BLACK; + __cl_fmap_rot_right( p_map, p_item->p_up ); + break; + } + } + p_item->color = CL_MAP_BLACK; +} + + +void +cl_fmap_remove_item( + IN cl_fmap_t* const p_map, + IN cl_fmap_item_t* const p_item ) +{ + cl_fmap_item_t *p_child, *p_del_item; + + CL_ASSERT( p_map ); + CL_ASSERT( p_map->state == CL_INITIALIZED ); + CL_ASSERT( p_item ); + CL_ASSERT( p_item->p_map == p_map ); + + if( p_item == cl_fmap_end( p_map ) ) + return; + + if( (p_item->p_right == &p_map->nil) || (p_item->p_left == &p_map->nil ) ) + { + /* The item being removed has children on at most on side. */ + p_del_item = p_item; + } + else + { + /* + * The item being removed has children on both side. + * We select the item that will replace it. After removing + * the substitute item and rebalancing, the tree will have the + * correct topology. Exchanging the substitute for the item + * will finalize the removal. + */ + p_del_item = cl_fmap_next( p_item ); + CL_ASSERT( p_del_item != &p_map->nil ); + } + + /* Remove the item from the list. */ + __cl_primitive_remove( &p_item->pool_item.list_item ); + /* Decrement the item count. */ + p_map->count--; + + /* Get the pointer to the new root's child, if any. */ + if( p_del_item->p_left != &p_map->nil ) + p_child = p_del_item->p_left; + else + p_child = p_del_item->p_right; + + /* + * This assignment may modify the parent pointer of the nil node. + * This is inconsequential. + */ + p_child->p_up = p_del_item->p_up; + (*__cl_fmap_get_parent_ptr_to_item( p_del_item )) = p_child; + + if( p_del_item->color != CL_MAP_RED ) + __cl_fmap_del_bal( p_map, p_child ); + + /* + * Note that the splicing done below does not need to occur before + * the tree is balanced, since the actual topology changes are made by the + * preceding code. The topology is preserved by the color assignment made + * below (reader should be reminded that p_del_item == p_item in some cases). + */ + if( p_del_item != p_item ) + { + /* + * Finalize the removal of the specified item by exchanging it with + * the substitute which we removed above. + */ + p_del_item->p_up = p_item->p_up; + p_del_item->p_left = p_item->p_left; + p_del_item->p_right = p_item->p_right; + (*__cl_fmap_get_parent_ptr_to_item( p_item )) = p_del_item; + p_item->p_right->p_up = p_del_item; + p_item->p_left->p_up = p_del_item; + p_del_item->color = p_item->color; + } + + CL_ASSERT( p_map->nil.color != CL_MAP_RED ); + +#ifdef _DEBUG_ + /* Clear the pointer to the map since the item has been removed. */ + p_item->p_map = NULL; +#endif +} + + +cl_fmap_item_t* +cl_fmap_remove( + IN cl_fmap_t* const p_map, + IN const void* const p_key ) +{ + cl_fmap_item_t *p_item; + + CL_ASSERT( p_map ); + CL_ASSERT( p_map->state == CL_INITIALIZED ); + + /* Seek the node with the specified key */ + p_item = cl_fmap_get( p_map, p_key ); + + cl_fmap_remove_item( p_map, p_item ); + + return( p_item ); +} + + +void +cl_fmap_merge( + OUT cl_fmap_t* const p_dest_map, + IN OUT cl_fmap_t* const p_src_map ) +{ + cl_fmap_item_t *p_item, *p_item2, *p_next; + + CL_ASSERT( p_dest_map ); + CL_ASSERT( p_src_map ); + + p_item = cl_fmap_head( p_src_map ); + + while( p_item != cl_fmap_end( p_src_map ) ) + { + p_next = cl_fmap_next( p_item ); + + /* Remove the item from its current map. */ + cl_fmap_remove_item( p_src_map, p_item ); + /* Insert the item into the destination map. */ + p_item2 = cl_fmap_insert( p_dest_map, cl_fmap_key( p_item ), p_item ); + /* Check that the item was successfully inserted. */ + if( p_item2 != p_item ) + { + /* Put the item in back in the source map. */ + p_item2 = + cl_fmap_insert( p_src_map, cl_fmap_key( p_item ), p_item ); + CL_ASSERT( p_item2 == p_item ); + } + p_item = p_next; + } +} + + +static void +__cl_fmap_delta_move( + IN OUT cl_fmap_t* const p_dest, + IN OUT cl_fmap_t* const p_src, + IN OUT cl_fmap_item_t** const pp_item ) +{ + cl_fmap_item_t *p_temp, *p_next; + + /* + * Get the next item so that we can ensure that pp_item points to + * a valid item upon return from the function. + */ + p_next = cl_fmap_next( *pp_item ); + /* Move the old item from its current map the the old map. */ + cl_fmap_remove_item( p_src, *pp_item ); + p_temp = cl_fmap_insert( p_dest, cl_fmap_key( *pp_item ), *pp_item ); + /* We should never have duplicates. */ + CL_ASSERT( p_temp == *pp_item ); + /* Point pp_item to a valid item in the source map. */ + (*pp_item) = p_next; +} + + +void +cl_fmap_delta( + IN OUT cl_fmap_t* const p_map1, + IN OUT cl_fmap_t* const p_map2, + OUT cl_fmap_t* const p_new, + OUT cl_fmap_t* const p_old ) +{ + cl_fmap_item_t *p_item1, *p_item2; + intn_t cmp; + + CL_ASSERT( p_map1 ); + CL_ASSERT( p_map2 ); + CL_ASSERT( p_new ); + CL_ASSERT( p_old ); + CL_ASSERT( cl_is_fmap_empty( p_new ) ); + CL_ASSERT( cl_is_fmap_empty( p_old ) ); + + p_item1 = cl_fmap_head( p_map1 ); + p_item2 = cl_fmap_head( p_map2 ); + + while( p_item1 != cl_fmap_end( p_map1 ) && + p_item2 != cl_fmap_end( p_map2 ) ) + { + cmp = p_map1->pfn_compare( cl_fmap_key( p_item1 ), + cl_fmap_key( p_item2 ) ); + if( cmp < 0 ) + { + /* We found an old item. */ + __cl_fmap_delta_move( p_old, p_map1, &p_item1 ); + } + else if( cmp > 0 ) + { + /* We found a new item. */ + __cl_fmap_delta_move( p_new, p_map2, &p_item2 ); + } + else + { + /* Move both forward since they have the same key. */ + p_item1 = cl_fmap_next( p_item1 ); + p_item2 = cl_fmap_next( p_item2 ); + } + } + + /* Process the remainder if the end of either source map was reached. */ + while( p_item2 != cl_fmap_end( p_map2 ) ) + __cl_fmap_delta_move( p_new, p_map2, &p_item2 ); + + while( p_item1 != cl_fmap_end( p_map1 ) ) + __cl_fmap_delta_move( p_old, p_map1, &p_item1 ); +} diff --git a/branches/WOF2-1/core/complib/cl_memory.c b/branches/WOF2-1/core/complib/cl_memory.c new file mode 100644 index 00000000..eec7a235 --- /dev/null +++ b/branches/WOF2-1/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, (uintn_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, (uintn_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-1/core/complib/cl_memtrack.h b/branches/WOF2-1/core/complib/cl_memtrack.h new file mode 100644 index 00000000..43e8deab --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/cl_obj.c b/branches/WOF2-1/core/complib/cl_obj.c new file mode 100644 index 00000000..259a5f53 --- /dev/null +++ b/branches/WOF2-1/core/complib/cl_obj.c @@ -0,0 +1,781 @@ +/* + * 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 ) + { + 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-1/core/complib/cl_perf.c b/branches/WOF2-1/core/complib/cl_perf.c new file mode 100644 index 00000000..49675786 --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/cl_pool.c b/branches/WOF2-1/core/complib/cl_pool.c new file mode 100644 index 00000000..9562da60 --- /dev/null +++ b/branches/WOF2-1/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(uintn_t) ); + } + + p_pool->max_objects = max_size? max_size : ~(size_t)0; + p_pool->grow_size = grow_size; + + /* Store callback function pointers. */ + p_pool->pfn_init = pfn_initializer; /* may be NULL */ + p_pool->pfn_dtor = pfn_destructor; /* may be NULL */ + p_pool->context = context; + + cl_qlist_init( &p_pool->alloc_list ); + + cl_qlist_init( &p_pool->free_list ); + + /* + * We are now initialized. We change the initialized flag before + * growing since the grow function asserts that we are initialized. + */ + p_pool->state = CL_INITIALIZED; + + /* Allocate the minimum number of objects as requested. */ + if( !min_size ) + return( CL_SUCCESS ); + + status = cl_qcpool_grow( p_pool, min_size ); + /* Trap for error and cleanup if necessary. */ + if( status != CL_SUCCESS ) + cl_qcpool_destroy( p_pool ); + + return( status ); +} + + +void +cl_qcpool_destroy( + IN cl_qcpool_t* const p_pool ) +{ + /* CL_ASSERT that a non-NULL pointer was provided. */ + CL_ASSERT( p_pool ); + /* CL_ASSERT that we are in a valid state (not uninitialized memory). */ + CL_ASSERT( cl_is_state_valid( p_pool->state ) ); + + if( p_pool->state == CL_INITIALIZED ) + { + /* + * Assert if the user hasn't put everything back in the pool + * before destroying it + * if they haven't, then most likely they are still using memory + * that will be freed, and the destructor will not be called! + */ + +// 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-1/core/complib/cl_ptr_vector.c b/branches/WOF2-1/core/complib/cl_ptr_vector.c new file mode 100644 index 00000000..dbb3d926 --- /dev/null +++ b/branches/WOF2-1/core/complib/cl_ptr_vector.c @@ -0,0 +1,357 @@ +/* + * 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 ); + } + } + + return( p_vector->size ); +} + + diff --git a/branches/WOF2-1/core/complib/cl_reqmgr.c b/branches/WOF2-1/core/complib/cl_reqmgr.c new file mode 100644 index 00000000..9ea1f08d --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/cl_statustext.c b/branches/WOF2-1/core/complib/cl_statustext.c new file mode 100644 index 00000000..76441704 --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/cl_threadpool.c b/branches/WOF2-1/core/complib/cl_threadpool.c new file mode 100644 index 00000000..cba8f2c7 --- /dev/null +++ b/branches/WOF2-1/core/complib/cl_threadpool.c @@ -0,0 +1,237 @@ +/* + * 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 ); + } + 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-1/core/complib/cl_vector.c b/branches/WOF2-1/core/complib/cl_vector.c new file mode 100644 index 00000000..843d9f4e --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/dirs b/branches/WOF2-1/core/complib/dirs new file mode 100644 index 00000000..ddf0ed7d --- /dev/null +++ b/branches/WOF2-1/core/complib/dirs @@ -0,0 +1,3 @@ +DIRS=\ + user \ + kernel diff --git a/branches/WOF2-1/core/complib/kernel/SOURCES b/branches/WOF2-1/core/complib/kernel/SOURCES new file mode 100644 index 00000000..dd385750 --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/kernel/cl_bus_ifc.c b/branches/WOF2-1/core/complib/kernel/cl_bus_ifc.c new file mode 100644 index 00000000..6c0810dd --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/kernel/cl_driver.c b/branches/WOF2-1/core/complib/kernel/cl_driver.c new file mode 100644 index 00000000..452df77a --- /dev/null +++ b/branches/WOF2-1/core/complib/kernel/cl_driver.c @@ -0,0 +1,81 @@ +/* + * 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-1/core/complib/kernel/cl_event.c b/branches/WOF2-1/core/complib/kernel/cl_event.c new file mode 100644 index 00000000..07f9790d --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/kernel/cl_exports.def b/branches/WOF2-1/core/complib/kernel/cl_exports.def new file mode 100644 index 00000000..7d05000b --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/kernel/cl_log.c b/branches/WOF2-1/core/complib/kernel/cl_log.c new file mode 100644 index 00000000..5aa2b0bf --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/kernel/cl_memory_osd.c b/branches/WOF2-1/core/complib/kernel/cl_memory_osd.c new file mode 100644 index 00000000..6205a5a6 --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/kernel/cl_pnp_po.c b/branches/WOF2-1/core/complib/kernel/cl_pnp_po.c new file mode 100644 index 00000000..ea8d1a27 --- /dev/null +++ b/branches/WOF2-1/core/complib/kernel/cl_pnp_po.c @@ -0,0 +1,1429 @@ +/* + * 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 ); + + /* 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; + } + + if( action != IrpDoNothing ) + IoReleaseRemoveLock( &p_ext->remove_lock, p_irp ); + + CL_TRACE_EXIT( CL_DBG_PNP, p_ext->dbg_lvl, ("returned with status %#x\n", status) ); + 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 ); + + /* + * If we get the start request when we're already started, don't + * re-initialize the stop lock. + */ + if( p_ext->last_pnp_state != Started ) { + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IoInitializeRemoveLock: stop_lock %p[\n", &p_ext->stop_lock)); + IoInitializeRemoveLock( &p_ext->stop_lock, 'dtci', 0, 1000 ); + } + + 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; + } + + if( p_ext->last_pnp_state == Started ) + { + /* + * Re-initialize the stop lock before rolling back the PnP + * state so that there's no contention while it's uninitialized. + */ + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IoInitializeRemoveLock: stop_lock %p[\n", &p_ext->stop_lock)); + IoInitializeRemoveLock( &p_ext->stop_lock, 'dtci', 0, 1000 ); +#if 0 + // leo: it seems like a bug, because it can never get released + { + /* + * Acquire the stop lock to allow releasing and waiting when stopping. + */ + NTSTATUS status1; + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IoAcquireRemoveLock: stop_lock %p[\n", &p_ext->stop_lock)); + status1 = IoAcquireRemoveLock( &p_ext->stop_lock, NULL ); + if( !NT_SUCCESS( status1 ) ) + { + CL_TRACE( CL_DBG_ERROR, p_ext->dbg_lvl, + ("IoAcquireRemoveLock returned %08x. Continue anyway ...\n", status) ); + } + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IoAcquireRemoveLock: stop_lock ]\n")); + } +#endif + } + + /* 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( PagedPool, 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-1/core/complib/kernel/cl_syscallback.c b/branches/WOF2-1/core/complib/kernel/cl_syscallback.c new file mode 100644 index 00000000..98246763 --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/kernel/cl_thread.c b/branches/WOF2-1/core/complib/kernel/cl_thread.c new file mode 100644 index 00000000..f68eb167 --- /dev/null +++ b/branches/WOF2-1/core/complib/kernel/cl_thread.c @@ -0,0 +1,138 @@ +/* + * 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 ); + + 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. */ + 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() ); +} \ No newline at end of file diff --git a/branches/WOF2-1/core/complib/kernel/cl_timer.c b/branches/WOF2-1/core/complib/kernel/cl_timer.c new file mode 100644 index 00000000..34cae8e3 --- /dev/null +++ b/branches/WOF2-1/core/complib/kernel/cl_timer.c @@ -0,0 +1,160 @@ +/* + * 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 ) +{ + UNUSED_PARAM( p_dpc ); + UNUSED_PARAM( arg1 ); + UNUSED_PARAM( arg2 ); + + p_timer->timeout_time = 0; + + (p_timer->pfn_callback)( (void*)p_timer->context ); +} + + +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 ); + + 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; + + 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); + + /* Store the timeout time in the timer object. */ + p_timer->timeout_time = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000); + + KeSetTimer( &p_timer->timer, due_time, &p_timer->dpc ); + return( CL_SUCCESS ); +} + + +cl_status_t +cl_timer_trim( + IN cl_timer_t* const p_timer, + IN const uint32_t time_ms ) +{ + uint64_t timeout_time; + + CL_ASSERT( p_timer ); + CL_ASSERT( p_timer->pfn_callback ); + + /* Calculate the timeout time in the timer object. */ + timeout_time = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000); + + /* Only pull in the timeout time. */ + if( p_timer->timeout_time && p_timer->timeout_time < timeout_time ) + return( CL_SUCCESS ); + + return cl_timer_start( p_timer, time_ms ); +} + + +void +cl_timer_stop( + IN cl_timer_t* const p_timer ) +{ + 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. */ + KeCancelTimer( &p_timer->timer ); + + p_timer->timeout_time = 0; +} diff --git a/branches/WOF2-1/core/complib/kernel/makefile b/branches/WOF2-1/core/complib/kernel/makefile new file mode 100644 index 00000000..9c985f57 --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/user/SOURCES b/branches/WOF2-1/core/complib/user/SOURCES new file mode 100644 index 00000000..f960a00a --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/user/cl_debug.c b/branches/WOF2-1/core/complib/user/cl_debug.c new file mode 100644 index 00000000..5ee2a650 --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/user/cl_dll.c b/branches/WOF2-1/core/complib/user/cl_dll.c new file mode 100644 index 00000000..dbc6405e --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/user/cl_event.c b/branches/WOF2-1/core/complib/user/cl_event.c new file mode 100644 index 00000000..2ec5b1cd --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/user/cl_log.c b/branches/WOF2-1/core/complib/user/cl_log.c new file mode 100644 index 00000000..a5821814 --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/user/cl_memory_osd.c b/branches/WOF2-1/core/complib/user/cl_memory_osd.c new file mode 100644 index 00000000..643e1b26 --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/user/cl_nodenamemap.c b/branches/WOF2-1/core/complib/user/cl_nodenamemap.c new file mode 100644 index 00000000..c3b6d65d --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/user/cl_syscallback.c b/branches/WOF2-1/core/complib/user/cl_syscallback.c new file mode 100644 index 00000000..feec61ce --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/user/cl_thread.c b/branches/WOF2-1/core/complib/user/cl_thread.c new file mode 100644 index 00000000..2edaee95 --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/user/cl_timer.c b/branches/WOF2-1/core/complib/user/cl_timer.c new file mode 100644 index 00000000..4f2ce0fc --- /dev/null +++ b/branches/WOF2-1/core/complib/user/cl_timer.c @@ -0,0 +1,195 @@ +/* + * 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" + + +static void CALLBACK +__timer_callback( + IN cl_timer_t* const p_timer, + IN BOOLEAN timer_signalled ) +{ + /* timer_signalled is always TRUE, and has no value. */ + CL_ASSERT( timer_signalled ); + UNUSED_PARAM( timer_signalled ); + + p_timer->timeout_time = 0; + p_timer->thread_id = GetCurrentThreadId(); + + (p_timer->pfn_callback)( (void*)p_timer->context ); + + p_timer->thread_id = 0; +} + + +void +cl_timer_construct( + IN cl_timer_t* const p_timer ) +{ + p_timer->h_timer = NULL; + p_timer->timeout_time = 0; + p_timer->thread_id = 0; +} + + + +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; + return( CL_SUCCESS ); +} + + +void +cl_timer_destroy( + IN cl_timer_t* const p_timer ) +{ + CL_ASSERT( p_timer ); + + cl_timer_stop( p_timer ); +} + + +cl_status_t +cl_timer_start( + IN cl_timer_t* const p_timer, + IN const uint32_t time_ms ) +{ + CL_ASSERT( p_timer ); + + cl_timer_stop( p_timer ); + + p_timer->timeout_time = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000); + + if( !CreateTimerQueueTimer( &p_timer->h_timer, NULL, __timer_callback, + p_timer, time_ms, 0, WT_EXECUTEINIOTHREAD ) ) + { + return( CL_ERROR ); + } + + return( CL_SUCCESS ); +} + + +cl_status_t +cl_timer_trim( + IN cl_timer_t* const p_timer, + IN const uint32_t time_ms ) +{ + uint64_t timeout_time; + + CL_ASSERT( p_timer ); + CL_ASSERT( p_timer->pfn_callback ); + + /* Calculate the timeout time in the timer object. */ + timeout_time = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000); + + /* Only pull in the timeout time. */ + if( p_timer->timeout_time && p_timer->timeout_time < timeout_time ) + return( CL_SUCCESS ); + + return cl_timer_start( p_timer, time_ms ); +} + + +void +cl_timer_stop( + IN cl_timer_t* const p_timer ) +{ + CL_ASSERT( p_timer ); + + if( p_timer->h_timer && p_timer->thread_id != GetCurrentThreadId() ) + { + /* Make sure we block until the timer is cancelled. */ + DeleteTimerQueueTimer( NULL, p_timer->h_timer, INVALID_HANDLE_VALUE ); + p_timer->h_timer = NULL; + } + p_timer->timeout_time = 0; +} + + +#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-1/core/complib/user/complib.rc b/branches/WOF2-1/core/complib/user/complib.rc new file mode 100644 index 00000000..6237874c --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/user/complib.src b/branches/WOF2-1/core/complib/user/complib.src new file mode 100644 index 00000000..58416100 --- /dev/null +++ b/branches/WOF2-1/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-1/core/complib/user/makefile b/branches/WOF2-1/core/complib/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/core/dirs b/branches/WOF2-1/core/dirs new file mode 100644 index 00000000..73c7806e --- /dev/null +++ b/branches/WOF2-1/core/dirs @@ -0,0 +1,8 @@ +DIRS=\ + complib \ + al \ + bus \ + iou \ + ibat \ + winverbs \ + winmad diff --git a/branches/WOF2-1/core/ibat/dirs b/branches/WOF2-1/core/ibat/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-1/core/ibat/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/core/ibat/user/SOURCES b/branches/WOF2-1/core/ibat/user/SOURCES new file mode 100644 index 00000000..bc2f63af --- /dev/null +++ b/branches/WOF2-1/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-1/core/ibat/user/ibat.cpp b/branches/WOF2-1/core/ibat/user/ibat.cpp new file mode 100644 index 00000000..9d489720 --- /dev/null +++ b/branches/WOF2-1/core/ibat/user/ibat.cpp @@ -0,0 +1,377 @@ +/* + * 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, 0, 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, 0, 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 +} + +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 ); +} + +} /* extern "C" */ diff --git a/branches/WOF2-1/core/ibat/user/makefile b/branches/WOF2-1/core/ibat/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/core/iou/dirs b/branches/WOF2-1/core/iou/dirs new file mode 100644 index 00000000..ed41dcf4 --- /dev/null +++ b/branches/WOF2-1/core/iou/dirs @@ -0,0 +1,2 @@ +DIRS=\ + kernel diff --git a/branches/WOF2-1/core/iou/kernel/SOURCES b/branches/WOF2-1/core/iou/kernel/SOURCES new file mode 100644 index 00000000..1a628db1 --- /dev/null +++ b/branches/WOF2-1/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-1/core/iou/kernel/ib_iou.cdf b/branches/WOF2-1/core/iou/kernel/ib_iou.cdf new file mode 100644 index 00000000..ecc21ac2 --- /dev/null +++ b/branches/WOF2-1/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-1/core/iou/kernel/ib_iou.inx b/branches/WOF2-1/core/iou/kernel/ib_iou.inx new file mode 100644 index 00000000..08fe50bb --- /dev/null +++ b/branches/WOF2-1/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-1/core/iou/kernel/ibiou.rc b/branches/WOF2-1/core/iou/kernel/ibiou.rc new file mode 100644 index 00000000..56b995af --- /dev/null +++ b/branches/WOF2-1/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-1/core/iou/kernel/iou_driver.c b/branches/WOF2-1/core/iou/kernel/iou_driver.c new file mode 100644 index 00000000..60b1b55b --- /dev/null +++ b/branches/WOF2-1/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-1/core/iou/kernel/iou_driver.h b/branches/WOF2-1/core/iou/kernel/iou_driver.h new file mode 100644 index 00000000..b779cec7 --- /dev/null +++ b/branches/WOF2-1/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-1/core/iou/kernel/iou_ioc_mgr.c b/branches/WOF2-1/core/iou/kernel/iou_ioc_mgr.c new file mode 100644 index 00000000..c475fdc2 --- /dev/null +++ b/branches/WOF2-1/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( PagedPool, 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( PagedPool, 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( PagedPool, 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( PagedPool, 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( PagedPool, 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( PagedPool, 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( PagedPool, 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( PagedPool, 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( PagedPool, 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( PagedPool, + 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( PagedPool, + 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( PagedPool, 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-1/core/iou/kernel/iou_ioc_mgr.h b/branches/WOF2-1/core/iou/kernel/iou_ioc_mgr.h new file mode 100644 index 00000000..330b2411 --- /dev/null +++ b/branches/WOF2-1/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-1/core/iou/kernel/iou_pnp.c b/branches/WOF2-1/core/iou/kernel/iou_pnp.c new file mode 100644 index 00000000..002412e2 --- /dev/null +++ b/branches/WOF2-1/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-1/core/iou/kernel/iou_pnp.h b/branches/WOF2-1/core/iou/kernel/iou_pnp.h new file mode 100644 index 00000000..80a53a54 --- /dev/null +++ b/branches/WOF2-1/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-1/core/iou/kernel/makefile b/branches/WOF2-1/core/iou/kernel/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/core/iou/kernel/makefile.inc b/branches/WOF2-1/core/iou/kernel/makefile.inc new file mode 100644 index 00000000..4f29f500 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winmad/dirs b/branches/WOF2-1/core/winmad/dirs new file mode 100644 index 00000000..697ddcdb --- /dev/null +++ b/branches/WOF2-1/core/winmad/dirs @@ -0,0 +1,3 @@ +DIRS=\ + kernel \ + user \ No newline at end of file diff --git a/branches/WOF2-1/core/winmad/kernel/SOURCES b/branches/WOF2-1/core/winmad/kernel/SOURCES new file mode 100644 index 00000000..e387657c --- /dev/null +++ b/branches/WOF2-1/core/winmad/kernel/SOURCES @@ -0,0 +1,21 @@ +TARGETNAME = winmad +TARGETPATH = ..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE = DRIVER + +KMDF_VERSION_MAJOR = 1 +INF_NAME = winmad +NTTARGETFILES = $(OBJ_PATH)\$(O)\$(INF_NAME).inf +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-1/core/winmad/kernel/makefile b/branches/WOF2-1/core/winmad/kernel/makefile new file mode 100644 index 00000000..128ed372 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winmad/kernel/makefile.inc b/branches/WOF2-1/core/winmad/kernel/makefile.inc new file mode 100644 index 00000000..017f9629 --- /dev/null +++ b/branches/WOF2-1/core/winmad/kernel/makefile.inc @@ -0,0 +1,9 @@ +_LNG=$(LANGUAGE) +_INX=. +STAMP=stampinf -f $@ -a $(_BUILDARCH) -k $(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR) + +!INCLUDE mod_ver.def + +$(OBJ_PATH)\$(O)\$(INF_NAME).inf: $(_INX)\$(INF_NAME).inx + copy $(_INX)\$(@B).inx $@ + $(STAMP) -d * -v $(IB_MAJORVERSION).$(IB_MINORVERSION).$(IB_BUILDVERSION).$(OPENIB_REV) diff --git a/branches/WOF2-1/core/winmad/kernel/winmad.inx b/branches/WOF2-1/core/winmad/kernel/winmad.inx new file mode 100644 index 00000000..89427ae9 --- /dev/null +++ b/branches/WOF2-1/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 + +[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-1/core/winmad/kernel/winmad.rc b/branches/WOF2-1/core/winmad/kernel/winmad.rc new file mode 100644 index 00000000..3669ed26 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winmad/kernel/wm_driver.c b/branches/WOF2-1/core/winmad/kernel/wm_driver.c new file mode 100644 index 00000000..b5b79e58 --- /dev/null +++ b/branches/WOF2-1/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) { + ExFreePool(attr); + 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: + ExFreePool(attr); + 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) { + ExFreePool(pdev->pPortArray); + } + + 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-1/core/winmad/kernel/wm_driver.h b/branches/WOF2-1/core/winmad/kernel/wm_driver.h new file mode 100644 index 00000000..423b1bf8 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winmad/kernel/wm_provider.c b/branches/WOF2-1/core/winmad/kernel/wm_provider.c new file mode 100644 index 00000000..a150bf1e --- /dev/null +++ b/branches/WOF2-1/core/winmad/kernel/wm_provider.c @@ -0,0 +1,432 @@ +/* + * 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.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_SUCCESS) { + ((WM_REGISTRATION *) Context)->pDevice->IbInterface.put_mad(pMad); + } else { + WmReceiveHandler(hService, Context, pMad); + } +} + +void WmProviderCancel(WM_PROVIDER *pProvider, WDFREQUEST Request) +{ + WDFREQUEST request; + NTSTATUS status; + + WdfObjectAcquireLock(pProvider->ReadQueue); + status = WdfIoQueueRetrieveNextRequest(pProvider->ReadQueue, &request); + + while (NT_SUCCESS(status)) { + WdfRequestComplete(request, STATUS_CANCELLED); + status = WdfIoQueueRetrieveNextRequest(pProvider->ReadQueue, &request); + } + WdfObjectReleaseLock(pProvider->ReadQueue); + + WdfRequestComplete(Request, status); +} diff --git a/branches/WOF2-1/core/winmad/kernel/wm_provider.h b/branches/WOF2-1/core/winmad/kernel/wm_provider.h new file mode 100644 index 00000000..3088f3d2 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winmad/kernel/wm_reg.c b/branches/WOF2-1/core/winmad/kernel/wm_reg.c new file mode 100644 index 00000000..59f50556 --- /dev/null +++ b/branches/WOF2-1/core/winmad/kernel/wm_reg.c @@ -0,0 +1,285 @@ +/* + * 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(PagedPool, 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_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; + } + + 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; + } + + 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; + } + + 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); + ExFreePool(pRegistatration); +} + +void WmRegRemoveHandler(WM_REGISTRATION *pRegistration) +{ + if (pRegistration->pDevice == NULL) { + return; + } + + 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-1/core/winmad/kernel/wm_reg.h b/branches/WOF2-1/core/winmad/kernel/wm_reg.h new file mode 100644 index 00000000..7de4acc6 --- /dev/null +++ b/branches/WOF2-1/core/winmad/kernel/wm_reg.h @@ -0,0 +1,67 @@ +/* + * 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; + ib_pd_handle_t hPd; + ib_qp_handle_t hQp; + ib_pool_key_t hMadPool; + ib_mad_svc_handle_t hService; + + 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-1/core/winmad/user/SOURCES b/branches/WOF2-1/core/winmad/user/SOURCES new file mode 100644 index 00000000..7d3d7c57 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winmad/user/makefile b/branches/WOF2-1/core/winmad/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winmad/user/winmad.rc b/branches/WOF2-1/core/winmad/user/winmad.rc new file mode 100644 index 00000000..ab68fe77 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winmad/user/wm_exports.src b/branches/WOF2-1/core/winmad/user/wm_exports.src new file mode 100644 index 00000000..2c26af39 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winmad/user/wm_main.cpp b/branches/WOF2-1/core/winmad/user/wm_main.cpp new file mode 100644 index 00000000..e8c6d57c --- /dev/null +++ b/branches/WOF2-1/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-1/core/winmad/user/wm_memory.h b/branches/WOF2-1/core/winmad/user/wm_memory.h new file mode 100644 index 00000000..30cbfb9b --- /dev/null +++ b/branches/WOF2-1/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-1/core/winmad/user/wm_provider.cpp b/branches/WOF2-1/core/winmad/user/wm_provider.cpp new file mode 100644 index 00000000..fb5efead --- /dev/null +++ b/branches/WOF2-1/core/winmad/user/wm_provider.cpp @@ -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 + +#include "wm_memory.h" +#include "wm_provider.h" +#include "wm_ioctl.h" + +CWMProvider::CWMProvider() +{ + InitializeCriticalSection(&m_CritSecRead); + InitializeCriticalSection(&m_CritSecWrite); + m_OverlapRead.hEvent = NULL; + m_OverlapWrite.hEvent = NULL; + 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_OverlapWrite.hEvent); + } + if (m_OverlapWrite.hEvent != NULL) { + CloseHandle(m_OverlapWrite.hEvent); + } + CloseHandle(m_hFile); + 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_(BOOL) CWMProvider:: +WmReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, + LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) +{ + BOOL ret; + + if (lpOverlapped == NULL) { + EnterCriticalSection(&m_CritSecRead); + ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, + lpNumberOfBytesRead, &m_OverlapRead); + ret = GetOverlappedResult(&m_OverlapRead, lpNumberOfBytesRead, TRUE); + LeaveCriticalSection(&m_CritSecRead); + } else { + ret = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, + lpNumberOfBytesRead, lpOverlapped); + } + + return ret; +} + +STDMETHODIMP_(BOOL) CWMProvider:: +WmWriteFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberIfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) +{ + BOOL ret; + + if (lpOverlapped == NULL) { + EnterCriticalSection(&m_CritSecWrite); + WriteFile(hFile, lpBuffer, nNumberIfBytesToWrite, + lpNumberOfBytesWritten, &m_OverlapWrite); + ret = GetOverlappedResult(&m_OverlapWrite, lpNumberOfBytesWritten, TRUE); + LeaveCriticalSection(&m_CritSecWrite); + } else { + ret = WriteFile(hFile, lpBuffer, nNumberIfBytesToWrite, + lpNumberOfBytesWritten, 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; + + if (WmWriteFile(m_hFile, pMad, (DWORD) sizeof(WM_MAD) + pMad->Length, + &bytes, pOverlapped)) { + return NOERROR; + } else { + return HRESULT_FROM_WIN32(GetLastError()); + } +} + +STDMETHODIMP CWMProvider:: +Receive(WM_MAD *pMad, SIZE_T BufferSize, OVERLAPPED *pOverlapped) +{ + DWORD bytes; + + if (WmReadFile(m_hFile, pMad, (DWORD) BufferSize, &bytes, pOverlapped)) { + return NOERROR; + } else { + return HRESULT_FROM_WIN32(GetLastError()); + } +} diff --git a/branches/WOF2-1/core/winmad/user/wm_provider.h b/branches/WOF2-1/core/winmad/user/wm_provider.h new file mode 100644 index 00000000..b75c2c23 --- /dev/null +++ b/branches/WOF2-1/core/winmad/user/wm_provider.h @@ -0,0 +1,118 @@ +/* + * 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); + STDMETHODIMP_(BOOL) WmReadFile(HANDLE hFile, LPVOID lpBuffer, + DWORD nNumberOfBytesToRead, + LPDWORD lpNumberOfBytesRead, + LPOVERLAPPED lpOverlapped); + STDMETHODIMP_(BOOL) WmWriteFile(HANDLE hFile, LPVOID lpBuffer, + DWORD nNumberIfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, + 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-1/core/winmad/wm_ioctl.h b/branches/WOF2-1/core/winmad/wm_ioctl.h new file mode 100644 index 00000000..628b5b62 --- /dev/null +++ b/branches/WOF2-1/core/winmad/wm_ioctl.h @@ -0,0 +1,118 @@ +/* + * 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; + +#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-1/core/winverbs/dirs b/branches/WOF2-1/core/winverbs/dirs new file mode 100644 index 00000000..a5a581d5 --- /dev/null +++ b/branches/WOF2-1/core/winverbs/dirs @@ -0,0 +1,3 @@ +DIRS=\ + kernel \ + user diff --git a/branches/WOF2-1/core/winverbs/kernel/SOURCES b/branches/WOF2-1/core/winverbs/kernel/SOURCES new file mode 100644 index 00000000..3322a7d6 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/kernel/makefile b/branches/WOF2-1/core/winverbs/kernel/makefile new file mode 100644 index 00000000..128ed372 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/kernel/makefile.inc b/branches/WOF2-1/core/winverbs/kernel/makefile.inc new file mode 100644 index 00000000..400aaaf2 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/kernel/winverbs.cdf b/branches/WOF2-1/core/winverbs/kernel/winverbs.cdf new file mode 100644 index 00000000..4e67010f --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/kernel/winverbs.inx b/branches/WOF2-1/core/winverbs/kernel/winverbs.inx new file mode 100644 index 00000000..225df71c --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/kernel/winverbs.rc b/branches/WOF2-1/core/winverbs/kernel/winverbs.rc new file mode 100644 index 00000000..50b57592 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/kernel/wv_cq.c b/branches/WOF2-1/core/winverbs/kernel/wv_cq.c new file mode 100644 index 00000000..6adcd15a --- /dev/null +++ b/branches/WOF2-1/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: + ExFreePool(cq); + 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); + ExFreePool(pCq); +} + +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-1/core/winverbs/kernel/wv_cq.h b/branches/WOF2-1/core/winverbs/kernel/wv_cq.h new file mode 100644 index 00000000..d0e20ae7 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/kernel/wv_device.c b/branches/WOF2-1/core/winverbs/kernel/wv_device.c new file mode 100644 index 00000000..cd97ae05 --- /dev/null +++ b/branches/WOF2-1/core/winverbs/kernel/wv_device.c @@ -0,0 +1,816 @@ +/* + * 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) { + ExFreePool(attr); + 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; + ExFreePool(attr); + + 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); + } +} + +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); + ExFreePool(pDevice); +} + +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 = 0; // TODO: missing in ib_port_attr_t + 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->link_width_supported; + pAttributes->ActiveSpeed = 0; // TODO: missing in ib_port_attr_t + pAttributes->PhysicalState = 0; // TODO: missing in ib_port_attr_t + 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); + ExFreePool(ca_attr); + +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: + ExFreePool(ca_attr); +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: + ExFreePool(ca_attr); +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: + ExFreePool(ca_attr); +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-1/core/winverbs/kernel/wv_device.h b/branches/WOF2-1/core/winverbs/kernel/wv_device.h new file mode 100644 index 00000000..1bbc5fef --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/kernel/wv_driver.c b/branches/WOF2-1/core/winverbs/kernel/wv_driver.c new file mode 100644 index 00000000..ee96f19b --- /dev/null +++ b/branches/WOF2-1/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); + InsertHeadList(&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-1/core/winverbs/kernel/wv_driver.h b/branches/WOF2-1/core/winverbs/kernel/wv_driver.h new file mode 100644 index 00000000..a9e884e5 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/kernel/wv_ep.c b/branches/WOF2-1/core/winverbs/kernel/wv_ep.c new file mode 100644 index 00000000..ab7ef666 --- /dev/null +++ b/branches/WOF2-1/core/winverbs/kernel/wv_ep.c @@ -0,0 +1,1297 @@ +/* + * 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 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) { + 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->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 err; + } + + *ppEndpoint = ep; + return STATUS_SUCCESS; + +err: + ExFreePool(ep); + 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); + + 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) +{ + if (pEndpoint->pIbCmId != NULL) { + IbCmInterface.CM.destroy_id(pEndpoint->pIbCmId); + } + + if (InterlockedDecrement(&pEndpoint->Ref) > 0) { + KeWaitForSingleObject(&pEndpoint->Event, Executive, KernelMode, FALSE, NULL); + } + + WdfIoQueuePurgeSynchronously(pEndpoint->Queue); + WdfObjectDelete(pEndpoint->Queue); + ExFreePool(pEndpoint); +} + +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) { + return STATUS_UNSUCCESSFUL; + } + + return STATUS_SUCCESS; +} + +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 void WvEpDisconnectHandler(WORK_ENTRY *pWork) +{ + WV_PROVIDER *prov; + WDFREQUEST request; + WV_IO_EP_DISCONNECT *pattr; + UINT8 *out; + size_t outlen = 0; + NTSTATUS status; + + request = (WDFREQUEST) pWork->Context; + prov = WvProviderGetContext(WdfRequestGetFileObject(request)); + + 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; + } + + status = (NTSTATUS) WdfRequestGetInformation(request); + if (NT_SUCCESS(status)) { + status = WvEpDisconnectQp(prov, pattr->QpId, out, outlen); + } else { + WvEpDisconnectQp(prov, pattr->QpId, out, outlen); + } + +complete: + WdfRequestCompleteWithInformation(request, status, outlen); +} + +// We use IRP DriverContext to queue the request for further processing, +// but the request/IRP are no longer owned by the framework. +static void WvEpCompleteDisconnect(WV_ENDPOINT *pEndpoint, NTSTATUS DiscStatus) +{ + WDFREQUEST request; + WDF_REQUEST_PARAMETERS param; + WORK_ENTRY *work; + NTSTATUS status; + + WdfObjectAcquireLock(pEndpoint->Queue); + pEndpoint->State = WvEpDisconnected; + + status = WdfIoQueueRetrieveNextRequest(pEndpoint->Queue, &request); + while (NT_SUCCESS(status)) { + WdfObjectReleaseLock(pEndpoint->Queue); + + WDF_REQUEST_PARAMETERS_INIT(¶m); + WdfRequestGetParameters(request, ¶m); + if (param.Parameters.DeviceIoControl.IoControlCode == WV_IOCTL_EP_DISCONNECT) { + work = WorkEntryFromIrp(WdfRequestWdmGetIrp(request)); + WdfRequestSetInformation(request, DiscStatus); + WorkEntryInit(work, WvEpDisconnectHandler, request); + WorkQueueInsert(&pEndpoint->pProvider->WorkQueue, work); + } else { + WdfRequestComplete(request, DiscStatus); + } + + WdfObjectAcquireLock(pEndpoint->Queue); + status = WdfIoQueueRetrieveNextRequest(pEndpoint->Queue, &request); + } + 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: + case iba_cm_rep_error: + WdfObjectAcquireLock(ep->Queue); + ep->State = WvEpDisconnected; + WvCompleteRequests(ep->Queue, STATUS_IO_TIMEOUT); + WdfObjectReleaseLock(ep->Queue); + break; + case iba_cm_dreq_error: + WvEpCompleteDisconnect(ep, STATUS_IO_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 { + 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_REQUEST_NOT_ACCEPTED); + } + WdfObjectReleaseLock(ep->Queue); + break; + case iba_cm_mra_received: + break; + default: + WdfObjectAcquireLock(ep->Queue); + ep->State = WvEpDisconnected; + WvCompleteRequests(ep->Queue, STATUS_NOT_IMPLEMENTED); + WdfObjectReleaseLock(ep->Queue); + break; + } + + return STATUS_SUCCESS; +} + +void WvEpConnectHandler(WORK_ENTRY *pWork) +{ + WV_PROVIDER *prov; + WDFREQUEST request; + WV_IO_EP_CONNECT *pattr; + WV_ENDPOINT *ep; + WV_QUEUE_PAIR *qp; + iba_cm_req req; + NTSTATUS status; + UINT8 data[IB_REQ_PDATA_SIZE]; + + request = (WDFREQUEST) pWork->Context; + prov = WvProviderGetContext(WdfRequestGetFileObject(request)); + + status = WdfRequestRetrieveInputBuffer(request, sizeof(WV_IO_EP_CONNECT), + &pattr, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + + if (pattr->Param.DataLength > sizeof(pattr->Param.Data)) { + status = STATUS_INVALID_BUFFER_SIZE; + goto complete; + } + + ep = WvEpAcquire(prov, pattr->Id); + if (ep == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + qp = WvQpAcquire(prov, pattr->QpId); + if (qp == NULL) { + status = STATUS_NOT_FOUND; + goto release; + } + + ep->Attributes.PeerAddress = pattr->PeerAddress; + WvFormatCmaHeader((IB_CMA_HEADER *) data, &ep->Attributes.LocalAddress, + &ep->Attributes.PeerAddress); + + req.service_id = WvGetServiceId(ep->EpType, &ep->Attributes.PeerAddress); + req.p_primary_path = &ep->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(&ep->Attributes.Param.Connect, &pattr->Param, + sizeof(pattr->Param)); + + WdfObjectAcquireLock(ep->Queue); + if (ep->State != WvEpRouteResolved) { + status = STATUS_NOT_SUPPORTED; + goto unlock; + } + + status = IbCmInterface.CM.create_id(WvEpIbCmHandler, ep, &ep->pIbCmId); + if (!NT_SUCCESS(status)) { + goto unlock; + } + + ep->State = WvEpActiveConnect; + status = IbCmInterface.CM.send_req(ep->pIbCmId, &req); + if (NT_SUCCESS(status)) { + status = WdfRequestForwardToIoQueue(request, ep->Queue); + } + + if (!NT_SUCCESS(status)) { + ep->State = WvEpDisconnected; + } +unlock: + WdfObjectReleaseLock(ep->Queue); +release: + WvEpRelease(ep); +complete: + if (!NT_SUCCESS(status)) { + WdfRequestComplete(request, status); + } +} + +static void WvEpProcessAsync(WV_PROVIDER *pProvider, WDFREQUEST Request, + void (*AsyncHandler)(struct _WORK_ENTRY *Work)) +{ + WORK_ENTRY *work; + + work = WorkEntryFromIrp(WdfRequestWdmGetIrp(Request)); + WorkEntryInit(work, AsyncHandler, Request); + WorkQueueInsert(&pProvider->WorkQueue, work); +} + +void WvEpConnect(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WvEpProcessAsync(pProvider, Request, WvEpConnectHandler); +} + +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 = WdfRequestForwardToIoQueue(Request, pEndpoint->Queue); + } + + if (!NT_SUCCESS(status)) { + pEndpoint->State = WvEpDisconnected; + } + +release: + WdfObjectReleaseLock(pEndpoint->Queue); +out: + return status; +} + +void WvEpAcceptHandler(WORK_ENTRY *pWork) +{ + WV_PROVIDER *prov; + WDFREQUEST request; + WV_IO_EP_ACCEPT *pattr; + WV_ENDPOINT *ep; + NTSTATUS status; + UINT8 *out; + size_t outlen; + + request = (WDFREQUEST) pWork->Context; + prov = WvProviderGetContext(WdfRequestGetFileObject(request)); + + status = WdfRequestRetrieveInputBuffer(request, sizeof(WV_IO_EP_ACCEPT), + &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; + } + + if (pattr->Param.DataLength > sizeof(pattr->Param.Data)) { + status = STATUS_INVALID_BUFFER_SIZE; + goto complete; + } + + ep = WvEpAcquire(prov, pattr->Id); + if (ep == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + /* EP state is re-checked under lock in WvEpAccept* calls */ + switch (ep->State) { + case WvEpActiveConnect: + status = WvEpAcceptActive(request, out, outlen, ep, pattr); + break; + case WvEpPassiveConnect: + status = WvEpAcceptPassive(request, out, outlen, ep, pattr); + break; + default: + status = STATUS_NOT_SUPPORTED; + break; + } + + WvEpRelease(ep); +complete: + if (!NT_SUCCESS(status)) { + WdfRequestComplete(request, status); + } +} + +void WvEpAccept(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WvEpProcessAsync(pProvider, Request, WvEpAcceptHandler); +} + +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); +} + +static NTSTATUS WvEpDisconnectActive(WDFREQUEST Request, + UINT8 *pVerbsData, size_t VerbsSize, + WV_ENDPOINT *pEndpoint, + WV_IO_EP_DISCONNECT *pAttr) +{ + NTSTATUS status, failure; + + WdfObjectAcquireLock(pEndpoint->Queue); + if (pEndpoint->State != WvEpConnected) { + status = STATUS_NOT_SUPPORTED; + goto release; + } + + pEndpoint->State = WvEpActiveDisconnect; + IbCmInterface.CM.send_dreq(pEndpoint->pIbCmId, NULL, 0); + + status = WdfRequestForwardToIoQueue(Request, pEndpoint->Queue); + if (!NT_SUCCESS(status)) { + pEndpoint->State = WvEpDisconnected; + WvCompleteRequests(pEndpoint->Queue, STATUS_UNSUCCESSFUL); + WdfObjectReleaseLock(pEndpoint->Queue); + + failure = status; + status = WvEpDisconnectQp(pEndpoint->pProvider, pAttr->QpId, + pVerbsData, VerbsSize); + if (NT_SUCCESS(status)) { + WdfRequestCompleteWithInformation(Request, failure, VerbsSize); + } + return status; + } + +release: + WdfObjectReleaseLock(pEndpoint->Queue); + return status; +} + +static NTSTATUS WvEpDisconnectPassive(WDFREQUEST Request, + UINT8 *pVerbsData, size_t VerbsSize, + WV_ENDPOINT *pEndpoint, + WV_IO_EP_DISCONNECT *pAttr) +{ + NTSTATUS status; + + WdfObjectAcquireLock(pEndpoint->Queue); + if (pEndpoint->State != WvEpPassiveDisconnect) { + WdfObjectReleaseLock(pEndpoint->Queue); + return STATUS_NOT_SUPPORTED; + } + + pEndpoint->State = WvEpDisconnected; + WdfObjectReleaseLock(pEndpoint->Queue); + + IbCmInterface.CM.send_drep(pEndpoint->pIbCmId, NULL, 0); + + status = WvEpDisconnectQp(pEndpoint->pProvider, pAttr->QpId, + pVerbsData, VerbsSize); + if (NT_SUCCESS(status)) { + WdfRequestCompleteWithInformation(Request, status, VerbsSize); + } + + return status; +} + +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; + } + + /* EP state is re-checked under lock in WvEpDisconnect* calls */ + switch (ep->State) { + case WvEpConnected: + status = WvEpDisconnectActive(Request, out, outlen, ep, pattr); + break; + case WvEpPassiveDisconnect: + status = WvEpDisconnectPassive(Request, out, outlen, ep, pattr); + break; + default: + status = STATUS_NOT_SUPPORTED; + break; + } + + 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 NTSTATUS WvEpIbListenHandler(iba_cm_id *pId, iba_cm_event *pEvent) +{ + WV_ENDPOINT *listen, *ep; + WDFREQUEST request; + NTSTATUS status; + IB_CMA_HEADER *hdr; + + listen = ((iba_cm_id *) pId->context)->context; + + WdfObjectAcquireLock(listen->Queue); + status = WdfIoQueueRetrieveNextRequest(listen->Queue, &request); + if (!NT_SUCCESS(status)) { + goto release; + } + + ASSERT(!IsListEmpty(&listen->Entry)); + ep = CONTAINING_RECORD(RemoveHeadList(&listen->Entry), WV_ENDPOINT, Entry); + ep->pIbCmId = pId; + pId->callback = WvEpIbCmHandler; + pId->context = ep; + + hdr = pEvent->data.req.req.p_pdata; + if (hdr->IpVersion == 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 = pEvent->data.req.local_ca_guid; + ep->Attributes.Device.Pkey = pEvent->data.req.req.p_primary_path->pkey; + ep->Attributes.Device.PortNumber = pEvent->data.req.port_num; + ep->Attributes.Param.Connect.ResponderResources = pEvent->data.req.req.resp_res; + ep->Attributes.Param.Connect.InitiatorDepth = pEvent->data.req.req.init_depth; + ep->Attributes.Param.Connect.RetryCount = pEvent->data.req.req.retry_cnt; + ep->Attributes.Param.Connect.RnrRetryCount = pEvent->data.req.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 = *pEvent->data.req.req.p_primary_path; + + ep->State = WvEpPassiveConnect; + WvEpPut(ep); + + WdfRequestComplete(request, STATUS_SUCCESS); +release: + WdfObjectReleaseLock(listen->Queue); + return status; +} + +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 complete; + } + + listen = WvEpAcquire(pProvider, req->Id); + if (listen == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + if (listen->State != WvEpListening) { + status = STATUS_NOT_SUPPORTED; + goto release1; + } + + ep = WvEpAcquire(pProvider, req->EpId); + if (ep == NULL) { + status = STATUS_NOT_FOUND; + goto release1; + } + + WdfObjectAcquireLock(ep->Queue); + if (ep->State == WvEpIdle) { + ep->State = WvEpQueued; + } else { + status = STATUS_CONNECTION_IN_USE; + } + WdfObjectReleaseLock(ep->Queue); + + if (!NT_SUCCESS(status)) { + goto release2; + } + + WdfObjectAcquireLock(listen->Queue); + status = WdfRequestForwardToIoQueue(Request, listen->Queue); + if (NT_SUCCESS(status)) { + InsertTailList(&listen->Entry, &ep->Entry); + WvEpGet(ep); + } + WdfObjectReleaseLock(listen->Queue); + +release2: + WvEpRelease(ep); +release1: + WvEpRelease(listen); +complete: + if (!NT_SUCCESS(status)) { + 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-1/core/winverbs/kernel/wv_ep.h b/branches/WOF2-1/core/winverbs/kernel/wv_ep.h new file mode 100644 index 00000000..10d0d7d7 --- /dev/null +++ b/branches/WOF2-1/core/winverbs/kernel/wv_ep.h @@ -0,0 +1,100 @@ +/* + * 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 + +} 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_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-1/core/winverbs/kernel/wv_pd.c b/branches/WOF2-1/core/winverbs/kernel/wv_pd.c new file mode 100644 index 00000000..5ae26298 --- /dev/null +++ b/branches/WOF2-1/core/winverbs/kernel/wv_pd.c @@ -0,0 +1,629 @@ +/* + * 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(PagedPool, 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; + } + + pd->pDevice = pDevice; + pd->pVerbs = pDevice->pVerbs; + *ppPd = pd; + return STATUS_SUCCESS; + +err: + ExFreePool(pd); + 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); + + WvProviderEnableRemove(pProvider); + 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); + ExFreePool(mr); + } + + if (pPd->hVerbsPd != NULL) { + pPd->pVerbs->deallocate_pd(pPd->hVerbsPd); + } + + WvDevicePut(pPd->pDevice); + ExFreePool(pPd); +} + +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: + ExFreePool(mr); +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; + } + + ExFreePool(mr); +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; + } + + 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 err3; + } + InsertHeadList(&pd->MwList, &mw->Entry); + KeReleaseGuardedMutex(&pProvider->Lock); + + mw->pPd = pd; + + WvProviderEnableRemove(pProvider); + outid->VerbInfo = verbsData.status; + WdfRequestCompleteWithInformation(Request, status, outlen); + return; + +err3: + KeReleaseGuardedMutex(&pProvider->Lock); + 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); + ExFreePool(pMw); +} + +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; + } + + 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 err3; + } + InsertHeadList(&pd->AhList, &ah->Entry); + KeReleaseGuardedMutex(&pProvider->Lock); + + ah->pPd = pd; + + WvProviderEnableRemove(pProvider); + poutAv->Id.VerbInfo = verbsData.status; + WdfRequestCompleteWithInformation(Request, status, outlen); + return; + +err3: + KeReleaseGuardedMutex(&pProvider->Lock); + 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); + ExFreePool(pAh); +} diff --git a/branches/WOF2-1/core/winverbs/kernel/wv_pd.h b/branches/WOF2-1/core/winverbs/kernel/wv_pd.h new file mode 100644 index 00000000..f30cf4e5 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/kernel/wv_provider.c b/branches/WOF2-1/core/winverbs/kernel/wv_provider.c new file mode 100644 index 00000000..19053a8f --- /dev/null +++ b/branches/WOF2-1/core/winverbs/kernel/wv_provider.c @@ -0,0 +1,231 @@ +/* + * 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); + } +} + +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; +} + +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; + + IndexListForEach(&pProvider->EpIndex, i) { + ep = (WV_ENDPOINT *) IndexListAt(&pProvider->EpIndex, i); + if (ep->State == WvEpListening) { + WvEpCancelListen(ep); + } + } + while ((ep = IndexListRemoveHead(&pProvider->EpIndex)) != NULL) { + RemoveEntryList(&ep->Entry); + 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); + } + + 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); +} + +// 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); +} + +/* + * 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-1/core/winverbs/kernel/wv_provider.h b/branches/WOF2-1/core/winverbs/kernel/wv_provider.h new file mode 100644 index 00000000..329145f2 --- /dev/null +++ b/branches/WOF2-1/core/winverbs/kernel/wv_provider.h @@ -0,0 +1,83 @@ +/* + * 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_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-1/core/winverbs/kernel/wv_qp.c b/branches/WOF2-1/core/winverbs/kernel/wv_qp.c new file mode 100644 index 00000000..26aec276 --- /dev/null +++ b/branches/WOF2-1/core/winverbs/kernel/wv_qp.c @@ -0,0 +1,763 @@ +/* + * 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); + 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: + ExFreePool(qp); +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); + } + WvQpPut(pQp); + ExFreePool(mc); + } + + 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); + ExFreePool(pQp); +} + +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->pPd->Lock); + InsertHeadList(&qp->McList, &pmc->Entry); + KeReleaseGuardedMutex(&qp->pPd->Lock); + + WvProviderEnableRemove(pProvider); + WdfRequestComplete(Request, STATUS_SUCCESS); + return; + +err3: + WvQpRelease(qp); +err2: + ExFreePool(pmc); +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->pPd->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->pPd->Lock); + + if (pmc->hVerbsMc != NULL) { + qp->pVerbs->detach_mcast(pmc->hVerbsMc); + } + WvQpPut(qp); + WvQpRelease(qp); + + ExFreePool(pmc); + status = STATUS_SUCCESS; + goto complete; + } + } + KeReleaseGuardedMutex(&qp->pPd->Lock); + WvQpRelease(qp); + status = STATUS_NOT_FOUND; + +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-1/core/winverbs/kernel/wv_qp.h b/branches/WOF2-1/core/winverbs/kernel/wv_qp.h new file mode 100644 index 00000000..449de594 --- /dev/null +++ b/branches/WOF2-1/core/winverbs/kernel/wv_qp.h @@ -0,0 +1,77 @@ +/* + * 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; + + 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-1/core/winverbs/kernel/wv_srq.c b/branches/WOF2-1/core/winverbs/kernel/wv_srq.c new file mode 100644 index 00000000..e2379ee0 --- /dev/null +++ b/branches/WOF2-1/core/winverbs/kernel/wv_srq.c @@ -0,0 +1,378 @@ +/* + * 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; + } + + srq->pPd = pPd; + srq->pProvider = pPd->pDevice->pProvider; + srq->pVerbs = pPd->pVerbs; + *ppSrq = srq; + return STATUS_SUCCESS; + +err2: + WdfObjectDelete(srq->Queue); +err1: + ExFreePool(srq); + 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); + + WvProviderEnableRemove(pProvider); + 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); + ExFreePool(pSrq); +} + +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-1/core/winverbs/kernel/wv_srq.h b/branches/WOF2-1/core/winverbs/kernel/wv_srq.h new file mode 100644 index 00000000..97bb93dd --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/SOURCES b/branches/WOF2-1/core/winverbs/user/SOURCES new file mode 100644 index 00000000..6939d1e7 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/makefile b/branches/WOF2-1/core/winverbs/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/winverbs.rc b/branches/WOF2-1/core/winverbs/user/winverbs.rc new file mode 100644 index 00000000..1be0d5c1 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/wv_base.cpp b/branches/WOF2-1/core/winverbs/user/wv_base.cpp new file mode 100644 index 00000000..52e9b6ef --- /dev/null +++ b/branches/WOF2-1/core/winverbs/user/wv_base.cpp @@ -0,0 +1,106 @@ +/* + * 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); + } +} + +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-1/core/winverbs/user/wv_base.h b/branches/WOF2-1/core/winverbs/user/wv_base.h new file mode 100644 index 00000000..592fc18a --- /dev/null +++ b/branches/WOF2-1/core/winverbs/user/wv_base.h @@ -0,0 +1,85 @@ +/* + * 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 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_ \ No newline at end of file diff --git a/branches/WOF2-1/core/winverbs/user/wv_cq.cpp b/branches/WOF2-1/core/winverbs/user/wv_cq.cpp new file mode 100644 index 00000000..9398a7a5 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/wv_cq.h b/branches/WOF2-1/core/winverbs/user/wv_cq.h new file mode 100644 index 00000000..717d9449 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/wv_device.cpp b/branches/WOF2-1/core/winverbs/user/wv_device.cpp new file mode 100644 index 00000000..9aac7889 --- /dev/null +++ b/branches/WOF2-1/core/winverbs/user/wv_device.cpp @@ -0,0 +1,408 @@ +/* + * 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_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); + } + + return hr; +} + +CWVDevice::~CWVDevice() +{ + 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); + } + + 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()); + } + + 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:: +QueryPkey(UINT8 PortNumber, UINT16 Index, NET16* pPkey) +{ + WV_IO_DEVICE_PORT_QUERY query; + NET16 *pkeytable; + DWORD npkey, bytes; + HRESULT hr; + CWVBuffer buf; + + bytes = sizeof NET16 * (Index + 1); + pkeytable = (NET16 *) buf.Get(bytes); + if (pkeytable == 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_PKEY_QUERY, &query, + sizeof query, pkeytable, bytes, &bytes, NULL)) { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto out; + } + + npkey = bytes / sizeof NET16; + if (Index >= npkey) { + hr = WV_INVALID_PARAMETER_2; + goto out; + } + *pPkey = pkeytable[Index]; + hr = WV_SUCCESS; + +out: + buf.Put(); + return hr; +} + +STDMETHODIMP CWVDevice:: +FindPkey(UINT8 PortNumber, NET16 Pkey, UINT16 *pIndex) +{ + NET16 key; + UINT16 index; + HRESULT hr; + + for (index = 0; true; index++) { + hr = QueryPkey(PortNumber, index, &key); + if (FAILED(hr)) { + return hr; + } + + if (Pkey == key) { + *pIndex = (UINT16) index; + return WV_SUCCESS; + } + } + + return WV_INVALID_ADDRESS; +} + +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-1/core/winverbs/user/wv_device.h b/branches/WOF2-1/core/winverbs/user/wv_device.h new file mode 100644 index 00000000..7e98da1b --- /dev/null +++ b/branches/WOF2-1/core/winverbs/user/wv_device.h @@ -0,0 +1,111 @@ +/* + * 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" + +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); +}; + +#endif // __WV_DEVICE_H_ diff --git a/branches/WOF2-1/core/winverbs/user/wv_ep.cpp b/branches/WOF2-1/core/winverbs/user/wv_ep.cpp new file mode 100644 index 00000000..31a3dfec --- /dev/null +++ b/branches/WOF2-1/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 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 = 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-1/core/winverbs/user/wv_ep.h b/branches/WOF2-1/core/winverbs/user/wv_ep.h new file mode 100644 index 00000000..0d8422bd --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/wv_exports.src b/branches/WOF2-1/core/winverbs/user/wv_exports.src new file mode 100644 index 00000000..ed6a38c0 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/wv_main.cpp b/branches/WOF2-1/core/winverbs/user/wv_main.cpp new file mode 100644 index 00000000..d1b5d020 --- /dev/null +++ b/branches/WOF2-1/core/winverbs/user/wv_main.cpp @@ -0,0 +1,119 @@ +/* + * 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; + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(hInstance); + UNREFERENCED_PARAMETER(dwReason); + UNREFERENCED_PARAMETER(lpReserved); + + 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; + } +} diff --git a/branches/WOF2-1/core/winverbs/user/wv_memory.h b/branches/WOF2-1/core/winverbs/user/wv_memory.h new file mode 100644 index 00000000..17a5953a --- /dev/null +++ b/branches/WOF2-1/core/winverbs/user/wv_memory.h @@ -0,0 +1,73 @@ +/* + * 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 + +__inline void* __cdecl operator new(size_t size) +{ + return HeapAlloc(GetProcessHeap(), 0, size); +} + +__inline void __cdecl operator delete(void *pObj) +{ + HeapFree(GetProcessHeap(), 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_ \ No newline at end of file diff --git a/branches/WOF2-1/core/winverbs/user/wv_pd.cpp b/branches/WOF2-1/core/winverbs/user/wv_pd.cpp new file mode 100644 index 00000000..ea93e224 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/wv_pd.h b/branches/WOF2-1/core/winverbs/user/wv_pd.h new file mode 100644 index 00000000..5f4c21a9 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/wv_provider.cpp b/branches/WOF2-1/core/winverbs/user/wv_provider.cpp new file mode 100644 index 00000000..65b0c878 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/wv_provider.h b/branches/WOF2-1/core/winverbs/user/wv_provider.h new file mode 100644 index 00000000..5daa4c77 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/wv_qp.cpp b/branches/WOF2-1/core/winverbs/user/wv_qp.cpp new file mode 100644 index 00000000..dd1038c8 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/wv_qp.h b/branches/WOF2-1/core/winverbs/user/wv_qp.h new file mode 100644 index 00000000..3060c151 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/wv_srq.cpp b/branches/WOF2-1/core/winverbs/user/wv_srq.cpp new file mode 100644 index 00000000..d7486a1d --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/wv_srq.h b/branches/WOF2-1/core/winverbs/user/wv_srq.h new file mode 100644 index 00000000..1527cd4e --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/user/wv_uverbs.cpp b/branches/WOF2-1/core/winverbs/user/wv_uverbs.cpp new file mode 100644 index 00000000..d7073a16 --- /dev/null +++ b/branches/WOF2-1/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); + + p_umv_buf->input_size = 0; + 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); + + p_umv_buf->input_size = 0; + 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); + + p_umv_buf->input_size = 0; + 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); + + p_umv_buf->input_size = 0; + 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); + + p_umv_buf->input_size = 0; + 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); + + p_umv_buf->input_size = 0; + 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); + + p_umv_buf->input_size = 0; + 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); + + p_umv_buf->input_size = 0; + 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); + + p_umv_buf->input_size = 0; + 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); + + p_umv_buf->input_size = 0; + 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); + + p_umv_buf->input_size = 0; + 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-1/core/winverbs/wv_ioctl.h b/branches/WOF2-1/core/winverbs/wv_ioctl.h new file mode 100644 index 00000000..898a3920 --- /dev/null +++ b/branches/WOF2-1/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-1/core/winverbs/wv_public.h b/branches/WOF2-1/core/winverbs/wv_public.h new file mode 100644 index 00000000..df0f3b92 --- /dev/null +++ b/branches/WOF2-1/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-1/dirs b/branches/WOF2-1/dirs new file mode 100644 index 00000000..23326682 --- /dev/null +++ b/branches/WOF2-1/dirs @@ -0,0 +1,6 @@ +DIRS=\ + core \ + ulp \ + hw \ + tools \ + tests diff --git a/branches/WOF2-1/docs/Manual.htm b/branches/WOF2-1/docs/Manual.htm new file mode 100644 index 00000000..8a72bcb9 --- /dev/null +++ b/branches/WOF2-1/docs/Manual.htm @@ -0,0 +1,4058 @@ + + + + + + +

Windows OpenFabrics

+

User's Manual

+

Release 2.1

+

+07/09/2009

+

Overview

+

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

+

The Windows OpenFabrics 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 utilities:

+
    +
  • +

    OpenSM: InfiniBand Subnet Manager

  • +
  • +

    Performance tests

  • +
  • +

    Diagnostic tools

  • +
+

Documentation

+
    +
  • +

    User's manual

  • +
  • +

    Release Notes

  • +
+

 

+

WinOF Features

+ + +

 

+

 

+

 

+
+

Tools

+
+
+
+

The OpenFabrics Alliance Windows release contains a set of + user mode tools which are designed to faciliate the smooth operation of an + Windows OpenFabrics installation. These tools are available from a command + window (cmd.exe) as the installation path '%SystemDrive%\Program + Files\WinOF' is appended to the system wide search path registry entry. + A start menu short-cut 'WinOF 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.

  • +
+

+ OFED + Diagnostics

+
    +
  • +

    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 WinOF 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
+<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(3).
+
+-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] [-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 Rev: openib-1.2.0

+
+

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 (WinOF) 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 file @ %SystemRoot%\Temp\osm.log to see what + OpenSM thinks is happening.
  6. +
+

 

+

Manual InfiniBand Subnet Management from a command window

+

Usage: opensm.exe [options]

+

Options:

+
+

-c
+ --cache-options

+
+

Cache the given command line options into the file
+ /var/cache/osm/opensm.opts for use next invocation
+ The cache directory can be changed by the environment
+ variable OSM_CACHE_DIR

+
+

-g[=]<GUID in hex>
+ --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 + trys to use the default port.

+
+

-l <LMC>
+ --lmc <LMC>

+
+

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

+
+

This option specifies the SM's PRIORITY.
+ This will effect the handover cases, where master
+ is chosen by priority and GUID.
+ -smkey <SM_Key>
+ This option specifies the SM's SM_Key (64 bits).
+ This will effect SM authentication.

+
+

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

+
+

-u
+ --updn

+
+

This option activate UPDN algorithm instead of Min Hop + algorithm (default).

+
+

-a
+ --add_guid_file <path to file>

+
+

Set the root nodes for the Up/Down routing algorithm to + the guids provided in the given file (one per line)

+
+

-o
+ --once

+
+

This option causes OpenSM to configure the subnet once, + then exit. Ports remain in the ACTIVE state.

+
+

-s <interval>
+ --sweep <interval>

+
+

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

+
+

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.

+
+

-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 one outstanding SMP.

+
+

-i <equalize-ignore-guids-file>
+ -ignore-guids <equalize-ignore-guids-file>

+
+

This option provides the means to define a set of ports + (by guids) that will be ignored by the link load  + equalization algorithm.

+
+

-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

+
+

This option names the OpenSM log file. By + default the log goes to %SystemRoot%\Temp\osm.log when started as
+ a Windows service. When OpenSM.exe is run from a command prompt, the + default log file is created as '%TEMP%\osm.log'.
+ For the log to go to standard output use -f stdout.

+
+

-e
+ --erase_log_file

+
+

This option will cause deletion of the log file  + (if it previously exists). By default, the log file is accumulative.

+
+

-y
+ --stay_on_fatal

+
+

This option will cause SM not to exit on fatal + initialization + issues: if SM discovers duplicated guids or 12x link with + lane reversal badly configured. + By default, the SM will exit on these errors.

+
+

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

+
+

-D <flags>

+
+

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

+
+

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
+ -d4 - Put OpenSM in memory tracking mode
+ -d10 - Put OpenSM in testability mode
+ Without -d, no debug options are enabled

+
+

-h
+ --help

+
+

Display this usage info then exit.

+
+

-?

+
+

Display this usage info then exit.

+
+
+

<return-to-top>

+

 

+


+Osmtest - Subnet Management Tests

+

Invoke open subnet management tests. osmtest currently can not +run on the same HCA port which OpenSM is currently using.

+
+

 Usage: osmtest [options]

+

Options:

+
+

 -f <c|a|v|s|e|f|m|q|t>
+ --flow <c|a|v|s|e|f|m|q|t>

+ +

This option directs osmtest to run a specific flow:

+

FLOW DESCRIPTIONS
+ c = create an inventory file with all nodes, ports & paths.
+ a = run all validation tests (expecting an input inventory)
+ v = only validate the given inventory file.
+ s = run service registration, un-registration and lease.
+ e = run event forwarding test.
+ f = flood the SA with queries accoring to the stress mode.
+ m = multicast flow.
+ q = QoS info - VLArb and SLtoVL tables.
+ t = run trap 64/65 flow; requires running an external tool.
+ (default is all but QoS).

+ +

-w <trap_wait_time>
+ --wait <trap_wait_time>

+
+

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

+
+

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 - Unused.
+ -d1 - Do not scan/compare path records.
+ -d2 - Force log flushing after each log message.
+ -d3 - Use mem tracking.
+ Without -d, no debug options are enabled.

+
+

-m <LID in hex>
+ --max_lid <LID in hex>

+
+

This option specifies the maximal LID number to be + searched + for during inventory file build (default to 100).

+
+

-g <GUID in hex>
+ --guid <GUID in hex>

+
+

This option specifies the local port GUID value + with which osmtest should bind. osmtest may be + bound to 1 port at a time. + Without -g, osmtest displays a menu of possible + port GUIDs and waits for user input.

+
+

-h
+ --help

+
+

Display this usage info then exit.

+
+

-i <filename>
+ --inventory <filename>

+
+

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 the -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 response SA queries .
+ -s2 - Multi-MAD (RMPP) response SA queries.
+ -s3 - Multi-MAD (RMPP) Path Record SA queries.
+ Without -s, stress testing is not performed.

+
+

-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 vs. OpenSM MC.
+ Multiple mode - Could be run with other apps using MC vs.
+ OpenSM. Without -M, default flow testing is performed.

+
+

-t <milliseconds>

+
+

This option specifies the time in milliseconds used + for transaction timeouts.
+ Specifying -t 0 disables timeouts.
+ Without -t, osmtest defaults to a timeout value of 1 second.

+
+

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

+
+

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

+
+
+
+

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

+

WinOF 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\WinOF\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>

+

 

+
+

Network Direct +Service Provider


+

Network Direct 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 [-i | -r | -l]
+
+ -i    Install (enable) the Network Direct (ND) service provider
+ -r    Remove the ND service provider
+ -r <name>    Remove the specified service provider
+ -l    List service providers

+
+

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.

+

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

+

WinOF 1.0.1, and future WinOF +releases, will include DAT/DAPL version 2.0 runtime libraries along with an optional +v2.0 application build environment.
+DAT 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 v1.1 (free-build) + runtime libraries are installed into %SystemRoot%, with the v1.1 Debug + versions located in '%SystemDrive%\%ProgramFiles(x86)%\WinOF'.  Debug + libraries are identified as datd.dll and dapld.dll.

+

IA32 (aka, 32-bit) + versions of DAT/DAPL 1.1 runtime libraries, found only on 64-bit systems, + are identified in '%SystemDrive%\%ProgramFiles(x86)%\WinOF' as dat32.dll and + dapl32.dll.
+
+ DAT/DAPL 2.0 (free-build) libraries are identified in %SystemRoot% as + dat2.dll and dapl2.dll.  Debug versions of the v2.0 runtime libraries + are located in '%SystemDrive%\%ProgramFiles(x86)%\WinOF'.

+

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

+

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

+

The default WinOF + installation places the runtime library files dat.dll and dapl.dll in the '%SystemRoot%' folder; + symbol files (.pdb) are located in '%SystemDrive%\%ProgramFiles(x86)%\WinOF'.

+

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%\dapl.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\\WinOF\\dapl.dll").

+

A sample InfiniBand dat.conf file is + installed as '\Program Files\WinOF\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'

+

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%\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 Connection + Manager (CM) to establish InfiniBand reliable connections to Windows based system. + IBAL is the original DAPL provider.

  • +
  • +

    Socket-CM Provider

    +
      +
    • +

      File: %windir%\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 (sock-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 for Linux.

  • +
  • +

    RDMA-CM Provider

    +
      +
    • +

      File: %windir%\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 tailored for each WinOF 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\v1-1' + or + '%SystemDrive%\DAT\v2-0'. Your C language based DAT 1.1 application compilation command line + should include'/I%SystemDrive%\DAT\v1-1' 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\v1-1
+ 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 datd.lib or + dat2d.lib for DAT v2.0.

+
+
+

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)
+
+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 local dapltest server process with debug verbosity.
+                        Server loops (listen for dapltest request, process request).
+    
+    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 ibnic0 -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 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.
+
+dt-svr.bat - DAPLtest server script; starts a DAPL2test.exe server on the local node.
+	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 on HCA0
+
+Verify dt-*.bat script is running same dapltest.exe(v1.1) or dapl2test.exe(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.

+

WinOF 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 WinOF stack +with a Subnet
+Manager running somewhere on the IB fabric.
+
+- Supported Operating Systems and Service Packs:
+   o Windows XP SP3 x86 & x64
+   o Windows Server 2008/Vista  (x86, x64)
+   o Windows Server 2008 HPC (x64)
+   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 SRP target has been tested.
+Testing included SRP target drive format, read, write and dismount/offline +operations.

+

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

+

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.

+

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

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

+

 

+
+

InfiniBand Software +Development Kit

+
+

If selected during a WinOF install, the IB Software Development Kit will +be installed as '%SystemDrive%\IBSDK'. Underneath the IBSDK\ folder you will find an +include folder 'Inc\',  library definition files 'Lib\'  along with a +'Samples' folder.

+

Compilation:

+
+

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

+
+

Linking:

+
+

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

+

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

+
+

Samples:

+
    +
  • DDK\ demonstrates how to build an IB application in the Windows + Server 2003 SP1 DDK  (Driver Development Kit) environment.
    + Consult the README.txt file for details.
    + See + http://www.microsoft.com/whdc/devtools/ddk/default.mspx for DDK + installation details.
  • +
  • VS\ demonstrates how to build an IB application in the Windows Server + 2003 R2 SP1 Visual Studio 2005 environment.
    + Consult the README.txt file for details.
  • +
+ +

 

+

<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 WinOF +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 WinOF 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-1/docs/build.txt b/branches/WOF2-1/docs/build.txt new file mode 100644 index 00000000..fcd7dc0c --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_async_proc_h.html b/branches/WOF2-1/docs/complib/cl_async_proc_h.html new file mode 100644 index 00000000..a7926d51 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_atomic_h.html b/branches/WOF2-1/docs/complib/cl_atomic_h.html new file mode 100644 index 00000000..1d78041a --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_byteswap_h.html b/branches/WOF2-1/docs/complib/cl_byteswap_h.html new file mode 100644 index 00000000..b9572798 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_comppool_h.html b/branches/WOF2-1/docs/complib/cl_comppool_h.html new file mode 100644 index 00000000..fbecd283 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_debug_h.html b/branches/WOF2-1/docs/complib/cl_debug_h.html new file mode 100644 index 00000000..6b946692 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_event_h.html b/branches/WOF2-1/docs/complib/cl_event_h.html new file mode 100644 index 00000000..001da4f3 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_fleximap_h.html b/branches/WOF2-1/docs/complib/cl_fleximap_h.html new file mode 100644 index 00000000..6eaf3845 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_ioctl_h.html b/branches/WOF2-1/docs/complib/cl_ioctl_h.html new file mode 100644 index 00000000..86ea18a0 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_irqlock_h.html b/branches/WOF2-1/docs/complib/cl_irqlock_h.html new file mode 100644 index 00000000..527b6ec7 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_list_h.html b/branches/WOF2-1/docs/complib/cl_list_h.html new file mode 100644 index 00000000..33a5f936 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_log_h.html b/branches/WOF2-1/docs/complib/cl_log_h.html new file mode 100644 index 00000000..7c3dffaf --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_map_h.html b/branches/WOF2-1/docs/complib/cl_map_h.html new file mode 100644 index 00000000..2845187a --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_math_h.html b/branches/WOF2-1/docs/complib/cl_math_h.html new file mode 100644 index 00000000..7dc206d8 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_memory_h.html b/branches/WOF2-1/docs/complib/cl_memory_h.html new file mode 100644 index 00000000..cd6a1ca0 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_mutex_h.html b/branches/WOF2-1/docs/complib/cl_mutex_h.html new file mode 100644 index 00000000..b9bbfdb4 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_obj_h.html b/branches/WOF2-1/docs/complib/cl_obj_h.html new file mode 100644 index 00000000..9dcd6e3c --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_passivelock_h.html b/branches/WOF2-1/docs/complib/cl_passivelock_h.html new file mode 100644 index 00000000..50cdf150 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_perf_h.html b/branches/WOF2-1/docs/complib/cl_perf_h.html new file mode 100644 index 00000000..df5184f7 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_pool_h.html b/branches/WOF2-1/docs/complib/cl_pool_h.html new file mode 100644 index 00000000..8502b831 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_ptr_vector_h.html b/branches/WOF2-1/docs/complib/cl_ptr_vector_h.html new file mode 100644 index 00000000..f9419dc2 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_qcomppool_h.html b/branches/WOF2-1/docs/complib/cl_qcomppool_h.html new file mode 100644 index 00000000..a89206ab --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_qlist_h.html b/branches/WOF2-1/docs/complib/cl_qlist_h.html new file mode 100644 index 00000000..e023b863 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_qlockpool_h.html b/branches/WOF2-1/docs/complib/cl_qlockpool_h.html new file mode 100644 index 00000000..f06edb61 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_qmap_h.html b/branches/WOF2-1/docs/complib/cl_qmap_h.html new file mode 100644 index 00000000..b80ebc54 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_qpool_h.html b/branches/WOF2-1/docs/complib/cl_qpool_h.html new file mode 100644 index 00000000..69575803 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_rbmap_h.html b/branches/WOF2-1/docs/complib/cl_rbmap_h.html new file mode 100644 index 00000000..f2c76df2 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_reqmgr_h.html b/branches/WOF2-1/docs/complib/cl_reqmgr_h.html new file mode 100644 index 00000000..50b7d70d --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_spinlock_h.html b/branches/WOF2-1/docs/complib/cl_spinlock_h.html new file mode 100644 index 00000000..960e2e2b --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_syscallback_h.html b/branches/WOF2-1/docs/complib/cl_syscallback_h.html new file mode 100644 index 00000000..e02cbcd0 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_thread_h.html b/branches/WOF2-1/docs/complib/cl_thread_h.html new file mode 100644 index 00000000..aeebc824 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_threadpool_h.html b/branches/WOF2-1/docs/complib/cl_threadpool_h.html new file mode 100644 index 00000000..e6ca4418 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_timer_h.html b/branches/WOF2-1/docs/complib/cl_timer_h.html new file mode 100644 index 00000000..86882a04 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_types_h.html b/branches/WOF2-1/docs/complib/cl_types_h.html new file mode 100644 index 00000000..fc26528f --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_vector_h.html b/branches/WOF2-1/docs/complib/cl_vector_h.html new file mode 100644 index 00000000..e316bdcd --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/cl_waitobj_h.html b/branches/WOF2-1/docs/complib/cl_waitobj_h.html new file mode 100644 index 00000000..d09adb96 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/complib/comp_lib_h.html b/branches/WOF2-1/docs/complib/comp_lib_h.html new file mode 100644 index 00000000..36e5f2d8 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/dontdiff.txt b/branches/WOF2-1/docs/dontdiff.txt new file mode 100644 index 00000000..0aeffb62 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/generate-patch.txt b/branches/WOF2-1/docs/generate-patch.txt new file mode 100644 index 00000000..3210baba --- /dev/null +++ b/branches/WOF2-1/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-1/docs/iba/ib_al_h.html b/branches/WOF2-1/docs/iba/ib_al_h.html new file mode 100644 index 00000000..3ee78d44 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/iba/ib_types_h.html b/branches/WOF2-1/docs/iba/ib_types_h.html new file mode 100644 index 00000000..085063ca --- /dev/null +++ b/branches/WOF2-1/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-1/docs/maintainers.txt b/branches/WOF2-1/docs/maintainers.txt new file mode 100644 index 00000000..91e3b949 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/masterindex.html b/branches/WOF2-1/docs/masterindex.html new file mode 100644 index 00000000..b0e6139b --- /dev/null +++ b/branches/WOF2-1/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-1/docs/openfabrics.gif b/branches/WOF2-1/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-1/docs/robo_functions.html b/branches/WOF2-1/docs/robo_functions.html new file mode 100644 index 00000000..823659ce --- /dev/null +++ b/branches/WOF2-1/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-1/docs/robo_modules.html b/branches/WOF2-1/docs/robo_modules.html new file mode 100644 index 00000000..64e6c96a --- /dev/null +++ b/branches/WOF2-1/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-1/docs/robo_sourcefiles.html b/branches/WOF2-1/docs/robo_sourcefiles.html new file mode 100644 index 00000000..cee58ddf --- /dev/null +++ b/branches/WOF2-1/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-1/docs/robo_strutures.html b/branches/WOF2-1/docs/robo_strutures.html new file mode 100644 index 00000000..19552812 --- /dev/null +++ b/branches/WOF2-1/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-1/docs/robodoc.css b/branches/WOF2-1/docs/robodoc.css new file mode 100644 index 00000000..44ae2c54 --- /dev/null +++ b/branches/WOF2-1/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-1/etc/bldwo.bat b/branches/WOF2-1/etc/bldwo.bat new file mode 100644 index 00000000..3896e9e4 --- /dev/null +++ b/branches/WOF2-1/etc/bldwo.bat @@ -0,0 +1,100 @@ +@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"=="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" 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% +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-1/etc/bldwoall.bat b/branches/WOF2-1/etc/bldwoall.bat new file mode 100644 index 00000000..659755ab --- /dev/null +++ b/branches/WOF2-1/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-1/etc/clean-build.bat b/branches/WOF2-1/etc/clean-build.bat new file mode 100644 index 00000000..608daa10 --- /dev/null +++ b/branches/WOF2-1/etc/clean-build.bat @@ -0,0 +1,61 @@ +@echo off +setlocal + +rem usage: clean-build {scan-only} +rem no args - remove build specific folders & files: +rem *_win7_* *_wxp_* *_wnet_* *_wlh_* +rem arg1 != "" - then report matched folders & files - no delete. + +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 ( _win7_ _wlh_ _wnet_ _wxp_ ) do ( + echo Folder Scan for *%%d* + dir /B /S /A:D *%%d* > %T% 2>&1 + if ERRORLEVEL 1 ( + del /Q/F %T% + ) else ( + for /f "delims=," %%f in ( %T% ) do ( + if EXIST "%%f" ( + if "%1" == "" ( + rmdir /S /Q "%%f" 1>nul + ) else ( + echo found "%%f" + ) + ) + ) + del /Q/F %T% + ) +) + +rem check/remove files + +for %%d in ( _win7_ _wlh_ _wxp_ _wnet_ ) do ( + echo File Scan for *%%d* + dir /B /S *%%d* > %T% 2>&1 + if ERRORLEVEL 1 ( + del /Q/F %T% + ) else ( + for /f "delims=," %%f in ( %T% ) do ( + if EXIST "%%f" ( + if "%1" == "" ( + del /F /Q "%%f" 1>nul + ) else ( + echo found %%f + ) + ) + ) + del /Q/F %T% + ) +) +endlocal + diff --git a/branches/WOF2-1/etc/cpinst.bat b/branches/WOF2-1/etc/cpinst.bat new file mode 100644 index 00000000..16904686 --- /dev/null +++ b/branches/WOF2-1/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-1/etc/kernel/index_list.c b/branches/WOF2-1/etc/kernel/index_list.c new file mode 100644 index 00000000..552c67b3 --- /dev/null +++ b/branches/WOF2-1/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(PagedPool, 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-1/etc/kernel/work_queue.c b/branches/WOF2-1/etc/kernel/work_queue.c new file mode 100644 index 00000000..24af0647 --- /dev/null +++ b/branches/WOF2-1/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); + } + ExFreePool(pWorkQueue->TaskArray); + 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-1/etc/makebin.bat b/branches/WOF2-1/etc/makebin.bat new file mode 100644 index 00000000..59336dd1 --- /dev/null +++ b/branches/WOF2-1/etc/makebin.bat @@ -0,0 +1,875 @@ +@echo off +setlocal + +rem usage: +rem makebin src dst [win7 | wlh | wnet | wxp] DDK_ROOT WdfCoInstaler_Ver +rem +rem src(%1) - OpenIB src path ...\gen1\trunk +rem dst(%2) - full path tp where binaries are copied, 'bin\' created here. +rem OSE(%3) - (Operating System Environment) which windows version +rem {win7,wxp,wlh,wnet} representing {XP, server 2008 & server 2003} +rem DDK_ROOT - {blank == assumes %SystemDrive%\WinDDK\6001.1801} +rem WdfCoInstall_ver - 5 digit WdfCoInstallerVersion # (blank == 01007} + +rem makebin is designed to take an openIB build tree path and produce a folder +rem tree of binaries suitable for input to a WIX builder which procduces +rem an OS .msi installer. +rem Building a WinOF 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 + +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' ? +goto usage + +:os_ok + +rem Enable tracing to indicate phase for potiential debug. +set DBG=TRUE + +set OSE=%3 + +rem setup DDK root path +if /I "%4"=="" ( + set _DDK=%systemdrive%\WinDDK\6001.18001 +) else ( + set _DDK=%4 +) +if not exist "%_DDK%" ( + echo Missing file %_DDK% ? + exit /B 1 +) + +set WdfCoInstaller=%_DDK%\redist\wdf +set DIFXP=%_DDK%\redist\DIFx\DIFxAPP\English\WixLib +set DPINST=%_DDK%\redist\DIFx\DPInst\EngMui + +if /I "%5"=="" ( + set CoInstallVer=01007 +) else ( + set CoInstallVer=%5 +) + +if not exist %1 goto usage +if not exist %2 goto usage + +if /I "%OSE%" == "wxp" ( + 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 +) else ( + if not exist %1\bin\kernel\objfre_%OSE%_amd64\amd64 goto error1 + if not exist %1\bin\kernel\objfre_%OSE%_ia64\ia64 goto error2 + if not exist %1\bin\kernel\objfre_%OSE%_x86\i386 goto error3 + if not exist %1\bin\user\objfre_%OSE%_amd64\amd64 goto error4 + if not exist %1\bin\user\objfre_%OSE%_ia64\ia64 goto error5 + if not exist %1\bin\user\objfre_%OSE%_x86\i386 goto error6 + if not exist %1\bin\user\objchk_%OSE%_amd64\amd64 goto error7 + if not exist %1\bin\user\objchk_%OSE%_ia64\ia64 goto error8 + if not exist %1\bin\user\objchk_%OSE%_x86\i386 goto error9 +) + +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 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 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 dat2d.dll dat2d.lib dat2d.pdb + +set DAPL_F=dapl.dll dapl.pdb dat.dll dat.lib dat.pdb + +set DAPL_D=dapld.dll dapld.pdb datd.dll datd.lib datd.pdb + + +rem +rem KERNEL MODE +rem + +if /I "%OSE%" == "wxp" goto wxp_drv + +rem Copy AMD64 Free drivers +set bin_dir=%1\bin\kernel\objfre_%OSE%_amd64\amd64 +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 + +xcopy %bin_dir%\ipoib.sys %2\net\amd64\ /yq +xcopy %bin_dir%\qlgcvnic.sys %2\net\amd64\ /yq +xcopy %bin_dir%\ibsrp.sys %2\storage\amd64\ /yq + +xcopy %bin_dir%\ipoib.pdb %2\net\amd64\ /yq +xcopy %bin_dir%\qlgcvnic.pdb %2\net\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 + +rem Copy IA64 drivers +set bin_dir=%1\bin\kernel\objfre_%OSE%_ia64\ia64 +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 + +xcopy %bin_dir%\ipoib.sys %2\net\ia64\ /yq +xcopy %bin_dir%\qlgcvnic.sys %2\net\ia64\ /yq +xcopy %bin_dir%\ibsrp.sys %2\storage\ia64\ /yq + +xcopy %bin_dir%\ipoib.pdb %2\net\ia64\ /yq +xcopy %bin_dir%\qlgcvnic.pdb %2\net\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 + +rem Copy x86 drivers + +: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 + +xcopy %bin_dir%\ipoib.sys %2\net\x86\ /yq +xcopy %bin_dir%\qlgcvnic.sys %2\net\x86\ /yq +xcopy %bin_dir%\ibsrp.sys %2\storage\x86\ /yq + +xcopy %bin_dir%\ipoib.pdb %2\net\x86\ /yq +xcopy %bin_dir%\qlgcvnic.pdb %2\net\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 + +rem Checked USER MODE + +if /I "%OSE%" == "wxp" goto wxp_userm + +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 ( %DAPL_D% ) do ( + xcopy %bin_dir%\%%i %2\DAPL\amd64\ /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %2\DAPL\amd64\ /yq + exit /B 1 + ) +) + +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 + ) +) + + +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 ( %DAPL_D% ) do ( + xcopy %bin_dir%\%%i %2\DAPL\ia64\ /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %2\DAPL\ia64\ /yq + exit /B 1 + ) +) + +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 + ) +) + + +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 ( %DAPL_D% ) do ( + xcopy %bin_dir%\%%i %2\DAPL\x86\ /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %2\DAPL\x86\ /yq + exit /B 1 + ) +) + +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 + +rem checked x86 DLLs --> WOW64 DLLs + +if "%DBG%" == "TRUE" echo DBG: x86 Checked dlls copy to WOW64 dlls + +rem xcopy had problems determining if dest was File | Dir ?? + +copy /B %bin_dir%\ibald.dll %2\HCA\amd64\ibal32d.dll /y +copy /B %bin_dir%\ibald.lib %2\HCA\amd64\ibal32d.lib /y +copy /B %bin_dir%\ibald.pdb %2\HCA\amd64\ibal32d.pdb /y +copy /B %bin_dir%\complibd.dll %2\HCA\amd64\cl32d.dll /y +copy /B %bin_dir%\complibd.lib %2\HCA\amd64\cl32d.lib /y +copy /B %bin_dir%\complibd.pdb %2\HCA\amd64\cl32d.pdb /y + +copy /B %bin_dir%\ibald.dll %2\HCA\ia64\ibal32d.dll /y +copy /B %bin_dir%\ibald.lib %2\HCA\ia64\ibal32d.lib /y +copy /B %bin_dir%\ibald.pdb %2\HCA\ia64\ibal32d.pdb /y +copy /B %bin_dir%\complibd.dll %2\HCA\ia64\cl32d.dll /y +copy /B %bin_dir%\complibd.lib %2\HCA\ia64\cl32d.lib /y +copy /B %bin_dir%\complibd.pdb %2\HCA\ia64\cl32d.pdb /y + +copy /B %bin_dir%\mthcaud.dll %2\HCA\amd64\mthca32d.dll /y +copy /B %bin_dir%\mthcaud.dll %2\HCA\ia64\mthca32d.dll /y + +copy /B %bin_dir%\mlx4ud.dll %2\HCA\amd64\mlx4u32d.dll /y +copy /B %bin_dir%\mlx4ud.dll %2\HCA\ia64\mlx4u32d.dll /y + +copy /B %bin_dir%\dapld.dll %2\DAPL\amd64\dapl32d.dll /y +copy /B %bin_dir%\datd.dll %2\DAPL\amd64\dat32d.dll /y +copy /B %bin_dir%\dapld.dll %2\DAPL\ia64\dapl32d.dll /y +copy /B %bin_dir%\datd.dll %2\DAPL\ia64\dat32d.dll /y + +copy /B %bin_dir%\dapl2d.dll %2\DAPL2\amd64\dapl232d.dll /y +copy /B %bin_dir%\dat2d.dll %2\DAPL2\amd64\dat232d.dll /y +copy /B %bin_dir%\dapl2d.dll %2\DAPL2\ia64\dapl232d.dll /y +copy /B %bin_dir%\dat2d.dll %2\DAPL2\ia64\dat232d.dll /y + +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 +) else ( + echo %0 - missing x64 Network Direct components [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 ( %DAPL_F% ) do ( + xcopy %bin_dir%\%%i %2\DAPL\amd64\ /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %2\DAPL\amd64\ /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 + ) +) + + +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 +rem xcopy %bin_dir%\ndinstall.exe %2\net\ia64\ /yq +rem xcopy %bin_dir%\ibndprov.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 ( %DAPL_F% ) do ( + xcopy %bin_dir%\%%i %2\DAPL\ia64\ /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %2\DAPL2\ia64\ /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 + ) +) + + +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 ( %DAPL_F% ) do ( + xcopy %bin_dir%\%%i %2\DAPL\x86\ /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %2\DAPL2\x86\ /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 +) 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 + +rem free x86 DLLs --> WOW64 DLLs + +if "%DBG%" == "TRUE" echo DBG: x86 Free dlls to WOW64 + +if exist "%bin_dir%\ibndprov.dll" ( + copy %bin_dir%\ibndprov.dll %2\net\amd64\ibndprov32.dll /y + copy %bin_dir%\ibndprov.dll %2\net\ia64\ibndprov32.dll /y +) +copy /B %bin_dir%\ibwsd.dll %2\net\amd64\ibwsd32.dll /y +copy /B %bin_dir%\ibwsd.dll %2\net\ia64\ibwsd32.dll /y + +copy /B %bin_dir%\ibal.dll %2\HCA\amd64\ibal32.dll /y +copy /B %bin_dir%\ibal.lib %2\HCA\amd64\ibal32.lib /y +copy /B %bin_dir%\ibal.pdb %2\HCA\amd64\ibal32.pdb /y +copy /B %bin_dir%\complib.dll %2\HCA\amd64\cl32.dll /y +copy /B %bin_dir%\complib.lib %2\HCA\amd64\cl32.lib /y +copy /B %bin_dir%\complib.pdb %2\HCA\amd64\cl32.pdb /y +copy /B %bin_dir%\winverbs.dll %2\HCA\amd64\winverbs32.dll /y +copy /B %bin_dir%\winverbs.lib %2\HCA\amd64\winverbs32.lib /y +copy /B %bin_dir%\winverbs.pdb %2\HCA\amd64\winverbs32.pdb /y +copy /B %bin_dir%\winmad.dll %2\HCA\amd64\winverbs32.dll /y +copy /B %bin_dir%\winmad.lib %2\HCA\amd64\winverbs32.lib /y +copy /B %bin_dir%\winmad.pdb %2\HCA\amd64\winverbs32.pdb /y + +copy /B %bin_dir%\ibal.dll %2\HCA\ia64\ibal32.dll /y +copy /B %bin_dir%\ibal.lib %2\HCA\ia64\ibal32.lib /y +copy /B %bin_dir%\ibal.pdb %2\HCA\ia64\ibal32.pdb /y +copy /B %bin_dir%\complib.dll %2\HCA\ia64\cl32.dll /y +copy /B %bin_dir%\complib.lib %2\HCA\ia64\cl32.lib /y +copy /B %bin_dir%\complib.pdb %2\HCA\ia64\cl32.pdb /y +copy /B %bin_dir%\winverbs.dll %2\HCA\ia64\winverbs32.dll /y +copy /B %bin_dir%\winverbs.lib %2\HCA\ia64\winverbs32.lib /y +copy /B %bin_dir%\winverbs.pdb %2\HCA\ia64\winverbs32.pdb /y +copy /B %bin_dir%\winmad.dll %2\HCA\ia64\winverbs32.dll /y +copy /B %bin_dir%\winmad.lib %2\HCA\ia64\winverbs32.lib /y +copy /B %bin_dir%\winmad.pdb %2\HCA\ia64\winverbs32.pdb /y + +copy /B %bin_dir%\mthcau.dll %2\HCA\amd64\mthca32.dll /y +copy /B %bin_dir%\mthcau.dll %2\HCA\ia64\mthca32.dll /y + +copy /B %bin_dir%\mlx4u.dll %2\HCA\amd64\mlx4u32.dll /y +copy /B %bin_dir%\mlx4u.dll %2\HCA\ia64\mlx4u32.dll /y + +copy /B %bin_dir%\dapl.dll %2\DAPL\amd64\dapl32.dll /y +copy /B %bin_dir%\dat.dll %2\DAPL\amd64\dat32.dll /y +copy /B %bin_dir%\dapl.dll %2\DAPL\ia64\dapl32.dll /y +copy /B %bin_dir%\dat.dll %2\DAPL\ia64\dat32.dll /y + +copy /B %bin_dir%\dapl2.dll %2\DAPL2\amd64\dapl232.dll /y +copy /B %bin_dir%\dat2.dll %2\DAPL2\amd64\dat232.dll /y +copy /B %bin_dir%\dapl2.dll %2\DAPL2\ia64\dapl232.dll /y +copy /B %bin_dir%\dat2.dll %2\DAPL2\ia64\dat232.dll /y + +:mk_sym_bin + +rem bin\bin used to generate a web based symbol store in build-ofa-dist.bat. + +echo 'Copy bin\obj{chk,fre}_%3_{x86,amd64,ia64} to bin' +rem xcopy %1\bin %2\bin\ /eyq +rem instead of copying the entire bin\ folder, pick items of OS interest. + +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 +if /I "%3" == "wxp" goto ucpy +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\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 + +:ucpy + +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 +if /I "%3" == "wxp" goto ucpyx +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 +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 + +:ucpyx + +rem echo Copy symbol files: bin\*.pdb to %2\symbols +rem xcopy %1\bin\*.pdb %2\symbols\ /eyq + +rem if "%DBG%" == "TRUE" echo DBG: bin\ file cleanup, file-not-found is OK. +rem pushd %2 +rem del /s bin\*.pdb > nul +rem del /s ibtest* > nul +rem del /s pingpong* > nul +rem del /s *Sdp* > nul +rem del /s Select* > nul +rem del /s usrp* > nul +rem del /s bin\*.lib > nul +rem del /s bin\*.exp > nul +rem popd + +rem Copy DAT v1.1 header files +if "%DBG%" == "TRUE" echo DBG: DAT v1.1 header files +if exist %1\ulp\dapl\dat\include\dat ( + pushd %1\ulp\dapl\dat\include\dat + + xcopy dat.h %2\DAPL /Y/Q + xcopy dat_error.h %2\DAPL /Y/Q + xcopy dat_platform_specific.h %2\DAPL /Y/Q + xcopy dat_redirection.h %2\DAPL /Y/Q + xcopy dat_registry.h %2\DAPL /Y/Q + xcopy dat_vendor_specific.h %2\DAPL /Y/Q + xcopy udat.h %2\DAPL /Y/Q + xcopy udat_config.h %2\DAPL /Y/Q + xcopy udat_redirection.h %2\DAPL /Y/Q + xcopy udat_vendor_specific.h %2\DAPL /Y/Q + popd +) + +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_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 openib.def %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 + 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\{amd64,ia64,x86}" +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\{amd64,ia64,x86}" +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\{amd64,ia64,x86}" +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-1/etc/user/comp_channel.cpp b/branches/WOF2-1/etc/user/comp_channel.cpp new file mode 100644 index 00000000..14849bd3 --- /dev/null +++ b/branches/WOF2-1/etc/user/comp_channel.cpp @@ -0,0 +1,324 @@ +/* + * 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 CompManagerQueue(COMP_MANAGER *pMgr, COMP_ENTRY *pEntry); +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) { + CompChannelQueue(entry->Channel, entry); + } else { + CompManagerQueue(mgr, entry); + } + } + + _endthreadex(0); + return 0; +} + +DWORD CompManagerOpen(COMP_MANAGER *pMgr) +{ + DWORD ret; + + InitializeCriticalSection(&pMgr->Lock); + pMgr->Busy = 0; + DListInit(&pMgr->DoneList); + CompEntryInit(NULL, &pMgr->Entry); + + pMgr->CompQueue = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, -1); + if (pMgr->CompQueue == NULL) { + ret = GetLastError(); + goto err1; + } + + pMgr->Event = CreateEvent(NULL, TRUE, TRUE, NULL); + if (pMgr->Event == NULL) { + ret = GetLastError(); + goto err2; + } + + pMgr->Run = TRUE; + pMgr->Thread = (HANDLE) _beginthreadex(NULL, 0, CompThreadPoll, pMgr, 0, NULL); + if (pMgr->Thread == NULL) { + ret = GetLastError(); + goto err3; + } + return 0; + +err3: + CloseHandle(pMgr->Event); +err2: + CloseHandle(pMgr->CompQueue); +err1: + DeleteCriticalSection(&pMgr->Lock); + return ret; +} + +void CompManagerClose(COMP_MANAGER *pMgr) +{ + pMgr->Run = FALSE; + CompManagerCancel(pMgr); + WaitForSingleObject(pMgr->Thread, INFINITE); + CloseHandle(pMgr->Thread); + + CloseHandle(pMgr->CompQueue); + CloseHandle(pMgr->Event); + DeleteCriticalSection(&pMgr->Lock); +} + +DWORD CompManagerMonitor(COMP_MANAGER *pMgr, HANDLE hFile, ULONG_PTR Key) +{ + HANDLE cq; + + cq = CreateIoCompletionPort(hFile, pMgr->CompQueue, Key, 0); + return (cq == NULL) ? GetLastError() : 0; +} + +static void CompManagerQueue(COMP_MANAGER *pMgr, COMP_ENTRY *pEntry) +{ + EnterCriticalSection(&pMgr->Lock); + DListInsertTail(&pEntry->MgrEntry, &pMgr->DoneList); + SetEvent(pMgr->Event); + LeaveCriticalSection(&pMgr->Lock); +} + +static void CompManagerRemoveEntry(COMP_MANAGER *pMgr, COMP_ENTRY *pEntry) +{ + EnterCriticalSection(&pMgr->Lock); + DListRemove(&pEntry->MgrEntry); + LeaveCriticalSection(&pMgr->Lock); +} + +DWORD CompManagerPoll(COMP_MANAGER *pMgr, DWORD Milliseconds, + COMP_CHANNEL **ppChannel) +{ + COMP_ENTRY *entry; + DWORD ret = 0; + + EnterCriticalSection(&pMgr->Lock); + while (DListEmpty(&pMgr->DoneList)) { + ResetEvent(pMgr->Event); + LeaveCriticalSection(&pMgr->Lock); + + ret = WaitForSingleObject(pMgr->Event, Milliseconds); + if (ret) { + return ret; + } + + EnterCriticalSection(&pMgr->Lock); + } + + entry = CONTAINING_RECORD(pMgr->DoneList.Next, COMP_ENTRY, MgrEntry); + *ppChannel = entry->Channel; + if (entry->Channel == NULL) { + DListRemove(&entry->MgrEntry); + InterlockedExchange(&entry->Busy, 0); + ret = ERROR_CANCELLED; + } + LeaveCriticalSection(&pMgr->Lock); + + return ret; +} + +void CompManagerCancel(COMP_MANAGER *pMgr) +{ + if (InterlockedCompareExchange(&pMgr->Entry.Busy, 1, 0) == 0) { + PostQueuedCompletionStatus(pMgr->CompQueue, 0, (ULONG_PTR) pMgr, + &pMgr->Entry.Overlap); + } +} + + +/* + * Completion channel + */ + +DWORD CompChannelInit(COMP_MANAGER *pMgr, COMP_CHANNEL *pChannel, DWORD Milliseconds) +{ + pChannel->Manager = pMgr; + 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; +} + +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; + } + CompManagerRemoveEntry(pChannel->Manager, pEntry); + InterlockedExchange(&pEntry->Busy, 0); + } + LeaveCriticalSection(&pChannel->Lock); + return entry; +} + +static void CompChannelQueue(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry) +{ + pEntry->Next = NULL; + EnterCriticalSection(&pChannel->Lock); + CompManagerQueue(pChannel->Manager, pEntry); + CompChannelInsertTail(pChannel, pEntry); + SetEvent(pChannel->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); + CompManagerRemoveEntry(pChannel->Manager, entry); + 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-1/etc/user/getopt.c b/branches/WOF2-1/etc/user/getopt.c new file mode 100644 index 00000000..9e05699b --- /dev/null +++ b/branches/WOF2-1/etc/user/getopt.c @@ -0,0 +1,169 @@ +/* + * 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 >= argc) { + return EOF; + } + + if (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; + } + + if (argv[optind][2] != '\0') { + optarg = &argv[optind][2]; + goto out; + } + + /* switch argument is optional (::) - be careful */ + if (loc[2] == ':' && (argv[optind+1] && 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 == argc) { + return EOF; + } + + if (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-1/etc/user/gtod.c b/branches/WOF2-1/etc/user/gtod.c new file mode 100644 index 00000000..b6ea6a92 --- /dev/null +++ b/branches/WOF2-1/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-1/etc/user/inet.c b/branches/WOF2-1/etc/user/inet.c new file mode 100644 index 00000000..47ff212c --- /dev/null +++ b/branches/WOF2-1/etc/user/inet.c @@ -0,0 +1,216 @@ +/* + * 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; +} + +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; + } +} + +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; +} + +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; + } +} diff --git a/branches/WOF2-1/etc/wpp/ALTraceRt.cmd b/branches/WOF2-1/etc/wpp/ALTraceRt.cmd new file mode 100644 index 00000000..e3846f2a --- /dev/null +++ b/branches/WOF2-1/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-1/etc/wpp/CreateTrace.cmd b/branches/WOF2-1/etc/wpp/CreateTrace.cmd new file mode 100644 index 00000000..91d05373 --- /dev/null +++ b/branches/WOF2-1/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-1/etc/wpp/IPoIBTraceRt.cmd b/branches/WOF2-1/etc/wpp/IPoIBTraceRt.cmd new file mode 100644 index 00000000..b8fb78c8 --- /dev/null +++ b/branches/WOF2-1/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-1/etc/wpp/MTHCATraceRt.cmd b/branches/WOF2-1/etc/wpp/MTHCATraceRt.cmd new file mode 100644 index 00000000..f2e3fed4 --- /dev/null +++ b/branches/WOF2-1/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-1/etc/wpp/SDPTraceRt.cmd b/branches/WOF2-1/etc/wpp/SDPTraceRt.cmd new file mode 100644 index 00000000..78249dc9 --- /dev/null +++ b/branches/WOF2-1/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-1/etc/wpp/StartSdpTrace.cmd b/branches/WOF2-1/etc/wpp/StartSdpTrace.cmd new file mode 100644 index 00000000..2f193ded --- /dev/null +++ b/branches/WOF2-1/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-1/etc/wpp/StartTrace.cmd b/branches/WOF2-1/etc/wpp/StartTrace.cmd new file mode 100644 index 00000000..0617de47 --- /dev/null +++ b/branches/WOF2-1/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-1/etc/wpp/StopSdpTrace.cmd b/branches/WOF2-1/etc/wpp/StopSdpTrace.cmd new file mode 100644 index 00000000..81533e31 --- /dev/null +++ b/branches/WOF2-1/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-1/etc/wpp/StopTrace.cmd b/branches/WOF2-1/etc/wpp/StopTrace.cmd new file mode 100644 index 00000000..daf7ca5a --- /dev/null +++ b/branches/WOF2-1/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-1/hw/dirs b/branches/WOF2-1/hw/dirs new file mode 100644 index 00000000..58242756 --- /dev/null +++ b/branches/WOF2-1/hw/dirs @@ -0,0 +1,3 @@ +DIRS=\ + mthca\ + mlx4 diff --git a/branches/WOF2-1/hw/mlx4/dirs b/branches/WOF2-1/hw/mlx4/dirs new file mode 100644 index 00000000..5927717d --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/dirs @@ -0,0 +1,3 @@ +DIRS= \ + kernel \ + user \ No newline at end of file diff --git a/branches/WOF2-1/hw/mlx4/inc/mx_abi.h b/branches/WOF2-1/hw/mlx4/inc/mx_abi.h new file mode 100644 index 00000000..02ec7b6f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/inc/public.h b/branches/WOF2-1/hw/mlx4/inc/public.h new file mode 100644 index 00000000..a522670c --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/inc/user.h b/branches/WOF2-1/hw/mlx4/inc/user.h new file mode 100644 index 00000000..a6220990 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/SOURCES b/branches/WOF2-1/hw/mlx4/kernel/bus/core/SOURCES new file mode 100644 index 00000000..fe394f67 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/cache.c b/branches/WOF2-1/hw/mlx4/kernel/bus/core/cache.c new file mode 100644 index 00000000..75da4051 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/core/cache.c @@ -0,0 +1,440 @@ +/* + * 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) +{ + struct ib_gid_cache *cache; + unsigned long flags; + int ret = 0; + + 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) + ret = -EINVAL; + else + *gid = cache->table[index]; + + read_unlock_irqrestore(&device->cache.lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_get_cached_gid); + +int ib_find_cached_gid(struct ib_device *device, + union ib_gid *gid, + u8 *port_num, + u16 *index) +{ + struct ib_gid_cache *cache; + unsigned long flags; + int p, i; + int ret = -ENOENT; + + if (mlx4_is_barred(device->dma_device)) + return -EFAULT; + + *port_num = (u8)-1; + if (index) + *index = (u16)-1; + + read_lock_irqsave(&device->cache.lock, &flags); + + for (p = 0; p <= end_port(device) - start_port(device); ++p) { + cache = device->cache.gid_cache[p]; + for (i = 0; i < cache->table_len; ++i) { + if (!memcmp(gid, &cache->table[i], sizeof *gid)) { + *port_num = (u8)(p + start_port(device)); + if (index) + *index = (u16)i; + ret = 0; + goto found; + } + } + } +found: + read_unlock_irqrestore(&device->cache.lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_find_cached_gid); + +int ib_get_cached_pkey(struct ib_device *device, + u8 port_num, + int index, + __be16 *pkey) +{ + struct ib_pkey_cache *cache; + unsigned long flags; + int ret = 0; + + 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) + ret = -EINVAL; + else + *pkey = cache->table[index]; + + read_unlock_irqrestore(&device->cache.lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_get_cached_pkey); + +int ib_find_cached_pkey(struct ib_device *device, + u8 port_num, + __be16 pkey, + u16 *index) +{ + struct ib_pkey_cache *cache; + unsigned long flags; + int i; + int ret = -ENOENT; + + 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)) { + *index = (u16)i; + ret = 0; + break; + } + + read_unlock_irqrestore(&device->cache.lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_find_cached_pkey); + +int ib_get_cached_lmc(struct ib_device *device, + u8 port_num, + u8 *lmc) +{ + unsigned long flags; + int ret = 0; + + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + read_lock_irqsave(&device->cache.lock, &flags); + *lmc = device->cache.lmc_cache[port_num - start_port(device)]; + read_unlock_irqrestore(&device->cache.lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_get_cached_lmc); + +static void ib_cache_update(struct ib_device *device, + u8 port) +{ + struct ib_port_attr *tprops = NULL; + struct ib_pkey_cache *pkey_cache = NULL, *old_pkey_cache; + struct ib_gid_cache *gid_cache = NULL, *old_gid_cache; + int i; + int ret; + + tprops = kmalloc(sizeof *tprops, GFP_KERNEL); + if (!tprops) + return; + + ret = ib_query_port(device, port, tprops); + if (ret) { + printk(KERN_WARNING "ib_query_port failed (%d) for %s. 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-1/hw/mlx4/kernel/bus/core/core.def b/branches/WOF2-1/hw/mlx4/kernel/bus/core/core.def new file mode 100644 index 00000000..bfbb2f18 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/core.h b/branches/WOF2-1/hw/mlx4/kernel/bus/core/core.h new file mode 100644 index 00000000..ba5787b3 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/core.rc b/branches/WOF2-1/hw/mlx4/kernel/bus/core/core.rc new file mode 100644 index 00000000..1d136d44 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/device.c b/branches/WOF2-1/hw/mlx4/kernel/bus/core/device.c new file mode 100644 index 00000000..481c5a20 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/ev_log.mc b/branches/WOF2-1/hw/mlx4/kernel/bus/core/ev_log.mc new file mode 100644 index 00000000..7eb7f3a7 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/core/ev_log.mc @@ -0,0 +1,56 @@ +;/*++ +;============================================================================= +;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 +. + diff --git a/branches/WOF2-1/hw/mlx4/kernel/bus/core/iobuf.c b/branches/WOF2-1/hw/mlx4/kernel/bus/core/iobuf.c new file mode 100644 index 00000000..62ce6af8 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/l2w.c b/branches/WOF2-1/hw/mlx4/kernel/bus/core/l2w.c new file mode 100644 index 00000000..4569e816 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/l2w_debug.c b/branches/WOF2-1/hw/mlx4/kernel/bus/core/l2w_debug.c new file mode 100644 index 00000000..3780b26d --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/core/l2w_debug.c @@ -0,0 +1,234 @@ +#include "l2w.h" +#include "ev_log.h" + +#define MAX_BUFFER_SIZE 256 + +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 */ + +// 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-1/hw/mlx4/kernel/bus/core/l2w_memory.c b/branches/WOF2-1/hw/mlx4/kernel/bus/core/l2w_memory.c new file mode 100644 index 00000000..49b8c92d --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/l2w_radix.c b/branches/WOF2-1/hw/mlx4/kernel/bus/core/l2w_radix.c new file mode 100644 index 00000000..abea412c --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/l2w_umem.c b/branches/WOF2-1/hw/mlx4/kernel/bus/core/l2w_umem.c new file mode 100644 index 00000000..245ca6bb --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/core/l2w_umem.c @@ -0,0 +1,184 @@ +#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 done; + + 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); + 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-1/hw/mlx4/kernel/bus/core/makefile b/branches/WOF2-1/hw/mlx4/kernel/bus/core/makefile new file mode 100644 index 00000000..d4938551 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/pa_cash.c b/branches/WOF2-1/hw/mlx4/kernel/bus/core/pa_cash.c new file mode 100644 index 00000000..26420c54 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/pa_cash.h b/branches/WOF2-1/hw/mlx4/kernel/bus/core/pa_cash.h new file mode 100644 index 00000000..a231c890 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/packer.c b/branches/WOF2-1/hw/mlx4/kernel/bus/core/packer.c new file mode 100644 index 00000000..5b0da952 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/core/ud_header.c b/branches/WOF2-1/hw/mlx4/kernel/bus/core/ud_header.c new file mode 100644 index 00000000..4be128e2 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/core/ud_header.c @@ -0,0 +1,281 @@ +/* + * 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 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); diff --git a/branches/WOF2-1/hw/mlx4/kernel/bus/core/verbs.c b/branches/WOF2-1/hw/mlx4/kernel/bus/core/verbs.c new file mode 100644 index 00000000..33e08f51 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/core/verbs.c @@ -0,0 +1,338 @@ +/* + * 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); + diff --git a/branches/WOF2-1/hw/mlx4/kernel/bus/dirs b/branches/WOF2-1/hw/mlx4/kernel/bus/dirs new file mode 100644 index 00000000..b70ba29a --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/dirs @@ -0,0 +1,5 @@ +DIRS=\ + core \ + net \ + ib \ + drv diff --git a/branches/WOF2-1/hw/mlx4/kernel/bus/drv/bus.mof b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/bus.mof new file mode 100644 index 00000000..f5b1f1a6 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/drv/bus.rc b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/bus.rc new file mode 100644 index 00000000..58cac5b6 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/drv/drv.c b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/drv.c new file mode 100644 index 00000000..f88b2d16 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/drv.c @@ -0,0 +1,1325 @@ +/*++ + +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 + +static +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; + + 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(number_of_ib_ports > 0) { + 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)); + } + } + + // Create ethernet ports if needed + for (i = 0; i < MLX4_MAX_PORTS; i++) { + if(mlx4_is_eth_port(mdev, i)) { + status = __create_child(Device, ETH_HARDWARE_IDS, ETH_HARDWARE_DESCRIPTION, i+1 ); + if (!NT_SUCCESS(status)) { + MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (eth) failed with 0x%x\n", status)); + } + } + } + + p_fdo->children_created = TRUE; + +end: + MLX4_EXIT( MLX4_DBG_DRV ); + return status; +} + + +NTSTATUS +__read_dev_params(IN WDFDEVICE Device, struct mlx4_dev_params *dev_params) +{ + NTSTATUS status = STATUS_SUCCESS; + WDFKEY hKey = NULL; + WDFKEY hParamsKey = NULL; + DECLARE_CONST_UNICODE_STRING(Parameters, L"Parameters"); + DECLARE_CONST_UNICODE_STRING(PortType, L"PortType"); +#define MAX_UVALUE 100 + WCHAR uvalue_data[MAX_UVALUE]; + UNICODE_STRING uvalue; + 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 Failed status = 0x%x\n", 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 Failed status = 0x%x\n", status)); + goto err; + } + + uvalue.Buffer = uvalue_data; + uvalue.MaximumLength = MAX_UVALUE; + uvalue.Length = 0; + + 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 { + dev_params->mod_port_type[0] = MLX4_PORT_TYPE_IB; + dev_params->mod_port_type[1] = MLX4_PORT_TYPE_IB; + } + +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; + + MLX4_ENTER(MLX4_DBG_DRV); + + MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("PreviousState 0x%x\n", PreviousState)); + + // start card (needed after Hibernetion) + 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_EV(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" + )); + +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 ); + + 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->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; + } + + // start the card + status = __start_card(Device, p_fdo ); + if( !NT_SUCCESS( status ) ) + goto err; + mdev = pdev->dev; + + // get VPD + 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_ERROR, MLX4_DBG_DRV, + ("pci_get_vpd failed, status=0x%x\n", status)); + goto err; + } + + // 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 + + 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 1" + 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"); + + // "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"); + + 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 = 1; + + 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, &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; + + + 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); + + // 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-1/hw/mlx4/kernel/bus/drv/drv.h b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/drv.h new file mode 100644 index 00000000..1b63fb7a --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/drv/makefile b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/makefile new file mode 100644 index 00000000..a0343a17 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/drv/makefile.inc b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/makefile.inc new file mode 100644 index 00000000..b23286df --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/drv/mlx4_bus.cdf b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/mlx4_bus.cdf new file mode 100644 index 00000000..2e0d1430 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/drv/mlx4_bus.inx b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/mlx4_bus.inx new file mode 100644 index 00000000..c91fcc80 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/mlx4_bus.inx @@ -0,0 +1,272 @@ +; Mellanox Technologies InfiniBand HCAs. +; Copyright 2008 Mellanox Technologies all Rights Reserved. + +[Version] +Signature="$WINDOWS NT$" +Class=Mlx4Bus +ClassGUID={714995B2-CD65-4a47-BCFE-95AC73A0D780} +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 +%MT26428.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_673c +%MT26448.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6750 +%MT26458.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_675A +%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 +%MT26428.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_673c +%MT26448.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6750 +%MT26458.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_675A +%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 +%MT26428.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_673c +%MT26448.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6750 +%MT26458.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_675A +%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 + +[MLX4BUS.DDInstall.ntamd64] +CopyFiles = MLX4BUS.CopyFiles +AddReg = MLX4BUS.SoftwareReg + +[MLX4BUS.DDInstall.ntia64] +CopyFiles = MLX4BUS.CopyFiles +AddReg = MLX4BUS.SoftwareReg + +[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%,0x00000001 +HKR,"Parameters","NumVlan",%REG_DWORD%,0x00000000 +HKR,"Parameters","UsePrio",%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" +MT25408.DeviceDesc="ConnectX (MT25408) - Mellanox ConnectX SDR Channel Adapter" +MT25418.DeviceDesc="ConnectX (MT25418) - Mellanox ConnectX DDR Channel Adapter" +MT25448.DeviceDesc="ConnectX (MT25448) - Mellanox ConnectX Ethernet Adapter" +MT25458.DeviceDesc="ConnectX (MT25458) - Mellanox ConnectX Ethernet Adapter" +MT26418.DeviceDesc="ConnectX (MT26418) - Mellanox ConnectX DDR PCI Gen2 Channel Adapter" +MT26428.DeviceDesc="ConnectX (MT26428) - Mellanox ConnectX QDR PCI Gen2 Channel Adapter" +MT26448.DeviceDesc="ConnectX (MT26448) - Mellanox ConnectX Ethernet PCI Gen2 Adapter" +MT26458.DeviceDesc="ConnectX (MT26458) - Mellanox ConnectX Ethernet PCI Gen2 Adapter" +MT00401.DeviceDesc="ConnectX (MT00401) - Mellanox ConnectX Channel 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-1/hw/mlx4/kernel/bus/drv/mlx4_bus32.cdf b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/mlx4_bus32.cdf new file mode 100644 index 00000000..2e0d1430 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/drv/pci.c b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/pci.c new file mode 100644 index 00000000..4fd5c8fb --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/pci.c @@ -0,0 +1,931 @@ + +#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 + ) +{ + ULONG len; + 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 */ + while ( !(addr & 0x8000) ) { + len = pBusIfc->GetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &addr, cap_offset+2, 2 ); + if ( len != 2 ) + goto err_read; + } + + /* 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; +} + + +#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-1/hw/mlx4/kernel/bus/drv/pdo.c b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/pdo.c new file mode 100644 index 00000000..2144404d --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/pdo.c @@ -0,0 +1,330 @@ +#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; + + // + // 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-1/hw/mlx4/kernel/bus/drv/precomp.h b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/precomp.h new file mode 100644 index 00000000..eefec294 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/precomp.h @@ -0,0 +1,15 @@ +#include +#include +#define NTSTRSAFE_LIB +#include +#include // required for GUID definitions +#include "public.h" +#include "l2w.h" +#include "ib\mlx4_ib.h" +#include "vip_dev.h" +#include "drv.h" +#include "driver.h" +#include "cmd.h" +#include + + diff --git a/branches/WOF2-1/hw/mlx4/kernel/bus/drv/sources b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/sources new file mode 100644 index 00000000..c8eb3b0a --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/sources @@ -0,0 +1,60 @@ +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 \ + +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-1/hw/mlx4/kernel/bus/drv/wmi.c b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/wmi.c new file mode 100644 index 00000000..6772be21 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/wmi.c @@ -0,0 +1,240 @@ +/*++ + +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; + PFDO_DEVICE_DATA deviceData; + NTSTATUS status; + DECLARE_CONST_UNICODE_STRING(busRsrcName, BUSRESOURCENAME); + + PAGED_CODE(); + + deviceData = FdoGetData(Device); + + // + // 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-1/hw/mlx4/kernel/bus/drv/wpptrace.h b/branches/WOF2-1/hw/mlx4/kernel/bus/drv/wpptrace.h new file mode 100644 index 00000000..bef591cb --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/ib/Kconfig b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/Kconfig new file mode 100644 index 00000000..4175a4bd --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/ib/Makefile.lnx b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/Makefile.lnx new file mode 100644 index 00000000..70f09c78 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/ib/SOURCES b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/SOURCES new file mode 100644 index 00000000..4a940f09 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/ib/ah.c b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/ah.c new file mode 100644 index 00000000..85a0da13 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/ah.c @@ -0,0 +1,139 @@ +/* + * 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" + +struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) +{ + struct mlx4_dev *dev = to_mdev(pd->device)->dev; + struct mlx4_ib_ah *ah; + + if (mlx4_is_barred(pd->device->dma_device)) + return ERR_PTR(-EFAULT); + + ah = kmalloc(sizeof *ah, GFP_ATOMIC); + if (!ah) + return ERR_PTR(-ENOMEM); + + memset(&ah->av, 0, sizeof ah->av); + + ah->av.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); + ah->av.g_slid = ah_attr->src_path_bits; + ah->av.dlid = cpu_to_be16(ah_attr->dlid); + if (ah_attr->static_rate) { + ah->av.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; + while (ah->av.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && + !(1 << ah->av.stat_rate & dev->caps.stat_rate_support)) + --ah->av.stat_rate; + } + ah->av.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); + if (ah_attr->ah_flags & IB_AH_GRH) { + ah->av.g_slid |= 0x80; + ah->av.gid_index = ah_attr->grh.sgid_index; + ah->av.hop_limit = ah_attr->grh.hop_limit; + ah->av.sl_tclass_flowlabel |= + cpu_to_be32((ah_attr->grh.traffic_class << 20) | + ah_attr->grh.flow_label); + memcpy(ah->av.dgid, ah_attr->grh.dgid.raw, 16); + } + + return &ah->ibah; +} + +int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) +{ + struct mlx4_ib_ah *ah = to_mah(ibah); + + if (mlx4_is_barred(ibah->device->dma_device)) + return -EFAULT; + + memset(ah_attr, 0, sizeof *ah_attr); + ah_attr->dlid = be16_to_cpu(ah->av.dlid); + ah_attr->sl = (u8)(be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28); + ah_attr->port_num = (u8)(be32_to_cpu(ah->av.port_pd) >> 24); + if (ah->av.stat_rate) + ah_attr->static_rate = ah->av.stat_rate - MLX4_STAT_RATE_OFFSET; + ah_attr->src_path_bits = ah->av.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.sl_tclass_flowlabel) >> 20); + ah_attr->grh.flow_label = + be32_to_cpu(ah->av.sl_tclass_flowlabel) & 0xfffff; + ah_attr->grh.hop_limit = ah->av.hop_limit; + ah_attr->grh.sgid_index = ah->av.gid_index; + memcpy(ah_attr->grh.dgid.raw, ah->av.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; + 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-1/hw/mlx4/kernel/bus/ib/cq.c b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/cq.c new file mode 100644 index 00000000..77f56d3f --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/cq.c @@ -0,0 +1,630 @@ +/* + * 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) + 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); + 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) + goto err_buf; + + err = mlx4_ib_umem_write_mtt(dev, &cq->buf.mtt, cq->umem); + if (err) + goto err_mtt; + + err = mlx4_ib_db_map_user(to_mucontext(context), ucmd.db_addr, + &cq->db); + if (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) + goto err_dbmap; + + uar = &to_mucontext(context)->uar; + } else { + err = mlx4_ib_db_alloc(dev, &cq->db, 1); + if (err) + goto err_cq; + + cq->mcq.set_ci_db = cq->db.db; + cq->mcq.arm_db = cq->db.db + 1; + *cq->mcq.set_ci_db = 0; + *cq->mcq.arm_db = 0; + + if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, &cq->buf.buf)) { + 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) + goto err_buf; + + err = mlx4_buf_write_mtt(dev->dev, &cq->buf.mtt, &cq->buf.buf); + if (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) + 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-1/hw/mlx4/kernel/bus/ib/doorbell.c b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/doorbell.c new file mode 100644 index 00000000..43f26219 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/ib/ib.def b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/ib.def new file mode 100644 index 00000000..a78e9d07 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/ib/ib.rc b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/ib.rc new file mode 100644 index 00000000..db7b710d --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/ib/mad.c b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/mad.c new file mode 100644 index 00000000..09f68691 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/ib/main.c b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/main.c new file mode 100644 index 00000000..a886302e --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/main.c @@ -0,0 +1,691 @@ +/* + * 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.reserved_qps_cnt[MLX4_QP_REGION_FW] - + dev->dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_EXCH]; + 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 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; + + 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; + + 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; + + 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; + +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.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-1/hw/mlx4/kernel/bus/ib/makefile b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/makefile new file mode 100644 index 00000000..d4938551 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/ib/mlx4_ib.h b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/mlx4_ib.h new file mode 100644 index 00000000..ef6999fb --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/mlx4_ib.h @@ -0,0 +1,331 @@ +/* + * 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" + +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; + struct mlx4_av av; +}; + +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); + +static inline int mlx4_ib_ah_grh_present(struct mlx4_ib_ah *ah) +{ + return !!(ah->av.g_slid & 0x80); +} + +#endif /* MLX4_IB_H */ diff --git a/branches/WOF2-1/hw/mlx4/kernel/bus/ib/mr.c b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/mr.c new file mode 100644 index 00000000..5b63f210 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/ib/qp.c b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/qp.c new file mode 100644 index 00000000..4198f477 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/qp.c @@ -0,0 +1,1879 @@ +/* + * 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" + +enum { + MLX4_IB_ACK_REQ_FREQ = 8, +}; + +enum { + MLX4_IB_DEFAULT_SCHED_QUEUE = 0x83, + MLX4_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f +}; + +enum { + /* + * Largest possible UD header: send with GRH and immediate data. + */ + MLX4_IB_UD_HEADER_SIZE = 72 +}; + +struct mlx4_ib_sqp { + struct mlx4_ib_qp qp; + int pkey_index; + u32 qkey; + u32 send_psn; + struct ib_ud_header ud_header; + u8 header_buf[MLX4_IB_UD_HEADER_SIZE]; +}; + +enum { + MLX4_IB_MIN_SQ_STRIDE = 6 +}; + +static const __be32 mlx4_ib_opcode[] = { + __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] */ +}; + +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) +{ + 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); + + 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; + } + return opcode; +} + +static int build_mlx_header(struct mlx4_ib_sqp *sqp, ib_send_wr_t *wr, + void *wqe) +{ + 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); + __be16 pkey; + int send_size; + int header_size; + int spc; + u32 i; + + send_size = 0; + for (i = 0; i < wr->num_ds; ++i) + send_size += wr->ds_array[i].length; + + ib_ud_header_init(send_size, mlx4_ib_ah_grh_present(ah), &sqp->ud_header); + + sqp->ud_header.lrh.service_level = + (u8)(be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28); + sqp->ud_header.lrh.destination_lid = ah->av.dlid; + sqp->ud_header.lrh.source_lid = cpu_to_be16(ah->av.g_slid & 0x7f); + if (mlx4_ib_ah_grh_present(ah)) { + sqp->ud_header.grh.traffic_class = + (u8)((be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20) & 0xff); + sqp->ud_header.grh.flow_label = + ah->av.sl_tclass_flowlabel & cpu_to_be32(0xfffff); + sqp->ud_header.grh.hop_limit = ah->av.hop_limit; + ib_get_cached_gid(ib_dev, (u8)(be32_to_cpu(ah->av.port_pd) >> 24), + ah->av.gid_index, &sqp->ud_header.grh.source_gid); + memcpy(sqp->ud_header.grh.destination_gid.raw, + ah->av.dgid, 16); + } + + mlx->flags &= cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE); + mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MLX4_WQE_MLX_VL15 : 0) | + (sqp->ud_header.lrh.destination_lid == + XIB_LID_PERMISSIVE ? MLX4_WQE_MLX_SLR : 0) | + (sqp->ud_header.lrh.service_level << 8)); + mlx->rlid = sqp->ud_header.lrh.destination_lid; + + switch (opcode) { + case IB_WR_SEND: + sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY; + sqp->ud_header.immediate_present = 0; + break; + case IB_WR_SEND_WITH_IMM: + sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; + sqp->ud_header.immediate_present = 1; + sqp->ud_header.immediate_data = wr->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(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); + sqp->ud_header.bth.pkey = pkey; + sqp->ud_header.bth.destination_qpn = wr->dgrm.ud.remote_qp; + sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1)); + sqp->ud_header.deth.qkey = wr->dgrm.ud.remote_qkey & 0x00000080 ? + cpu_to_be32(sqp->qkey) : wr->dgrm.ud.remote_qkey; + sqp->ud_header.deth.source_qpn = cpu_to_be32(sqp->qp.ibqp.qp_num); + + header_size = ib_ud_header_pack(&sqp->ud_header, sqp->header_buf); + +#if 0 + { + printk(KERN_ERR "built UD header of size %d:\n", header_size); + for (i = 0; i < header_size / 4; ++i) { + if (i % 8 == 0) + printk(" [%02x] ", i * 4); + printk(" %08x", + be32_to_cpu(((__be32 *) sqp->header_buf)[i])); + if ((i + 1) % 8 == 0) + printk("\n"); + } + printk("\n"); + } +#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; + } + + return ALIGN(i * sizeof (struct mlx4_wqe_inline_seg) + header_size, 16); +} + +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; +} + +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; + struct mlx4_ib_qp *qp = to_mqp(ibqp); + 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); + if (err < 0) { + if (bad_wr) + *bad_wr = wr; + goto out; + } + wqe += err; + size += err / 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); + + /* + * 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-1/hw/mlx4/kernel/bus/ib/srq.c b/branches/WOF2-1/hw/mlx4/kernel/bus/ib/srq.c new file mode 100644 index 00000000..9067e1fc --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/inc/bus_intf.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/bus_intf.h new file mode 100644 index 00000000..ef401d9d --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/bus_intf.h @@ -0,0 +1,193 @@ +#pragma once + +#define MLX4_BUS_IB_INTERFACE_VERSION 3 + +#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_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; + +}; + + +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-1/hw/mlx4/kernel/bus/inc/cmd.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/cmd.h new file mode 100644 index 00000000..28285277 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/cmd.h @@ -0,0 +1,188 @@ +/* + * 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, + + /* 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, +}; + +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-1/hw/mlx4/kernel/bus/inc/cq.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/cq.h new file mode 100644 index 00000000..93b56ea1 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/inc/device.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/device.h new file mode 100644 index 00000000..74ea047a --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/device.h @@ -0,0 +1,523 @@ +/* + * 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_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 */ +}; + +enum { + MLX4_NUM_FEXCH = 64 * 1024, +}; + + +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; + enum mlx4_port_type port_type[MLX4_MAX_PORTS + 1]; + int reserved_fexch_mpts_base; +}; + +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]; +}; + +#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-1/hw/mlx4/kernel/bus/inc/doorbell.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/doorbell.h new file mode 100644 index 00000000..0d694cbe --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/inc/driver.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/driver.h new file mode 100644 index 00000000..e7962b28 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/inc/eq.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/eq.h new file mode 100644 index 00000000..85c5e07f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/inc/ib_cache.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/ib_cache.h new file mode 100644 index 00000000..9dda15ad --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/inc/ib_mad.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/ib_mad.h new file mode 100644 index 00000000..e28a8f32 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/inc/ib_pack.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/ib_pack.h new file mode 100644 index 00000000..ac7283d5 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/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: 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_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_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, + 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); + +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-1/hw/mlx4/kernel/bus/inc/ib_smi.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/ib_smi.h new file mode 100644 index 00000000..1f80dab5 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/inc/ib_verbs.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/ib_verbs.h new file mode 100644 index 00000000..d4964e45 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/ib_verbs.h @@ -0,0 +1,1876 @@ +/* + * 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" + +enum rdma_node_type { + /* IB values map to NodeInfo:NodeType. */ + RDMA_NODE_IB_CA = 1, + RDMA_NODE_IB_SWITCH, + RDMA_NODE_IB_ROUTER, + RDMA_NODE_RNIC +}; + +enum rdma_transport_type { + RDMA_TRANSPORT_IB, + RDMA_TRANSPORT_IWARP +}; + +enum rdma_transport_type +rdma_node_get_transport(enum rdma_node_type node_type) __attribute_const__; + +enum 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 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 +}; + +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); + 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); + +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-1/hw/mlx4/kernel/bus/inc/ib_verbs_ex.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/ib_verbs_ex.h new file mode 100644 index 00000000..6ad4ad7e --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/inc/qp.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/qp.h new file mode 100644 index 00000000..4fbe077d --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/qp.h @@ -0,0 +1,309 @@ +/* + * 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[7]; +}; + +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; + __be32 reservd[2]; +}; + +#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-1/hw/mlx4/kernel/bus/inc/srq.h b/branches/WOF2-1/hw/mlx4/kernel/bus/inc/srq.h new file mode 100644 index 00000000..799a0697 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/net/Makefile.lnx b/branches/WOF2-1/hw/mlx4/kernel/bus/net/Makefile.lnx new file mode 100644 index 00000000..0952a652 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/net/SOURCES b/branches/WOF2-1/hw/mlx4/kernel/bus/net/SOURCES new file mode 100644 index 00000000..37441cf0 --- /dev/null +++ b/branches/WOF2-1/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;..\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-1/hw/mlx4/kernel/bus/net/alloc.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/alloc.c new file mode 100644 index 00000000..52d999fe --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/net/catas.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/catas.c new file mode 100644 index 00000000..2c287aa7 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/net/catas.c @@ -0,0 +1,401 @@ +/* + * 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); + + 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); + } + + dev->flags |= MLX4_FLAG_RESET_DRIVER; // bar the device + } + + dump_err_buf(dev); + 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_err(pdev->dev, "\n Performing HCA restart ... \n\n"); + err = mlx4_restart_one(pdev); + if (err || mlx4_is_livefish(pdev->dev)) { + mlx4_err(pdev->dev, "\n HCA restart failed ! \n\n"); + 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_err(pdev->dev, "\n HCA restart finished. Notifying the clients ... \n\n"); + } + + // 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-1/hw/mlx4/kernel/bus/net/cmd.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/cmd.c new file mode 100644 index 00000000..ff8f45e8 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/net/cmd.c @@ -0,0 +1,595 @@ +/* + * 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, + /* must be the last and have max value */ + CMD_STAT_SIZE = CMD_STAT_BAD_SIZE + 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; +}; + +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; + 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 status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); + + return (status & swab32(1 << HCR_GO_BIT)) || + (mlx4_priv(dev)->cmd.toggle == + !!(status & swab32(1 << HCR_T_BIT))); +} + +static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, + u32 in_modifier, u8 op_modifier, u16 op, u16 token, + int event) +{ + struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; + u32 __iomem *hcr = (u32 __iomem *)cmd->hcr; + int ret = -EAGAIN; + u64 end; + + mutex_lock(&cmd->hcr_mutex); + + end = jiffies; + if (event) + end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); + + while (cmd_pending(dev)) { + if (time_after_eq(jiffies, end)) + goto out; + cond_resched(); + } + + /* + * We use writel (instead of something like memcpy_toio) + * because writes of less than 32 bits to the HCR don't work + * (and some architectures such as ia64 implement memcpy_toio + * in terms of writeb). + */ + __raw_writel((__force u32) cpu_to_be32(in_param >> 32), hcr + 0); + __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), hcr + 1); + __raw_writel((__force u32) cpu_to_be32(in_modifier), hcr + 2); + __raw_writel((__force u32) cpu_to_be32(out_param >> 32), hcr + 3); + __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4); + __raw_writel((__force u32) cpu_to_be32(token << 16), hcr + 5); + + /* __raw_writel may not order writes. */ + wmb(); + + __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) | + (cmd->toggle << HCR_T_BIT) | + (event ? (1 << HCR_E_BIT) : 0) | + (op_modifier << HCR_OPMOD_SHIFT) | + op), hcr + 6); + + /* + * Make sure that our HCR writes don't get mixed in with + * writes from another CPU starting a FW command. + */ + mmiowb(); + + cmd->toggle = cmd->toggle ^ 1; + + ret = 0; + +out: + mutex_unlock(&cmd->hcr_mutex); + return ret; +} + +static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, + int out_is_imm, u32 in_modifier, u8 op_modifier, + u16 op, unsigned long timeout) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + u8 __iomem *hcr = priv->cmd.hcr; + int err = 0; + u64 end; + u8 status; + long do_reset; + + down(&priv->cmd.poll_sem); + + err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, + in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); + if (err) + goto out; + + end = msecs_to_jiffies(timeout) + jiffies; + while (cmd_pending(dev) && time_before(jiffies, end)) + cond_resched(); + + if (cmd_pending(dev)) { + err = -ETIMEDOUT; + + do_reset = InterlockedCompareExchange(&dev->reset_pending, 1, 0); + if (!do_reset) { + NTSTATUS status1; + status1 = mlx4_reset(dev); + if ( !NT_SUCCESS( status1 ) ) { + mlx4_err(dev, "Failed to reset HCA, aborting.(status %#x)\n", status1); + } + + 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); + if (status) + mlx4_err(dev, "Command failed: op %#hx, status %d, errno %d.\n", + op, status, err); + +out: + up(&priv->cmd.poll_sem); + return err; +} + +void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cmd_context *context = + &priv->cmd.context[token & priv->cmd.token_mask]; + + /* previously timed out command completing at long last */ + if (token != context->token) + return; + + context->result = mlx4_status_to_errno(status); + + if (status) + mlx4_err(dev, "Command failed: token %#hx, status %d, errno %d.\n", + token, status, context->result); + 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; + + 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); + + mlx4_cmd_post(dev, in_param, out_prm, + in_modifier, op_modifier, op, context->token, 1); + + 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, "Failed to reset HCA, aborting.(status %#x)\n", status); + } + + 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 comand \n"); + ASSERT(0); + } + } + else + err = context->result; + + 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); + +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-1/hw/mlx4/kernel/bus/net/cq.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/cq.c new file mode 100644 index 00000000..9bec57d8 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/net/eq.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/eq.c new file mode 100644 index 00000000..21658947 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/net/eq.c @@ -0,0 +1,989 @@ +/* + * 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 */ + 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(priv->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(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); + DbgPrint("Signaled to stop polling while in polling mode.\n"); + break; /* thread stopped */ + } + } + + if(priv->eq_table.bTerminated) break; + } + + DbgPrint("Polling thread terminated.\n"); + 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_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int ret = -ENOMEM; + + /* + * 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 64 bytes of context + * memory, or 1 KB total. + */ + priv->eq_table.icm_virt = icm_virt; + priv->eq_table.icm_page = alloc_page(dev->pdev, GFP_HIGHUSER); + if (!priv->eq_table.icm_page.da) + goto err_out; + + priv->eq_table.icm_dma = pci_map_page(dev->pdev, priv->eq_table.icm_page, 0, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(priv->eq_table.icm_dma)) + goto err_dma_map; + + ret = mlx4_MAP_ICM_page(dev, priv->eq_table.icm_dma.da, icm_virt); + if (ret) + goto err_icm_map; + mlx4_dbg(dev,"mlx4_MAP_ICM_page: dma %#I64x, icm_virt %#I64x\n", priv->eq_table.icm_dma.da, icm_virt); + + return 0; + +err_icm_map: + pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + +err_dma_map: + __free_page(dev->pdev, priv->eq_table.icm_page); + +err_out: + return ret; +} + +void mlx4_unmap_eq_icm(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + mlx4_UNMAP_ICM(dev, priv->eq_table.icm_virt, 1); + pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); + __free_page(dev->pdev, priv->eq_table.icm_page); +} + +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-1/hw/mlx4/kernel/bus/net/fw.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/fw.c new file mode 100644 index 00000000..5e8ad60f --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/net/fw.c @@ -0,0 +1,899 @@ +/* + * 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 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-1/hw/mlx4/kernel/bus/net/fw.h b/branches/WOF2-1/hw/mlx4/kernel/bus/net/fw.h new file mode 100644 index 00000000..f5113e6e --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/net/fw.h @@ -0,0 +1,172 @@ +/* + * 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_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-1/hw/mlx4/kernel/bus/net/icm.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/icm.c new file mode 100644 index 00000000..d0ba8930 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/net/icm.h b/branches/WOF2-1/hw/mlx4/kernel/bus/net/icm.h new file mode 100644 index 00000000..008138fb --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/net/intf.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/intf.c new file mode 100644 index 00000000..1a1b604a --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/net/main.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/main.c new file mode 100644 index 00000000..508336dd --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/net/main.c @@ -0,0 +1,1099 @@ +/* + * 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, ETH, HERMON), + HCA(MELLANOX, ETH_YATIR, HERMON), + HCA(MELLANOX, DDR_G2, HERMON), + HCA(MELLANOX, QDR_G2, HERMON), + HCA(MELLANOX, ETH_G2, HERMON), + HCA(MELLANOX, ETH_YATIR_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 < MLX4_MAX_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+1] == MLX4_PORT_TYPE_ETH) { + return TRUE; + } + return FALSE; +} + +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; + + 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 { + MLX4_PRINT_EV(TRACE_LEVEL_ERROR ,MLX4_DBG_DRV , + ("Requested port type %#x for port %d is " + "not supported by HW. Supported %#x\n", + port_type[i-1], i, (int)dev_cap->supported_port_types[i])); + MLX4_PRINT_EV(TRACE_LEVEL_ERROR ,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" + )); + + return -ENODEV; + } + 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; + } + + 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] = MLX4_NUM_FEXCH; + + 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_err(dev, "MAP_FA command failed, aborting.\n"); + goto err_free; + } + + err = mlx4_RUN_FW(dev); + if (err) { + mlx4_err(dev, "RUN_FW command failed, aborting.\n"); + goto err_unmap_fa; + } + + return 0; + +err_unmap_fa: + mlx4_UNMAP_FA(dev); + +err_free: + mlx4_free_icm(dev, priv->fw.fw_icm, 0); + return err; +} + +static int __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_map_eq_icm(dev, init_hca->eqc_base); + 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_unmap_eq_icm(dev); + +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.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_eq_icm(dev); + + 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) { + mlx4_err(dev, "QUERY_FW command failed, aborting.\n"); + return err; + } + + err = mlx4_load_fw(dev); + if (err) { + mlx4_err(dev, "Failed to start FW, aborting.\n"); + return err; + } + + err = mlx4_dev_cap(dev, &dev_cap); + if (err) { + mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n"); + goto err_stop_fw; + } + + process_mod_param_profile(); + profile = default_profile; + + 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"); + 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 i, n_cpus; + u64 cpus; + + /* calculate the number of processors */ + cpus = (u64)KeQueryActiveProcessors(); + for (i=0,n_cpus=0; i<(sizeof(KAFFINITY)<<3); i++) { + if ((1I64<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, Affinity %#I64x\n", + (dev->flags & MLX4_FLAG_MSI_X) ? "MSI-X" : "Legacy", + dev->pdev->n_msi_vectors_alloc, n_cpus, 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")); + pdev->dev = NULL; + kfree(priv); + } + else { + MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_LOW , + ("MLX4_BUS started in \"livefish\" mode !!!.\n")); + } + 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) + 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-1/hw/mlx4/kernel/bus/net/makefile b/branches/WOF2-1/hw/mlx4/kernel/bus/net/makefile new file mode 100644 index 00000000..d4938551 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/net/mcg.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/mcg.c new file mode 100644 index 00000000..2f46cd0f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/net/mlx4.h b/branches/WOF2-1/hw/mlx4/kernel/bus/net/mlx4.h new file mode 100644 index 00000000..d3f74cbd --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/net/mlx4.h @@ -0,0 +1,451 @@ +/* + * 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, +}; + +#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_enable_qos; + int mod_mlx4_blck_lb; + int mod_interrupt_from_first; + + int mod_affinity; + 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]; + u64 icm_virt; + dma_addr_t icm_page; + dma_addr_t icm_dma; + 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); +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_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt); +void mlx4_unmap_eq_icm(struct mlx4_dev *dev); + +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-1/hw/mlx4/kernel/bus/net/mr.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/mr.c new file mode 100644 index 00000000..1036e70d --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/net/mr.c @@ -0,0 +1,655 @@ +/* + * 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) + return -ENOMEM; + + for (i = 0; i < npages; ++i) + mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); + + dma_sync_single(&dev->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE); + + return 0; +} + +int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + int start_index, int npages, u64 *page_list) +{ + int chunk; + int err; + + if (mtt->order < 0) + return -EINVAL; + + while (npages > 0) { + chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages); + err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list); + if (err) + return err; + + npages -= chunk; + start_index += chunk; + page_list += chunk; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_write_mtt); + +int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + struct mlx4_buf *buf) +{ + u64 *page_list; + int err; + int i; + + page_list = kmalloc(buf->npages * sizeof *page_list, GFP_KERNEL); + if (!page_list) + return -ENOMEM; + + for (i = 0; i < buf->npages; ++i) + if (buf->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-1/hw/mlx4/kernel/bus/net/net.def b/branches/WOF2-1/hw/mlx4/kernel/bus/net/net.def new file mode 100644 index 00000000..71305a19 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/net/net.rc b/branches/WOF2-1/hw/mlx4/kernel/bus/net/net.rc new file mode 100644 index 00000000..61840a0b --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/net/pd.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/pd.c new file mode 100644 index 00000000..ed036c9d --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/bus/net/port.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/port.c new file mode 100644 index 00000000..12547084 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/net/port.c @@ -0,0 +1,293 @@ +/* + * 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" + + +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_MAC_NUM; i++) { + table->entries[i] = 0; + table->refs[i] = 0; + } + table->max = 1 << dev->caps.log_num_vlans; + table->total = 0; +} + +static int mlx4_SET_PORT_mac_table(struct mlx4_dev *dev, u8 port, + __be64 *entries) +{ + struct mlx4_cmd_mailbox *mailbox; + u32 in_mod; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); + + in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; + err = mlx4_cmd(dev, mailbox->dma.da, in_mod, 1, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) +{ + struct mlx4_mac_table *table = + &mlx4_priv(dev)->port[port - 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 - 1; i++) { + if (free < 0 && !table->refs[i]) { + free = i; + continue; + } + + if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { + /* Mac already registered, increase refernce count */ + *index = i; + ++table->refs[i]; + goto out; + } + } + mlx4_dbg(dev, "Free mac index is %d\n", free); + + if (table->total == table->max) { + /* No free mac entries */ + err = -ENOSPC; + goto out; + } + + /* Register new MAC */ + table->refs[free] = 1; + table->entries[free] = cpu_to_be64(mac | 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; +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) { + /* 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-1/hw/mlx4/kernel/bus/net/profile.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/profile.c new file mode 100644 index 00000000..a456da7d --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/net/profile.c @@ -0,0 +1,236 @@ +/* + * 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; + + 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; + profile[MLX4_RES_EQ].num = MLX4_NUM_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-1/hw/mlx4/kernel/bus/net/qp.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/qp.c new file mode 100644 index 00000000..9b5c52d4 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/bus/net/qp.c @@ -0,0 +1,416 @@ +/* + * 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; + + 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]]; + } + + } + + 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-1/hw/mlx4/kernel/bus/net/reset.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/reset.c new file mode 100644 index 00000000..e69de29b diff --git a/branches/WOF2-1/hw/mlx4/kernel/bus/net/srq.c b/branches/WOF2-1/hw/mlx4/kernel/bus/net/srq.c new file mode 100644 index 00000000..1d2d1003 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/dirs b/branches/WOF2-1/hw/mlx4/kernel/dirs new file mode 100644 index 00000000..4f2a471f --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/dirs @@ -0,0 +1,3 @@ +DIRS=\ + hca \ + bus diff --git a/branches/WOF2-1/hw/mlx4/kernel/hca/Makefile b/branches/WOF2-1/hw/mlx4/kernel/hca/Makefile new file mode 100644 index 00000000..ddc9da43 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/SOURCES b/branches/WOF2-1/hw/mlx4/kernel/hca/SOURCES new file mode 100644 index 00000000..f497a488 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/av.c b/branches/WOF2-1/hw/mlx4/kernel/hca/av.c new file mode 100644 index 00000000..ccd8393f --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/hca/av.c @@ -0,0 +1,233 @@ +/* + * 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); + 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-1/hw/mlx4/kernel/hca/ca.c b/branches/WOF2-1/hw/mlx4/kernel/hca/ca.c new file mode 100644 index 00000000..6a3352f8 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/cq.c b/branches/WOF2-1/hw/mlx4/kernel/hca/cq.c new file mode 100644 index 00000000..dbd8cfa4 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/data.c b/branches/WOF2-1/hw/mlx4/kernel/hca/data.c new file mode 100644 index 00000000..23f42800 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/hca/data.c @@ -0,0 +1,1006 @@ +/* + * 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->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->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; +} + +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 = 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 + } + 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 = 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; + } + } + 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-1/hw/mlx4/kernel/hca/data.h b/branches/WOF2-1/hw/mlx4/kernel/hca/data.h new file mode 100644 index 00000000..f02b1787 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/debug.h b/branches/WOF2-1/hw/mlx4/kernel/hca/debug.h new file mode 100644 index 00000000..a8107981 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/direct.c b/branches/WOF2-1/hw/mlx4/kernel/hca/direct.c new file mode 100644 index 00000000..3ac85e58 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/drv.c b/branches/WOF2-1/hw/mlx4/kernel/hca/drv.c new file mode 100644 index 00000000..a8be1767 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/hca/drv.c @@ -0,0 +1,1992 @@ +/* + * 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 + +// +// TODO: add support for Hibernate/Standby as in WDM version below +// + + + +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( PagedPool, 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 + ) +{ + UNUSED_PARAM(Device); + UNUSED_PARAM(PreviousState); + HCA_ENTER( HCA_DBG_PNP ); + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, ("EvtDeviceD0Entry: PreviousState 0x%x\n", PreviousState)); + 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 WdfPowerDevicePrepareForHibernation: + if (atomic_read(&p_fdo->usecnt)) { + status = STATUS_UNSUCCESSFUL; + break; + } + /* Fall through. */ + default: + status = STATUS_SUCCESS; + break; + } + + 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 */ + 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( PagedPool, + 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 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-1/hw/mlx4/kernel/hca/drv.h b/branches/WOF2-1/hw/mlx4/kernel/hca/drv.h new file mode 100644 index 00000000..732d9fd7 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/fw.c b/branches/WOF2-1/hw/mlx4/kernel/hca/fw.c new file mode 100644 index 00000000..678bb5b6 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/hca.mof b/branches/WOF2-1/hw/mlx4/kernel/hca/hca.mof new file mode 100644 index 00000000..665df469 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/hca.rc b/branches/WOF2-1/hw/mlx4/kernel/hca/hca.rc new file mode 100644 index 00000000..80d226e6 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/hverbs.c b/branches/WOF2-1/hw/mlx4/kernel/hca/hverbs.c new file mode 100644 index 00000000..4fcf5b14 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/hverbs.h b/branches/WOF2-1/hw/mlx4/kernel/hca/hverbs.h new file mode 100644 index 00000000..d160159c --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/makefile.inc b/branches/WOF2-1/hw/mlx4/kernel/hca/makefile.inc new file mode 100644 index 00000000..bdf9eb23 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/mcast.c b/branches/WOF2-1/hw/mlx4/kernel/hca/mcast.c new file mode 100644 index 00000000..7ae1f8ad --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/mlx4_hca.cdf b/branches/WOF2-1/hw/mlx4/kernel/hca/mlx4_hca.cdf new file mode 100644 index 00000000..fe3beb7c --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/mlx4_hca.inx b/branches/WOF2-1/hw/mlx4/kernel/hca/mlx4_hca.inx new file mode 100644 index 00000000..6db18532 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/mlx4_hca32.cdf b/branches/WOF2-1/hw/mlx4/kernel/hca/mlx4_hca32.cdf new file mode 100644 index 00000000..bf027678 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/mr.c b/branches/WOF2-1/hw/mlx4/kernel/hca/mr.c new file mode 100644 index 00000000..b23b0392 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/pd.c b/branches/WOF2-1/hw/mlx4/kernel/hca/pd.c new file mode 100644 index 00000000..38d01a36 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/precomp.h b/branches/WOF2-1/hw/mlx4/kernel/hca/precomp.h new file mode 100644 index 00000000..1d316185 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/qp.c b/branches/WOF2-1/hw/mlx4/kernel/hca/qp.c new file mode 100644 index 00000000..5da9c0e7 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/srq.c b/branches/WOF2-1/hw/mlx4/kernel/hca/srq.c new file mode 100644 index 00000000..971b8358 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/vp.c b/branches/WOF2-1/hw/mlx4/kernel/hca/vp.c new file mode 100644 index 00000000..646d01f2 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/hca/wmi.c b/branches/WOF2-1/hw/mlx4/kernel/hca/wmi.c new file mode 100644 index 00000000..3a95832a --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/hca/wmi.c @@ -0,0 +1,257 @@ +/* + * 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; + PFDO_DEVICE_DATA deviceData; + NTSTATUS status; + DECLARE_CONST_UNICODE_STRING(hcaRsrcName, HCARESOURCENAME); + + PAGED_CODE(); + + deviceData = FdoGetData(Device); + + // + // 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-1/hw/mlx4/kernel/inc/iobuf.h b/branches/WOF2-1/hw/mlx4/kernel/inc/iobuf.h new file mode 100644 index 00000000..44002497 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/l2w.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w.h new file mode 100644 index 00000000..57f8b347 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w.h @@ -0,0 +1,350 @@ +#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 + +//////////////////////////////////////////////////////// +// +// 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 */ +}; + +// 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; + DMA_ADAPTER * p_dma_adapter; /* HCA adapter object */ + DEVICE_OBJECT * p_self_do; /* mlx4_bus's FDO */ + DEVICE_OBJECT * pdo; /* mlx4_bus's PDO */ + // 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 +}; + +/* 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-1/hw/mlx4/kernel/inc/l2w_atomic.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_atomic.h new file mode 100644 index 00000000..51bd7779 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/l2w_bit.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_bit.h new file mode 100644 index 00000000..3641c516 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/l2w_bitmap.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_bitmap.h new file mode 100644 index 00000000..85ba3608 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/l2w_debug.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_debug.h new file mode 100644 index 00000000..022f28ae --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_debug.h @@ -0,0 +1,45 @@ +#pragma once + +VOID +WriteEventLogEntryStr( + PVOID pi_pIoObject, + ULONG pi_ErrorCode, + ULONG pi_UniqueErrorCode, + ULONG pi_FinalStatus, + PWCHAR pi_InsertionStr, + 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-1/hw/mlx4/kernel/inc/l2w_list.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_list.h new file mode 100644 index 00000000..1779a191 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/l2w_memory.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_memory.h new file mode 100644 index 00000000..b10242cb --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/l2w_pci.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_pci.h new file mode 100644 index 00000000..0a42ee55 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_pci.h @@ -0,0 +1,112 @@ +#pragma once + +// =========================================== +// LITERALS +// =========================================== + +#define DEVID_HERMON_SDR 0x6340 /* 25408 */ +#define DEVID_HERMON_DDR 0x634a /* 25418 */ +#define DEVID_HERMON_ETH 0x6368 /* 25448 */ +#define DEVID_HERMON_ETH_YATIR 0x6372 /* 25458 */ +#define DEVID_HERMON_DDR_G2 0x6732 /* 26418 */ +#define DEVID_HERMON_QDR_G2 0x673c /* 26428 */ +#define DEVID_HERMON_ETH_G2 0x6750 /* 26448 */ +#define DEVID_HERMON_ETH_YATIR_G2 0x675A /* 26458 */ +/* 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-1/hw/mlx4/kernel/inc/l2w_pcipool.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_pcipool.h new file mode 100644 index 00000000..fd17b8fb --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/l2w_radix.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_radix.h new file mode 100644 index 00000000..b12c2d78 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/l2w_spinlock.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_spinlock.h new file mode 100644 index 00000000..9e8cb07a --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/l2w_sync.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_sync.h new file mode 100644 index 00000000..779af46b --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/l2w_time.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_time.h new file mode 100644 index 00000000..672b9547 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/l2w_umem.h b/branches/WOF2-1/hw/mlx4/kernel/inc/l2w_umem.h new file mode 100644 index 00000000..682dcfdd --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/mlx4_debug.h b/branches/WOF2-1/hw/mlx4/kernel/inc/mlx4_debug.h new file mode 100644 index 00000000..051a590c --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/shutter.h b/branches/WOF2-1/hw/mlx4/kernel/inc/shutter.h new file mode 100644 index 00000000..fcecb3dc --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/kernel/inc/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; + ASSERT(p_shutter->cnt == -MAX_OPERATIONS); + // Mark the counter as locked + res = InterlockedExchangeAdd(&p_shutter->cnt, MAX_OPERATIONS); + ASSERT(res < 0); +} + + diff --git a/branches/WOF2-1/hw/mlx4/kernel/inc/vc.h b/branches/WOF2-1/hw/mlx4/kernel/inc/vc.h new file mode 100644 index 00000000..bc90e926 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel/inc/vip_dev.h b/branches/WOF2-1/hw/mlx4/kernel/inc/vip_dev.h new file mode 100644 index 00000000..08041f82 --- /dev/null +++ b/branches/WOF2-1/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 uar_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-1/hw/mlx4/kernel_patches/core_0020_csum.patch b/branches/WOF2-1/hw/mlx4/kernel_patches/core_0020_csum.patch new file mode 100644 index 00000000..9b21e568 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel_patches/core_0025_qp_create_flags.patch b/branches/WOF2-1/hw/mlx4/kernel_patches/core_0025_qp_create_flags.patch new file mode 100644 index 00000000..d5fff8ba --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel_patches/core_0030_lso.patch b/branches/WOF2-1/hw/mlx4/kernel_patches/core_0030_lso.patch new file mode 100644 index 00000000..16a8e08c --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel_patches/mlx4_0010_add_wc.patch b/branches/WOF2-1/hw/mlx4/kernel_patches/mlx4_0010_add_wc.patch new file mode 100644 index 00000000..767bb269 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel_patches/mlx4_0030_checksum_offload.patch b/branches/WOF2-1/hw/mlx4/kernel_patches/mlx4_0030_checksum_offload.patch new file mode 100644 index 00000000..2df85b1d --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel_patches/mlx4_0045_qp_flags.patch b/branches/WOF2-1/hw/mlx4/kernel_patches/mlx4_0045_qp_flags.patch new file mode 100644 index 00000000..835b2911 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel_patches/mlx4_0050_lso.patch b/branches/WOF2-1/hw/mlx4/kernel_patches/mlx4_0050_lso.patch new file mode 100644 index 00000000..f84b686d --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/kernel_patches/mlx4_0170_shrinking_wqe.patch b/branches/WOF2-1/hw/mlx4/kernel_patches/mlx4_0170_shrinking_wqe.patch new file mode 100644 index 00000000..588881bb --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/todo.txt b/branches/WOF2-1/hw/mlx4/todo.txt new file mode 100644 index 00000000..96870109 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/dirs b/branches/WOF2-1/hw/mlx4/user/dirs new file mode 100644 index 00000000..f1a57f04 --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/user/dirs @@ -0,0 +1,2 @@ +DIRS=\ + hca diff --git a/branches/WOF2-1/hw/mlx4/user/hca/Makefile b/branches/WOF2-1/hw/mlx4/user/hca/Makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/SOURCES b/branches/WOF2-1/hw/mlx4/user/hca/SOURCES new file mode 100644 index 00000000..5e71b11e --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/buf.c b/branches/WOF2-1/hw/mlx4/user/hca/buf.c new file mode 100644 index 00000000..0f01bd91 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/cq.c b/branches/WOF2-1/hw/mlx4/user/hca/cq.c new file mode 100644 index 00000000..a224ebb8 --- /dev/null +++ b/branches/WOF2-1/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), htonl(cqe->wqe_index), + cqe->vendor_err, + cqe->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK); + + switch (cqe->syndrome) { + case MLX4_CQE_SYNDROME_LOCAL_LENGTH_ERR: + wc->status = 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-1/hw/mlx4/user/hca/dbrec.c b/branches/WOF2-1/hw/mlx4/user/hca/dbrec.c new file mode 100644 index 00000000..d4ba0659 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/doorbell.h b/branches/WOF2-1/hw/mlx4/user/hca/doorbell.h new file mode 100644 index 00000000..ff0c1965 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/l2w.h b/branches/WOF2-1/hw/mlx4/user/hca/l2w.h new file mode 100644 index 00000000..b2fff316 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/mlx4.c b/branches/WOF2-1/hw/mlx4/user/hca/mlx4.c new file mode 100644 index 00000000..7166316d --- /dev/null +++ b/branches/WOF2-1/hw/mlx4/user/hca/mlx4.c @@ -0,0 +1,325 @@ +/* + * 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, 0x673c), /* MT26428 "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, 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-1/hw/mlx4/user/hca/mlx4.def b/branches/WOF2-1/hw/mlx4/user/hca/mlx4.def new file mode 100644 index 00000000..07e29ca4 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/mlx4.h b/branches/WOF2-1/hw/mlx4/user/hca/mlx4.h new file mode 100644 index 00000000..e7f70bb7 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/mlx4_debug.c b/branches/WOF2-1/hw/mlx4/user/hca/mlx4_debug.c new file mode 100644 index 00000000..38c8a37f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/mlx4_debug.h b/branches/WOF2-1/hw/mlx4/user/hca/mlx4_debug.h new file mode 100644 index 00000000..0c4ec5a4 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/mlx4u.rc b/branches/WOF2-1/hw/mlx4/user/hca/mlx4u.rc new file mode 100644 index 00000000..158a0096 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/qp.c b/branches/WOF2-1/hw/mlx4/user/hca/qp.c new file mode 100644 index 00000000..12c1ff9f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/srq.c b/branches/WOF2-1/hw/mlx4/user/hca/srq.c new file mode 100644 index 00000000..c5e9ac89 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/verbs.c b/branches/WOF2-1/hw/mlx4/user/hca/verbs.c new file mode 100644 index 00000000..a39de5a6 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/verbs.h b/branches/WOF2-1/hw/mlx4/user/hca/verbs.h new file mode 100644 index 00000000..9f7f2c14 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mlx4/user/hca/wqe.h b/branches/WOF2-1/hw/mlx4/user/hca/wqe.h new file mode 100644 index 00000000..fa2f8ac6 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/dirs b/branches/WOF2-1/hw/mthca/dirs new file mode 100644 index 00000000..aa698135 --- /dev/null +++ b/branches/WOF2-1/hw/mthca/dirs @@ -0,0 +1,3 @@ +DIRS=\ + kernel \ + user diff --git a/branches/WOF2-1/hw/mthca/hca_utils.c b/branches/WOF2-1/hw/mthca/hca_utils.c new file mode 100644 index 00000000..a86b5ab5 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/hca_utils.h b/branches/WOF2-1/hw/mthca/hca_utils.h new file mode 100644 index 00000000..9b8a5683 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/Makefile b/branches/WOF2-1/hw/mthca/kernel/Makefile new file mode 100644 index 00000000..1c8f2940 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/SOURCES b/branches/WOF2-1/hw/mthca/kernel/SOURCES new file mode 100644 index 00000000..269da791 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/hca.rc b/branches/WOF2-1/hw/mthca/kernel/hca.rc new file mode 100644 index 00000000..2780199f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/hca_data.c b/branches/WOF2-1/hw/mthca/kernel/hca_data.c new file mode 100644 index 00000000..92a39187 --- /dev/null +++ b/branches/WOF2-1/hw/mthca/kernel/hca_data.c @@ -0,0 +1,964 @@ +/* + * 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->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; +} + +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 = 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 = 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-1/hw/mthca/kernel/hca_data.h b/branches/WOF2-1/hw/mthca/kernel/hca_data.h new file mode 100644 index 00000000..57d4c513 --- /dev/null +++ b/branches/WOF2-1/hw/mthca/kernel/hca_data.h @@ -0,0 +1,395 @@ +/* + * 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, + 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 ); + +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_memory_if_livefish( + 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-1/hw/mthca/kernel/hca_debug.h b/branches/WOF2-1/hw/mthca/kernel/hca_debug.h new file mode 100644 index 00000000..62a016cd --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/hca_direct.c b/branches/WOF2-1/hw/mthca/kernel/hca_direct.c new file mode 100644 index 00000000..27e044ee --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/hca_driver.c b/branches/WOF2-1/hw/mthca/kernel/hca_driver.c new file mode 100644 index 00000000..e7dd5eb0 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/hca_driver.h b/branches/WOF2-1/hw/mthca/kernel/hca_driver.h new file mode 100644 index 00000000..23106121 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/hca_mcast.c b/branches/WOF2-1/hw/mthca/kernel/hca_mcast.c new file mode 100644 index 00000000..14ce52dd --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/hca_memory.c b/branches/WOF2-1/hw/mthca/kernel/hca_memory.c new file mode 100644 index 00000000..4c817da8 --- /dev/null +++ b/branches/WOF2-1/hw/mthca/kernel/hca_memory.c @@ -0,0 +1,601 @@ +/* + * 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); + + if (mthca_is_livefish(to_mdev(ib_pd_p->device))) { + mr_p = kzalloc(sizeof *mr_p, GFP_KERNEL); + if (!mr_p) { + status = IB_INSUFFICIENT_MEMORY; + goto err_mem; + } + mr_p->device = ib_pd_p->device; + mr_p->pd = ib_pd_p; + 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) + { + 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 +done: + 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: +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 ) +{ + 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; + struct ib_mr *ib_mr = (struct ib_mr *)h_mr; + + HCA_ENTER(HCA_DBG_SHIM); + + if (mthca_is_livefish(to_mdev(ib_mr->device))) { + kfree(ib_mr); + goto done; + } + + // 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; + } + +done: + 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; +} + +void +mlnx_memory_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-1/hw/mthca/kernel/hca_pci.c b/branches/WOF2-1/hw/mthca/kernel/hca_pci.c new file mode 100644 index 00000000..806490d9 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/hca_pci.h b/branches/WOF2-1/hw/mthca/kernel/hca_pci.h new file mode 100644 index 00000000..dd8e9c0e --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/hca_pnp.c b/branches/WOF2-1/hw/mthca/kernel/hca_pnp.c new file mode 100644 index 00000000..b1d810de --- /dev/null +++ b/branches/WOF2-1/hw/mthca/kernel/hca_pnp.c @@ -0,0 +1,1386 @@ +/* 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( PagedPool, + 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, + !!mthca_is_livefish(p_ext->hca.mdev), + 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 ); + + // there will be no resources for "livefish" (PCI memory controller mode) + if (!pHcaResList || !pHostResList) + goto done; + + 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; + } + +done: + 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 int mthca_get_livefish_info(struct mthca_dev *mdev, __be64 *node_guid, u32 *hw_id) +{ + *node_guid = cl_hton64((uint64_t)(ULONG_PTR)mdev); + mdev->ib_dev.node_guid = *node_guid; + *hw_id = 0; + return 0; +} + +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; + + 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; + } + + /*leo: get node GUID */ + { + int err; + if (mthca_is_livefish(p_ext->hca.mdev)) + err = mthca_get_livefish_info( p_ext->hca.mdev, &p_ext->hca.guid, &p_ext->hca.hw_ver ); + else + 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%s\n", + (mdev->mthca_flags & MTHCA_FLAG_LIVEFISH) ? "Flash Recovery Mode:" : "", + (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 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-1/hw/mthca/kernel/hca_pnp.h b/branches/WOF2-1/hw/mthca/kernel/hca_pnp.h new file mode 100644 index 00000000..bc74c8e1 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/hca_verbs.c b/branches/WOF2-1/hw/mthca/kernel/hca_verbs.c new file mode 100644 index 00000000..68fd2635 --- /dev/null +++ b/branches/WOF2-1/hw/mthca/kernel/hca_verbs.c @@ -0,0 +1,1720 @@ +/* + * 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; + + if (mthca_is_livefish(p_hca->mdev)) + goto done; + + 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 +done: + 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) +{ + mlnx_hob_t *hob_p = (mlnx_hob_t *)h_ca; + HCA_ENTER(HCA_DBG_SHIM); + + if (mthca_is_livefish(MDEV_FROM_HOB( hob_p ))) + goto done; + + mlnx_hobs_remove(h_ca); + +done: + 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 ); + + if (mthca_is_livefish(to_mdev(p_ucontext->device))) + goto done; + unmap_crspace_for_all(p_ucontext); +done: + 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 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. */ + p_interface->open_ca = mlnx_open_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; + + if (is_livefish) { + mlnx_memory_if_livefish(p_interface); + } + else { + p_interface->modify_ca = mlnx_modify_ca; + + 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-1/hw/mthca/kernel/ib_cache.h b/branches/WOF2-1/hw/mthca/kernel/ib_cache.h new file mode 100644 index 00000000..a1105b8f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/ib_mad.h b/branches/WOF2-1/hw/mthca/kernel/ib_mad.h new file mode 100644 index 00000000..e8a80806 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/ib_pack.h b/branches/WOF2-1/hw/mthca/kernel/ib_pack.h new file mode 100644 index 00000000..deb42e6c --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/ib_smi.h b/branches/WOF2-1/hw/mthca/kernel/ib_smi.h new file mode 100644 index 00000000..8cfe1a2a --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/ib_verbs.h b/branches/WOF2-1/hw/mthca/kernel/ib_verbs.h new file mode 100644 index 00000000..35125ec5 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/makefile.inc b/branches/WOF2-1/hw/mthca/kernel/makefile.inc new file mode 100644 index 00000000..3f3c0013 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_atomic.h b/branches/WOF2-1/hw/mthca/kernel/mt_atomic.h new file mode 100644 index 00000000..c86198cb --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_bitmap.h b/branches/WOF2-1/hw/mthca/kernel/mt_bitmap.h new file mode 100644 index 00000000..85e3a788 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_cache.c b/branches/WOF2-1/hw/mthca/kernel/mt_cache.c new file mode 100644 index 00000000..07e046ec --- /dev/null +++ b/branches/WOF2-1/hw/mthca/kernel/mt_cache.c @@ -0,0 +1,402 @@ +/* + * 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) +{ + struct ib_gid_cache *cache; + int ret = 0; + 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) + ret = -EINVAL; + else + *gid = cache->table[index]; + + read_unlock_irqrestore(&lh); + + return ret; +} + +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; + int ret = -ENOENT; + SPIN_LOCK_PREP(lh); + + *port_num = (u8)-1; + if (index) + *index = (u16)-1; + + 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)) { + *port_num = p + start_port(device); + if (index) + *index = (u16)i; + ret = 0; + goto found; + } + } + } +found: + read_unlock_irqrestore(&lh); + + return ret; +} + +int ib_get_cached_pkey(struct ib_device *device, + u8 port_num, + int index, + __be16 *pkey) +{ + struct ib_pkey_cache *cache; + int ret = 0; + 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) + ret = -EINVAL; + else + *pkey = cache->table[index]; + + read_unlock_irqrestore(&lh); + + return ret; +} + +int ib_find_cached_pkey(struct ib_device *device, + u8 port_num, + __be16 pkey, + u16 *index) +{ + struct ib_pkey_cache *cache; + int i; + int ret = -ENOENT; + 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)]; + + *index = (u16)-1; + + for (i = 0; i < cache->table_len; ++i) + if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) { + *index = (u16)i; + ret = 0; + break; + } + + read_unlock_irqrestore(&lh); + + return ret; +} + +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-1/hw/mthca/kernel/mt_device.c b/branches/WOF2-1/hw/mthca/kernel/mt_device.c new file mode 100644 index 00000000..883c9868 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_l2w.c b/branches/WOF2-1/hw/mthca/kernel/mt_l2w.c new file mode 100644 index 00000000..0979a74c --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_l2w.h b/branches/WOF2-1/hw/mthca/kernel/mt_l2w.h new file mode 100644 index 00000000..faf34055 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_list.h b/branches/WOF2-1/hw/mthca/kernel/mt_list.h new file mode 100644 index 00000000..092057ee --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_memory.c b/branches/WOF2-1/hw/mthca/kernel/mt_memory.c new file mode 100644 index 00000000..5a8bd1ca --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_memory.h b/branches/WOF2-1/hw/mthca/kernel/mt_memory.h new file mode 100644 index 00000000..fdfcbea7 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_pa_cash.c b/branches/WOF2-1/hw/mthca/kernel/mt_pa_cash.c new file mode 100644 index 00000000..7ff2baf6 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_pa_cash.h b/branches/WOF2-1/hw/mthca/kernel/mt_pa_cash.h new file mode 100644 index 00000000..4ca6eb57 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_packer.c b/branches/WOF2-1/hw/mthca/kernel/mt_packer.c new file mode 100644 index 00000000..a61cece8 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_pci.h b/branches/WOF2-1/hw/mthca/kernel/mt_pci.h new file mode 100644 index 00000000..3f389ca9 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_pcipool.h b/branches/WOF2-1/hw/mthca/kernel/mt_pcipool.h new file mode 100644 index 00000000..996cb11d --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_reset_tavor.c b/branches/WOF2-1/hw/mthca/kernel/mt_reset_tavor.c new file mode 100644 index 00000000..399c2f16 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_spinlock.h b/branches/WOF2-1/hw/mthca/kernel/mt_spinlock.h new file mode 100644 index 00000000..57f3ea5a --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_sync.h b/branches/WOF2-1/hw/mthca/kernel/mt_sync.h new file mode 100644 index 00000000..90d3f38c --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_types.h b/branches/WOF2-1/hw/mthca/kernel/mt_types.h new file mode 100644 index 00000000..ec8f70e7 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_ud_header.c b/branches/WOF2-1/hw/mthca/kernel/mt_ud_header.c new file mode 100644 index 00000000..e649c53a --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_uverbs.c b/branches/WOF2-1/hw/mthca/kernel/mt_uverbs.c new file mode 100644 index 00000000..0e4e5674 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mt_verbs.c b/branches/WOF2-1/hw/mthca/kernel/mt_verbs.c new file mode 100644 index 00000000..38e8a4fa --- /dev/null +++ b/branches/WOF2-1/hw/mthca/kernel/mt_verbs.c @@ -0,0 +1,933 @@ +/* + * 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) +{ + if (mthca_is_livefish(to_mdev(pd->device))) + goto done; + + // 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; + } + +done: + 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-1/hw/mthca/kernel/mthca.cdf b/branches/WOF2-1/hw/mthca/kernel/mthca.cdf new file mode 100644 index 00000000..7a865639 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca.h b/branches/WOF2-1/hw/mthca/kernel/mthca.h new file mode 100644 index 00000000..9570421a --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca.inx b/branches/WOF2-1/hw/mthca/kernel/mthca.inx new file mode 100644 index 00000000..ce14a7d0 --- /dev/null +++ b/branches/WOF2-1/hw/mthca/kernel/mthca.inx @@ -0,0 +1,479 @@ +; 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 +%MT23109.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5A45 +%MT25208.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6278 +%MT25209.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6279 +%MT25218.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6282 +%MT24204.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5E8C +%MT24205.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5E8D +%MT25204.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6274 +%MT25205.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6275 + +[HCA.DeviceSection.ntamd64] +%MT23108.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5A44 +%MT23109.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5A45 +%MT25208.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6278 +%MT25209.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6279 +%MT25218.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6282 +%MT24204.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5E8C +%MT24205.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5E8D +%MT25204.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6274 +%MT25205.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6275 + +[HCA.DeviceSection.ntia64] +%MT23108.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5A44 +%MT23109.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5A45 +%MT25208.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6278 +%MT25209.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6279 +%MT25218.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6282 +%MT24204.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5E8C +%MT24205.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5E8D +%MT25204.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6274 +%MT25205.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6275 + +[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" +MT23109.DeviceDesc="InfiniHost (MT23109) - Mellanox InfiniBand HCA (burner device)" +MT25208.DeviceDesc="InfiniHost (MT25208) - Mellanox InfiniBand HCA for PCI Express" +MT25209.DeviceDesc="InfiniHost (MT25209) - Mellanox InfiniBand HCA for PCI Express (burner device)" +MT25218.DeviceDesc="InfiniHost III Ex (MT25218) - Mellanox InfiniBand HCA for PCI Express" +MT24204.DeviceDesc="InfiniHost III Lx (MT24204) - Mellanox InfiniBand HCA for PCI Express" +MT24205.DeviceDesc="InfiniHost III Lx (MT24205) - Mellanox InfiniBand HCA for PCI Express (burner device)" +MT25204.DeviceDesc="InfiniHost III Lx (MT25204) - Mellanox InfiniBand HCA for PCI Express" +MT25205.DeviceDesc="InfiniHost III Lx (MT25205) - Mellanox InfiniBand HCA for PCI Express (burner device)" +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-1/hw/mthca/kernel/mthca32.cdf b/branches/WOF2-1/hw/mthca/kernel/mthca32.cdf new file mode 100644 index 00000000..4fc455ea --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_allocator.c b/branches/WOF2-1/hw/mthca/kernel/mthca_allocator.c new file mode 100644 index 00000000..28dd974f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_av.c b/branches/WOF2-1/hw/mthca/kernel/mthca_av.c new file mode 100644 index 00000000..9d266fee --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_catas.c b/branches/WOF2-1/hw/mthca/kernel/mthca_catas.c new file mode 100644 index 00000000..0c91518f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_cmd.c b/branches/WOF2-1/hw/mthca/kernel/mthca_cmd.c new file mode 100644 index 00000000..e3483f7c --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_cmd.h b/branches/WOF2-1/hw/mthca/kernel/mthca_cmd.h new file mode 100644 index 00000000..f5bda231 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_config_reg.h b/branches/WOF2-1/hw/mthca/kernel/mthca_config_reg.h new file mode 100644 index 00000000..9ff4a97a --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_cq.c b/branches/WOF2-1/hw/mthca/kernel/mthca_cq.c new file mode 100644 index 00000000..ff9be740 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_dev.h b/branches/WOF2-1/hw/mthca/kernel/mthca_dev.h new file mode 100644 index 00000000..ad31d151 --- /dev/null +++ b/branches/WOF2-1/hw/mthca/kernel/mthca_dev.h @@ -0,0 +1,618 @@ +/* + * 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, + MTHCA_FLAG_LIVEFISH = 1 << 10 +}; + +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, + ... + ); + + +static inline int mthca_is_livefish(struct mthca_dev *mdev) +{ + if(mdev == NULL) { + return TRUE; + } + return mdev->mthca_flags & MTHCA_FLAG_LIVEFISH; +} + +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-1/hw/mthca/kernel/mthca_doorbell.h b/branches/WOF2-1/hw/mthca/kernel/mthca_doorbell.h new file mode 100644 index 00000000..92cfb3fd --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_eq.c b/branches/WOF2-1/hw/mthca/kernel/mthca_eq.c new file mode 100644 index 00000000..9c47e824 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_log.c b/branches/WOF2-1/hw/mthca/kernel/mthca_log.c new file mode 100644 index 00000000..07bfb6c8 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_log.mc b/branches/WOF2-1/hw/mthca/kernel/mthca_log.mc new file mode 100644 index 00000000..08cbddae --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_mad.c b/branches/WOF2-1/hw/mthca/kernel/mthca_mad.c new file mode 100644 index 00000000..6c6c0e6f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_main.c b/branches/WOF2-1/hw/mthca/kernel/mthca_main.c new file mode 100644 index 00000000..6b41f25f --- /dev/null +++ b/branches/WOF2-1/hw/mthca/kernel/mthca_main.c @@ -0,0 +1,1129 @@ +/* + * 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 */ + LIVEFISH /* a burning device */ +}; + +#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 */ + { MTHCA_FW_VER(0, 0, 0), MTHCA_FW_VER(0, 0, 0), 0, 0 } /* LIVEFISH */ +}; + + +#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), + // live fishes + HCA(MELLANOX, TAVOR_BD, LIVEFISH), + HCA(MELLANOX, ARBEL_BD, LIVEFISH), + HCA(MELLANOX, SINAI_OLD_BD, LIVEFISH), + HCA(MELLANOX, SINAI_BD, LIVEFISH), + HCA(TOPSPIN, TAVOR_BD, LIVEFISH), + HCA(TOPSPIN, ARBEL_BD, LIVEFISH), + HCA(TOPSPIN, SINAI_OLD_BD, LIVEFISH), + HCA(TOPSPIN, SINAI_BD, LIVEFISH), +}; +#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); + +run_as_livefish: + /* 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 (p_id->driver_data == LIVEFISH) + mdev->mthca_flags |= MTHCA_FLAG_LIVEFISH; + if (mthca_is_livefish(mdev)) + goto done; + 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; + } + + done: + 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); + + /* we failed device initialization - try to simulate "livefish" device to facilitate using FW burning tools */ + { + USHORT dev_id = ext->hcaConfig.DeviceID; + + if (dev_id == PCI_DEVICE_ID_MELLANOX_ARBEL) + dev_id = PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT; + p_id = mthca_find_pci_dev( (unsigned)ext->hcaConfig.VendorID, dev_id + 1 ); + if (p_id == NULL) { + status = STATUS_NO_SUCH_DEVICE; + goto end; + } + goto run_as_livefish; + } + +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; + if (mthca_is_livefish(mdev)) + goto done; + 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); +done: + kfree(mdev); + } +} + + + diff --git a/branches/WOF2-1/hw/mthca/kernel/mthca_mcg.c b/branches/WOF2-1/hw/mthca/kernel/mthca_mcg.c new file mode 100644 index 00000000..dbf436b4 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_memfree.c b/branches/WOF2-1/hw/mthca/kernel/mthca_memfree.c new file mode 100644 index 00000000..a781f116 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_memfree.h b/branches/WOF2-1/hw/mthca/kernel/mthca_memfree.h new file mode 100644 index 00000000..97367ce7 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_mr.c b/branches/WOF2-1/hw/mthca/kernel/mthca_mr.c new file mode 100644 index 00000000..57f6d08f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_pd.c b/branches/WOF2-1/hw/mthca/kernel/mthca_pd.c new file mode 100644 index 00000000..c2afdd6e --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_profile.c b/branches/WOF2-1/hw/mthca/kernel/mthca_profile.c new file mode 100644 index 00000000..a2aaca20 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_profile.h b/branches/WOF2-1/hw/mthca/kernel/mthca_profile.h new file mode 100644 index 00000000..f1887c58 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_provider.c b/branches/WOF2-1/hw/mthca/kernel/mthca_provider.c new file mode 100644 index 00000000..7332bf92 --- /dev/null +++ b/branches/WOF2-1/hw/mthca/kernel/mthca_provider.c @@ -0,0 +1,1340 @@ +/* + * 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); + + if (mthca_is_livefish(mdev)) { + props->max_pd = 1; + if ( !mdev || !mdev->ext ) + return err; + props->vendor_id = mdev->ext->hcaConfig.VendorID; + props->vendor_part_id = mdev->ext->hcaConfig.DeviceID; + return 0; + } + + 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; + } + + if (mthca_is_livefish(to_mdev(ibdev))) + goto done; + + 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; + } + +done: + 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); + + if (mthca_is_livefish(to_mdev(context->device))) + goto done; + 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); +done: + 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; + } + + if (mthca_is_livefish(to_mdev(ibdev))) + goto done; + + err = mthca_pd_alloc(to_mdev(ibdev), !context, pd); + if (err) { + goto err_pd_alloc; + } + +done: + 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) +{ + if (mthca_is_livefish(to_mdev(pd->device))) + goto done; + + mthca_pd_free(to_mdev(pd->device), to_mpd(pd)); + +done: + 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-1/hw/mthca/kernel/mthca_provider.h b/branches/WOF2-1/hw/mthca/kernel/mthca_provider.h new file mode 100644 index 00000000..ca5db21f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_qp.c b/branches/WOF2-1/hw/mthca/kernel/mthca_qp.c new file mode 100644 index 00000000..d64f8071 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_srq.c b/branches/WOF2-1/hw/mthca/kernel/mthca_srq.c new file mode 100644 index 00000000..7c004847 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/kernel/mthca_uar.c b/branches/WOF2-1/hw/mthca/kernel/mthca_uar.c new file mode 100644 index 00000000..b5bb7b3b --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/mt_utils.c b/branches/WOF2-1/hw/mthca/mt_utils.c new file mode 100644 index 00000000..3d2124a8 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/mt_utils.h b/branches/WOF2-1/hw/mthca/mt_utils.h new file mode 100644 index 00000000..ddbcf389 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/Makefile b/branches/WOF2-1/hw/mthca/user/Makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/SOURCES b/branches/WOF2-1/hw/mthca/user/SOURCES new file mode 100644 index 00000000..55a9619c --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/arch.h b/branches/WOF2-1/hw/mthca/user/arch.h new file mode 100644 index 00000000..9f23be4b --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_ual_av.c b/branches/WOF2-1/hw/mthca/user/mlnx_ual_av.c new file mode 100644 index 00000000..17dd8963 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_ual_ca.c b/branches/WOF2-1/hw/mthca/user/mlnx_ual_ca.c new file mode 100644 index 00000000..4cea6bd1 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_ual_cq.c b/branches/WOF2-1/hw/mthca/user/mlnx_ual_cq.c new file mode 100644 index 00000000..28f223dc --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_ual_data.h b/branches/WOF2-1/hw/mthca/user/mlnx_ual_data.h new file mode 100644 index 00000000..d57d4b07 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_ual_main.c b/branches/WOF2-1/hw/mthca/user/mlnx_ual_main.c new file mode 100644 index 00000000..35a949e0 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_ual_main.h b/branches/WOF2-1/hw/mthca/user/mlnx_ual_main.h new file mode 100644 index 00000000..9d717d8f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_ual_mcast.c b/branches/WOF2-1/hw/mthca/user/mlnx_ual_mcast.c new file mode 100644 index 00000000..78c8f0fd --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_ual_mrw.c b/branches/WOF2-1/hw/mthca/user/mlnx_ual_mrw.c new file mode 100644 index 00000000..635ff32f --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_ual_osbypass.c b/branches/WOF2-1/hw/mthca/user/mlnx_ual_osbypass.c new file mode 100644 index 00000000..02a5cad6 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_ual_pd.c b/branches/WOF2-1/hw/mthca/user/mlnx_ual_pd.c new file mode 100644 index 00000000..2b53f75b --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_ual_qp.c b/branches/WOF2-1/hw/mthca/user/mlnx_ual_qp.c new file mode 100644 index 00000000..53792155 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_ual_srq.c b/branches/WOF2-1/hw/mthca/user/mlnx_ual_srq.c new file mode 100644 index 00000000..7d5ff1dc --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_uvp.c b/branches/WOF2-1/hw/mthca/user/mlnx_uvp.c new file mode 100644 index 00000000..2e36bb62 --- /dev/null +++ b/branches/WOF2-1/hw/mthca/user/mlnx_uvp.c @@ -0,0 +1,238 @@ +/* + * 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 + +/* 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 + + +#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), + // live fishes + HCA(MELLANOX, TAVOR_BD, LIVEFISH), + HCA(MELLANOX, ARBEL_BD, LIVEFISH), + HCA(MELLANOX, SINAI_OLD_BD, LIVEFISH), + HCA(MELLANOX, SINAI_BD, LIVEFISH), + HCA(TOPSPIN, TAVOR_BD, LIVEFISH), + HCA(TOPSPIN, ARBEL_BD, LIVEFISH), + HCA(TOPSPIN, SINAI_OLD_BD, LIVEFISH), + HCA(TOPSPIN, SINAI_BD, LIVEFISH), +}; + +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-1/hw/mthca/user/mlnx_uvp.def b/branches/WOF2-1/hw/mthca/user/mlnx_uvp.def new file mode 100644 index 00000000..55f97537 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_uvp.h b/branches/WOF2-1/hw/mthca/user/mlnx_uvp.h new file mode 100644 index 00000000..cc7cb051 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_uvp.rc b/branches/WOF2-1/hw/mthca/user/mlnx_uvp.rc new file mode 100644 index 00000000..f3d2e34a --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_uvp_ah.c b/branches/WOF2-1/hw/mthca/user/mlnx_uvp_ah.c new file mode 100644 index 00000000..be1eb898 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_uvp_cq.c b/branches/WOF2-1/hw/mthca/user/mlnx_uvp_cq.c new file mode 100644 index 00000000..bfc0adda --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_uvp_debug.c b/branches/WOF2-1/hw/mthca/user/mlnx_uvp_debug.c new file mode 100644 index 00000000..3fc71134 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_uvp_debug.h b/branches/WOF2-1/hw/mthca/user/mlnx_uvp_debug.h new file mode 100644 index 00000000..2a9cbc5b --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_uvp_doorbell.h b/branches/WOF2-1/hw/mthca/user/mlnx_uvp_doorbell.h new file mode 100644 index 00000000..7928eceb --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_uvp_memfree.c b/branches/WOF2-1/hw/mthca/user/mlnx_uvp_memfree.c new file mode 100644 index 00000000..c0b4a925 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_uvp_qp.c b/branches/WOF2-1/hw/mthca/user/mlnx_uvp_qp.c new file mode 100644 index 00000000..4fa37679 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_uvp_srq.c b/branches/WOF2-1/hw/mthca/user/mlnx_uvp_srq.c new file mode 100644 index 00000000..061f2d8b --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_uvp_verbs.c b/branches/WOF2-1/hw/mthca/user/mlnx_uvp_verbs.c new file mode 100644 index 00000000..904b71b9 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mlnx_uvp_verbs.h b/branches/WOF2-1/hw/mthca/user/mlnx_uvp_verbs.h new file mode 100644 index 00000000..069271cd --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/mt_l2w.h b/branches/WOF2-1/hw/mthca/user/mt_l2w.h new file mode 100644 index 00000000..e7bb2ab2 --- /dev/null +++ b/branches/WOF2-1/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-1/hw/mthca/user/opcode.h b/branches/WOF2-1/hw/mthca/user/opcode.h new file mode 100644 index 00000000..cf2598b6 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_async_proc.h b/branches/WOF2-1/inc/complib/cl_async_proc.h new file mode 100644 index 00000000..083571a4 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_atomic.h b/branches/WOF2-1/inc/complib/cl_atomic.h new file mode 100644 index 00000000..11cce604 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_byteswap.h b/branches/WOF2-1/inc/complib/cl_byteswap.h new file mode 100644 index 00000000..60fd59ae --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_comppool.h b/branches/WOF2-1/inc/complib/cl_comppool.h new file mode 100644 index 00000000..19050918 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_debug.h b/branches/WOF2-1/inc/complib/cl_debug.h new file mode 100644 index 00000000..17a8fe7a --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_event.h b/branches/WOF2-1/inc/complib/cl_event.h new file mode 100644 index 00000000..8fed078f --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_fleximap.h b/branches/WOF2-1/inc/complib/cl_fleximap.h new file mode 100644 index 00000000..ffb5fcb7 --- /dev/null +++ b/branches/WOF2-1/inc/complib/cl_fleximap.h @@ -0,0 +1,929 @@ +/* + * 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. + * + * Environment: + * All + */ + + +#ifndef _CL_FLEXIMAP_H_ +#define _CL_FLEXIMAP_H_ + + +#include + + +/****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 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, +*********/ + + +/****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 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 +*********/ + + +/****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 +*********/ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/****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_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 +*********/ + + +/****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 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 +*********/ + + +/****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 +*********/ + +#ifdef __cplusplus +} +#endif + + +#endif /* _CL_FLEXIMAP_H_ */ diff --git a/branches/WOF2-1/inc/complib/cl_ioctl.h b/branches/WOF2-1/inc/complib/cl_ioctl.h new file mode 100644 index 00000000..93998a48 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_irqlock.h b/branches/WOF2-1/inc/complib/cl_irqlock.h new file mode 100644 index 00000000..ea139e69 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_list.h b/branches/WOF2-1/inc/complib/cl_list.h new file mode 100644 index 00000000..c05dcdef --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_log.h b/branches/WOF2-1/inc/complib/cl_log.h new file mode 100644 index 00000000..1563cbe7 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_map.h b/branches/WOF2-1/inc/complib/cl_map.h new file mode 100644 index 00000000..d7732988 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_math.h b/branches/WOF2-1/inc/complib/cl_math.h new file mode 100644 index 00000000..8e8af960 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_memory.h b/branches/WOF2-1/inc/complib/cl_memory.h new file mode 100644 index 00000000..b66f22cc --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_mutex.h b/branches/WOF2-1/inc/complib/cl_mutex.h new file mode 100644 index 00000000..2ae4de31 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_nodenamemap.h b/branches/WOF2-1/inc/complib/cl_nodenamemap.h new file mode 100644 index 00000000..e836cf50 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_obj.h b/branches/WOF2-1/inc/complib/cl_obj.h new file mode 100644 index 00000000..e691d101 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_passivelock.h b/branches/WOF2-1/inc/complib/cl_passivelock.h new file mode 100644 index 00000000..a1a5d117 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_perf.h b/branches/WOF2-1/inc/complib/cl_perf.h new file mode 100644 index 00000000..58c4d634 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_pool.h b/branches/WOF2-1/inc/complib/cl_pool.h new file mode 100644 index 00000000..df09b500 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_ptr_vector.h b/branches/WOF2-1/inc/complib/cl_ptr_vector.h new file mode 100644 index 00000000..bfba4f73 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_qcomppool.h b/branches/WOF2-1/inc/complib/cl_qcomppool.h new file mode 100644 index 00000000..8cdbb55f --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_qlist.h b/branches/WOF2-1/inc/complib/cl_qlist.h new file mode 100644 index 00000000..4c411f6e --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_qlockpool.h b/branches/WOF2-1/inc/complib/cl_qlockpool.h new file mode 100644 index 00000000..3187dcb6 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_qmap.h b/branches/WOF2-1/inc/complib/cl_qmap.h new file mode 100644 index 00000000..4981b4e9 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_qpool.h b/branches/WOF2-1/inc/complib/cl_qpool.h new file mode 100644 index 00000000..03b27376 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_rbmap.h b/branches/WOF2-1/inc/complib/cl_rbmap.h new file mode 100644 index 00000000..7e73fb42 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_reqmgr.h b/branches/WOF2-1/inc/complib/cl_reqmgr.h new file mode 100644 index 00000000..7077e13b --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_spinlock.h b/branches/WOF2-1/inc/complib/cl_spinlock.h new file mode 100644 index 00000000..8dd45e1e --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_syscallback.h b/branches/WOF2-1/inc/complib/cl_syscallback.h new file mode 100644 index 00000000..09678969 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_thread.h b/branches/WOF2-1/inc/complib/cl_thread.h new file mode 100644 index 00000000..aef5c9c6 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_threadpool.h b/branches/WOF2-1/inc/complib/cl_threadpool.h new file mode 100644 index 00000000..b4c0089b --- /dev/null +++ b/branches/WOF2-1/inc/complib/cl_threadpool.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 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; + +} 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-1/inc/complib/cl_timer.h b/branches/WOF2-1/inc/complib/cl_timer.h new file mode 100644 index 00000000..8df14d8b --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_types.h b/branches/WOF2-1/inc/complib/cl_types.h new file mode 100644 index 00000000..be7fddac --- /dev/null +++ b/branches/WOF2-1/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 +* uintn_t +* offsetof( +* IN TYPE, +* IN MEMBER ); +* +* PARAMETERS +* TYPE +* [in] Name of the structure containing the specified member. +* +* MEMBER +* [in] Name of the member whose offset in the specified structure +* is to be returned. +* +* RETURN VALUE +* Number of bytes from the beginning of the structure to the +* specified member. +* +* SEE ALSO +* PARENT_STRUCT +*********/ +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((uintn_t) &((TYPE *)0)->MEMBER) +#endif + + +/****d* Component Library: Pointer Manipulation/PARENT_STRUCT +* NAME +* PARENT_STRUCT +* +* DESCRIPTION +* The PARENT_STRUCT macro returns a pointer to a structure +* given a name and pointer to one of its members. +* +* SYNOPSIS +* PARENT_TYPE* +* PARENT_STRUCT( +* IN void* const p_member, +* IN PARENT_TYPE, +* IN MEMBER_NAME ); +* +* PARAMETERS +* p_member +* [in] Pointer to the MEMBER_NAME member of a PARENT_TYPE structure. +* +* PARENT_TYPE +* [in] Name of the structure containing the specified member. +* +* MEMBER_NAME +* [in] Name of the member whose address is passed in the p_member +* parameter. +* +* RETURN VALUE +* Pointer to a structure of type PARENT_TYPE whose MEMBER_NAME member is +* located at p_member. +* +* SEE ALSO +* offsetof +*********/ +#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-1/inc/complib/cl_vector.h b/branches/WOF2-1/inc/complib/cl_vector.h new file mode 100644 index 00000000..86dad3f2 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/cl_waitobj.h b/branches/WOF2-1/inc/complib/cl_waitobj.h new file mode 100644 index 00000000..7138b1bb --- /dev/null +++ b/branches/WOF2-1/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-1/inc/complib/comp_lib.h b/branches/WOF2-1/inc/complib/comp_lib.h new file mode 100644 index 00000000..39f5e0cb --- /dev/null +++ b/branches/WOF2-1/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-1/inc/iba/ib_al.h b/branches/WOF2-1/inc/iba/ib_al.h new file mode 100644 index 00000000..ba30e9be --- /dev/null +++ b/branches/WOF2-1/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-1/inc/iba/ib_al_ioctl.h b/branches/WOF2-1/inc/iba/ib_al_ioctl.h new file mode 100644 index 00000000..c94f562b --- /dev/null +++ b/branches/WOF2-1/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-1/inc/iba/ib_at_ioctl.h b/branches/WOF2-1/inc/iba/ib_at_ioctl.h new file mode 100644 index 00000000..70b899e7 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/iba/ib_ci.h b/branches/WOF2-1/inc/iba/ib_ci.h new file mode 100644 index 00000000..89ec8816 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/iba/ib_types.h b/branches/WOF2-1/inc/iba/ib_types.h new file mode 100644 index 00000000..74d16c6c --- /dev/null +++ b/branches/WOF2-1/inc/iba/ib_types.h @@ -0,0 +1,11021 @@ +/* + * 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_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_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_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 +* NodeDescription attribute (16.1.2) +* +* 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 +* NodeInfo attribute (16.1.2) +* +* 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 +* SwitchInfo attribute (16.1.2) +* +* 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_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_NTOH16(0x003B)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_INFORM_INFO_RECORD +* NAME +* IB_MAD_ATTR_INFORM_INFO_RECORD +* +* DESCRIPTION +* InformInfo Record attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_INFORM_INFO_RECORD (CL_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_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_NODE_TYPE_CA +* 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)) +/**********/ + +/****d* IBA Base: Constants/IB_NOTICE_NODE_TYPE_SWITCH +* 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)) +/**********/ + +/****d* IBA Base: Constants/IB_NOTICE_NODE_TYPE_ROUTER +* 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)) +/**********/ + +/****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_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_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_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 ) == 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; + uint16_t resv1; + uint32_t resv2; + +} PACK_SUFFIX ib_path_rec_t; +#include +/* +* 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 +* 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. +* +* 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 +*********/ + +/* 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_RESV2 (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_RESV4 (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; + + 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] 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. +* +* 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); +} + +/****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_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. +* +* 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 +* +*********/ + +/****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), +* 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 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 +*********/ + +/****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 ) +{ + if( attr_size & 0x07 ) + return( cl_hton16( (uint16_t)(attr_size >> 3) + 1 ) ); + else + 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_smp +* [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 +* 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 +*********/ + +/****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), resrv( +2b), timeout(5b) */ + uint8_t resp_time_value; + uint8_t error_threshold; + +} PACK_SUFFIX ib_port_info_t; +#include +/************/ + +#define IB_PORT_STATE_MASK 0x0F +#define IB_PORT_LMC_MASK 0x07 +#define IB_PORT_LMC_MAX 0x07 +#define IB_PORT_MPB_MASK 0xC0 +#define IB_PORT_MPB_SHIFT 6 +#define IB_PORT_LINK_SPEED_SHIFT 4 +#define IB_PORT_LINK_SPEED_SUPPORTED_MASK 0xF0 +#define IB_PORT_LINK_SPEED_ACTIVE_MASK 0xF0 +#define IB_PORT_LINK_SPEED_ENABLED_MASK 0x0F +#define IB_PORT_PHYS_STATE_MASK 0xF0 +#define IB_PORT_PHYS_STATE_SHIFT 4 +#define IB_PORT_PHYS_STATE_NO_CHANGE 0 +#define IB_PORT_PHYS_STATE_SLEEP 1 +#define IB_PORT_PHYS_STATE_POLLING 2 +#define IB_PORT_PHYS_STATE_DISABLED 3 +#define IB_PORT_PHYS_STATE_PORTCONFTRAIN 4 +#define IB_PORT_PHYS_STATE_LINKUP 5 +#define IB_PORT_PHYS_STATE_LINKERRRECOVER 6 +#define IB_PORT_PHYS_STATE_PHYTEST 7 +#define IB_PORT_LNKDWNDFTSTATE_MASK 0x0F + +#define IB_PORT_CAP_RESV0 (CL_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_RESV26 (CL_NTOH32(0x04000000)) +#define IB_PORT_CAP_RESV27 (CL_NTOH32(0x08000000)) +#define IB_PORT_CAP_RESV28 (CL_NTOH32(0x10000000)) +#define IB_PORT_CAP_RESV29 (CL_NTOH32(0x20000000)) +#define IB_PORT_CAP_RESV30 (CL_NTOH32(0x40000000)) +#define IB_PORT_CAP_RESV31 (CL_NTOH32(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_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_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 LMC value assigned to 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_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 & 0x80) | (timeout & 0x1F)); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* timeout +* [in] Encoded timeout value to set +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_client_rereg +* NAME +* ib_port_info_set_client_rereg +* +* DESCRIPTION +* Sets the encoded client reregistration bit value in the PortInfo attribute. +* +* SYNOPSIS +*/ +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 & 0x1F) | ((client_rereg << 7) & 0x80)); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* client_rereg +* [in] Client reregistration value to set (either 1 or 0). +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_timeout +* NAME +* ib_port_info_get_timeout +* +* DESCRIPTION +* Gets the encoded subnet timeout value in the PortInfo attribute. +* +* SYNOPSIS +*/ +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; + uint8_t pad[6]; + +} PACK_SUFFIX ib_portinfo_record_t; +#include + +#include +typedef struct _ib_link_record +{ + ib_net16_t from_lid; + uint8_t from_port_num; + uint8_t to_port_num; + ib_net16_t to_lid; + uint8_t pad[2]; + +} PACK_SUFFIX ib_link_record_t; +#include + +#include +typedef struct _ib_sminfo_record +{ + ib_net16_t lid; + uint16_t resv0; + ib_sm_info_t sm_info; + uint8_t pad[7]; + +} PACK_SUFFIX ib_sminfo_record_t; +#include + +/****s* IBA Base: Types/ib_lft_record_t +* NAME +* ib_lft_record_t +* +* DESCRIPTION +* IBA defined LinearForwardingTableRecord (15.2.5.6) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_lft_record +{ + ib_net16_t lid; + ib_net16_t block_num; + uint32_t resv0; + uint8_t lft[64]; +} PACK_SUFFIX ib_lft_record_t; +#include +/************/ + +/****s* IBA Base: Types/ib_mft_record_t +* NAME +* ib_mft_record_t +* +* DESCRIPTION +* IBA defined MulticastForwardingTableRecord (15.2.5.8) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_mft_record +{ + ib_net16_t lid; + ib_net16_t position_block_num; + uint32_t resv0; + ib_net16_t mft[IB_MCAST_BLOCK_SIZE]; +} PACK_SUFFIX ib_mft_record_t; +#include +/************/ + +/****s* IBA Base: Types/ib_switch_info_t +* NAME +* ib_switch_info_t +* +* DESCRIPTION +* IBA defined SwitchInfo. (14.2.5.4) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_switch_info +{ + ib_net16_t lin_cap; + ib_net16_t rand_cap; + ib_net16_t mcast_cap; + ib_net16_t lin_top; + uint8_t def_port; + uint8_t def_mcast_pri_port; + uint8_t def_mcast_not_port; + uint8_t life_state; + ib_net16_t lids_per_port; + ib_net16_t enforce_cap; + uint8_t flags; + +} PACK_SUFFIX ib_switch_info_t; +#include +/************/ + +#include +typedef struct _ib_switch_info_record +{ + ib_net16_t lid; + uint16_t resv0; + ib_switch_info_t switch_info; + uint8_t pad[3]; + +} PACK_SUFFIX ib_switch_info_record_t; +#include + +#define IB_SWITCH_PSC 0x04 + +/****f* IBA Base: Types/ib_switch_info_get_state_change +* NAME +* ib_switch_info_get_state_change +* +* DESCRIPTION +* Returns the value of the state change flag. +* +* SYNOPSIS +*/ +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_ni +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the LMC value assigned to this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_switch_info_is_enhanced_port0 +* NAME +* ib_switch_info_is_enhanced_port0 +* +* DESCRIPTION +* Returns TRUE if the enhancedPort0 bit is on (meaning the switch +* port zero supports enhanced functions). +* Returns FALSE otherwise. +* +* SYNOPSIS +*/ +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; + uint8_t resv0; + uint8_t sl; + uint8_t mtu; + uint8_t rate; + uint8_t pkt_life; + uint8_t resv1; + uint8_t independence; /* formerly resv2 */ + uint8_t sgid_count; + uint8_t dgid_count; + uint8_t resv3[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. +* +* 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. +* +* 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_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->sl )) & 0xF) ); +} +/* +* 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_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 +*********/ + +#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 vl_table[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->vl_table[idx] = ( p_slvl_tbl->vl_table[idx] & 0xF0 ) | vl ; + } + else + { + /* this is an even sl. Need to update the ms bits */ + p_slvl_tbl->vl_table[idx] = ( vl << 4 ) | ( p_slvl_tbl->vl_table[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->vl_table[idx] & 0x0F ); + } + else + { + /* this is an even sl. Need to return the ms bits. */ + return ( (p_slvl_tbl->vl_table[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. +* +* 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 +*********/ + +/****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 with sw info 53 + { + ib_net16_t data_valid; // 2 + ib_net16_t lid1; // 2 + ib_net16_t lid2; // 2 + ib_net32_t key; // 4 + uint8_t sl; // 1 + ib_net32_t qp1; // 4 + uint8_t qp2_msb; // 1 + ib_net16_t qp2_lsb; // 2 + ib_gid_t gid1; // 16 + ib_gid_t gid2; // 16 + ib_net16_t sw_lid; // 2 + uint8_t port_no; // 1 + } PACK_SUFFIX ntc_259; + + } data_details; + + ib_gid_t issuer_gid; // 16 80 + +} PACK_SUFFIX ib_mad_notice_attr_t; +#include + +/** + * Trap 259 masks + */ +#define TRAP_259_MASK_SL (CL_HTON32(0xF0000000)) +#define TRAP_259_MASK_QP (CL_HTON32(0x00FFFFFF)) + +/** + * Trap 144 masks + */ +#define TRAP_144_MASK_OTHER_LOCAL_CHANGES 0x01 +#define TRAP_144_MASK_SM_PRIORITY_CHANGE (CL_HTON16(0x0008)) +#define TRAP_144_MASK_LINK_SPEED_ENABLE_CHANGE (CL_HTON16(0x0004)) +#define TRAP_144_MASK_LINK_WIDTH_ENABLE_CHANGE (CL_HTON16(0x0002)) +#define TRAP_144_MASK_NODE_DESCRIPTION_CHANGE (CL_HTON16(0x0001)) + +#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; + uint16_t reserved[3]; + ib_inform_info_t inform_info; + uint8_t pad[4]; + +} PACK_SUFFIX ib_inform_info_record_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_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 +*****/ + +/****s* Access Layer/ib_port_attr_t +* NAME +* ib_port_attr_t +* +* DESCRIPTION +* Information about a port on a given channel adapter. +* +* SYNOPSIS +*/ +typedef struct _ib_port_attr +{ + ib_net64_t port_guid; + uint8_t port_num; + uint8_t mtu; + uint64_t max_msg_size; + ib_net16_t lid; + uint8_t lmc; + + /* + * LinkWidthSupported as defined in PortInfo. Required to calculate + * inter-packet delay (a.k.a. static rate). + */ + uint8_t link_width_supported; + + uint16_t max_vls; + + ib_net16_t sm_lid; + uint8_t sm_sl; + uint8_t link_state; + + ib_init_type_t init_type_reply; /* Optional */ + + /* + * subnet_timeout: + * The maximum expected subnet propagation delay to reach any port on + * the subnet. This value also determines the rate at which traps can + * be generated from this node. + * + * timeout = 4.096 microseconds * 2^subnet_timeout + */ + uint8_t subnet_timeout; + 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_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_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_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. +*****/ + + +#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-1/inc/kernel/complib/cl_atomic_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_atomic_osd.h new file mode 100644 index 00000000..90289d59 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_bus_ifc.h b/branches/WOF2-1/inc/kernel/complib/cl_bus_ifc.h new file mode 100644 index 00000000..9ec8e1b3 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_byteswap_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_byteswap_osd.h new file mode 100644 index 00000000..dfa29043 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_debug_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_debug_osd.h new file mode 100644 index 00000000..f72585a1 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_event_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_event_osd.h new file mode 100644 index 00000000..9e5ea3f9 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_init.h b/branches/WOF2-1/inc/kernel/complib/cl_init.h new file mode 100644 index 00000000..206e6308 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_ioctl_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_ioctl_osd.h new file mode 100644 index 00000000..450f3ef9 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_irqlock_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_irqlock_osd.h new file mode 100644 index 00000000..4398b2c3 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_memory_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_memory_osd.h new file mode 100644 index 00000000..20584619 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_mutex_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_mutex_osd.h new file mode 100644 index 00000000..5b607c1d --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_packoff.h b/branches/WOF2-1/inc/kernel/complib/cl_packoff.h new file mode 100644 index 00000000..2117feb7 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_packon.h b/branches/WOF2-1/inc/kernel/complib/cl_packon.h new file mode 100644 index 00000000..648b239e --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_pnp_po.h b/branches/WOF2-1/inc/kernel/complib/cl_pnp_po.h new file mode 100644 index 00000000..073b57b1 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_spinlock_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_spinlock_osd.h new file mode 100644 index 00000000..bf6a4196 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_syscallback_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_syscallback_osd.h new file mode 100644 index 00000000..280835c8 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_thread_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_thread_osd.h new file mode 100644 index 00000000..14b501ae --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_timer_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_timer_osd.h new file mode 100644 index 00000000..4cb99b08 --- /dev/null +++ b/branches/WOF2-1/inc/kernel/complib/cl_timer_osd.h @@ -0,0 +1,102 @@ +/* + * 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; + +} 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-1/inc/kernel/complib/cl_types_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_types_osd.h new file mode 100644 index 00000000..851d8ea6 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/complib/cl_waitobj_osd.h b/branches/WOF2-1/inc/kernel/complib/cl_waitobj_osd.h new file mode 100644 index 00000000..9320cba9 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/iba/ib_al_ifc.h b/branches/WOF2-1/inc/kernel/iba/ib_al_ifc.h new file mode 100644 index 00000000..18faa8e7 --- /dev/null +++ b/branches/WOF2-1/inc/kernel/iba/ib_al_ifc.h @@ -0,0 +1,774 @@ +/* + * 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_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. + */ +/* {707A1BDE-BF9F-4565-8FDD-144EF6514FE8} */ +DEFINE_GUID(GUID_IB_AL_INTERFACE, +0x707a1bde, 0xbf9f, 0x4565, 0x8f, 0xdd, 0x14, 0x4e, 0xf6, 0x51, 0x4f, 0xe8); diff --git a/branches/WOF2-1/inc/kernel/iba/ib_ci_ifc.h b/branches/WOF2-1/inc/kernel/iba/ib_ci_ifc.h new file mode 100644 index 00000000..22fc4849 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/iba/ib_cm_ifc.h b/branches/WOF2-1/inc/kernel/iba/ib_cm_ifc.h new file mode 100644 index 00000000..0949482b --- /dev/null +++ b/branches/WOF2-1/inc/kernel/iba/ib_cm_ifc.h @@ -0,0 +1,296 @@ +/* + * 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 +{ + iba_cm_req req; + 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 (*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; +} + +// {EACC1466-BB2D-4478-B5BE-40EDF7EE08AB} +DEFINE_GUID(GUID_INFINIBAND_INTERFACE_CM, 0xeacc1466, 0xbb2d, 0x4478, + 0xb5, 0xbe, 0x40, 0xed, 0xf7, 0xee, 0x8, 0xab); + +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-1/inc/kernel/iba/ib_rdma_cm.h b/branches/WOF2-1/inc/kernel/iba/ib_rdma_cm.h new file mode 100644 index 00000000..b6f01f1c --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/iba/ioc_ifc.h b/branches/WOF2-1/inc/kernel/iba/ioc_ifc.h new file mode 100644 index 00000000..6ea9328b --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/iba/iou_ifc.h b/branches/WOF2-1/inc/kernel/iba/iou_ifc.h new file mode 100644 index 00000000..ca34e9c2 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/iba/ipoib_ifc.h b/branches/WOF2-1/inc/kernel/iba/ipoib_ifc.h new file mode 100644 index 00000000..d34eaf6d --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/index_list.h b/branches/WOF2-1/inc/kernel/index_list.h new file mode 100644 index 00000000..ec0ab7f1 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/ip_packet.h b/branches/WOF2-1/inc/kernel/ip_packet.h new file mode 100644 index 00000000..12fdb351 --- /dev/null +++ b/branches/WOF2-1/inc/kernel/ip_packet.h @@ -0,0 +1,535 @@ +/* + * 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_ARP CL_HTON16(0x806) +#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 ehternet 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 ) + +#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-1/inc/kernel/rdma/verbs.h b/branches/WOF2-1/inc/kernel/rdma/verbs.h new file mode 100644 index 00000000..67f5eac4 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/kernel/work_queue.h b/branches/WOF2-1/inc/kernel/work_queue.h new file mode 100644 index 00000000..8873442f --- /dev/null +++ b/branches/WOF2-1/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-1/inc/mod_ver.def b/branches/WOF2-1/inc/mod_ver.def new file mode 100644 index 00000000..1d4ff65e --- /dev/null +++ b/branches/WOF2-1/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-1/inc/mthca/mthca_vc.h b/branches/WOF2-1/inc/mthca/mthca_vc.h new file mode 100644 index 00000000..f2059b95 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/oib_ver.h b/branches/WOF2-1/inc/oib_ver.h new file mode 100644 index 00000000..5af45565 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/openib.def b/branches/WOF2-1/inc/openib.def new file mode 100644 index 00000000..9e606bb2 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/comp_channel.h b/branches/WOF2-1/inc/user/comp_channel.h new file mode 100644 index 00000000..98768715 --- /dev/null +++ b/branches/WOF2-1/inc/user/comp_channel.h @@ -0,0 +1,98 @@ +/* + * 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; + DLIST_ENTRY MgrEntry; + OVERLAPPED Overlap; + struct _COMP_CHANNEL *Channel; + LONG volatile Busy; + +} COMP_ENTRY; + +typedef struct _COMP_CHANNEL +{ + struct _COMP_MANAGER *Manager; + COMP_ENTRY *Head; + COMP_ENTRY **TailPtr; + COMP_ENTRY Entry; + HANDLE Event; + CRITICAL_SECTION Lock; + DWORD Milliseconds; + +} COMP_CHANNEL; + +typedef struct _COMP_MANAGER +{ + HANDLE CompQueue; + DLIST_ENTRY DoneList; + COMP_ENTRY Entry; + HANDLE Thread; + BOOL Run; + HANDLE Event; + LONG volatile Busy; + CRITICAL_SECTION Lock; + +} COMP_MANAGER; + +DWORD CompManagerOpen(COMP_MANAGER *pMgr); +void CompManagerClose(COMP_MANAGER *pMgr); +DWORD CompManagerMonitor(COMP_MANAGER *pMgr, HANDLE hFile, ULONG_PTR Key); +DWORD CompManagerPoll(COMP_MANAGER *pMgr, DWORD Milliseconds, + COMP_CHANNEL **ppChannel); +void CompManagerCancel(COMP_MANAGER *pMgr); + +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-1/inc/user/complib/cl_atomic_osd.h b/branches/WOF2-1/inc/user/complib/cl_atomic_osd.h new file mode 100644 index 00000000..062177d8 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/complib/cl_byteswap_osd.h b/branches/WOF2-1/inc/user/complib/cl_byteswap_osd.h new file mode 100644 index 00000000..3f20c6da --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/complib/cl_debug_osd.h b/branches/WOF2-1/inc/user/complib/cl_debug_osd.h new file mode 100644 index 00000000..3bf6208d --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/complib/cl_event_osd.h b/branches/WOF2-1/inc/user/complib/cl_event_osd.h new file mode 100644 index 00000000..44fad4ba --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/complib/cl_ioctl_osd.h b/branches/WOF2-1/inc/user/complib/cl_ioctl_osd.h new file mode 100644 index 00000000..2c5b9e41 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/complib/cl_memory_osd.h b/branches/WOF2-1/inc/user/complib/cl_memory_osd.h new file mode 100644 index 00000000..f3cc5db3 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/complib/cl_mutex_osd.h b/branches/WOF2-1/inc/user/complib/cl_mutex_osd.h new file mode 100644 index 00000000..4fd9415f --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/complib/cl_packoff.h b/branches/WOF2-1/inc/user/complib/cl_packoff.h new file mode 100644 index 00000000..2117feb7 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/complib/cl_packon.h b/branches/WOF2-1/inc/user/complib/cl_packon.h new file mode 100644 index 00000000..648b239e --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/complib/cl_spinlock_osd.h b/branches/WOF2-1/inc/user/complib/cl_spinlock_osd.h new file mode 100644 index 00000000..eb07caed --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/complib/cl_syscallback_osd.h b/branches/WOF2-1/inc/user/complib/cl_syscallback_osd.h new file mode 100644 index 00000000..142eaec9 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/complib/cl_thread_osd.h b/branches/WOF2-1/inc/user/complib/cl_thread_osd.h new file mode 100644 index 00000000..23705ed8 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/complib/cl_timer_osd.h b/branches/WOF2-1/inc/user/complib/cl_timer_osd.h new file mode 100644 index 00000000..0a023ba6 --- /dev/null +++ b/branches/WOF2-1/inc/user/complib/cl_timer_osd.h @@ -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$ + */ + + + + +#ifndef _CL_TIMER_OSD_H_ +#define _CL_TIMER_OSD_H_ + + +#include "cl_types.h" + + +/* Timer object definition. */ +typedef struct _cl_timer +{ + HANDLE h_timer; + cl_pfn_timer_callback_t pfn_callback; + const void *context; + uint64_t timeout_time; + DWORD thread_id; + +} cl_timer_t; + + +#endif // _CL_TIMER_OSD_H_ \ No newline at end of file diff --git a/branches/WOF2-1/inc/user/complib/cl_types_osd.h b/branches/WOF2-1/inc/user/complib/cl_types_osd.h new file mode 100644 index 00000000..e205de66 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/complib/cl_waitobj_osd.h b/branches/WOF2-1/inc/user/complib/cl_waitobj_osd.h new file mode 100644 index 00000000..b9f4eee8 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/dlist.h b/branches/WOF2-1/inc/user/dlist.h new file mode 100644 index 00000000..5cf93042 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/getopt.h b/branches/WOF2-1/inc/user/getopt.h new file mode 100644 index 00000000..2f2e9a72 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/iba/ib_uvp.h b/branches/WOF2-1/inc/user/iba/ib_uvp.h new file mode 100644 index 00000000..cc159686 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/iba/ibat.h b/branches/WOF2-1/inc/user/iba/ibat.h new file mode 100644 index 00000000..c9a17405 --- /dev/null +++ b/branches/WOF2-1/inc/user/iba/ibat.h @@ -0,0 +1,67 @@ +/* + * 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 + ); + +} +#else /* __cplusplus */ + +HRESULT +IbatResolve( + __in const struct sockaddr* pSrcAddr, + __in const struct sockaddr* pDestAddr, + __out IBAT_PATH_BLOB* pPath + ); + +#endif /* __cplusplus */ + +#endif // _IBAT_H_ \ No newline at end of file diff --git a/branches/WOF2-1/inc/user/iba/winmad.h b/branches/WOF2-1/inc/user/iba/winmad.h new file mode 100644 index 00000000..779ef74e --- /dev/null +++ b/branches/WOF2-1/inc/user/iba/winmad.h @@ -0,0 +1,159 @@ +/* + * 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; + +#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-1/inc/user/linux/_string.h b/branches/WOF2-1/inc/user/linux/_string.h new file mode 100644 index 00000000..63c2f83c --- /dev/null +++ b/branches/WOF2-1/inc/user/linux/_string.h @@ -0,0 +1,45 @@ +/* + * 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 strtoull _strtoui64 +#define strtok_r strtok_s + +#endif /* __STRING_H_ */ diff --git a/branches/WOF2-1/inc/user/linux/arpa/inet.h b/branches/WOF2-1/inc/user/linux/arpa/inet.h new file mode 100644 index 00000000..18c13a06 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/linux/inttypes.h b/branches/WOF2-1/inc/user/linux/inttypes.h new file mode 100644 index 00000000..19776665 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/linux/netinet/in.h b/branches/WOF2-1/inc/user/linux/netinet/in.h new file mode 100644 index 00000000..ebdff291 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/linux/sys/time.h b/branches/WOF2-1/inc/user/linux/sys/time.h new file mode 100644 index 00000000..36df6ab2 --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/linux/unistd.h b/branches/WOF2-1/inc/user/linux/unistd.h new file mode 100644 index 00000000..6d17e37a --- /dev/null +++ b/branches/WOF2-1/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-1/inc/user/rdma/winverbs.h b/branches/WOF2-1/inc/user/rdma/winverbs.h new file mode 100644 index 00000000..eb73b1bb --- /dev/null +++ b/branches/WOF2-1/inc/user/rdma/winverbs.h @@ -0,0 +1,1530 @@ +/* + * 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 _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; + +// 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; + HRESULT 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 + +// 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-1/inc/user/rdma/wvstatus.h b/branches/WOF2-1/inc/user/rdma/wvstatus.h new file mode 100644 index 00000000..0259076f --- /dev/null +++ b/branches/WOF2-1/inc/user/rdma/wvstatus.h @@ -0,0 +1,133 @@ +/* + * 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_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-1/inc/user/wsd/ibsp_regpath.h b/branches/WOF2-1/inc/user/wsd/ibsp_regpath.h new file mode 100644 index 00000000..90661199 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/allocdeallocpd.c b/branches/WOF2-1/tests/alts/allocdeallocpd.c new file mode 100644 index 00000000..350dad8e --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/alts_common.h b/branches/WOF2-1/tests/alts/alts_common.h new file mode 100644 index 00000000..36653946 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/alts_debug.h b/branches/WOF2-1/tests/alts/alts_debug.h new file mode 100644 index 00000000..9167c963 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/alts_misc.c b/branches/WOF2-1/tests/alts/alts_misc.c new file mode 100644 index 00000000..ae29f36a --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/alts_readme.txt b/branches/WOF2-1/tests/alts/alts_readme.txt new file mode 100644 index 00000000..c5976dfc --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/cmtests.c b/branches/WOF2-1/tests/alts/cmtests.c new file mode 100644 index 00000000..c3585d48 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/createanddestroycq.c b/branches/WOF2-1/tests/alts/createanddestroycq.c new file mode 100644 index 00000000..f1cc008c --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/createanddestroyqp.c b/branches/WOF2-1/tests/alts/createanddestroyqp.c new file mode 100644 index 00000000..39f864c8 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/createdestroyav.c b/branches/WOF2-1/tests/alts/createdestroyav.c new file mode 100644 index 00000000..ca7c7106 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/creatememwindow.c b/branches/WOF2-1/tests/alts/creatememwindow.c new file mode 100644 index 00000000..e14ef2d2 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/dirs b/branches/WOF2-1/tests/alts/dirs new file mode 100644 index 00000000..d1917e8a --- /dev/null +++ b/branches/WOF2-1/tests/alts/dirs @@ -0,0 +1,3 @@ +DIRS=\ + user \ +# kernel diff --git a/branches/WOF2-1/tests/alts/ibquery.c b/branches/WOF2-1/tests/alts/ibquery.c new file mode 100644 index 00000000..d2f2ec55 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/kernel/SOURCES b/branches/WOF2-1/tests/alts/kernel/SOURCES new file mode 100644 index 00000000..e78ba363 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/kernel/alts.inf b/branches/WOF2-1/tests/alts/kernel/alts.inf new file mode 100644 index 00000000..84b7cffc --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/kernel/alts.rc b/branches/WOF2-1/tests/alts/kernel/alts.rc new file mode 100644 index 00000000..0b0ca481 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/kernel/alts_driver.c b/branches/WOF2-1/tests/alts/kernel/alts_driver.c new file mode 100644 index 00000000..f16ad350 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/kernel/alts_driver.h b/branches/WOF2-1/tests/alts/kernel/alts_driver.h new file mode 100644 index 00000000..1b097345 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/kernel/makefile b/branches/WOF2-1/tests/alts/kernel/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/madtests.c b/branches/WOF2-1/tests/alts/madtests.c new file mode 100644 index 00000000..043b5311 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/multisendrecv.c b/branches/WOF2-1/tests/alts/multisendrecv.c new file mode 100644 index 00000000..5ca95db6 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/openclose.c b/branches/WOF2-1/tests/alts/openclose.c new file mode 100644 index 00000000..5b404ca0 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/querycaattr.c b/branches/WOF2-1/tests/alts/querycaattr.c new file mode 100644 index 00000000..c0a02320 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/registermemregion.c b/branches/WOF2-1/tests/alts/registermemregion.c new file mode 100644 index 00000000..7dc9babe --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/smatests.c b/branches/WOF2-1/tests/alts/smatests.c new file mode 100644 index 00000000..0b8a2f43 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/user/SOURCES b/branches/WOF2-1/tests/alts/user/SOURCES new file mode 100644 index 00000000..acd63375 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/user/alts_main.c b/branches/WOF2-1/tests/alts/user/alts_main.c new file mode 100644 index 00000000..adce92a7 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/alts/user/makefile b/branches/WOF2-1/tests/alts/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/cmtest/dirs b/branches/WOF2-1/tests/cmtest/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-1/tests/cmtest/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/tests/cmtest/user/SOURCES b/branches/WOF2-1/tests/cmtest/user/SOURCES new file mode 100644 index 00000000..3001b4a5 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/cmtest/user/cmtest.rc b/branches/WOF2-1/tests/cmtest/user/cmtest.rc new file mode 100644 index 00000000..19c4021d --- /dev/null +++ b/branches/WOF2-1/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-1/tests/cmtest/user/cmtest_main.c b/branches/WOF2-1/tests/cmtest/user/cmtest_main.c new file mode 100644 index 00000000..0ce9f102 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/cmtest/user/makefile b/branches/WOF2-1/tests/cmtest/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/dirs b/branches/WOF2-1/tests/dirs new file mode 100644 index 00000000..9485cbef --- /dev/null +++ b/branches/WOF2-1/tests/dirs @@ -0,0 +1,8 @@ +DIRS=\ + alts \ + cmtest \ + wsd \ + ibat \ + limits \ + wherebu \ + perftest diff --git a/branches/WOF2-1/tests/ibat/dirs b/branches/WOF2-1/tests/ibat/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-1/tests/ibat/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/tests/ibat/user/PrintIp.c b/branches/WOF2-1/tests/ibat/user/PrintIp.c new file mode 100644 index 00000000..bfc7577a --- /dev/null +++ b/branches/WOF2-1/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-1/tests/ibat/user/SOURCES b/branches/WOF2-1/tests/ibat/user/SOURCES new file mode 100644 index 00000000..99f5ed7e --- /dev/null +++ b/branches/WOF2-1/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-1/tests/ibat/user/makefile b/branches/WOF2-1/tests/ibat/user/makefile new file mode 100644 index 00000000..128ed372 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/limits/dirs b/branches/WOF2-1/tests/limits/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-1/tests/limits/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/tests/limits/user/SOURCES b/branches/WOF2-1/tests/limits/user/SOURCES new file mode 100644 index 00000000..b6059f76 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/limits/user/limits_main.c b/branches/WOF2-1/tests/limits/user/limits_main.c new file mode 100644 index 00000000..c23f2d42 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/limits/user/makefile b/branches/WOF2-1/tests/limits/user/makefile new file mode 100644 index 00000000..9c985f57 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/dirs b/branches/WOF2-1/tests/perftest/dirs new file mode 100644 index 00000000..de675306 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/perftest.c b/branches/WOF2-1/tests/perftest/perftest.c new file mode 100644 index 00000000..10136635 --- /dev/null +++ b/branches/WOF2-1/tests/perftest/perftest.c @@ -0,0 +1,174 @@ +/* + * 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 +#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-1/tests/perftest/perftest.h b/branches/WOF2-1/tests/perftest/perftest.h new file mode 100644 index 00000000..d06e42d0 --- /dev/null +++ b/branches/WOF2-1/tests/perftest/perftest.h @@ -0,0 +1,50 @@ +/* + * 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 +#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-1/tests/perftest/rdma_bw/SOURCES b/branches/WOF2-1/tests/perftest/rdma_bw/SOURCES new file mode 100644 index 00000000..f0bbf0e4 --- /dev/null +++ b/branches/WOF2-1/tests/perftest/rdma_bw/SOURCES @@ -0,0 +1,32 @@ +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; + +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-1/tests/perftest/rdma_bw/makefile b/branches/WOF2-1/tests/perftest/rdma_bw/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/rdma_bw/rdma_bw.c b/branches/WOF2-1/tests/perftest/rdma_bw/rdma_bw.c new file mode 100644 index 00000000..c09f13d8 --- /dev/null +++ b/branches/WOF2-1/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 "..\..\..\etc\user\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, *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_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, *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) +{ + 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-1/tests/perftest/rdma_bw/rdma_bw.rc b/branches/WOF2-1/tests/perftest/rdma_bw/rdma_bw.rc new file mode 100644 index 00000000..70745e7a --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/rdma_lat/SOURCES b/branches/WOF2-1/tests/perftest/rdma_lat/SOURCES new file mode 100644 index 00000000..c1e26ada --- /dev/null +++ b/branches/WOF2-1/tests/perftest/rdma_lat/SOURCES @@ -0,0 +1,32 @@ +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; + +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-1/tests/perftest/rdma_lat/makefile b/branches/WOF2-1/tests/perftest/rdma_lat/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/rdma_lat/rdma_lat.c b/branches/WOF2-1/tests/perftest/rdma_lat/rdma_lat.c new file mode 100644 index 00000000..41be5a26 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/rdma_lat/rdma_lat.rc b/branches/WOF2-1/tests/perftest/rdma_lat/rdma_lat.rc new file mode 100644 index 00000000..96b19557 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/read_bw/SOURCES b/branches/WOF2-1/tests/perftest/read_bw/SOURCES new file mode 100644 index 00000000..0c28233c --- /dev/null +++ b/branches/WOF2-1/tests/perftest/read_bw/SOURCES @@ -0,0 +1,29 @@ +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; + +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-1/tests/perftest/read_bw/makefile b/branches/WOF2-1/tests/perftest/read_bw/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/read_bw/read_bw.c b/branches/WOF2-1/tests/perftest/read_bw/read_bw.c new file mode 100644 index 00000000..62137179 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/read_bw/read_bw.rc b/branches/WOF2-1/tests/perftest/read_bw/read_bw.rc new file mode 100644 index 00000000..2f131528 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/read_lat/SOURCES b/branches/WOF2-1/tests/perftest/read_lat/SOURCES new file mode 100644 index 00000000..2aebbe01 --- /dev/null +++ b/branches/WOF2-1/tests/perftest/read_lat/SOURCES @@ -0,0 +1,29 @@ +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; + +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-1/tests/perftest/read_lat/makefile b/branches/WOF2-1/tests/perftest/read_lat/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/read_lat/read_lat.c b/branches/WOF2-1/tests/perftest/read_lat/read_lat.c new file mode 100644 index 00000000..0d334075 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/read_lat/read_lat.rc b/branches/WOF2-1/tests/perftest/read_lat/read_lat.rc new file mode 100644 index 00000000..b35d8321 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/send_bw/SOURCES b/branches/WOF2-1/tests/perftest/send_bw/SOURCES new file mode 100644 index 00000000..907bcfb1 --- /dev/null +++ b/branches/WOF2-1/tests/perftest/send_bw/SOURCES @@ -0,0 +1,29 @@ +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; + +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-1/tests/perftest/send_bw/makefile b/branches/WOF2-1/tests/perftest/send_bw/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/send_bw/send_bw.c b/branches/WOF2-1/tests/perftest/send_bw/send_bw.c new file mode 100644 index 00000000..3a736d82 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/send_bw/send_bw.rc b/branches/WOF2-1/tests/perftest/send_bw/send_bw.rc new file mode 100644 index 00000000..192ed112 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/send_lat/SOURCES b/branches/WOF2-1/tests/perftest/send_lat/SOURCES new file mode 100644 index 00000000..e92f25b7 --- /dev/null +++ b/branches/WOF2-1/tests/perftest/send_lat/SOURCES @@ -0,0 +1,29 @@ +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; + +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-1/tests/perftest/send_lat/makefile b/branches/WOF2-1/tests/perftest/send_lat/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/send_lat/send_lat.c b/branches/WOF2-1/tests/perftest/send_lat/send_lat.c new file mode 100644 index 00000000..57958038 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/send_lat/send_lat.rc b/branches/WOF2-1/tests/perftest/send_lat/send_lat.rc new file mode 100644 index 00000000..f70c64da --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/write_bw/SOURCES b/branches/WOF2-1/tests/perftest/write_bw/SOURCES new file mode 100644 index 00000000..4e7a5a16 --- /dev/null +++ b/branches/WOF2-1/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; + +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-1/tests/perftest/write_bw/makefile b/branches/WOF2-1/tests/perftest/write_bw/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/write_bw/write_bw.c b/branches/WOF2-1/tests/perftest/write_bw/write_bw.c new file mode 100644 index 00000000..194899f5 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/write_bw/write_bw.rc b/branches/WOF2-1/tests/perftest/write_bw/write_bw.rc new file mode 100644 index 00000000..fc997c6a --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/write_bw_postlist/SOURCES b/branches/WOF2-1/tests/perftest/write_bw_postlist/SOURCES new file mode 100644 index 00000000..c31e7564 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/write_bw_postlist/makefile b/branches/WOF2-1/tests/perftest/write_bw_postlist/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/write_bw_postlist/write_bw_postlist.c b/branches/WOF2-1/tests/perftest/write_bw_postlist/write_bw_postlist.c new file mode 100644 index 00000000..d80a7a5b --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/write_bw_postlist/write_bw_postlist.rc b/branches/WOF2-1/tests/perftest/write_bw_postlist/write_bw_postlist.rc new file mode 100644 index 00000000..0f144d37 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/write_lat/SOURCES b/branches/WOF2-1/tests/perftest/write_lat/SOURCES new file mode 100644 index 00000000..f869ff1a --- /dev/null +++ b/branches/WOF2-1/tests/perftest/write_lat/SOURCES @@ -0,0 +1,29 @@ +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; + +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-1/tests/perftest/write_lat/makefile b/branches/WOF2-1/tests/perftest/write_lat/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/write_lat/write_lat.c b/branches/WOF2-1/tests/perftest/write_lat/write_lat.c new file mode 100644 index 00000000..af7d782c --- /dev/null +++ b/branches/WOF2-1/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-1/tests/perftest/write_lat/write_lat.rc b/branches/WOF2-1/tests/perftest/write_lat/write_lat.rc new file mode 100644 index 00000000..4d028fd0 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/wherebu/dirs b/branches/WOF2-1/tests/wherebu/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-1/tests/wherebu/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/tests/wherebu/user/SOURCES b/branches/WOF2-1/tests/wherebu/user/SOURCES new file mode 100644 index 00000000..f2f18046 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/wherebu/user/makefile b/branches/WOF2-1/tests/wherebu/user/makefile new file mode 100644 index 00000000..128ed372 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/wherebu/user/wherebu.cpp b/branches/WOF2-1/tests/wherebu/user/wherebu.cpp new file mode 100644 index 00000000..c87ed852 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/wsd/dirs b/branches/WOF2-1/tests/wsd/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-1/tests/wsd/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/tests/wsd/user/contest/contest.c b/branches/WOF2-1/tests/wsd/user/contest/contest.c new file mode 100644 index 00000000..78012031 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/wsd/user/test2/ibwrap.c b/branches/WOF2-1/tests/wsd/user/test2/ibwrap.c new file mode 100644 index 00000000..50a6cce4 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/wsd/user/test2/ibwrap.h b/branches/WOF2-1/tests/wsd/user/test2/ibwrap.h new file mode 100644 index 00000000..0b30d8c4 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/wsd/user/test2/test2.c b/branches/WOF2-1/tests/wsd/user/test2/test2.c new file mode 100644 index 00000000..5a1348b0 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/wsd/user/test3/ibwrap.c b/branches/WOF2-1/tests/wsd/user/test3/ibwrap.c new file mode 100644 index 00000000..dd3e90d3 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/wsd/user/test3/ibwrap.h b/branches/WOF2-1/tests/wsd/user/test3/ibwrap.h new file mode 100644 index 00000000..c4e4ec37 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/wsd/user/test3/test3.c b/branches/WOF2-1/tests/wsd/user/test3/test3.c new file mode 100644 index 00000000..a202da82 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/wsd/user/ttcp/SOURCES b/branches/WOF2-1/tests/wsd/user/ttcp/SOURCES new file mode 100644 index 00000000..2012f091 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/wsd/user/ttcp/makefile b/branches/WOF2-1/tests/wsd/user/ttcp/makefile new file mode 100644 index 00000000..9c985f57 --- /dev/null +++ b/branches/WOF2-1/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-1/tests/wsd/user/ttcp/ttcp.c b/branches/WOF2-1/tests/wsd/user/ttcp/ttcp.c new file mode 100644 index 00000000..aba293e3 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/dirs b/branches/WOF2-1/tools/dirs new file mode 100644 index 00000000..58507221 --- /dev/null +++ b/branches/WOF2-1/tools/dirs @@ -0,0 +1,9 @@ +DIRS = \ + wsdinstall \ + vstat \ + nsc \ + perftests \ + part_man \ + infiniband-diags \ + qlgcvnic_config \ + ndinstall diff --git a/branches/WOF2-1/tools/infiniband-diags/dirs b/branches/WOF2-1/tools/infiniband-diags/dirs new file mode 100644 index 00000000..60fcb0f9 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/dirs @@ -0,0 +1 @@ +DIRS = src diff --git a/branches/WOF2-1/tools/infiniband-diags/include/grouping.h b/branches/WOF2-1/tools/infiniband-diags/include/grouping.h new file mode 100644 index 00000000..811e372f --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/include/ibdiag_common.h b/branches/WOF2-1/tools/infiniband-diags/include/ibdiag_common.h new file mode 100644 index 00000000..5c74b072 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/include/ibdiag_common.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2006-2007 The Regents of the University of California. + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _IBDIAG_COMMON_H_ +#define _IBDIAG_COMMON_H_ + +#include + +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 || ibverbose) IBWARN(fmt, ## __VA_ARGS__); \ +} while (0) +#define VERBOSE(fmt, ...) do { \ + if (ibdebug || ibverbose > 1) IBWARN(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-1/tools/infiniband-diags/include/ibnetdiscover.h b/branches/WOF2-1/tools/infiniband-diags/include/ibnetdiscover.h new file mode 100644 index 00000000..02266155 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/include/windows/config.h b/branches/WOF2-1/tools/infiniband-diags/include/windows/config.h new file mode 100644 index 00000000..e5d7c134 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/include/windows/config.h @@ -0,0 +1,41 @@ +/* + * 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 <../../../../ulp/libibverbs/include/infiniband/verbs.h> + +#include <_string.h> + +#endif /* _CONFIG_H_ */ diff --git a/branches/WOF2-1/tools/infiniband-diags/include/windows/ibdiag_version.h b/branches/WOF2-1/tools/infiniband-diags/include/windows/ibdiag_version.h new file mode 100644 index 00000000..6464d3e5 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/patches/ibping-cdecl.diff b/branches/WOF2-1/tools/infiniband-diags/patches/ibping-cdecl.diff new file mode 100644 index 00000000..50a309a1 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/dirs b/branches/WOF2-1/tools/infiniband-diags/src/dirs new file mode 100644 index 00000000..822f3257 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/grouping.c b/branches/WOF2-1/tools/infiniband-diags/src/grouping.c new file mode 100644 index 00000000..048efc74 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibaddr.c b/branches/WOF2-1/tools/infiniband-diags/src/ibaddr.c new file mode 100644 index 00000000..7909a528 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/ibaddr.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "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-1/tools/infiniband-diags/src/ibaddr/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/ibaddr/SOURCES new file mode 100644 index 00000000..1a98f88c --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibaddr/ibaddr.rc b/branches/WOF2-1/tools/infiniband-diags/src/ibaddr/ibaddr.rc new file mode 100644 index 00000000..c7341a87 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibaddr/makefile b/branches/WOF2-1/tools/infiniband-diags/src/ibaddr/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibdiag_common.c b/branches/WOF2-1/tools/infiniband-diags/src/ibdiag_common.c new file mode 100644 index 00000000..4ffa3f0a --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/ibdiag_common.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2006-2007 The Regents of the University of California. + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/** + * Define common functions which can be included in the various C based diags. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#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", 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(2); + 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-1/tools/infiniband-diags/src/ibdiag_windows.c b/branches/WOF2-1/tools/infiniband-diags/src/ibdiag_windows.c new file mode 100644 index 00000000..419dde92 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/iblinkinfo.c b/branches/WOF2-1/tools/infiniband-diags/src/iblinkinfo.c new file mode 100644 index 00000000..cf38ecb2 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/iblinkinfo.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2004-2007 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 + +char *argv0 = "iblinkinfotest"; +static FILE *f; + +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; + +static int timeout_ms = 500; + +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 int v = num; // 32-bit word to find the log base 2 of + unsigned r = 0; // r will be lg(v) + + while (v >>= 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'; + + n = snprintf(link_str, 256, "(%3s %s %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)); + + if (add_sw_settings) + 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); +} + +void +usage(void) +{ + fprintf(stderr, + "Usage: %s [-hclp -S -D -C -P ]\n" + " Report link speed and connection for each port of each switch which is active\n" + " -h This help message\n" + " -S output only the node specified by guid\n" + " -D print only node specified by \n" + " -f specify node to start \"from\"\n" + " -n Number of hops to include away from specified node\n" + " -d print only down links\n" + " -l (line mode) print all information for each link on each line\n" + " -p print additional switch settings (PktLifeTime,HoqLife,VLStallCount)\n" + + + " -t timeout for any single fabric query\n" + " -s show progress during scan\n" + " --node-name-map use specified node name map\n" + + " -C use selected Channel Adaptor name for queries\n" + " -P use selected channel adaptor port for queries\n" + " -g print port guids instead of node guids\n" + " --debug print debug messages\n" + " -R (this option is obsolete and does nothing)\n" + , + argv0); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int rc = 0; + char *ca = 0; + int ca_port = 0; + ibnd_fabric_t *fabric = NULL; + uint64_t guid = 0; + char *guid_str = NULL; + char *dr_path = NULL; + char *from = NULL; + int hops = 0; + ib_portid_t port_id = {0}; + + struct ibmad_port *ibmad_port; + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + + static char const str_opts[] = "S:D:n:C:P:t:sldgphuf:R"; + static const struct option long_opts[] = { + { "S", 1, 0, 'S'}, + { "D", 1, 0, 'D'}, + { "num-hops", 1, 0, 'n'}, + { "down-links-only", 0, 0, 'd'}, + { "line-mode", 0, 0, 'l'}, + { "ca-name", 1, 0, 'C'}, + { "ca-port", 1, 0, 'P'}, + { "timeout", 1, 0, 't'}, + { "show", 0, 0, 's'}, + { "print-port-guids", 0, 0, 'g'}, + { "print-additional", 0, 0, 'p'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { "node-name-map", 1, 0, 1}, + { "debug", 0, 0, 2}, + { "compat", 0, 0, 3}, + { "from", 1, 0, 'f'}, + { "R", 0, 0, 'R'}, + { 0 } + }; + + f = stdout; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 1: + node_name_map_file = strdup(optarg); + break; + case 2: + ibnd_debug(1); + break; + case 'f': + from = strdup(optarg); + break; + case 'C': + ca = strdup(optarg); + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'D': + dr_path = strdup(optarg); + break; + case 'n': + hops = (int)strtol(optarg, NULL, 0); + break; + case 'd': + down_links_only = 1; + break; + case 'l': + line_mode = 1; + break; + case 't': + timeout_ms = strtoul(optarg, 0, 0); + break; + case 's': + ibnd_show_progress(1); + break; + case 'g': + print_port_guids = 1; + break; + case 'S': + guid_str = optarg; + guid = (uint64_t)strtoull(guid_str, 0, 0); + break; + case 'p': + add_sw_settings = 1; + break; + case 'R': + /* GNDN */ + break; + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc && !(f = fopen(argv[0], "w"))) + fprintf(stderr, "can't open file %s for writing", argv[0]); + + ibmad_port = mad_rpc_open_port(ca, ca_port, mgmt_classes, 3); + if (!ibmad_port) { + fprintf(stderr, "Failed to open %s port %d", ca, ca_port); + exit(1); + } + + node_name_map = open_node_name_map(node_name_map_file); + + if (from) { + /* only scan part of the fabric */ + str2drpath(&(port_id.drpath), from, 0, 0); + if ((fabric = ibnd_discover_fabric(ibmad_port, timeout_ms, &port_id, hops)) == NULL) { + fprintf(stderr, "discover failed\n"); + rc = 1; + goto close_port; + } + guid = 0; + } else if (guid_str) { + if (ib_resolve_portid_str_via(&port_id, guid_str, IB_DEST_GUID, + NULL, ibmad_port) >= 0) { + if ((fabric = ibnd_discover_fabric(ibmad_port, + timeout_ms, &port_id, 1)) == NULL) + IBWARN("Single node discover failed; attempting full scan\n"); + } else + IBWARN("Failed to resolve %s; attempting full scan\n", + guid_str); + } + + if (!fabric) /* do a full scan */ + if ((fabric = ibnd_discover_fabric(ibmad_port, timeout_ms, NULL, -1)) == NULL) { + fprintf(stderr, "discover failed\n"); + rc = 1; + goto close_port; + } + + if (guid) { + ibnd_node_t *sw = ibnd_find_node_guid(fabric, guid); + print_switch(sw, NULL); + } else if (dr_path) { + ibnd_node_t *sw = ibnd_find_node_dr(fabric, dr_path); + print_switch(sw, NULL); + } 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-1/tools/infiniband-diags/src/iblinkinfo/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/iblinkinfo/SOURCES new file mode 100644 index 00000000..ee5de7bb --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/iblinkinfo/iblinkinfo.rc b/branches/WOF2-1/tools/infiniband-diags/src/iblinkinfo/iblinkinfo.rc new file mode 100644 index 00000000..9dfb7538 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/iblinkinfo/makefile b/branches/WOF2-1/tools/infiniband-diags/src/iblinkinfo/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibnetdiscover.c b/branches/WOF2-1/tools/infiniband-diags/src/ibnetdiscover.c new file mode 100644 index 00000000..17996189 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/ibnetdiscover.c @@ -0,0 +1,697 @@ +/* + * Copyright (c) 2004-2008 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) + +struct ibmad_port *srcport; + +static int timeout = 2000; /* ms */ +static FILE *f; + +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; + +/** + * 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) +{ + uint64_t sysimgguid = mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F); + + fprintf(f, "\nvendid=0x%x\ndevid=0x%x\n", + mad_get_field(node->info, 0, IB_NODE_VENDORID_F), + mad_get_field(node->info, 0, IB_NODE_DEVID_F)); + if (sysimgguid) + fprintf(f, "sysimgguid=0x%" PRIx64, 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(ibnd_node_t *node, int group, char *chname) +{ + char *str; + char str2[256]; + char *nodename = NULL; + + out_ids(node, group, chname); + fprintf(f, "switchguid=0x%" PRIx64, node->guid); + fprintf(f, "(%" PRIx64 ")", mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F)); + if (group) { + 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); + } + + nodename = remap_node_name(node_name_map, node->guid, node->nodedesc); + + fprintf(f, "\nSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d\n", + node->numports, node_name(node), nodename, + node->smaenhsp0 ? "enhanced" : "base", + node->smalid, node->smalmc); + + free(nodename); +} + +void +out_ca(ibnd_node_t *node, int group, char *chname) +{ + char *node_type; + char *node_type2; + + out_ids(node, group, chname); + switch(node->type) { + case IB_NODE_CA: + node_type = "ca"; + node_type2 = "Ca"; + break; + case IB_NODE_ROUTER: + node_type = "rt"; + node_type2 = "Rt"; + break; + default: + node_type = "???"; + node_type2 = "???"; + break; + } + + fprintf(f, "%sguid=0x%" PRIx64 "\n", node_type, node->guid); + fprintf(f, "%s\t%d %s\t\t# \"%s\"", + node_type2, node->numports, node_name(node), + clean_nodedesc(node->nodedesc)); + 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 *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, "[%d]", port->portnum); + + ext_port_str = out_ext_port(port, group); + if (ext_port_str) + fprintf(f, "%s", ext_port_str); + + rem_nodename = remap_node_name(node_name_map, + port->remoteport->node->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 *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, "[%d]", 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); + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (port && port->remoteport) + out_switch_port(port, data->group); + } +} + +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); + + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (port && port->remoteport) + out_ca_port(port, data->group); + } +} + +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); + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (port && port->remoteport) + out_ca_port(port, data->group); + } +} + +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)); + fprintf(f, "# Max of %d hops discovered\n", fabric->maxhops_discovered); + 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; +/** + * Will this work for Xsigo? + */ + 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); + for (p = 1; p <= ch->spinenode[n]->numports; p++) { + port = ch->spinenode[n]->ports[p]; + if (port && port->remoteport) + out_switch_port(port, group); + } + } + } + fprintf(f, "\n# Line Nodes"); + for (n = 1; n <= LINES_MAX_NUM; n++) { + if (ch->linenode[n]) { + out_switch(ch->linenode[n], group, chname); + for (p = 1; p <= ch->linenode[n]->numports; p++) { + port = ch->linenode[n]->ports[p]; + if (port && port->remoteport) + out_switch_port(port, group); + } + } + } + + 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); + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (port && port->remoteport) + out_switch_port(port, group); + } + } + + } + + 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); + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (port && port->remoteport) + out_ca_port(port, group); + } + } + } + + } + + + } 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); + } +} + +static int list, group, ports_report; + +static int process_opt(void *context, int ch, char *optarg) +{ + switch (ch) { + case 1: + node_name_map_file = strdup(optarg); + break; + case 's': + ibnd_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; + default: + return -1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + ibnd_fabric_t *fabric = NULL; + + struct ibmad_port *ibmad_port; + int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS}; + + 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" }, + { "ports", 'p', 0, NULL, "obtain a ports report" }, + { 0 } + }; + char usage_args[] = "[topology-file]"; + + ibdiag_process_opts(argc, argv, NULL, "sGDL", opts, process_opt, + usage_args, NULL); + + f = stdout; + + argc -= optind; + argv += optind; + + if (ibd_timeout) + timeout = ibd_timeout; + + if (ibverbose) + ibnd_debug(1); + + ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 2); + if (!ibmad_port) + IBERROR("Failed to open %s port %d", ibd_ca, ibd_ca_port); + + 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 ((fabric = ibnd_discover_fabric(ibmad_port, ibd_timeout, NULL, -1)) == NULL) + IBERROR("discover failed\n"); + + if (ports_report) + ibnd_iter_nodes(fabric, + dump_ports_report, + NULL); + else if (list) + list_nodes(fabric, list); + else + dump_topology(group, fabric); + + ibnd_destroy_fabric(fabric); + close_node_name_map(node_name_map); + mad_rpc_close_port(ibmad_port); + exit(0); +} diff --git a/branches/WOF2-1/tools/infiniband-diags/src/ibnetdiscover/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/ibnetdiscover/SOURCES new file mode 100644 index 00000000..03f03844 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibnetdiscover/ibnetdiscover.rc b/branches/WOF2-1/tools/infiniband-diags/src/ibnetdiscover/ibnetdiscover.rc new file mode 100644 index 00000000..8f3509a3 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibnetdiscover/makefile b/branches/WOF2-1/tools/infiniband-diags/src/ibnetdiscover/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibping.c b/branches/WOF2-1/tools/infiniband-diags/src/ibping.c new file mode 100644 index 00000000..7da48e2d --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/ibping.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +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-1/tools/infiniband-diags/src/ibping/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/ibping/SOURCES new file mode 100644 index 00000000..2b187a8b --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibping/ibping.rc b/branches/WOF2-1/tools/infiniband-diags/src/ibping/ibping.rc new file mode 100644 index 00000000..62ee7657 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibping/makefile b/branches/WOF2-1/tools/infiniband-diags/src/ibping/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibportstate.c b/branches/WOF2-1/tools/infiniband-diags/src/ibportstate.c new file mode 100644 index 00000000..65c9ca19 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/ibportstate.c @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "ibdiag_common.h" + +struct ibmad_port *srcport; + +/*******************************************/ + +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)) + return -1; + + node_type = mad_get_field(data, 0, IB_NODE_TYPE_F); + if (node_type == IB_NODE_SWITCH) /* Switch NodeType ? */ + return 0; + else + return 1; +} + +static int +get_port_info(ib_portid_t *dest, uint8_t *data, int portnum, int port_op) +{ + char buf[2048]; + char val[64]; + + if (!smp_query_via(data, dest, IB_ATTR_PORT_INFO, portnum, 0, srcport)) + return -1; + + if (port_op != 4) { + mad_dump_portstates(buf, sizeof buf, data, sizeof data); + mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, val); + mad_dump_field(IB_PORT_LINK_WIDTH_SUPPORTED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, val); + mad_dump_field(IB_PORT_LINK_WIDTH_ENABLED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, val); + mad_dump_field(IB_PORT_LINK_WIDTH_ACTIVE_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_SUPPORTED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_ACTIVE_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + } else { + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf, sizeof buf, val); + sprintf(buf+strlen(buf), "%s", "\n"); + } + + printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf); + return 0; +} + +static int +set_port_info(ib_portid_t *dest, uint8_t *data, int portnum, int port_op) +{ + char buf[2048]; + char val[64]; + + if (!smp_set_via(data, dest, IB_ATTR_PORT_INFO, portnum, 0, srcport)) + return -1; + + if (port_op != 4) + mad_dump_portstates(buf, sizeof buf, data, sizeof data); + else { + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf, sizeof buf, val); + sprintf(buf+strlen(buf), "%s", "\n"); + } + + printf("\nAfter PortInfo set:\n"); + printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf); + return 0; +} + +static int +get_link_width(int lwe, int lws) +{ + if (lwe == 255) + return lws; + else + return lwe; +} + +static int +get_link_speed(int lse, int lss) +{ + if (lse == 15) + return lss; + else + return lse; +} + +static void +validate_width(int width, int peerwidth, int lwa) +{ + if ((width & 0x8) && (peerwidth & 0x8)) { + if (lwa != 8) + IBWARN("Peer ports operating at active width %d rather than 8 (12x)", lwa); + } else { + if ((width & 0x4) && (peerwidth & 0x4)) { + if (lwa != 4) + IBWARN("Peer ports operating at active width %d rather than 4 (8x)", lwa); + } else { + if ((width & 0x2) && (peerwidth & 0x2)) { + if (lwa != 2) + IBWARN("Peer ports operating at active width %d rather than 2 (4x)", lwa); + } else { + if ((width & 0x1) && (peerwidth & 0x1)) { + if (lwa != 1) + IBWARN("Peer ports operating at active width %d rather than 1 (1x)", lwa); + } + } + } + } +} + +static void +validate_speed(int speed, int peerspeed, int lsa) +{ + if ((speed & 0x4) && (peerspeed & 0x4)) { + if (lsa != 4) + IBWARN("Peer ports operating at active speed %d rather than 4 (10.0 Gbps)", lsa); + } else { + if ((speed & 0x2) && (peerspeed & 0x2)) { + if (lsa != 2) + IBWARN("Peer ports operating at active speed %d rather than 2 (5.0 Gbps)", lsa); + } else { + if ((speed & 0x1) && (peerspeed & 0x1)) { + if (lsa != 1) + IBWARN("Peer ports operating at active speed %d rather than 1 (2.5 Gbps)", lsa); + } + } + } +} + +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 err; + int port_op = 0; /* default to query */ + int speed = 15; + int is_switch = 1; + int state, physstate, lwe, lws, lwa, lse, lss, lsa; + int peerlocalportnum, peerlwe, peerlws, peerlwa, peerlse, peerlss, peerlsa; + int width, peerwidth, peerspeed; + uint8_t data[IB_SMP_DATA_SIZE]; + ib_portid_t peerportid = {0}; + int portnum = 0; + ib_portid_t selfportid = {0}; + int selfport = 0; + + char usage_args[] = " []\n" + "\nSupported ops: enable, disable, reset, speed, query"; + 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", + 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]); + + /* First, make sure it is a switch port if it is a "set" */ + if (argc >= 3) { + if (!strcmp(argv[2], "enable")) + port_op = 1; + else if (!strcmp(argv[2], "disable")) + port_op = 2; + else if (!strcmp(argv[2], "reset")) + port_op = 3; + else if (!strcmp(argv[2], "speed")) { + if (argc < 4) + IBERROR("speed requires an additional parameter"); + port_op = 4; + /* Parse speed value */ + speed = strtoul(argv[3], 0, 0); + if (speed > 15) + IBERROR("invalid speed value %d", speed); + } + } + + err = get_node_info(&portid, data); + if (err < 0) + IBERROR("smp query nodeinfo failed"); + if (err) { /* not switch */ + if (port_op == 0) /* query op */ + is_switch = 0; + else if (port_op != 4) /* other than speed op */ + IBERROR("smp query nodeinfo: Node type not switch"); + } + + if (argc-1 > 0) + portnum = strtol(argv[1], 0, 0); + + if (port_op) + printf("Initial PortInfo:\n"); + else + printf("PortInfo:\n"); + err = get_port_info(&portid, data, portnum, port_op); + if (err < 0) + IBERROR("smp query portinfo failed"); + + /* Only if one of the "set" options is chosen */ + if (port_op) { + if (port_op == 1) /* Enable port */ + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2); /* Polling */ + else if ((port_op == 2) || (port_op == 3)) { /* Disable port */ + mad_set_field(data, 0, IB_PORT_STATE_F, 1); /* Down */ + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 3); /* Disabled */ + } else if (port_op == 4) { /* Set speed */ + mad_set_field(data, 0, IB_PORT_LINK_SPEED_ENABLED_F, speed); + mad_set_field(data, 0, IB_PORT_STATE_F, 0); + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 0); + } + + err = set_port_info(&portid, data, portnum, port_op); + if (err < 0) + IBERROR("smp set portinfo failed"); + + if (port_op == 3) { /* Reset port - so also enable */ + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2); /* Polling */ + err = set_port_info(&portid, data, portnum, port_op); + if (err < 0) + IBERROR("smp set portinfo failed"); + } + } else { /* query op */ + /* only compare peer port if switch port */ + if (is_switch) { + /* First, exclude SP0 */ + if (portnum) { + /* Now, make sure PortState is Active */ + /* Or is PortPhysicalState LinkUp sufficient ? */ + mad_decode_field(data, IB_PORT_STATE_F, &state); + mad_decode_field(data, IB_PORT_PHYS_STATE_F, &physstate); + if (state == 4) { /* Active */ + mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, &lwe ); + mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, &lws); + mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, &lwa); + mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, &lss); + mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, &lsa); + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, &lse); + + /* Setup portid for peer port */ + memcpy(&peerportid, &portid, sizeof(peerportid)); + peerportid.drpath.cnt = 1; + peerportid.drpath.p[1] = (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 */ + err = get_node_info(&peerportid, data); + if (err < 0) + IBERROR("smp query nodeinfo failed"); + + mad_decode_field(data, IB_NODE_LOCAL_PORT_F, &peerlocalportnum); + + printf("Peer PortInfo:\n"); + /* Get peer port characteristics */ + err = get_port_info(&peerportid, data, peerlocalportnum, port_op); + if (err < 0) + IBERROR("smp query peer portinfofailed"); + + mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, &peerlwe ); + mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, &peerlws); + mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, &peerlwa); + mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, &peerlss); + mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, &peerlsa); + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, &peerlse); + + /* Now validate peer port characteristics */ + /* Examine Link Width */ + width = get_link_width(lwe, lws); + peerwidth = get_link_width(peerlwe, peerlws); + validate_width(width, peerwidth, lwa); + + /* Examine Link Speed */ + speed = get_link_speed(lse, lss); + peerspeed = get_link_speed(peerlse, peerlss); + validate_speed(speed, peerspeed, lsa); + } + } + } + } + + mad_rpc_close_port(srcport); + exit(0); +} diff --git a/branches/WOF2-1/tools/infiniband-diags/src/ibportstate/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/ibportstate/SOURCES new file mode 100644 index 00000000..da92223e --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibportstate/ibportstate.rc b/branches/WOF2-1/tools/infiniband-diags/src/ibportstate/ibportstate.rc new file mode 100644 index 00000000..8ba95aff --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibportstate/makefile b/branches/WOF2-1/tools/infiniband-diags/src/ibportstate/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibqueryerrors.c b/branches/WOF2-1/tools/infiniband-diags/src/ibqueryerrors.c new file mode 100644 index 00000000..525af709 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/ibqueryerrors.c @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2004-2007 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 + +#include "ibdiag_common.h" + +struct ibmad_port *ibmad_port; +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; +int data_counters = 0; +int port_config = 0; +uint64_t switch_guid = 0; +char *switch_guid_str = NULL; +int sup_total = 0; +enum MAD_FIELDS *suppressed_fields = NULL; +char *dr_path = NULL; +int all_nodes = 0; + +static unsigned int +get_max(unsigned int num) +{ + unsigned int v = num; // 32-bit word to find the log base 2 of + unsigned r = 0; // r will be lg(v) + + while (v >>= 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(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'; + + snprintf(link_str, 256, "(%3s %s %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)); + + 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); + + 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, + 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 (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; + if (suppressed_fields) + for (i = 0; i < sup_total; i++) { + if (field == suppressed_fields[i]) + return (1); + } + return (0); +} + +static void +report_suppressed(void) +{ + int i = 0; + if (suppressed_fields) { + printf("Suppressing:"); + for (i = 0; i < sup_total; i++) { + printf(" %s", mad_field_name(suppressed_fields[i])); + } + printf("\n"); + } +} + +static void +print_results(ibnd_node_t *node, uint8_t *pc, int portnum, int *header_printed) +{ + char buf[1024]; + char *str = buf; + uint32_t val = 0; + int n = 0; + int i = 0; + + for (n = 0, i = IB_PC_ERR_SYM_F; i <= IB_PC_VL15_DROPPED_F; i++) { + if (suppress(i)) + continue; + + mad_decode_field(pc, i, (void *)&val); + if (val) + n += snprintf(str+n, 1024-n, " [%s == %d]", + mad_field_name(i), val); + } + + 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 == %d]", mad_field_name(i), 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 == %"PRId64"]", + mad_field_name(i), val64); + } + + if (!*header_printed) { + char *nodename = remap_node_name(node_name_map, node->guid, node->nodedesc); + printf("Errors for 0x%" PRIx64 " \"%s\"\n", node->guid, nodename); + *header_printed = 1; + free(nodename); + } + + printf(" GUID 0x%" PRIx64 " port %d:%s\n", node->guid, portnum, str); + if (port_config) + print_port_config(node, portnum); + } +} + +static void +print_port(ibnd_node_t *node, int portnum, int *header_printed) +{ + uint8_t pc[1024]; + uint16_t cap_mask; + ib_portid_t portid = {0}; + char *nodename = remap_node_name(node_name_map, node->guid, node->nodedesc); + + if (node->type == IB_NODE_SWITCH) + ib_portid_set(&portid, node->smalid, 0, 0); + else + ib_portid_set(&portid, node->ports[portnum]->base_lid, 0, 0); + + /* 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", + nodename, portid2str(&portid), portnum); + goto cleanup; + } + /* ClassPortInfo should be supported as part of libibmad */ + memcpy(&cap_mask, pc + 2, sizeof(cap_mask)); /* CapabilityMask */ + + 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\n", + nodename, portid2str(&portid), portnum); + goto cleanup; + } + if (!(cap_mask & 0x1000)) { + /* if PortCounters:PortXmitWait not suppported clear this counter */ + uint32_t foo = 0; + mad_encode_field(pc, IB_PC_XMT_WAIT_F, &foo); + } + print_results(node, pc, portnum, header_printed); + +cleanup: + free(nodename); +} + +void +print_node(ibnd_node_t *node, void *user_data) +{ + int header_printed = 0; + int p = 0; + int startport = 1; + + if (!all_nodes && node->type != IB_NODE_SWITCH) + return; + + if (node->type == IB_NODE_SWITCH && node->smaenhsp0) + startport = 0; + + for (p = startport; p <= node->numports; p++) { + if (node->ports[p]) { + print_port(node, p, &header_printed); + } + } +} + +static void +add_suppressed(enum MAD_FIELDS field) +{ + suppressed_fields = realloc(suppressed_fields, sizeof(enum MAD_FIELDS)); + suppressed_fields[sup_total] = field; + sup_total++; +} + +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) +{ + 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: + all_nodes++; + break; + case 'S': + switch_guid_str = optarg; + switch_guid = strtoull(optarg, 0, 0); + break; + case 'D': + dr_path = strdup(optarg); + break; + case 'r': + port_config++; + break; + case 'R': /* nop */ + break; + default: + return -1; + } + + return 0; +} + +int +main(int argc, char **argv) +{ + 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" }, + { "switch", 'S', 1, "", "query only (hex format)"}, + { "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"}, + { "all", 3, 0, NULL, "output all nodes (not just switches)"}, + { 0 } + }; + char usage_args[] = ""; + + ibdiag_process_opts(argc, argv, "sDLG", "snSrR", opts, process_opt, + usage_args, NULL); + + argc -= optind; + argv += optind; + + if (ibverbose) + ibnd_debug(1); + + 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); + + node_name_map = open_node_name_map(node_name_map_file); + + if (switch_guid) { + /* limit the scan the fabric around the target */ + ib_portid_t portid = {0}; + + if (ib_resolve_portid_str_via(&portid, switch_guid_str, IB_DEST_GUID, + ibd_sm_id, ibmad_port) >= 0) { + if ((fabric = ibnd_discover_fabric(ibmad_port, ibd_timeout, &portid, 1)) == NULL) + IBWARN("Single node discover failed; attempting full scan\n"); + } else + IBWARN("Failed to resolve %s; attempting full scan\n", switch_guid_str); + } + + if (!fabric) /* do a full scan */ + if ((fabric = ibnd_discover_fabric(ibmad_port, ibd_timeout, NULL, -1)) == NULL) { + fprintf(stderr, "discover failed\n"); + rc = 1; + goto close_port; + } + + report_suppressed(); + + if (switch_guid) { + ibnd_node_t *node = ibnd_find_node_guid(fabric, switch_guid); + print_node(node, NULL); + } else if (dr_path) { + ibnd_node_t *node = ibnd_find_node_dr(fabric, dr_path); + print_node(node, NULL); + } else + ibnd_iter_nodes(fabric, print_node, NULL); + + 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-1/tools/infiniband-diags/src/ibqueryerrors/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/ibqueryerrors/SOURCES new file mode 100644 index 00000000..d1acafe8 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/ibqueryerrors/SOURCES @@ -0,0 +1,35 @@ +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 \ +!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-1/tools/infiniband-diags/src/ibqueryerrors/ibqueryerrors.rc b/branches/WOF2-1/tools/infiniband-diags/src/ibqueryerrors/ibqueryerrors.rc new file mode 100644 index 00000000..a14b4a05 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibqueryerrors/makefile b/branches/WOF2-1/tools/infiniband-diags/src/ibqueryerrors/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibroute.c b/branches/WOF2-1/tools/infiniband-diags/src/ibroute.c new file mode 100644 index 00000000..31b8e4cc --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/ibroute.c @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +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; + 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); + + if (!endlid || endlid > IB_MIN_MCAST_LID + cap - 1) + endlid = IB_MIN_MCAST_LID + cap - 1; + + if (!startlid) + startlid = IB_MIN_MCAST_LID; + + if (startlid < IB_MIN_MCAST_LID) { + IBWARN("illegal start mlid %x, set to %x", startlid, IB_MIN_MCAST_LID); + startlid = IB_MIN_MCAST_LID; + } + + if (endlid > IB_MAX_MCAST_LID) { + IBWARN("illegal end mlid %x, truncate to %x", endlid, IB_MAX_MCAST_LID); + endlid = IB_MAX_MCAST_LID; + } + + printf("Multicast mlids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 " (%s):\n", + startlid, endlid, portid2str(portid), nodeguid, clean_nodedesc(nd)); + + if (brief) + printf(" MLid Port Mask\n"); + else { + if (nports > 9) { + for (i = 0, s = str; i <= nports; i++) { + *s++ = (i%10) ? ' ' : '0' + i/10; + *s++ = ' '; + } + *s = 0; + printf(" %s\n", str); + } + for (i = 0, s = str; i <= nports; i++) + s += sprintf(s, "%d ", i%10); + printf(" Ports: %s\n", str); + printf(" MLid\n"); + } + if (ibverbose) + printf("Switch muticast mlids capability is 0x%d\n", cap); + + chunks = ALIGN(nports + 1, 16) / 16; + + startblock = startlid / IB_MLIDS_IN_BLOCK; + lastblock = endlid / IB_MLIDS_IN_BLOCK; + for (block = startblock; block <= lastblock; block++) { + for (j = 0; j < chunks; j++) { + mod = (block - IB_MIN_MCAST_LID/IB_MLIDS_IN_BLOCK) | (j << 28); + + DEBUG("reading block %x chunk %d mod %x", block, j, mod); + if (!smp_query_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("ilegal lft top %d, truncate to %d", endlid, IB_MAX_UCAST_LID); + endlid = IB_MAX_UCAST_LID; + } + + printf("Unicast lids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 " (%s):\n", + startlid, endlid, portid2str(portid), nodeguid, clean_nodedesc(nd)); + + DEBUG("Switch top is 0x%x\n", top); + + printf(" Lid Out Destination\n"); + printf(" Port Info \n"); + startblock = startlid / IB_SMP_DATA_SIZE; + endblock = ALIGN(endlid, IB_SMP_DATA_SIZE) / IB_SMP_DATA_SIZE; + for (block = startblock; block <= endblock; block++) { + DEBUG("reading block %d", block); + if (!smp_query_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-1/tools/infiniband-diags/src/ibroute/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/ibroute/SOURCES new file mode 100644 index 00000000..9c01dfcf --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibroute/ibroute.rc b/branches/WOF2-1/tools/infiniband-diags/src/ibroute/ibroute.rc new file mode 100644 index 00000000..8fa48bbf --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibroute/makefile b/branches/WOF2-1/tools/infiniband-diags/src/ibroute/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibsendtrap.c b/branches/WOF2-1/tools/infiniband-diags/src/ibsendtrap.c new file mode 100644 index 00000000..ac8dcf4e --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/ibsendtrap.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2008 Lawrence Livermore National Security + * Copyright (c) 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 void build_trap144(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.local_changes = + TRAP_144_MASK_OTHER_LOCAL_CHANGES; + n->data_details.ntc_144.change_flgs = + TRAP_144_MASK_NODE_DESCRIPTION_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; + +trap_def_t traps[3] = { + {"node_desc_change", build_trap144}, + {"local_link_integrity", build_trap129}, + {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-1/tools/infiniband-diags/src/ibsendtrap/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/ibsendtrap/SOURCES new file mode 100644 index 00000000..f50020db --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibsendtrap/ibsendtrap.rc b/branches/WOF2-1/tools/infiniband-diags/src/ibsendtrap/ibsendtrap.rc new file mode 100644 index 00000000..19e3e8f0 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibsendtrap/makefile b/branches/WOF2-1/tools/infiniband-diags/src/ibsendtrap/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibstat.c b/branches/WOF2-1/tools/infiniband-diags/src/ibstat.c new file mode 100644 index 00000000..06f39aec --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/ibstat.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#define _GNU_SOURCE + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +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)); + 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-1/tools/infiniband-diags/src/ibstat/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/ibstat/SOURCES new file mode 100644 index 00000000..e78103c9 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibstat/ibstat.rc b/branches/WOF2-1/tools/infiniband-diags/src/ibstat/ibstat.rc new file mode 100644 index 00000000..08dcd480 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibstat/makefile b/branches/WOF2-1/tools/infiniband-diags/src/ibstat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibsysstat.c b/branches/WOF2-1/tools/infiniband-diags/src/ibsysstat.c new file mode 100644 index 00000000..03c0515d --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/ibsysstat.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "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-1/tools/infiniband-diags/src/ibsysstat/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/ibsysstat/SOURCES new file mode 100644 index 00000000..4fb54642 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibsysstat/ibsysstat.rc b/branches/WOF2-1/tools/infiniband-diags/src/ibsysstat/ibsysstat.rc new file mode 100644 index 00000000..b1afa84f --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibsysstat/makefile b/branches/WOF2-1/tools/infiniband-diags/src/ibsysstat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibtracert.c b/branches/WOF2-1/tools/infiniband-diags/src/ibtracert.c new file mode 100644 index 00000000..a887157a --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/ibtracert.c @@ -0,0 +1,812 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "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-1/tools/infiniband-diags/src/ibtracert/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/ibtracert/SOURCES new file mode 100644 index 00000000..3f5b8065 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibtracert/ibtracert.rc b/branches/WOF2-1/tools/infiniband-diags/src/ibtracert/ibtracert.rc new file mode 100644 index 00000000..bca55815 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/ibtracert/makefile b/branches/WOF2-1/tools/infiniband-diags/src/ibtracert/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/mcm_rereg_test.c b/branches/WOF2-1/tools/infiniband-diags/src/mcm_rereg_test.c new file mode 100644 index 00000000..de5ea904 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/mcm_rereg_test.c @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2006 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#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-1/tools/infiniband-diags/src/mcm_rereg_test/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/mcm_rereg_test/SOURCES new file mode 100644 index 00000000..ac933ad2 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/mcm_rereg_test/makefile b/branches/WOF2-1/tools/infiniband-diags/src/mcm_rereg_test/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/mcm_rereg_test/mcm_rereg_test.rc b/branches/WOF2-1/tools/infiniband-diags/src/mcm_rereg_test/mcm_rereg_test.rc new file mode 100644 index 00000000..b10df8f6 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/perfquery.c b/branches/WOF2-1/tools/infiniband-diags/src/perfquery.c new file mode 100644 index 00000000..b0bda492 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/perfquery.c @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "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 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 suppported clear 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_perfcounters(buf, sizeof buf, pc, sizeof pc); + } else { + if (!(cap_mask & 0x200)) /* 1.2 errata: bit 9 is extended counter support */ + IBWARN("PerfMgt ClassPortInfo 0x%x extended counters not indicated\n", cap_mask); + + if (!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) + 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; + +void xmt_sl_query(ib_portid_t *portid, int port, int mask) +{ + char buf[1024]; + + if (reset_only) { + if (!performance_reset_via(pc, portid, port, mask, ibd_timeout, + IB_GSI_PORT_XMIT_DATA_SL, srcport)) + IBERROR("perfslreset"); + return; + } + + if (!pma_query_via(pc, portid, port, ibd_timeout, + IB_GSI_PORT_XMIT_DATA_SL, srcport)) + IBERROR("perfslquery"); + + mad_dump_perfcounters_xmt_sl(buf, sizeof buf, pc, sizeof pc); + printf("# PortXmitDataSL counters: %s port %d\n%s", portid2str(portid), port, buf); + + if (reset) + if (!performance_reset_via(pc, portid, port, mask, ibd_timeout, + IB_GSI_PORT_XMIT_DATA_SL, srcport)) + IBERROR("perfslreset"); +} + +void rcv_sl_query(ib_portid_t *portid, int port, int mask) +{ + char buf[1024]; + + if (reset_only) { + if (!performance_reset_via(pc, portid, port, mask, ibd_timeout, + IB_GSI_PORT_RCV_DATA_SL, srcport)) + IBERROR("perfslreset"); + return; + } + + if (!pma_query_via(pc, portid, port, ibd_timeout, + IB_GSI_PORT_RCV_DATA_SL, srcport)) + IBERROR("perfslquery"); + + mad_dump_perfcounters_rcv_sl(buf, sizeof buf, pc, sizeof pc); + printf("# PortRcvDataSL counters: %s port %d\n%s", portid2str(portid), port, buf); + + if (reset) + if (!performance_reset_via(pc, portid, port, mask, ibd_timeout, + IB_GSI_PORT_RCV_DATA_SL, srcport)) + IBERROR("perfslreset"); +} + +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 '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" }, + { "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 (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-1/tools/infiniband-diags/src/perfquery/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/perfquery/SOURCES new file mode 100644 index 00000000..2467aedd --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/perfquery/makefile b/branches/WOF2-1/tools/infiniband-diags/src/perfquery/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/perfquery/perfquery.rc b/branches/WOF2-1/tools/infiniband-diags/src/perfquery/perfquery.rc new file mode 100644 index 00000000..b555e062 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/saquery.c b/branches/WOF2-1/tools/infiniband-diags/src/saquery.c new file mode 100644 index 00000000..5920edab --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/saquery.c @@ -0,0 +1,1767 @@ +/* + * Copyright (c) 2006,2007 The Regents of the University of California. + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * Produced at Lawrence Livermore National Laboratory. + * Written by Ira Weiny . + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#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; + +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...............0x%X\n" + "\t\tsys_guid................0x%016" PRIx64 "\n" + "\t\tnode_guid...............0x%016" PRIx64 "\n" + "\t\tport_guid...............0x%016" PRIx64 "\n" + "\t\tpartition_cap...........0x%X\n" + "\t\tdevice_id...............0x%X\n" + "\t\trevision................0x%X\n" + "\t\tport_num................0x%X\n" + "\t\tvendor_id...............0x%X\n" + "\t\tNodeDescription.........%s\n", + cl_ntoh16(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....................0x%X\n" + "\t\tslid....................0x%X\n" + "\t\thop_flow_raw............0x%X\n" + "\t\ttclass..................0x%X\n" + "\t\tnum_path_revers.........0x%X\n" + "\t\tpkey....................0x%X\n" + "\t\tqos_class...............0x%X\n" + "\t\tsl......................0x%X\n" + "\t\tmtu.....................0x%X\n" + "\t\trate....................0x%X\n" + "\t\tpkt_life................0x%X\n" + "\t\tpreference..............0x%X\n" + "\t\tresv2...................0x%X\n" + "\t\tresv3...................0x%X\n", + cl_ntoh64(p_pr->service_id), + inet_ntop(AF_INET6, p_pr->dgid.raw, gid_str, sizeof gid_str), + inet_ntop(AF_INET6, p_pr->sgid.raw, gid_str2, sizeof gid_str2), + cl_ntoh16(p_pr->dlid), cl_ntoh16(p_pr->slid), + cl_ntoh32(p_pr->hop_flow_raw), p_pr->tclass, p_pr->num_path, + cl_ntoh16(p_pr->pkey), ib_path_rec_qos_class(p_pr), + ib_path_rec_sl(p_pr), p_pr->mtu, p_pr->rate, p_pr->pkt_life, + p_pr->preference, + *(uint32_t *) & p_pr->resv2, *((uint16_t *) & p_pr->resv2 + 2)); +} + +static void dump_class_port_info(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + ib_class_port_info_t *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.................0x%X\n" + "\t\tbase_lid................0x%X\n" + "\t\tmaster_sm_base_lid......0x%X\n" + "\t\tcapability_mask.........0x%X\n", + cl_ntoh16(p_pir->lid), p_pir->port_num, + cl_ntoh16(p_pi->base_lid), cl_ntoh16(p_pi->master_sm_base_lid), + cl_ntoh32(p_pi->capability_mask)); +} + +static void dump_one_portinfo_record(void *data) +{ + char buf[2048], buf2[4096]; + ib_portinfo_record_t *pir = data; + ib_port_info_t *pi = &pir->port_info; + + mad_dump_portinfo(buf, sizeof(buf), pi, sizeof(*pi)); + format_buf(buf, buf2, sizeof(buf2)); + printf("PortInfoRecord dump:\n" + "\tRID:\n" + "\t\tEndPortLid..............%u\n" + "\t\tPortNum.................0x%x\n" + "\t\tReserved................0x%x\n" + "\tPortInfo dump:\n\t\t%s", + cl_ntoh16(pir->lid), pir->port_num, pir->resv, buf2); +} + +static void dump_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.........0x%X\n" + "\t\tlid_range_end...........0x%X\n" + "\t\tis_generic..............0x%X\n" + "\t\tsubscribe...............0x%X\n" + "\t\ttrap_type...............0x%X\n" + "\t\ttrap_num................%u\n" + "\t\tqpn.....................0x%06X\n" + "\t\tresp_time_val...........0x%X\n" + "\t\tnode_type...............0x%06X\n", + inet_ntop(AF_INET6, p_iir->subscriber_gid.raw, gid_str, + sizeof gid_str), + cl_ntoh16(p_iir->subscriber_enum), + inet_ntop(AF_INET6, p_iir->inform_info.gid.raw, gid_str2, + sizeof gid_str2), + cl_ntoh16(p_iir->inform_info.lid_range_begin), + cl_ntoh16(p_iir->inform_info.lid_range_end), + p_iir->inform_info.is_generic, + p_iir->inform_info.subscribe, + cl_ntoh16(p_iir->inform_info.trap_type), + cl_ntoh16(p_iir->inform_info.g_or_v.generic.trap_num), + cl_ntoh32(qpn), resp_time_val, + cl_ntoh32(ib_inform_info_get_prod_type + (&p_iir->inform_info))); + else + printf("InformInfoRecord dump:\n" + "\t\tRID\n" + "\t\tSubscriberGID...........%s\n" + "\t\tSubscriberEnum..........0x%X\n" + "\t\tInformInfo dump:\n" + "\t\tgid.....................%s\n" + "\t\tlid_range_begin.........0x%X\n" + "\t\tlid_range_end...........0x%X\n" + "\t\tis_generic..............0x%X\n" + "\t\tsubscribe...............0x%X\n" + "\t\ttrap_type...............0x%X\n" + "\t\tdev_id..................0x%X\n" + "\t\tqpn.....................0x%06X\n" + "\t\tresp_time_val...........0x%X\n" + "\t\tvendor_id...............0x%06X\n", + inet_ntop(AF_INET6, p_iir->subscriber_gid.raw, gid_str, + sizeof gid_str), + cl_ntoh16(p_iir->subscriber_enum), + inet_ntop(AF_INET6, p_iir->inform_info.gid.raw, + gid_str2, sizeof gid_str2), + cl_ntoh16(p_iir->inform_info.lid_range_begin), + cl_ntoh16(p_iir->inform_info.lid_range_end), + p_iir->inform_info.is_generic, + p_iir->inform_info.subscribe, + cl_ntoh16(p_iir->inform_info.trap_type), + cl_ntoh16(p_iir->inform_info.g_or_v.vend.dev_id), + cl_ntoh32(qpn), resp_time_val, + cl_ntoh32(ib_inform_info_get_prod_type + (&p_iir->inform_info))); +} + +static void dump_one_link_record(void *data) +{ + ib_link_record_t *lr = data; + printf("LinkRecord dump:\n" + "\t\tFromLID....................%u\n" + "\t\tFromPort...................%u\n" + "\t\tToPort.....................%u\n" + "\t\tToLID......................%u\n", + cl_ntoh16(lr->from_lid), lr->from_port_num, + lr->to_port_num, cl_ntoh16(lr->to_lid)); +} + +static void dump_one_slvl_record(void *data) +{ + ib_slvl_table_record_t *slvl = data; + ib_slvl_table_t *t = &slvl->slvl_tbl; + printf("SL2VLTableRecord dump:\n" + "\t\tLID........................%u\n" + "\t\tInPort.....................%u\n" + "\t\tOutPort....................%u\n" + "\t\tSL: 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|\n" + "\t\tVL:%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u" + "|%2u|%2u|%2u|\n", + cl_ntoh16(slvl->lid), slvl->in_port_num, slvl->out_port_num, + ib_slvl_table_get(t, 0), ib_slvl_table_get(t, 1), + ib_slvl_table_get(t, 2), ib_slvl_table_get(t, 3), + ib_slvl_table_get(t, 4), ib_slvl_table_get(t, 5), + ib_slvl_table_get(t, 6), ib_slvl_table_get(t, 7), + ib_slvl_table_get(t, 8), ib_slvl_table_get(t, 9), + ib_slvl_table_get(t, 10), ib_slvl_table_get(t, 11), + ib_slvl_table_get(t, 12), ib_slvl_table_get(t, 13), + ib_slvl_table_get(t, 14), ib_slvl_table_get(t, 15)); +} + +static void dump_one_vlarb_record(void *data) +{ + ib_vl_arb_table_record_t *vlarb = data; + ib_vl_arb_element_t *e = vlarb->vl_arb_tbl.vl_entry; + int i; + printf("VLArbTableRecord dump:\n" + "\t\tLID........................%u\n" + "\t\tPort.......................%u\n" + "\t\tBlock......................%u\n", + cl_ntoh16(vlarb->lid), vlarb->port_num, vlarb->block_num); + for (i = 0; i < 32; i += 16) + printf("\t\tVL :%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|" + "%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|\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) { + fprintf(stderr, "Query result returned: %s\n", + ib_get_err_str(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) { + fprintf(stderr, "ERROR: Query result returned: %s\n", + ib_get_err_str(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: + 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': + 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)" }, + { "qos_calss", '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)" }, + { "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-1/tools/infiniband-diags/src/saquery/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/saquery/SOURCES new file mode 100644 index 00000000..02d6ebd8 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/saquery/makefile b/branches/WOF2-1/tools/infiniband-diags/src/saquery/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/saquery/saquery.rc b/branches/WOF2-1/tools/infiniband-diags/src/saquery/saquery.rc new file mode 100644 index 00000000..52109aba --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/sminfo.c b/branches/WOF2-1/tools/infiniband-diags/src/sminfo.c new file mode 100644 index 00000000..ebf6a476 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/sminfo.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "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-1/tools/infiniband-diags/src/sminfo/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/sminfo/SOURCES new file mode 100644 index 00000000..ffc43cf3 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/sminfo/makefile b/branches/WOF2-1/tools/infiniband-diags/src/sminfo/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/sminfo/sminfo.rc b/branches/WOF2-1/tools/infiniband-diags/src/sminfo/sminfo.rc new file mode 100644 index 00000000..b1afa84f --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/smpdump.c b/branches/WOF2-1/tools/infiniband-diags/src/smpdump.c new file mode 100644 index 00000000..03277b3a --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/smpdump.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#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-1/tools/infiniband-diags/src/smpdump/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/smpdump/SOURCES new file mode 100644 index 00000000..4afe2ac6 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/smpdump/makefile b/branches/WOF2-1/tools/infiniband-diags/src/smpdump/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/smpdump/smpdump.rc b/branches/WOF2-1/tools/infiniband-diags/src/smpdump/smpdump.rc new file mode 100644 index 00000000..1c68e93b --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/smpquery.c b/branches/WOF2-1/tools/infiniband-diags/src/smpquery.c new file mode 100644 index 00000000..2ed1e650 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/smpquery.c @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#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-1/tools/infiniband-diags/src/smpquery/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/smpquery/SOURCES new file mode 100644 index 00000000..84765275 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/smpquery/makefile b/branches/WOF2-1/tools/infiniband-diags/src/smpquery/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/smpquery/smpquery.rc b/branches/WOF2-1/tools/infiniband-diags/src/smpquery/smpquery.rc new file mode 100644 index 00000000..0f8b2d41 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/vendstat.c b/branches/WOF2-1/tools/infiniband-diags/src/vendstat.c new file mode 100644 index 00000000..0bf96165 --- /dev/null +++ b/branches/WOF2-1/tools/infiniband-diags/src/vendstat.c @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "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 { + uint32_t address; + uint32_t data; + uint32_t mask; +} is3_record_t; + +typedef struct { + uint8_t reserved[8]; + is3_record_t record[18]; +} is3_config_space_t; + +#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; + +void counter_groups_info(ib_portid_t *portid, int port) +{ + char buf[1024]; + ib_vendor_call_t call; + is4_counter_group_info_t *cg_info; + int i, num_cg; + + memset(&call, 0, sizeof(call)); + call.mgmt_class = IB_MLX_VENDOR_CLASS; + call.method = IB_MAD_METHOD_GET; + call.timeout = ibd_timeout; + call.attrid = IB_MLX_IS4_COUNTER_GROUP_INFO; + call.mod = port; + + /* Counter Group Info */ + memset(&buf, 0, sizeof(buf)); + if (!ib_vendor_call_via(&buf, portid, &call, srcport)) + 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; + +void config_counter_groups(ib_portid_t *portid, int port) +{ + char buf[1024]; + ib_vendor_call_t call; + is4_config_counter_groups_t *cg_config; + + memset(&call, 0, sizeof(call)); + call.mgmt_class = IB_MLX_VENDOR_CLASS; + call.attrid = IB_MLX_IS4_CONFIG_COUNTER_GROUP; + call.timeout = ibd_timeout; + call.mod = port; + /* configure counter groups for groups 0 and 1 */ + call.method = IB_MAD_METHOD_SET; + + 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 (!ib_vendor_call_via(&buf, portid, &call, srcport)) + IBERROR("config counter group set"); + + /* get config counter groups */ + memset(&buf, 0, sizeof(buf)); + call.method = IB_MAD_METHOD_GET; + + if (!ib_vendor_call_via(&buf, portid, &call, srcport)) + IBERROR("config counter group query"); +} + +static int general_info, xmit_wait, counter_group_info, config_counter_group; + +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; + 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]; + ib_vendor_call_t call; + is3_general_info_t *gi; + is3_config_space_t *cs; + int i; + + const struct ibdiag_opt opts[] = { + { "N", 'N', 0, NULL, "show IS3 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"}, + { 0 } + }; + + char usage_args[] = " [port]"; + const char *usage_examples[] = { + "-N 6\t\t# read IS3 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); + } + + /* 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 */ + + memset(&call, 0, sizeof(call)); + call.mgmt_class = IB_MLX_VENDOR_CLASS; + call.method = IB_MAD_METHOD_GET; + call.timeout = ibd_timeout; + + memset(&buf, 0, sizeof(buf)); + /* vendor ClassPortInfo is required attribute if class supported */ + call.attrid = CLASS_PORT_INFO; + if (!ib_vendor_call_via(&buf, &portid, &call, srcport)) + IBERROR("classportinfo query"); + + memset(&buf, 0, sizeof(buf)); + call.attrid = IB_MLX_IS3_GENERAL_INFO; + if (!ib_vendor_call_via(&buf, &portid, &call, srcport)) + IBERROR("vendstat"); + gi = (is3_general_info_t *)&buf; + + if (general_info) { + /* dump IS3 general info here */ + printf("hw_dev_rev: 0x%04x\n", ntohs(gi->hw_info.hw_revision)); + printf("hw_dev_id: 0x%04x\n", ntohs(gi->hw_info.device_id)); + printf("hw_uptime: 0x%08x\n", ntohl(gi->hw_info.uptime)); + printf("fw_version: %02d.%02d.%02d\n", + gi->fw_info.major, gi->fw_info.minor, gi->fw_info.sub_minor); + printf("fw_build_id: 0x%04x\n", ntohl(gi->fw_info.build_id)); + printf("fw_date: %02d/%02d/%04x\n", + gi->fw_info.month, gi->fw_info.day, ntohs(gi->fw_info.year)); + printf("fw_psid: '%s'\n", gi->fw_info.psid); + printf("fw_ini_ver: %d\n", ntohl(gi->fw_info.ini_file_version)); + printf("sw_version: %02d.%02d.%02d\n", + gi->sw_info.major, gi->sw_info.minor, gi->sw_info.sub_minor); + } + + if (xmit_wait) { + if (ntohs(gi->hw_info.device_id) != IS3_DEVICE_ID) + IBERROR("Unsupported device ID 0x%x", ntohs(gi->hw_info.device_id)); + + memset(&buf, 0, sizeof(buf)); + call.attrid = IB_MLX_IS3_CONFIG_SPACE_ACCESS; + /* Limit of 18 accesses per MAD ? */ + call.mod = 2 << 22 | 16 << 16; /* 16 records */ + /* Set record addresses for each port */ + cs = (is3_config_space_t *)&buf; + for (i = 0; i < 16; i++) + cs->record[i].address = htonl(IB_MLX_IS3_PORT_XMIT_WAIT + ((i + 1) << 12)); + if (!ib_vendor_call_via(&buf, &portid, &call, srcport)) + IBERROR("vendstat"); + + for (i = 0; i < 16; i++) + if (cs->record[i].data) /* PortXmitWait is 32 bit counter */ + printf("Port %d: PortXmitWait 0x%x\n", i + 4, ntohl(cs->record[i].data)); /* port 4 is first port */ + + /* Last 8 ports is another query */ + memset(&buf, 0, sizeof(buf)); + call.attrid = IB_MLX_IS3_CONFIG_SPACE_ACCESS; + call.mod = 2 << 22 | 8 << 16; /* 8 records */ + /* Set record addresses for each port */ + cs = (is3_config_space_t *)&buf; + for (i = 0; i < 8; i++) + cs->record[i].address = htonl(IB_MLX_IS3_PORT_XMIT_WAIT + ((i + 17) << 12)); + if (!ib_vendor_call_via(&buf, &portid, &call, srcport)) + 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-1/tools/infiniband-diags/src/vendstat/SOURCES b/branches/WOF2-1/tools/infiniband-diags/src/vendstat/SOURCES new file mode 100644 index 00000000..fcda4188 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/vendstat/makefile b/branches/WOF2-1/tools/infiniband-diags/src/vendstat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/infiniband-diags/src/vendstat/vendstat.rc b/branches/WOF2-1/tools/infiniband-diags/src/vendstat/vendstat.rc new file mode 100644 index 00000000..2ad580c7 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/ndinstall/dirs b/branches/WOF2-1/tools/ndinstall/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-1/tools/ndinstall/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/tools/ndinstall/user/SOURCES b/branches/WOF2-1/tools/ndinstall/user/SOURCES new file mode 100644 index 00000000..9bcc2e49 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/ndinstall/user/installsp.c b/branches/WOF2-1/tools/ndinstall/user/installsp.c new file mode 100644 index 00000000..d8b37c8d --- /dev/null +++ b/branches/WOF2-1/tools/ndinstall/user/installsp.c @@ -0,0 +1,332 @@ +/* + * 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 Infiband 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 + +int 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) +{ + printf("usage: %s\n", progname); + printf("\tRemove, install, and list OFA Network Direct providers\n\n"); + printf("\t[-[i|r] provider_name] Install/remove the specified provider\n"); + printf("\t[-d] Install/remove debug version of provider\n"); + printf("\tprovider_name must be one of the following:\n"); + printf("\t\tibal\n"); + printf("\t\twinverbs\n"); +} + + +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 void install_provider(void) +{ + int rc; + INT err_no; + LONG reg_error; + WSAPROTOCOL_INFOW provider; + HKEY hkey; + + /* 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[index]; + provider.dwCatalogEntryId = 0; + provider.ProtocolChain.ChainLen = 1; /* Base Protocol Service Provider */ + provider.iVersion = 1; + if (index == IBAL_INDEX || 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[index] ); + + printf("\nInstalling %s provider: ", provider_name[index]); + rc = WSCInstallProvider( + &provider_guid[index], provider_path[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); + } else { + printf("successful\n"); + } +} + +/* + * Function: remove_provider + * Description: removes our provider. + */ +static void remove_provider(void) +{ + int rc; + int err_no; + LONG reg_error; + HKEY hkey; + + /* Remove from the catalog */ + printf("\nRemoving %s provider: ", provider_name[index]); + rc = WSCDeinstallProvider(&provider_guid[index], &err_no); + if (rc == SOCKET_ERROR) { + printf ("WSCDeinstallProvider failed: %d\n", err_no); + } else { + printf ("successful\n"); + } + +#ifdef _WIN64 + /* Remove from the 32-bit catalog too! */ + printf("Removing 32-bit %s provider: ", provider_name[index]); + rc = WSCDeinstallProvider32(&provider_guid[index], &err_no); + if (rc == SOCKET_ERROR) { + printf ("WSCDeinstallProvider32 failed: %d\n", err_no); + } else { + printf ("successful\n"); + } +#endif /* _WIN64 */ +} + +static int get_prov_index(char *name) +{ + int i; + + for (i = 0; i < MAX_INDEX; i++) { + if (!_stricmp(provider_name[i], name)) { + index = i; + return 0; + } + } + return -1; +} + +int __cdecl main (int argc, char *argv[]) +{ + int ret, op; + int install = 0, remove = 0, debug = 0; + WSADATA wsd; + char *prov; + + while ((op = getopt(argc, argv, "i:r:d")) != -1) { + switch (op) { + 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; + default: + goto usage; + } + } + + 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) { + install_provider(); +#ifdef PERFMON_ENABLED + _IBSPPerfmonIniFilesGenerate(); + if ( _IBSPPerfmonRegisterKeys() == ERROR_SUCCESS ) + _IBSPPerfmonRegisterCounters(); +#endif + } else if (remove) { + remove_provider(); +#ifdef PERFMON_ENABLED + _IBSPPerfmonIniFilesRemove(); + if ( _IBSPPerfmonDeregisterCounters() == ERROR_SUCCESS ) + _IBSPPerfmonDeregisterKeys(); +#endif + } + + print_providers(); + +exit: + WSACleanup(); + return ret; + +usage: + show_usage(argv[0]); + return -1; +} diff --git a/branches/WOF2-1/tools/ndinstall/user/installsp.rc b/branches/WOF2-1/tools/ndinstall/user/installsp.rc new file mode 100644 index 00000000..afac7a57 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/ndinstall/user/makefile b/branches/WOF2-1/tools/ndinstall/user/makefile new file mode 100644 index 00000000..8b9aa233 --- /dev/null +++ b/branches/WOF2-1/tools/ndinstall/user/makefile @@ -0,0 +1,17 @@ +# +# 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 installed then disable only IA64 builds +# Otherwise disable all builds. +!IFDEF ND_INC +DDK_BLOCK_ON_IA64=1 +!ELSE +!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-1/tools/nsc/SOURCES b/branches/WOF2-1/tools/nsc/SOURCES new file mode 100644 index 00000000..54ced72c --- /dev/null +++ b/branches/WOF2-1/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-1/tools/nsc/makefile b/branches/WOF2-1/tools/nsc/makefile new file mode 100644 index 00000000..af203a50 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/nsc/nsc.c b/branches/WOF2-1/tools/nsc/nsc.c new file mode 100644 index 00000000..19d102ff --- /dev/null +++ b/branches/WOF2-1/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-1/tools/nsc/nsc.rc b/branches/WOF2-1/tools/nsc/nsc.rc new file mode 100644 index 00000000..92df29a5 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/part_man/dirs b/branches/WOF2-1/tools/part_man/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-1/tools/part_man/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/tools/part_man/user/SOURCES b/branches/WOF2-1/tools/part_man/user/SOURCES new file mode 100644 index 00000000..1c2a3bc7 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/part_man/user/makefile b/branches/WOF2-1/tools/part_man/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/part_man/user/part_man.c b/branches/WOF2-1/tools/part_man/user/part_man.c new file mode 100644 index 00000000..5eda787f --- /dev/null +++ b/branches/WOF2-1/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-1/tools/part_man/user/part_man.rc b/branches/WOF2-1/tools/part_man/user/part_man.rc new file mode 100644 index 00000000..d095f33d --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/dirs b/branches/WOF2-1/tools/perftests/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-1/tools/perftests/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/tools/perftests/user/README b/branches/WOF2-1/tools/perftests/user/README new file mode 100644 index 00000000..213a6e17 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/TODO b/branches/WOF2-1/tools/perftests/user/TODO new file mode 100644 index 00000000..9cd24526 --- /dev/null +++ b/branches/WOF2-1/tools/perftests/user/TODO @@ -0,0 +1 @@ +- support -- option ( like --port ...) diff --git a/branches/WOF2-1/tools/perftests/user/clock_test.c b/branches/WOF2-1/tools/perftests/user/clock_test.c new file mode 100644 index 00000000..3effb469 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/dirs b/branches/WOF2-1/tools/perftests/user/dirs new file mode 100644 index 00000000..efc41e71 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/get_clock.c b/branches/WOF2-1/tools/perftests/user/get_clock.c new file mode 100644 index 00000000..eceb5152 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/get_clock.h b/branches/WOF2-1/tools/perftests/user/get_clock.h new file mode 100644 index 00000000..d46cb2c2 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/getopt.c b/branches/WOF2-1/tools/perftests/user/getopt.c new file mode 100644 index 00000000..485e272a --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/getopt.h b/branches/WOF2-1/tools/perftests/user/getopt.h new file mode 100644 index 00000000..20efd5cc --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/perf_defs.h b/branches/WOF2-1/tools/perftests/user/perf_defs.h new file mode 100644 index 00000000..e2370544 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/perf_utils.c b/branches/WOF2-1/tools/perftests/user/perf_utils.c new file mode 100644 index 00000000..e56f5ee7 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/read_bw/SOURCES b/branches/WOF2-1/tools/perftests/user/read_bw/SOURCES new file mode 100644 index 00000000..3edb8ece --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/read_bw/makefile b/branches/WOF2-1/tools/perftests/user/read_bw/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/read_bw/read_bw.c b/branches/WOF2-1/tools/perftests/user/read_bw/read_bw.c new file mode 100644 index 00000000..b0c4d2bc --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/read_bw/read_bw.rc b/branches/WOF2-1/tools/perftests/user/read_bw/read_bw.rc new file mode 100644 index 00000000..13e5f43d --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/read_lat/SOURCES b/branches/WOF2-1/tools/perftests/user/read_lat/SOURCES new file mode 100644 index 00000000..554d8707 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/read_lat/makefile b/branches/WOF2-1/tools/perftests/user/read_lat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/read_lat/read_lat.c b/branches/WOF2-1/tools/perftests/user/read_lat/read_lat.c new file mode 100644 index 00000000..0c15f83c --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/read_lat/read_lat.rc b/branches/WOF2-1/tools/perftests/user/read_lat/read_lat.rc new file mode 100644 index 00000000..2dd3fb9e --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/send_bw/SOURCES b/branches/WOF2-1/tools/perftests/user/send_bw/SOURCES new file mode 100644 index 00000000..274106a1 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/send_bw/makefile b/branches/WOF2-1/tools/perftests/user/send_bw/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/send_bw/send_bw.c b/branches/WOF2-1/tools/perftests/user/send_bw/send_bw.c new file mode 100644 index 00000000..e5755390 --- /dev/null +++ b/branches/WOF2-1/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:ebaV", 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-1/tools/perftests/user/send_bw/send_bw.rc b/branches/WOF2-1/tools/perftests/user/send_bw/send_bw.rc new file mode 100644 index 00000000..b66c9e13 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/send_lat/SOURCES b/branches/WOF2-1/tools/perftests/user/send_lat/SOURCES new file mode 100644 index 00000000..86150e1e --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/send_lat/makefile b/branches/WOF2-1/tools/perftests/user/send_lat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/send_lat/send_lat.c b/branches/WOF2-1/tools/perftests/user/send_lat/send_lat.c new file mode 100644 index 00000000..b0a91362 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/send_lat/send_lat.rc b/branches/WOF2-1/tools/perftests/user/send_lat/send_lat.rc new file mode 100644 index 00000000..f661becc --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/write_bw/SOURCES b/branches/WOF2-1/tools/perftests/user/write_bw/SOURCES new file mode 100644 index 00000000..4e9a6794 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/write_bw/makefile b/branches/WOF2-1/tools/perftests/user/write_bw/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/write_bw/write_bw.c b/branches/WOF2-1/tools/perftests/user/write_bw/write_bw.c new file mode 100644 index 00000000..8dde1593 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/write_bw/write_bw.rc b/branches/WOF2-1/tools/perftests/user/write_bw/write_bw.rc new file mode 100644 index 00000000..98e02bb3 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/write_lat/SOURCES b/branches/WOF2-1/tools/perftests/user/write_lat/SOURCES new file mode 100644 index 00000000..77075732 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/write_lat/makefile b/branches/WOF2-1/tools/perftests/user/write_lat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/write_lat/write_lat.c b/branches/WOF2-1/tools/perftests/user/write_lat/write_lat.c new file mode 100644 index 00000000..5eb21aff --- /dev/null +++ b/branches/WOF2-1/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-1/tools/perftests/user/write_lat/write_lat.rc b/branches/WOF2-1/tools/perftests/user/write_lat/write_lat.rc new file mode 100644 index 00000000..9cd1a3f9 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/qlgcvnic_config/SOURCES b/branches/WOF2-1/tools/qlgcvnic_config/SOURCES new file mode 100644 index 00000000..c65295f9 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/qlgcvnic_config/makefile b/branches/WOF2-1/tools/qlgcvnic_config/makefile new file mode 100644 index 00000000..783b1843 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/qlgcvnic_config/qlgcvnic_config.rc b/branches/WOF2-1/tools/qlgcvnic_config/qlgcvnic_config.rc new file mode 100644 index 00000000..b31d14cd --- /dev/null +++ b/branches/WOF2-1/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-1/tools/qlgcvnic_config/vnic_child_config.c b/branches/WOF2-1/tools/qlgcvnic_config/vnic_child_config.c new file mode 100644 index 00000000..dd018891 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/vstat/dirs b/branches/WOF2-1/tools/vstat/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-1/tools/vstat/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/tools/vstat/user/SOURCES b/branches/WOF2-1/tools/vstat/user/SOURCES new file mode 100644 index 00000000..75b634bb --- /dev/null +++ b/branches/WOF2-1/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-1/tools/vstat/user/makefile b/branches/WOF2-1/tools/vstat/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/vstat/user/vstat.rc b/branches/WOF2-1/tools/vstat/user/vstat.rc new file mode 100644 index 00000000..19a9103b --- /dev/null +++ b/branches/WOF2-1/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-1/tools/vstat/user/vstat_main.c b/branches/WOF2-1/tools/vstat/user/vstat_main.c new file mode 100644 index 00000000..3f1e4a47 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/wsdinstall/dirs b/branches/WOF2-1/tools/wsdinstall/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-1/tools/wsdinstall/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/tools/wsdinstall/user/InstallSP.sln b/branches/WOF2-1/tools/wsdinstall/user/InstallSP.sln new file mode 100644 index 00000000..9c8f2cb0 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/wsdinstall/user/SOURCES b/branches/WOF2-1/tools/wsdinstall/user/SOURCES new file mode 100644 index 00000000..5914a25d --- /dev/null +++ b/branches/WOF2-1/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-1/tools/wsdinstall/user/installsp.c b/branches/WOF2-1/tools/wsdinstall/user/installsp.c new file mode 100644 index 00000000..e0cba2e8 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/wsdinstall/user/installsp.exe.manifest b/branches/WOF2-1/tools/wsdinstall/user/installsp.exe.manifest new file mode 100644 index 00000000..d5e574e6 --- /dev/null +++ b/branches/WOF2-1/tools/wsdinstall/user/installsp.exe.manifest @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/branches/WOF2-1/tools/wsdinstall/user/installsp.rc b/branches/WOF2-1/tools/wsdinstall/user/installsp.rc new file mode 100644 index 00000000..51a73c81 --- /dev/null +++ b/branches/WOF2-1/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-1/tools/wsdinstall/user/makefile b/branches/WOF2-1/tools/wsdinstall/user/makefile new file mode 100644 index 00000000..a28a5610 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_adapter_util.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_adapter_util.h new file mode 100644 index 00000000..f032aae0 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cno_create.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_create.c new file mode 100644 index 00000000..f7fee96b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cno_free.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_free.c new file mode 100644 index 00000000..5efee23d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cno_modify_agent.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_modify_agent.c new file mode 100644 index 00000000..b60ebb9d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cno_query.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_query.c new file mode 100644 index 00000000..76b3e4ab --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cno_util.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_util.c new file mode 100644 index 00000000..cc83220b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cno_util.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_util.h new file mode 100644 index 00000000..4d647e6e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cno_wait.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cno_wait.c new file mode 100644 index 00000000..0504734a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cookie.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cookie.c new file mode 100644 index 00000000..28dbddfd --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cookie.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cookie.h new file mode 100644 index 00000000..8502b2c4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cr_accept.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_accept.c new file mode 100644 index 00000000..cb9a0c18 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cr_callback.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_callback.c new file mode 100644 index 00000000..b67043b6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cr_handoff.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_handoff.c new file mode 100644 index 00000000..9495d785 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cr_query.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_query.c new file mode 100644 index 00000000..4bb7de02 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cr_reject.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_reject.c new file mode 100644 index 00000000..fbe6356a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cr_util.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_util.c new file mode 100644 index 00000000..e0c5b6f9 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_cr_util.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_cr_util.h new file mode 100644 index 00000000..392f3ef4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_debug.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_debug.c new file mode 100644 index 00000000..4dd36838 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_connect.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_connect.c new file mode 100644 index 00000000..a2c6c096 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_create.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_create.c new file mode 100644 index 00000000..f68e4a0e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_disconnect.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_disconnect.c new file mode 100644 index 00000000..a26f2294 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_dup_connect.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_dup_connect.c new file mode 100644 index 00000000..d5eb6cb7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_free.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_free.c new file mode 100644 index 00000000..0f4ff677 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_get_status.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_get_status.c new file mode 100644 index 00000000..217581a4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_modify.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_modify.c new file mode 100644 index 00000000..6c0a84ed --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_post_rdma_read.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_post_rdma_read.c new file mode 100644 index 00000000..8d5b8d20 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_post_rdma_write.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_post_rdma_write.c new file mode 100644 index 00000000..3e92b299 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_post_recv.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_post_recv.c new file mode 100644 index 00000000..cbde689a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_post_send.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_post_send.c new file mode 100644 index 00000000..335cc4b6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_query.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_query.c new file mode 100644 index 00000000..77a80103 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_reset.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_reset.c new file mode 100644 index 00000000..31bb1103 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_util.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_util.c new file mode 100644 index 00000000..0ef2ff50 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ep_util.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ep_util.h new file mode 100644 index 00000000..a1675221 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_clear_unwaitable.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_clear_unwaitable.c new file mode 100644 index 00000000..eeda8a24 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_connection_callb.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_connection_callb.c new file mode 100644 index 00000000..1510ad09 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_cq_async_error_callb.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_cq_async_error_callb.c new file mode 100644 index 00000000..aba28eaf --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_create.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_create.c new file mode 100644 index 00000000..c0e16236 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_dequeue.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_dequeue.c new file mode 100644 index 00000000..e1a80305 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_disable.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_disable.c new file mode 100644 index 00000000..a35659c6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_dto_callb.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_dto_callb.c new file mode 100644 index 00000000..76a38a1f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_enable.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_enable.c new file mode 100644 index 00000000..6e2758e7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_free.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_free.c new file mode 100644 index 00000000..3835a083 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_modify_cno.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_modify_cno.c new file mode 100644 index 00000000..88ede7dc --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_post_se.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_post_se.c new file mode 100644 index 00000000..05614fb4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_qp_async_error_callb.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_qp_async_error_callb.c new file mode 100644 index 00000000..70425530 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_query.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_query.c new file mode 100644 index 00000000..5aa596bc --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_resize.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_resize.c new file mode 100644 index 00000000..f183a3e8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_set_unwaitable.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_set_unwaitable.c new file mode 100644 index 00000000..f2fea18f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_un_async_error_callb.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_un_async_error_callb.c new file mode 100644 index 00000000..c55a280a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_util.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_util.c new file mode 100644 index 00000000..a5cf340f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_util.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_util.h new file mode 100644 index 00000000..7fe76c9f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_evd_wait.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_evd_wait.c new file mode 100644 index 00000000..d4189e4c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_get_consumer_context.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_get_consumer_context.c new file mode 100644 index 00000000..90125b1f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_get_handle_type.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_get_handle_type.c new file mode 100644 index 00000000..009b72fa --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_hash.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_hash.c new file mode 100644 index 00000000..7b5011ba --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_hash.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_hash.h new file mode 100644 index 00000000..0c5c15b4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_hca_util.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_hca_util.c new file mode 100644 index 00000000..87204727 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_hca_util.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_hca_util.h new file mode 100644 index 00000000..f722e70d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ia_close.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ia_close.c new file mode 100644 index 00000000..d2652f25 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ia_open.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ia_open.c new file mode 100644 index 00000000..283cfdbc --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ia_query.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ia_query.c new file mode 100644 index 00000000..c213b050 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ia_util.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ia_util.c new file mode 100644 index 00000000..6a970db6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ia_util.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ia_util.h new file mode 100644 index 00000000..a674a019 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_init.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_init.h new file mode 100644 index 00000000..2002c911 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_llist.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_llist.c new file mode 100644 index 00000000..95d2d8ef --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_lmr_create.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_lmr_create.c new file mode 100644 index 00000000..07773d37 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_lmr_free.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_lmr_free.c new file mode 100644 index 00000000..923ad9b1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_lmr_query.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_lmr_query.c new file mode 100644 index 00000000..35b89c6a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_lmr_util.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_lmr_util.c new file mode 100644 index 00000000..99de0c9a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_lmr_util.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_lmr_util.h new file mode 100644 index 00000000..5e92f186 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_mr_util.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_mr_util.c new file mode 100644 index 00000000..0b931a02 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_mr_util.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_mr_util.h new file mode 100644 index 00000000..4b07164d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_provider.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_provider.c new file mode 100644 index 00000000..01c0db38 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_provider.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_provider.h new file mode 100644 index 00000000..06a2d7ff --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_psp_create.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_psp_create.c new file mode 100644 index 00000000..7fd3024c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_psp_create_any.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_psp_create_any.c new file mode 100644 index 00000000..64f1728d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_psp_free.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_psp_free.c new file mode 100644 index 00000000..1f184279 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_psp_query.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_psp_query.c new file mode 100644 index 00000000..6bd49c89 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_pz_create.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_pz_create.c new file mode 100644 index 00000000..b129b845 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_pz_free.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_pz_free.c new file mode 100644 index 00000000..95c3950a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_pz_query.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_pz_query.c new file mode 100644 index 00000000..7ebcd534 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_pz_util.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_pz_util.c new file mode 100644 index 00000000..ac3d871e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_pz_util.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_pz_util.h new file mode 100644 index 00000000..6e90fd72 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ring_buffer_util.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ring_buffer_util.c new file mode 100644 index 00000000..11d574ff --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_ring_buffer_util.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_ring_buffer_util.h new file mode 100644 index 00000000..58a585b1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_rmr_bind.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_rmr_bind.c new file mode 100644 index 00000000..4de96685 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_rmr_create.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_rmr_create.c new file mode 100644 index 00000000..3b47d761 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_rmr_free.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_rmr_free.c new file mode 100644 index 00000000..15878bd5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_rmr_query.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_rmr_query.c new file mode 100644 index 00000000..500b7b05 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_rmr_util.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_rmr_util.c new file mode 100644 index 00000000..23fc30fa --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_rmr_util.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_rmr_util.h new file mode 100644 index 00000000..e9cf2eb9 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_rsp_create.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_rsp_create.c new file mode 100644 index 00000000..2434369c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_rsp_free.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_rsp_free.c new file mode 100644 index 00000000..2c279e90 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_rsp_query.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_rsp_query.c new file mode 100644 index 00000000..dc811de7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_set_consumer_context.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_set_consumer_context.c new file mode 100644 index 00000000..7f0914ef --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_sp_util.c b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_sp_util.c new file mode 100644 index 00000000..a5554bf4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/common/dapl_sp_util.h b/branches/WOF2-1/ulp/dapl/dapl/common/dapl_sp_util.h new file mode 100644 index 00000000..1442ace0 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/dirs b/branches/WOF2-1/ulp/dapl/dapl/dirs new file mode 100644 index 00000000..2d7badc4 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl/dapl/dirs @@ -0,0 +1 @@ +DIRS=udapl diff --git a/branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_cm.c b/branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_cm.c new file mode 100644 index 00000000..cbc90475 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/ibal/dapl_ibal_dto.h b/branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_dto.h new file mode 100644 index 00000000..ae9159f4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/ibal/dapl_ibal_kmod.h b/branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_kmod.h new file mode 100644 index 00000000..114687e2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.c b/branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.c new file mode 100644 index 00000000..883dca9b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.h b/branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.h new file mode 100644 index 00000000..c0a94e56 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/ibal/dapl_ibal_qp.c b/branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_qp.c new file mode 100644 index 00000000..09510278 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/ibal/dapl_ibal_util.c b/branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_util.c new file mode 100644 index 00000000..f409a85e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/ibal/dapl_ibal_util.h b/branches/WOF2-1/ulp/dapl/dapl/ibal/dapl_ibal_util.h new file mode 100644 index 00000000..c123ebf2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/include/dapl.h b/branches/WOF2-1/ulp/dapl/dapl/include/dapl.h new file mode 100644 index 00000000..6c377931 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/include/dapl_debug.h b/branches/WOF2-1/ulp/dapl/dapl/include/dapl_debug.h new file mode 100644 index 00000000..de67aa96 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/include/dapl_ipoib_names.h b/branches/WOF2-1/ulp/dapl/dapl/include/dapl_ipoib_names.h new file mode 100644 index 00000000..f0d117d8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/include/dapl_vendor.h b/branches/WOF2-1/ulp/dapl/dapl/include/dapl_vendor.h new file mode 100644 index 00000000..1741b871 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/Makefile.cygwin b/branches/WOF2-1/ulp/dapl/dapl/udapl/Makefile.cygwin new file mode 100644 index 00000000..7d1cbbc9 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/Makefile.org b/branches/WOF2-1/ulp/dapl/dapl/udapl/Makefile.org new file mode 100644 index 00000000..49c880db --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/Makefile.orig b/branches/WOF2-1/ulp/dapl/dapl/udapl/Makefile.orig new file mode 100644 index 00000000..f98ef9d0 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/SOURCES b/branches/WOF2-1/ulp/dapl/dapl/udapl/SOURCES new file mode 100644 index 00000000..0d227c56 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/dapl_init.c b/branches/WOF2-1/ulp/dapl/dapl/udapl/dapl_init.c new file mode 100644 index 00000000..856be598 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/dapl_name_service.c b/branches/WOF2-1/ulp/dapl/dapl/udapl/dapl_name_service.c new file mode 100644 index 00000000..1adcad58 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/dapl_name_service.h b/branches/WOF2-1/ulp/dapl/dapl/udapl/dapl_name_service.h new file mode 100644 index 00000000..8982f59d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/dapl_timer_util.c b/branches/WOF2-1/ulp/dapl/dapl/udapl/dapl_timer_util.c new file mode 100644 index 00000000..7907a69d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/dapl_timer_util.h b/branches/WOF2-1/ulp/dapl/dapl/udapl/dapl_timer_util.h new file mode 100644 index 00000000..21cea8cb --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/linux/dapl_osd.c b/branches/WOF2-1/ulp/dapl/dapl/udapl/linux/dapl_osd.c new file mode 100644 index 00000000..fec18fe7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/linux/dapl_osd.h b/branches/WOF2-1/ulp/dapl/dapl/udapl/linux/dapl_osd.h new file mode 100644 index 00000000..3f786b6f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/makefile b/branches/WOF2-1/ulp/dapl/dapl/udapl/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/makefile.wnd b/branches/WOF2-1/ulp/dapl/dapl/udapl/makefile.wnd new file mode 100644 index 00000000..ba237b8a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/udapl.rc b/branches/WOF2-1/ulp/dapl/dapl/udapl/udapl.rc new file mode 100644 index 00000000..e00b3280 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/udapl_exports.src b/branches/WOF2-1/ulp/dapl/dapl/udapl/udapl_exports.src new file mode 100644 index 00000000..214effb7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/udapl_sources.c b/branches/WOF2-1/ulp/dapl/dapl/udapl/udapl_sources.c new file mode 100644 index 00000000..1acb06e2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/windows/dapl_osd.c b/branches/WOF2-1/ulp/dapl/dapl/udapl/windows/dapl_osd.c new file mode 100644 index 00000000..6d07686b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/windows/dapl_osd.h b/branches/WOF2-1/ulp/dapl/dapl/udapl/windows/dapl_osd.h new file mode 100644 index 00000000..0f39272b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/windows/dapl_win.def b/branches/WOF2-1/ulp/dapl/dapl/udapl/windows/dapl_win.def new file mode 100644 index 00000000..681a02c1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dapl/udapl/windows/dapllib.rc b/branches/WOF2-1/ulp/dapl/dapl/udapl/windows/dapllib.rc new file mode 100644 index 00000000..e4b5f803 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/common/dat_dictionary.c b/branches/WOF2-1/ulp/dapl/dat/common/dat_dictionary.c new file mode 100644 index 00000000..9ab6ae26 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/common/dat_dictionary.h b/branches/WOF2-1/ulp/dapl/dat/common/dat_dictionary.h new file mode 100644 index 00000000..a96c4fbe --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/common/dat_dr.c b/branches/WOF2-1/ulp/dapl/dat/common/dat_dr.c new file mode 100644 index 00000000..aef07ece --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/common/dat_dr.h b/branches/WOF2-1/ulp/dapl/dat/common/dat_dr.h new file mode 100644 index 00000000..12546f7d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/common/dat_init.c b/branches/WOF2-1/ulp/dapl/dat/common/dat_init.c new file mode 100644 index 00000000..3d7dbc37 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/common/dat_init.h b/branches/WOF2-1/ulp/dapl/dat/common/dat_init.h new file mode 100644 index 00000000..523d8133 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/common/dat_sr.c b/branches/WOF2-1/ulp/dapl/dat/common/dat_sr.c new file mode 100644 index 00000000..e140ccec --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/common/dat_sr.h b/branches/WOF2-1/ulp/dapl/dat/common/dat_sr.h new file mode 100644 index 00000000..5551ee20 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/common/dat_strerror.c b/branches/WOF2-1/ulp/dapl/dat/common/dat_strerror.c new file mode 100644 index 00000000..6ee77fe4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/dirs b/branches/WOF2-1/ulp/dapl/dat/dirs new file mode 100644 index 00000000..97d2b67c --- /dev/null +++ b/branches/WOF2-1/ulp/dapl/dat/dirs @@ -0,0 +1 @@ +DIRS=udat diff --git a/branches/WOF2-1/ulp/dapl/dat/include/dat/dat.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/dat.h new file mode 100644 index 00000000..10854020 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/include/dat/dat_error.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/dat_error.h new file mode 100644 index 00000000..67e46f09 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/include/dat/dat_platform_specific.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/dat_platform_specific.h new file mode 100644 index 00000000..3ce32fa8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/include/dat/dat_redirection.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/dat_redirection.h new file mode 100644 index 00000000..7324a57c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/include/dat/dat_registry.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/dat_registry.h new file mode 100644 index 00000000..c0b20384 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/include/dat/dat_vendor_specific.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/dat_vendor_specific.h new file mode 100644 index 00000000..81e6d100 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/include/dat/kdat.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/kdat.h new file mode 100644 index 00000000..d30a601e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/include/dat/kdat_config.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/kdat_config.h new file mode 100644 index 00000000..6e45f162 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/include/dat/kdat_redirection.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/kdat_redirection.h new file mode 100644 index 00000000..532e1d95 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/include/dat/kdat_vendor_specific.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/kdat_vendor_specific.h new file mode 100644 index 00000000..d617713c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/include/dat/udat.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/udat.h new file mode 100644 index 00000000..1900408c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/include/dat/udat_config.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/udat_config.h new file mode 100644 index 00000000..172a12ba --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/include/dat/udat_redirection.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/udat_redirection.h new file mode 100644 index 00000000..848679c9 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/include/dat/udat_vendor_specific.h b/branches/WOF2-1/ulp/dapl/dat/include/dat/udat_vendor_specific.h new file mode 100644 index 00000000..6321abbc --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/kdat/Makefile b/branches/WOF2-1/ulp/dapl/dat/kdat/Makefile new file mode 100644 index 00000000..875fa01d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/kdat/dat_kdapl.c b/branches/WOF2-1/ulp/dapl/dat/kdat/dat_kdapl.c new file mode 100644 index 00000000..c702e931 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/kdat/dat_module.c b/branches/WOF2-1/ulp/dapl/dat/kdat/dat_module.c new file mode 100644 index 00000000..f1264227 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/kdat/linux/dat_osd.c b/branches/WOF2-1/ulp/dapl/dat/kdat/linux/dat_osd.c new file mode 100644 index 00000000..b463e68b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/kdat/linux/dat_osd.h b/branches/WOF2-1/ulp/dapl/dat/kdat/linux/dat_osd.h new file mode 100644 index 00000000..1a4cf15c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/Makefile.cygwin b/branches/WOF2-1/ulp/dapl/dat/udat/Makefile.cygwin new file mode 100644 index 00000000..aad1d67c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/Makefile.org b/branches/WOF2-1/ulp/dapl/dat/udat/Makefile.org new file mode 100644 index 00000000..fdb4c64d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/Makefile.orig b/branches/WOF2-1/ulp/dapl/dat/udat/Makefile.orig new file mode 100644 index 00000000..2e2f4f9c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/SOURCES b/branches/WOF2-1/ulp/dapl/dat/udat/SOURCES new file mode 100644 index 00000000..efcc8b9d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/dat.conf b/branches/WOF2-1/ulp/dapl/dat/udat/dat.conf new file mode 100644 index 00000000..3eaa4782 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/ibhosts b/branches/WOF2-1/ulp/dapl/dat/udat/ibhosts new file mode 100644 index 00000000..1463f9d8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/linux/dat-1.1.spec b/branches/WOF2-1/ulp/dapl/dat/udat/linux/dat-1.1.spec new file mode 100644 index 00000000..1f0c0122 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/linux/dat_osd.c b/branches/WOF2-1/ulp/dapl/dat/udat/linux/dat_osd.c new file mode 100644 index 00000000..3101eea6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/linux/dat_osd.h b/branches/WOF2-1/ulp/dapl/dat/udat/linux/dat_osd.h new file mode 100644 index 00000000..d7f5e312 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/makefile b/branches/WOF2-1/ulp/dapl/dat/udat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/makefile.wnd b/branches/WOF2-1/ulp/dapl/dat/udat/makefile.wnd new file mode 100644 index 00000000..0b4e4f9e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/udat.c b/branches/WOF2-1/ulp/dapl/dat/udat/udat.c new file mode 100644 index 00000000..99678152 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/udat.rc b/branches/WOF2-1/ulp/dapl/dat/udat/udat.rc new file mode 100644 index 00000000..6f200001 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/udat_exports.src b/branches/WOF2-1/ulp/dapl/dat/udat/udat_exports.src new file mode 100644 index 00000000..1ee36f72 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/udat_sources.c b/branches/WOF2-1/ulp/dapl/dat/udat/udat_sources.c new file mode 100644 index 00000000..4232086d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/udat_sr_parser.c b/branches/WOF2-1/ulp/dapl/dat/udat/udat_sr_parser.c new file mode 100644 index 00000000..81a24c49 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/udat_sr_parser.h b/branches/WOF2-1/ulp/dapl/dat/udat/udat_sr_parser.h new file mode 100644 index 00000000..de5b3e61 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/windows/dat_osd.c b/branches/WOF2-1/ulp/dapl/dat/udat/windows/dat_osd.c new file mode 100644 index 00000000..8cf0b3f3 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/windows/dat_osd.h b/branches/WOF2-1/ulp/dapl/dat/udat/windows/dat_osd.h new file mode 100644 index 00000000..a8d3185f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/windows/dat_osd_sr.h b/branches/WOF2-1/ulp/dapl/dat/udat/windows/dat_osd_sr.h new file mode 100644 index 00000000..fa24ed3d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dat/udat/windows/dat_win.def b/branches/WOF2-1/ulp/dapl/dat/udat/windows/dat_win.def new file mode 100644 index 00000000..976ef99a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/dirs b/branches/WOF2-1/ulp/dapl/dirs new file mode 100644 index 00000000..11081a4b --- /dev/null +++ b/branches/WOF2-1/ulp/dapl/dirs @@ -0,0 +1,4 @@ +DIRS=\ + test \ + dat \ + dapl diff --git a/branches/WOF2-1/ulp/dapl/doc/dapl_coding_style.txt b/branches/WOF2-1/ulp/dapl/doc/dapl_coding_style.txt new file mode 100644 index 00000000..cf41ae68 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/doc/dapl_end_point_design.txt b/branches/WOF2-1/ulp/dapl/doc/dapl_end_point_design.txt new file mode 100644 index 00000000..c03cda76 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/doc/dapl_environ.txt b/branches/WOF2-1/ulp/dapl/doc/dapl_environ.txt new file mode 100644 index 00000000..6cca3b27 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/doc/dapl_event_design.txt b/branches/WOF2-1/ulp/dapl/doc/dapl_event_design.txt new file mode 100644 index 00000000..0b896bb7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/doc/dapl_memory_management_design.txt b/branches/WOF2-1/ulp/dapl/doc/dapl_memory_management_design.txt new file mode 100644 index 00000000..70d41dba --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/doc/dapl_registry_design.txt b/branches/WOF2-1/ulp/dapl/doc/dapl_registry_design.txt new file mode 100644 index 00000000..c4701a25 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/doc/dapl_shared_memory_design.txt b/branches/WOF2-1/ulp/dapl/doc/dapl_shared_memory_design.txt new file mode 100644 index 00000000..4f0ca14c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/doc/dapl_vendor_specific_changes.txt b/branches/WOF2-1/ulp/dapl/doc/dapl_vendor_specific_changes.txt new file mode 100644 index 00000000..aa437807 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/doc/dat.conf b/branches/WOF2-1/ulp/dapl/doc/dat.conf new file mode 100644 index 00000000..eba45e7a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/doc/dat_environ.txt b/branches/WOF2-1/ulp/dapl/doc/dat_environ.txt new file mode 100644 index 00000000..638ba9dc --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/doc/ibhosts b/branches/WOF2-1/ulp/dapl/doc/ibhosts new file mode 100644 index 00000000..792fb503 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/doc/mv_dapl_readme.txt b/branches/WOF2-1/ulp/dapl/doc/mv_dapl_readme.txt new file mode 100644 index 00000000..b7e7dc3f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/doc/mv_dapl_relnotes.txt b/branches/WOF2-1/ulp/dapl/doc/mv_dapl_relnotes.txt new file mode 100644 index 00000000..5702eea8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/dirs b/branches/WOF2-1/ulp/dapl/test/dirs new file mode 100644 index 00000000..2d7badc4 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl/test/dirs @@ -0,0 +1 @@ +DIRS=udapl diff --git a/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/.DT_defaults b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/.DT_defaults new file mode 100644 index 00000000..706d8296 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/.DT_onetest b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/.DT_onetest new file mode 100644 index 00000000..a56089e0 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/.DT_perf.csh b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/.DT_perf.csh new file mode 100644 index 00000000..88d67aa9 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/DaplTest_how_2.txt b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/DaplTest_how_2.txt new file mode 100644 index 00000000..8085e39c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/Makefile.cygwin b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/Makefile.cygwin new file mode 100644 index 00000000..a0766ef1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/Makefile.org b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/Makefile.org new file mode 100644 index 00000000..479afca2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/Makefile.orig b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/Makefile.orig new file mode 100644 index 00000000..996384de --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/SOURCES b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/SOURCES new file mode 100644 index 00000000..58285780 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/bw.sh b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/bw.sh new file mode 100644 index 00000000..9a5c03e5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/cl.sh b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/cl.sh new file mode 100644 index 00000000..94c8cfe2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_bpool.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_bpool.c new file mode 100644 index 00000000..0acd5965 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_bpool.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_bpool.h new file mode 100644 index 00000000..161416e6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_client.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_client.c new file mode 100644 index 00000000..d170a830 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_client_info.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_client_info.c new file mode 100644 index 00000000..1e346b3a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_client_info.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_client_info.h new file mode 100644 index 00000000..3a3b20c6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_cnxn.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_cnxn.c new file mode 100644 index 00000000..d653150c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_cnxn.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_cnxn.h new file mode 100644 index 00000000..97548bae --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_common.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_common.h new file mode 100644 index 00000000..7216067f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_endian.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_endian.c new file mode 100644 index 00000000..d1ab3fac --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.c new file mode 100644 index 00000000..96fae75a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.h new file mode 100644 index 00000000..45e24c6f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_fft_connmgt.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_connmgt.c new file mode 100644 index 00000000..0c5bb378 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer.c new file mode 100644 index 00000000..14786994 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer_client.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer_client.c new file mode 100644 index 00000000..b37cd6ef --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_fft_endpoint.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_endpoint.c new file mode 100644 index 00000000..4fc9427a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_fft_hwconn.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_hwconn.c new file mode 100644 index 00000000..6cd9e332 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_fft_mem.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_mem.c new file mode 100644 index 00000000..fe263066 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_fft_pz.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_pz.c new file mode 100644 index 00000000..c7d48c6b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_fft_queryinfo.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_queryinfo.c new file mode 100644 index 00000000..5c0676e3 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_fft_test.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_test.c new file mode 100644 index 00000000..6852b716 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_fft_util.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_util.c new file mode 100644 index 00000000..cbe1d698 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_fft_util.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_fft_util.h new file mode 100644 index 00000000..bd046444 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_funcs.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_funcs.h new file mode 100644 index 00000000..3833b91e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_getopt.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_getopt.c new file mode 100644 index 00000000..2712f5e5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_getopt.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_getopt.h new file mode 100644 index 00000000..2cc379d7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_limit.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_limit.c new file mode 100644 index 00000000..b273a4b0 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.c new file mode 100644 index 00000000..3fe9347c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.h new file mode 100644 index 00000000..4d495deb --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_main.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_main.c new file mode 100644 index 00000000..2a1b2083 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_mdep.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_mdep.c new file mode 100644 index 00000000..8f205bf6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_mdep.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_mdep.h new file mode 100644 index 00000000..8b28870c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_memlist.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_memlist.c new file mode 100644 index 00000000..8d7d525d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_memlist.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_memlist.h new file mode 100644 index 00000000..83d9806a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_netaddr.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_netaddr.c new file mode 100644 index 00000000..e88d19a2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_params.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_params.c new file mode 100644 index 00000000..96516bb4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_params.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_params.h new file mode 100644 index 00000000..d64fe8d7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_performance_client.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_client.c new file mode 100644 index 00000000..7eb8c667 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.c new file mode 100644 index 00000000..025c14bc --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.h new file mode 100644 index 00000000..6a0d9b4c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_performance_server.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_server.c new file mode 100644 index 00000000..53c85393 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.c new file mode 100644 index 00000000..1f42887b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.h new file mode 100644 index 00000000..143291f1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_performance_test.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_test.h new file mode 100644 index 00000000..fda5e147 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_performance_util.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_performance_util.c new file mode 100644 index 00000000..48db4add --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_proto.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_proto.h new file mode 100644 index 00000000..8a92abf1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.c new file mode 100644 index 00000000..5580eba2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.h new file mode 100644 index 00000000..e78ea5fe --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_server.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_server.c new file mode 100644 index 00000000..13ef24bf --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.c new file mode 100644 index 00000000..059cbe6e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.h new file mode 100644 index 00000000..ee44d9d5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_server_info.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_server_info.c new file mode 100644 index 00000000..8ce3413b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_server_info.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_server_info.h new file mode 100644 index 00000000..aadf2044 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_test_data.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_test_data.c new file mode 100644 index 00000000..20d826d5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_test_data.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_test_data.h new file mode 100644 index 00000000..7ec0824b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_test_util.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_test_util.c new file mode 100644 index 00000000..60ba5873 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_thread.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_thread.c new file mode 100644 index 00000000..466a3548 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.c new file mode 100644 index 00000000..d2518c82 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.h new file mode 100644 index 00000000..849f50ce --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.c new file mode 100644 index 00000000..65972351 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.h new file mode 100644 index 00000000..ed1cb6eb --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.c new file mode 100644 index 00000000..c358de74 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.h new file mode 100644 index 00000000..96baddd7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_util.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_transaction_util.c new file mode 100644 index 00000000..2d6e73a7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_util.c b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_util.c new file mode 100644 index 00000000..8ddf787d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapl_version.h b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapl_version.h new file mode 100644 index 00000000..a625c462 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/dapltest.rc b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/dapltest.rc new file mode 100644 index 00000000..230df9f7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/lat_block.sh b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/lat_block.sh new file mode 100644 index 00000000..572d9ba0 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/lat_poll.sh b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/lat_poll.sh new file mode 100644 index 00000000..f79edb11 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/lim.sh b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/lim.sh new file mode 100644 index 00000000..350316ea --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/makefile b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/makefile new file mode 100644 index 00000000..d4938551 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/makefile.wnd b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/makefile.wnd new file mode 100644 index 00000000..6464da17 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/quit.sh b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/quit.sh new file mode 100644 index 00000000..75c040f0 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/regress.sh b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/regress.sh new file mode 100644 index 00000000..9757e1ab --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dapltest/srv.sh b/branches/WOF2-1/ulp/dapl/test/udapl/dapltest/srv.sh new file mode 100644 index 00000000..45d4b1f1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl/test/udapl/dirs b/branches/WOF2-1/ulp/dapl/test/udapl/dirs new file mode 100644 index 00000000..fc0447f1 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl/test/udapl/dirs @@ -0,0 +1 @@ +DIRS=dapltest diff --git a/branches/WOF2-1/ulp/dapl2/AUTHORS b/branches/WOF2-1/ulp/dapl2/AUTHORS new file mode 100644 index 00000000..b2c6a581 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/COPYING b/branches/WOF2-1/ulp/dapl2/COPYING new file mode 100644 index 00000000..2012c043 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/COPYING @@ -0,0 +1,36 @@ +# +# Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. +# Copyright (c) 2005 Voltaire Inc. All rights reserved. +# Copyright (c) 2005 Intel Corporation. All rights reserved. +# Copyright (c) 2004-2005, Mellanox Technologies, Inc. All rights reserved. +# Copyright (c) 2003 Topspin Corporation. All rights reserved. +# Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. +# +# This Software is licensed under one of the following licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.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. +# + + diff --git a/branches/WOF2-1/ulp/dapl2/ChangeLog b/branches/WOF2-1/ulp/dapl2/ChangeLog new file mode 100644 index 00000000..f23b9bf6 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/ChangeLog @@ -0,0 +1,3275 @@ +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-1/ulp/dapl2/LICENSE.txt b/branches/WOF2-1/ulp/dapl2/LICENSE.txt new file mode 100644 index 00000000..b69ef809 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/LICENSE2.txt b/branches/WOF2-1/ulp/dapl2/LICENSE2.txt new file mode 100644 index 00000000..04c18392 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/LICENSE3.txt b/branches/WOF2-1/ulp/dapl2/LICENSE3.txt new file mode 100644 index 00000000..0ecbca23 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/Makefile.am b/branches/WOF2-1/ulp/dapl2/Makefile.am new file mode 100644 index 00000000..15ef52e1 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/Makefile.am @@ -0,0 +1,439 @@ +# $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_CMA = dapl/openib_common/ib_extensions.c +XPROGRAMS_SCM = dapl/openib_common/ib_extensions.c +else +XFLAGS = +XPROGRAMS_CMA = +XPROGRAMS_SCM = +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) + +datlib_LTLIBRARIES = dat/udat/libdat2.la +dapllibofa_LTLIBRARIES = dapl/udapl/libdaplofa.la +daplliboscm_LTLIBRARIES = dapl/udapl/libdaploscm.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 + +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 +else + dat_version_script = + daplofa_version_script = + daploscm_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_CMA) + +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: 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_SCM) + +dapl_udapl_libdaploscm_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 \ + dat/udat/libdat2.map \ + dapl/udapl/libdaplofa.map \ + dapl/udapl/libdaploscm.map \ + 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-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-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-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; + +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-1/ulp/dapl2/README b/branches/WOF2-1/ulp/dapl2/README new file mode 100644 index 00000000..1fc55a22 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/README.windows b/branches/WOF2-1/ulp/dapl2/README.windows new file mode 100644 index 00000000..fafdadce --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/autogen.sh b/branches/WOF2-1/ulp/dapl2/autogen.sh new file mode 100644 index 00000000..343c5a61 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/configure.in b/branches/WOF2-1/ulp/dapl2/configure.in new file mode 100644 index 00000000..3283dbc9 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/configure.in @@ -0,0 +1,101 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(dapl, 2.0.20, general@lists.openfabrics.org) +AC_CONFIG_SRCDIR([dat/udat/udat.c]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(dapl, 2.0.20) + +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.])) +fi + +dnl Checks for header files. +if test "$disable_libcheck" != "yes" +then +AC_CHECK_HEADER(infiniband/verbs.h, [], + AC_MSG_ERROR([ not found. Is libibverbs installed?])) +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-1/ulp/dapl2/dapl.spec.in b/branches/WOF2-1/ulp/dapl2/dapl.spec.in new file mode 100644 index 00000000..2b74a22b --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl.spec.in @@ -0,0 +1,200 @@ +# 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-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-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-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 + +%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 ChangeLog + +%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 +* 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-1/ulp/dapl2/dapl/common/dapl_adapter_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_adapter_util.h new file mode 100644 index 00000000..1a8b7ccb --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_adapter_util.h @@ -0,0 +1,302 @@ +/* + * 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_PRIVATE *prd_ptr, + IN DAPL_PDATA_OP conn_op, + IN DAPL_HCA *hca_ptr); + +void +dapls_query_provider_specific_attr( + IN DAPL_IA *ia_ptr, + IN DAT_PROVIDER_ATTR *attr_ptr ); + +#ifdef CQ_WAIT_OBJECT +DAT_RETURN +dapls_ib_wait_object_create ( + IN DAPL_EVD *evd_ptr, + IN ib_wait_obj_handle_t *p_cq_wait_obj_handle); + +DAT_RETURN +dapls_ib_wait_object_destroy ( + IN ib_wait_obj_handle_t cq_wait_obj_handle); + +DAT_RETURN +dapls_ib_wait_object_wakeup ( + IN ib_wait_obj_handle_t cq_wait_obj_handle); + +DAT_RETURN +dapls_ib_wait_object_wait ( + IN ib_wait_obj_handle_t cq_wait_obj_handle, + IN uint32_t timeout); +#endif + +#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-1/ulp/dapl2/dapl/common/dapl_cno_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cno_util.c new file mode 100644 index 00000000..2215f29e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_cno_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cno_util.h new file mode 100644 index 00000000..1cd601f6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_cookie.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cookie.c new file mode 100644 index 00000000..990ff663 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_cookie.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cookie.h new file mode 100644 index 00000000..f953b28a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_cr_accept.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_accept.c new file mode 100644 index 00000000..74ebd6ae --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_cr_callback.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_callback.c new file mode 100644 index 00000000..23404890 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_callback.c @@ -0,0 +1,549 @@ +/* + * 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 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, /* event data */ + 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, 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; + 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_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; + ep_ptr->cm_handle = IB_INVALID_HANDLE; + 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 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; + if (prd_ptr == NULL) { + cr_ptr->param.private_data_size = 0; + } else { + cr_ptr->param.private_data_size = + dapls_ib_private_data_size(prd_ptr, DAPL_PDATA_CONN_REQ, + sp_ptr->header.owner_ia-> + hca_ptr); + } + 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; + } + ep_ptr->cm_handle = 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-1/ulp/dapl2/dapl/common/dapl_cr_handoff.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_handoff.c new file mode 100644 index 00000000..fe1b3b59 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_cr_query.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_query.c new file mode 100644 index 00000000..7332639d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_cr_reject.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_reject.c new file mode 100644 index 00000000..edac95cc --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_cr_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_util.c new file mode 100644 index 00000000..39b61add --- /dev/null +++ b/branches/WOF2-1/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 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-1/ulp/dapl2/dapl/common/dapl_cr_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_cr_util.h new file mode 100644 index 00000000..33aed7cb --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/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 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 *instant_data_p, + IN const void *context); + +#endif /* _DAPL_CR_UTIL_H_ */ diff --git a/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_csp.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_csp.c new file mode 100644 index 00000000..ce7c0152 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_debug.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_debug.c new file mode 100644 index 00000000..960bc008 --- /dev/null +++ b/branches/WOF2-1/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_gettid()); + 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-1/ulp/dapl2/dapl/common/dapl_ep_connect.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_connect.c new file mode 100644 index 00000000..5e4dc416 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_connect.c @@ -0,0 +1,416 @@ +/* + * 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; + DAT_UINT32 max_req_pdata_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); + + max_req_pdata_size = + dapls_ib_private_data_size(NULL, DAPL_PDATA_CONN_REQ, + ep_ptr->header.owner_ia->hca_ptr); + + if (private_data_size + req_hdr_size > (DAT_COUNT) 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); + +#ifdef IBHOSTS_NAMING + /* + * Special case: put the remote HCA address into the private data + * prefix. This is a spec violation as it introduces a protocol, but + * some implementations may find it necessary for a time. + * Copy the private data into the EP area so the data is contiguous. + * If the provider needs to pad the buffer with NULLs, it happens at + * the provider layer. + */ + dapl_os_memcpy(&ep_ptr->hca_address, + &ep_ptr->header.owner_ia->hca_ptr->hca_address, + sizeof(DAT_SOCK_ADDR)); + dapl_os_memcpy(ep_ptr->private.private_data, private_data, + private_data_size); + private_data_ptr = (void *)&ep_ptr->private.private_data; +#else + private_data_ptr = private_data; +#endif /* IBHOSTS_NAMING */ + + /* Copy the connection qualifiers */ + dapl_os_memcpy(ep_ptr->param.remote_ia_address_ptr, + remote_ia_address, sizeof(DAT_SOCK_ADDR)); + ep_ptr->param.remote_port_qual = remote_conn_qual; + + dat_status = dapls_ib_connect(ep_handle, + remote_ia_address, + remote_conn_qual, + private_data_size + req_hdr_size, + private_data_ptr); + + if (dat_status != DAT_SUCCESS) { + ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; + + /* + * Some implementations provide us with an error code that the + * remote destination is unreachable, but DAT doesn't have a + * synchronous error code to communicate this. So the provider + * layer generates an INTERNAL_ERROR with a subtype; when + * this happens, return SUCCESS and generate the event + */ + if (dat_status == DAT_ERROR(DAT_INTERNAL_ERROR, 1)) { + dapls_evd_post_connection_event((DAPL_EVD *) ep_ptr-> + param. + connect_evd_handle, + DAT_CONNECTION_EVENT_UNREACHABLE, + (DAT_HANDLE) ep_ptr, 0, + 0); + dat_status = DAT_SUCCESS; + } + } else { + /* + * Acquire the lock and recheck the state of the EP; this + * thread could have been descheduled after issuing the connect + * request and the EP is now connected. Set up a timer if + * necessary. + */ + dapl_os_lock(&ep_ptr->header.lock); + if (ep_ptr->param.ep_state == + DAT_EP_STATE_ACTIVE_CONNECTION_PENDING + && timeout != DAT_TIMEOUT_INFINITE) { + ep_ptr->cxn_timer = + (DAPL_OS_TIMER *) + dapl_os_alloc(sizeof(DAPL_OS_TIMER)); + + dapls_timer_set(ep_ptr->cxn_timer, + dapls_ep_timeout, ep_ptr, timeout); + } + dapl_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-1/ulp/dapl2/dapl/common/dapl_ep_create.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_create.c new file mode 100644 index 00000000..e154b8de --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_create_with_srq.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_create_with_srq.c new file mode 100644 index 00000000..b85abfd1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_disconnect.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_disconnect.c new file mode 100644 index 00000000..72da6200 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_dup_connect.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_dup_connect.c new file mode 100644 index 00000000..799cdb46 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_free.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_free.c new file mode 100644 index 00000000..fd9fcc7e --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_free.c @@ -0,0 +1,204 @@ +/* + * 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; + 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); + + /* + * 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-1/ulp/dapl2/dapl/common/dapl_ep_get_status.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_get_status.c new file mode 100644 index 00000000..6880f6f0 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_modify.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_modify.c new file mode 100644 index 00000000..9f0095fe --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read.c new file mode 100644 index 00000000..437cc5a4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read_to_rmr.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read_to_rmr.c new file mode 100644 index 00000000..ff84db0a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_post_rdma_write.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_post_rdma_write.c new file mode 100644 index 00000000..b8bea977 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_post_recv.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_post_recv.c new file mode 100644 index 00000000..fe3a6058 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_post_send.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_post_send.c new file mode 100644 index 00000000..fc1aade7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_post_send_invalidate.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_post_send_invalidate.c new file mode 100644 index 00000000..0589b282 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_query.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_query.c new file mode 100644 index 00000000..f5f548ff --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_recv_query.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_recv_query.c new file mode 100644 index 00000000..55621c43 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_reset.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_reset.c new file mode 100644 index 00000000..c5a0506d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_set_watermark.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_set_watermark.c new file mode 100644 index 00000000..3bceed7f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ep_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_util.c new file mode 100644 index 00000000..a50a6cba --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_util.c @@ -0,0 +1,585 @@ +/* + * 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_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; + ep_ptr->cm_handle = IB_INVALID_HANDLE; + + 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)); + } +#if defined(_WIN32) || defined(_WIN64) + if (ep_ptr->ibal_cm_handle) { + dapl_os_free(ep_ptr->ibal_cm_handle, + sizeof(*ep_ptr->ibal_cm_handle)); + ep_ptr->ibal_cm_handle = NULL; + } +#endif + +#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_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 */ + +/* + * 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; + + /* + * 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; + 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, cr_ptr->sp_ptr); + } else { + dapl_evd_connection_callback(ep_ptr->cm_handle, + ib_cm_event, + NULL, (void *)ep_ptr); + } + } else { + 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-1/ulp/dapl2/dapl/common/dapl_ep_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_util.h new file mode 100644 index 00000000..7ac40614 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ep_util.h @@ -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. + */ + +/********************************************************************** + * + * 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); + +#endif /* _DAPL_EP_UTIL_H_ */ diff --git a/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_connection_callb.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_connection_callb.c new file mode 100644 index 00000000..e2fb93b2 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_connection_callb.c @@ -0,0 +1,244 @@ +/* + * 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 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 %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; + 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_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; + 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, + ep_ptr->header. + owner_ia-> + hca_ptr); + } + + 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 (prd_ptr != NULL) + private_data_size = + dapls_ib_private_data_size(prd_ptr, + DAPL_PDATA_CONN_REJ, + ep_ptr->header. + owner_ia-> + hca_ptr); + + 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-1/ulp/dapl2/dapl/common/dapl_evd_cq_async_error_callb.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_cq_async_error_callb.c new file mode 100644 index 00000000..258f8f28 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_evd_dequeue.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_dequeue.c new file mode 100644 index 00000000..7632fe1e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_evd_dto_callb.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_dto_callb.c new file mode 100644 index 00000000..2f0d1060 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_dto_callb.c @@ -0,0 +1,164 @@ +/* + * 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. + */ +#ifdef CQ_WAIT_OBJECT + if (evd_ptr->cq_wait_obj_handle) + dapls_ib_wait_object_wakeup(evd_ptr-> + cq_wait_obj_handle); + else +#endif + 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_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-1/ulp/dapl2/dapl/common/dapl_evd_free.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_free.c new file mode 100644 index 00000000..43f2fee5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_evd_post_se.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_post_se.c new file mode 100644 index 00000000..52736d0c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_evd_qp_async_error_callb.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_qp_async_error_callb.c new file mode 100644 index 00000000..a9ea4ffb --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_evd_resize.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_resize.c new file mode 100644 index 00000000..762fad42 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_evd_un_async_error_callb.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_un_async_error_callb.c new file mode 100644 index 00000000..8b3f1bb6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_evd_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_util.c new file mode 100644 index 00000000..2cfd693b --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_util.c @@ -0,0 +1,1535 @@ +/* + * 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_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. + */ + 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; + } + + /* 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); + +#ifdef CQ_WAIT_OBJECT + /* Create CQ wait object; no CNO and data stream type */ + if ((cno_ptr == NULL) && + ((evd_flags & ~(DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG)) == 0)) { + dapls_ib_wait_object_create(evd_ptr, + &evd_ptr->cq_wait_obj_handle); + if (evd_ptr->cq_wait_obj_handle == NULL) { + dapl_os_free(evd_ptr, sizeof(DAPL_EVD)); + evd_ptr = NULL; + goto bail; + } + } +#endif + + 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. + */ + 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 CQ_WAIT_OBJECT + if (evd_ptr->cq_wait_obj_handle) { + dapls_ib_wait_object_destroy(evd_ptr->cq_wait_obj_handle); + } +#endif + +#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: 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_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); + +#ifdef CQ_WAIT_OBJECT + if (evd_ptr->cq_wait_obj_handle) + dapls_ib_wait_object_wakeup(evd_ptr-> + cq_wait_obj_handle); + else +#endif + 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; + } + ep_ptr->cm_handle = 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; + 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-1/ulp/dapl2/dapl/common/dapl_evd_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_util.h new file mode 100644 index 00000000..23044355 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_evd_util.h @@ -0,0 +1,174 @@ +/* + * 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 *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 * 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-1/ulp/dapl2/dapl/common/dapl_get_consumer_context.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_get_consumer_context.c new file mode 100644 index 00000000..fe780368 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_get_handle_type.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_get_handle_type.c new file mode 100644 index 00000000..ac487602 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_hash.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_hash.c new file mode 100644 index 00000000..0811d7c8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_hash.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_hash.h new file mode 100644 index 00000000..8242bf08 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_hca_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_hca_util.c new file mode 100644 index 00000000..b8f068c9 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_hca_util.c @@ -0,0 +1,176 @@ +/* + * 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" +#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) { + goto bail; + } + + dapl_os_memzero(hca_ptr, sizeof(DAPL_HCA)); + + if (DAT_SUCCESS != + dapls_hash_create(DAPL_HASH_TABLE_DEFAULT_CAPACITY, + &hca_ptr->lmr_hash_table)) { + goto bail; + } + + 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) { + if (NULL != hca_ptr->lmr_hash_table) { + dapls_hash_free(hca_ptr->lmr_hash_table); + } + + 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) +{ + (void)dapls_hash_free(hca_ptr->lmr_hash_table); + 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-1/ulp/dapl2/dapl/common/dapl_hca_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_hca_util.h new file mode 100644 index 00000000..fd006ed6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ia_close.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ia_close.c new file mode 100644 index 00000000..75c7bca2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ia_ha.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ia_ha.c new file mode 100644 index 00000000..b09edbd3 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ia_open.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ia_open.c new file mode 100644 index 00000000..edead04d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ia_query.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ia_query.c new file mode 100644 index 00000000..6fcc4a25 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ia_query.c @@ -0,0 +1,233 @@ +/* + * 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(NULL, DAPL_PDATA_CONN_REQ, + 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-1/ulp/dapl2/dapl/common/dapl_ia_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ia_util.c new file mode 100644 index 00000000..2208c23b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ia_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ia_util.h new file mode 100644 index 00000000..6290cf81 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_init.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_init.h new file mode 100644 index 00000000..0c985411 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_llist.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_llist.c new file mode 100644 index 00000000..436444e1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_lmr_free.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_lmr_free.c new file mode 100644 index 00000000..e72824a8 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_lmr_free.c @@ -0,0 +1,135 @@ +/* + * 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_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) { + 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; + } +#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-1/ulp/dapl2/dapl/common/dapl_lmr_query.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_lmr_query.c new file mode 100644 index 00000000..4ac37ec1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_read.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_read.c new file mode 100644 index 00000000..9f26377c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_write.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_write.c new file mode 100644 index 00000000..f20df69d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_lmr_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_lmr_util.c new file mode 100644 index 00000000..40634f16 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_lmr_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_lmr_util.h new file mode 100644 index 00000000..6b401076 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_mr_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_mr_util.c new file mode 100644 index 00000000..f0c9a342 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_mr_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_mr_util.h new file mode 100644 index 00000000..140fcaa5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_name_service.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_name_service.c new file mode 100644 index 00000000..84ef4682 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_name_service.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_name_service.h new file mode 100644 index 00000000..2d4725fd --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_provider.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_provider.c new file mode 100644 index 00000000..38db8d75 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_provider.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_provider.h new file mode 100644 index 00000000..32b91df1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_psp_create.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_psp_create.c new file mode 100644 index 00000000..adef59f8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_psp_create_any.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_psp_create_any.c new file mode 100644 index 00000000..c9f53e07 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_psp_free.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_psp_free.c new file mode 100644 index 00000000..9df2db1b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_psp_query.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_psp_query.c new file mode 100644 index 00000000..d990ebdc --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_pz_create.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_pz_create.c new file mode 100644 index 00000000..95a47037 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_pz_free.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_pz_free.c new file mode 100644 index 00000000..6c3970cc --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_pz_query.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_pz_query.c new file mode 100644 index 00000000..5829af4e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_pz_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_pz_util.c new file mode 100644 index 00000000..ebfb6c8c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_pz_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_pz_util.h new file mode 100644 index 00000000..c7aa8de8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ring_buffer_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ring_buffer_util.c new file mode 100644 index 00000000..54517a93 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_ring_buffer_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_ring_buffer_util.h new file mode 100644 index 00000000..46c82c95 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_rmr_bind.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rmr_bind.c new file mode 100644 index 00000000..9793f38c --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rmr_bind.c @@ -0,0 +1,319 @@ +/* + * 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 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 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; + DAPL_HASH_DATA hash_lmr; + + dat_status = + dapls_hash_search(rmr->header.owner_ia->hca_ptr->lmr_hash_table, + lmr_triplet->lmr_context, &hash_lmr); + if (DAT_SUCCESS != dat_status) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + lmr = (DAPL_LMR *) hash_lmr; + + /* 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_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-1/ulp/dapl2/dapl/common/dapl_rmr_create.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rmr_create.c new file mode 100644 index 00000000..3811bf93 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_rmr_free.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rmr_free.c new file mode 100644 index 00000000..d3abecb8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_rmr_query.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rmr_query.c new file mode 100644 index 00000000..d18aa84b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_rmr_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rmr_util.c new file mode 100644 index 00000000..26214914 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_rmr_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rmr_util.h new file mode 100644 index 00000000..3c2f6301 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_rsp_create.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rsp_create.c new file mode 100644 index 00000000..3e36e81d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_rsp_free.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rsp_free.c new file mode 100644 index 00000000..6d5c4641 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_rsp_query.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_rsp_query.c new file mode 100644 index 00000000..dfc8145f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_set_consumer_context.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_set_consumer_context.c new file mode 100644 index 00000000..86874b9a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_sp_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_sp_util.c new file mode 100644 index 00000000..c1a3fdb7 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_sp_util.c @@ -0,0 +1,280 @@ +/* + * 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); + + /* 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-1/ulp/dapl2/dapl/common/dapl_sp_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_sp_util.h new file mode 100644 index 00000000..fde8bea6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_srq_create.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_create.c new file mode 100644 index 00000000..7631a5eb --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_srq_free.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_free.c new file mode 100644 index 00000000..d93e1881 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_srq_post_recv.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_post_recv.c new file mode 100644 index 00000000..d46f9bd5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_srq_query.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_query.c new file mode 100644 index 00000000..af395d49 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_srq_resize.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_resize.c new file mode 100644 index 00000000..32386ff0 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_srq_set_lw.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_set_lw.c new file mode 100644 index 00000000..1e4254fd --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_srq_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_util.c new file mode 100644 index 00000000..3b298908 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_srq_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_srq_util.h new file mode 100644 index 00000000..952f7674 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/common/dapl_timer_util.c b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_timer_util.c new file mode 100644 index 00000000..f0d79649 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_timer_util.c @@ -0,0 +1,319 @@ +/* + * 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" + +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) (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); + } + + 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); + /* + * 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; + + 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((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); + } + } + /* + * 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-1/ulp/dapl2/dapl/common/dapl_timer_util.h b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_timer_util.h new file mode 100644 index 00000000..c24d26a0 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/common/dapl_timer_util.h @@ -0,0 +1,47 @@ +/* + * 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 ); + +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-1/ulp/dapl2/dapl/dapl_common_src.c b/branches/WOF2-1/ulp/dapl2/dapl/dapl_common_src.c new file mode 100644 index 00000000..0e5f7497 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/dapl_udapl_src.c b/branches/WOF2-1/ulp/dapl2/dapl/dapl_udapl_src.c new file mode 100644 index 00000000..6cd68760 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/dirs b/branches/WOF2-1/ulp/dapl2/dapl/dirs new file mode 100644 index 00000000..e721ef5c --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/dirs @@ -0,0 +1 @@ +DIRS = ibal openib_common openib_scm openib_cma diff --git a/branches/WOF2-1/ulp/dapl2/dapl/ibal/SOURCES b/branches/WOF2-1/ulp/dapl2/dapl/ibal/SOURCES new file mode 100644 index 00000000..b8c9932a --- /dev/null +++ b/branches/WOF2-1/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; + +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-1/ulp/dapl2/dapl/ibal/dapl_ibal_cm.c b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_cm.c new file mode 100644 index 00000000..c3575f64 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_cm.c @@ -0,0 +1,1798 @@ + +/* + * 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 + +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:\n ",prefix); + + 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) % 20) == 0 ) + dapl_log ( DAPL_DBG_TYPE_CM, "\n "); + } + dapl_log ( DAPL_DBG_TYPE_CM, "\n"); +} +#endif + + +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; + + 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; + } + + 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) + { + dapl_os_assert(ep_ptr->ibal_cm_handle->cid + == p_cm_dreq_rec->h_cm_dreq.cid); + /* passive side */ + dapls_cr_callback ( ep_ptr->cm_handle, + IB_CME_DISCONNECTED, + (void * __ptr64) p_cm_dreq_rec->p_dreq_pdata, + (void *) (((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr) ); + } + else + { + /* active side */ + dapl_evd_connection_callback ( + (dp_ib_cm_handle_t) &p_cm_dreq_rec->h_cm_dreq, + IB_CME_DISCONNECTED, + (void * __ptr64) + p_cm_dreq_rec->p_dreq_pdata, + 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; + + 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; + } + + 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), + ep_ptr->cm_handle); + + 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->cm_handle == IB_INVALID_HANDLE ) + { + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> %s: Invalid EP->CM handle?\n", __FUNCTION__); + return; + } + + if (ep_ptr->cr_ptr) + { + /* passive connection side */ + dapls_cr_callback ( ep_ptr->cm_handle, + IB_CME_DISCONNECTED, + (void * __ptr64) p_cm_drep_rec->p_drep_pdata, + (void *) (((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr) ); + } + else + { + /* active connection side */ + dapl_evd_connection_callback ( + ep_ptr->cm_handle, + IB_CME_DISCONNECTED, + (void * __ptr64) p_cm_drep_rec->p_drep_pdata, + 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; + + 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; + } + 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 ( + (dp_ib_cm_handle_t)&p_cm_rep_rec->h_cm_rep, + cm_cb_op, + (void *) prd_ptr, + (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; + + 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; + } + + 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 ( ep_ptr->cm_handle, + cm_event, + (void * __ptr64) p_cm_rej_rec->p_rej_pdata, + (void *) ((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr); + } + else + { + dapl_evd_connection_callback ( + ep_ptr->cm_handle, + cm_event, + (void * __ptr64) p_cm_rej_rec->p_rej_pdata, + (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_handle; + + struct ibal_cr_data { + ib_cm_handle_t cm_hdl; + DAT_SOCK_ADDR6 dst_ip_addr; + } *crd; + + 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. + */ + crd = dapl_os_alloc ( sizeof(struct ibal_cr_data) ); + if ( !crd ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "%s: FAILED to alloc IB CM handle storage?\n", + __FUNCTION__); + return; + } + + cm_handle = &crd->cm_hdl; + dapl_os_memzero ( (void*)crd, sizeof(*crd) ); + + /* + * 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 */ + +#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 for RemoteAddr: %s\n", + __FUNCTION__, + dapli_get_ip_addr_str( (DAT_SOCK_ADDR6*) + &dest_ia_addr, ipa) ); + } +#endif + + /* preserve CR cm handle data */ + dapl_os_memcpy( (void*)cm_handle, + (void*)&p_cm_req_rec->h_cm_req, + sizeof(ib_cm_handle_t) ); + + /* preserve remote IP address */ + dapl_os_memcpy( (void*)&crd->dst_ip_addr, + (void*)&dest_ia_addr, + sizeof(dest_ia_addr) ); + + /* 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_handle, + IB_CME_CONNECTION_REQUEST_PENDING, + (void * __ptr64) p_cm_req_rec->p_req_pdata, + (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; + + 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; + } + + dapl_dbg_log (DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "--> DiCRucb: EP %lx QP %lx\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 * __ptr64) p_cm_rtu_rec->p_rtu_pdata, + (void *) sp_ptr); + + } + else + { + dapl_evd_connection_callback ( + ep_ptr->cm_handle, + IB_CME_CONNECTED, + (void * __ptr64) p_cm_rtu_rec->p_rtu_pdata, + (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; + void *vp; + char ipa[20]; + + header = (DAPL_HEADER *)dat_handle; + + if (header->magic == DAPL_MAGIC_EP) + { + vp = &((DAPL_EP *) dat_handle)->remote_ia_address; + } + else if (header->magic == DAPL_MAGIC_CR) + { + vp = &((DAPL_CR *) dat_handle)->remote_ia_address; + } + 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, vp, sizeof(DAT_SOCK_ADDR6) ); + + dapl_dbg_log ( DAPL_DBG_TYPE_CM, "%s: returns %s\n", + __FUNCTION__, + 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; + + 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); + } + + if (ep_ptr->cm_handle == IB_INVALID_HANDLE ) + { + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> %s: Invalid EP->CM handle, OK.\n", __FUNCTION__); + 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 ); + /* 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, + "%s() EP %p ib_cm_dreq() status %s\n", + __FUNCTION__,ep_ptr,ib_get_err_str(ib_status)); + } + if ( ib_status == IB_SUCCESS ) + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DsD: EP %p DREQ SENT\n", ep_ptr); + } + 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]); + + if (private_data_size > + dapls_ib_private_data_size(NULL,DAPL_PDATA_CONN_REJ,NULL)) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsRjC: private_data size(%d) > Max(%d)\n", + private_data_size, IB_MAX_REJ_PDATA_SIZE ); + return DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + } + + 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, &cm_rej); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsRjC: cm_handle %lx 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; + + 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; + ep_ptr->cm_handle = cr_ptr->ib_cm_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_ptr->ibal_cm_handle = cr_ptr->ib_cm_handle; + + /* 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*)(ep_ptr->cm_handle+1), + 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) && 0 + { + 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 + + ep_ptr->qp_state = IB_QPS_INIT; + 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 ( *ep_ptr->cm_handle, &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) ); + + /* errors not perculated back to CR callback which allocated the + * memory, free it here on error. + */ + dapl_os_free ( (void*)ep_ptr->ibal_cm_handle, sizeof(ib_cm_handle_t) ); + ep_ptr->ibal_cm_handle = NULL; + } + + 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; + if ( ep_ptr->ibal_cm_handle ) + { + dapl_os_free ( (void*)ep_ptr->ibal_cm_handle, sizeof(ib_cm_handle_t) ); + } + ep_ptr->ibal_cm_handle = NULL; + + /* + * 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->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 == 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, 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 + +/* + * dapls_ib_private_data_size + * + * Return the size of private data given a connection op type + * + * Input: + * prd_ptr private data pointer + * conn_op connection operation type + * hca_ptr hca pointer, needed for transport type + * + * If prd_ptr is NULL, this is a query for the max size supported by + * the provider, otherwise it is the actual size of the private data + * contained in prd_ptr. + * + * Infiniband has fixed size private data, so prd_ptr is ignored. + * + * Output: + * None + * + * Returns: + * length of private data + * + */ +int +dapls_ib_private_data_size ( + IN DAPL_PRIVATE *prd_ptr, + IN DAPL_PDATA_OP conn_op, + IN DAPL_HCA *hca_ptr) +{ + int size; + + UNUSED_PARAM( prd_ptr ); + UNUSED_PARAM( hca_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 */ + +#if defined(DAPL_DBG) && 0 + dapl_dbg_log (DAPL_DBG_TYPE_CM, "%s: returns %d\n", __FUNCTION__, size ); +#endif + + return size; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_cq.c b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_cq.c new file mode 100644 index 00000000..28de045c --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_cq.c @@ -0,0 +1,492 @@ + +/* + * 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; + +#ifdef CQ_WAIT_OBJECT + 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 +#endif + { + 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 + * + */ + +#if 0 + +/* windows delays CQ creation as a PD (Protection Domain) is required + * and we do not have one at this juncture. The follow code is for future + * reference only. + */ + +DAT_RETURN +dapls_ib_cq_alloc ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr, + IN DAT_COUNT *cqlen ) +{ + dapl_dbg_log ( DAPL_DBG_TYPE_UTIL, + "dapls_ib_cq_alloc: evd %lx cqlen=%d \n", evd_ptr, *cqlen ); + + struct ibv_comp_channel *channel = ia_ptr->hca_ptr->ib_trans.ib_cq; + +#ifdef CQ_WAIT_OBJECT + if (evd_ptr->cq_wait_obj_handle) + channel = evd_ptr->cq_wait_obj_handle; +#endif + + /* Call IB verbs to create CQ */ + 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) + return DAT_INSUFFICIENT_RESOURCES; + + /* 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 %lx cqlen=%d \n", + evd_ptr->ib_cq_handle, *cqlen ); + + return DAT_SUCCESS; +} +#endif + + +/* + * 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-1/ulp/dapl2/dapl/ibal/dapl_ibal_dto.h b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_dto.h new file mode 100644 index 00000000..4694072c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/ibal/dapl_ibal_extensions.c b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_extensions.c new file mode 100644 index 00000000..643125da --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/ibal/dapl_ibal_kmod.h b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_kmod.h new file mode 100644 index 00000000..dde89004 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.c b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.c new file mode 100644 index 00000000..68fcf45a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.h b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.h new file mode 100644 index 00000000..f07e6d24 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.c b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.c new file mode 100644 index 00000000..ac99856f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.h b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.h new file mode 100644 index 00000000..d322d71f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/ibal/dapl_ibal_qp.c b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_qp.c new file mode 100644 index 00000000..cc8c394a --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_qp.c @@ -0,0 +1,695 @@ + +/* + * Copyright (c) 2005-2007 Intel Corporation. All rights reserved. + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under the terms of the "Common Public + * License" a copy of which is in the file LICENSE.txt in the root + * directory. The license is also available from the Open Source + * Initiative, see http://www.opensource.org/licenses/cpl.php. + * + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_qp.c + * + * PURPOSE: IB QP routines for access to IBAL APIs + * + * $Id: dapl_ibal_qp.c 33 2005-07-11 19:51:17Z ftillier $ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_ibal_util.h" + +#define DAPL_IBAL_QKEY 0 +#define DAPL_IBAL_START_PSN 0 + +extern DAT_RETURN +dapls_ib_cq_late_alloc ( IN ib_pd_handle_t pd_handle, + IN DAPL_EVD *evd_ptr ); + +static void +dapli_ib_qp_async_error_cb( IN ib_async_event_rec_t* p_err_rec ) +{ + DAPL_EP *ep_ptr = (DAPL_EP *)p_err_rec->context; + DAPL_EVD *evd_ptr; + DAPL_IA *ia_ptr; + dapl_ibal_ca_t *p_ca; + dapl_ibal_evd_cb_t *evd_cb; + + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC QP event %s qp ctx %p\n", + ib_get_async_event_str(p_err_rec->code), p_err_rec->context); + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC qp_handle %p qpn %u\n", + ((DAPL_EP *)p_err_rec->context)->qp_handle, + ((DAPL_EP *)p_err_rec->context)->qpn); + + /* + * Verify handles EP, EVD, and hca_handle + */ + if (DAPL_BAD_HANDLE (ep_ptr, DAPL_MAGIC_EP ) || + DAPL_BAD_HANDLE (ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiQpAEC: invalid EP %p \n", ep_ptr); + return; + } + ia_ptr = ep_ptr->header.owner_ia; + evd_ptr = ia_ptr->async_error_evd; + + if (DAPL_BAD_HANDLE (evd_ptr, DAPL_MAGIC_EVD) || + ! (evd_ptr->evd_flags & DAT_EVD_ASYNC_FLAG)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiQpAEC: invalid EVD %p \n", evd_ptr); + return; + } + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiQpAEC: can't find %s HCA\n", + (ia_ptr->header.provider)->device_name); + return; + } + + /* find QP error callback using ia_ptr for context */ + evd_cb = dapli_find_evd_cb_by_context (ia_ptr, p_ca); + if ((evd_cb == NULL) || (evd_cb->pfn_async_qp_err_cb == NULL)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiQpAEC: no ERROR cb on p_ca %p found\n", p_ca); + return; + } + + dapl_os_lock (&ep_ptr->header.lock); + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECT_PENDING; + dapl_os_unlock (&ep_ptr->header.lock); + + /* force disconnect, QP error state, to insure DTO's get flushed */ + dapls_ib_disconnect ( ep_ptr, DAT_CLOSE_ABRUPT_FLAG ); + + /* maps to dapl_evd_qp_async_error_callback(), context is EP */ + evd_cb->pfn_async_qp_err_cb( (ib_hca_handle_t)p_ca, + ep_ptr->qp_handle, + (ib_error_record_t*)&p_err_rec->code, + ep_ptr ); +} + +/* + * dapls_ib_qp_alloc + * + * Alloc a QP + * + * Input: + * *ia_ptr pointer to DAPL IA + * *ep_ptr pointer to DAPL EP + * *ep_ctx_ptr pointer to DAPL EP context + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_qp_alloc ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr, + IN DAPL_EP *ep_ctx_ptr) +{ + DAT_EP_ATTR *attr; + DAPL_EVD *recv_evd_ptr, *request_evd_ptr; + DAT_RETURN dat_status; + ib_api_status_t ib_status; + ib_qp_create_t qp_create; + ib_pd_handle_t ib_pd_handle; + ib_cq_handle_t cq_recv; + ib_cq_handle_t cq_send; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + ib_qp_attr_t qp_attr; + + attr = &ep_ptr->param.ep_attr; + + dapl_os_assert ( ep_ptr->param.pz_handle != NULL ); + + ib_pd_handle = ((DAPL_PZ *)ep_ptr->param.pz_handle)->pd_handle; + dapl_os_assert(ib_pd_handle); + recv_evd_ptr = (DAPL_EVD *) ep_ptr->param.recv_evd_handle; + request_evd_ptr = (DAPL_EVD *) ep_ptr->param.request_evd_handle; + + cq_recv = IB_INVALID_HANDLE; + cq_send = IB_INVALID_HANDLE; + + dapl_os_assert ( recv_evd_ptr != DAT_HANDLE_NULL ); + { + cq_recv = (ib_cq_handle_t) recv_evd_ptr->ib_cq_handle; + + if ((cq_recv == IB_INVALID_HANDLE) && + ( 0 != (recv_evd_ptr->evd_flags & ~DAT_EVD_SOFTWARE_FLAG) )) + { + dat_status = dapls_ib_cq_late_alloc ( ib_pd_handle, recv_evd_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: failed to create CQ\n","DsQA"); + return (dat_status); + } + + dat_status = dapls_set_cq_notify (ia_ptr, recv_evd_ptr); + + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: failed to enable notify CQ\n","DsQA"); + return (dat_status); + } + + cq_recv = (ib_cq_handle_t) recv_evd_ptr->ib_cq_handle; + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsQA: alloc_recv_CQ = %p\n", cq_recv); + + } + } + + dapl_os_assert ( request_evd_ptr != DAT_HANDLE_NULL ); + { + cq_send = (ib_cq_handle_t) request_evd_ptr->ib_cq_handle; + + if ((cq_send == IB_INVALID_HANDLE) && + ( 0 != (request_evd_ptr->evd_flags & ~DAT_EVD_SOFTWARE_FLAG) )) + { + dat_status = dapls_ib_cq_late_alloc (ib_pd_handle, request_evd_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: failed to create CQ\n","DsQA"); + return (dat_status); + } + + dat_status = dapls_set_cq_notify (ia_ptr, request_evd_ptr); + + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: failed to enable notify CQ\n","DsQA"); + return (dat_status); + } + + cq_send = (ib_cq_handle_t) request_evd_ptr->ib_cq_handle; + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsQA: alloc_send_CQ = %p\n", cq_send); + } + } + + /* + * Get the CA structure + */ + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + + dapl_os_memzero (&qp_create, sizeof (qp_create)); + qp_create.qp_type = IB_QPT_RELIABLE_CONN; + qp_create.sq_depth = attr->max_request_dtos; + qp_create.rq_depth = attr->max_recv_dtos; + qp_create.sq_sge = attr->max_recv_iov; + qp_create.rq_sge = attr->max_request_iov; + qp_create.h_sq_cq = cq_send; + qp_create.h_rq_cq = cq_recv; + qp_create.sq_signaled = FALSE; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsQA: sqd,iov=%d,%d rqd,iov=%d,%d\n", + attr->max_request_dtos, attr->max_request_iov, + attr->max_recv_dtos, attr->max_recv_iov); + + ib_status = ib_create_qp ( + ib_pd_handle, + &qp_create, + (void *) ep_ctx_ptr /* context */, + dapli_ib_qp_async_error_cb, + &ep_ptr->qp_handle); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsQA: Create QP failed = %s\n", + ib_get_err_str(ib_status)); + return (DAT_INSUFFICIENT_RESOURCES); + } + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQA: EP=%p, tEVD=%p, rEVD=%p QP=%p\n", + ep_ptr, ep_ptr->param.request_evd_handle, + ep_ptr->param.recv_evd_handle, + ep_ptr->qp_handle ); + + ep_ptr->qp_state = IB_QPS_RESET; + + p_active_port = dapli_ibal_get_port(p_ca,(uint8_t)ia_ptr->hca_ptr->port_num); + + if (NULL == p_active_port) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsQA: Port %d is not available = %d\n", + ia_ptr->hca_ptr->port_num, __LINE__); + return (DAT_INVALID_STATE); + } + + ib_status = dapls_modify_qp_state_to_init ( ep_ptr->qp_handle, + &ep_ptr->param.ep_attr, + p_active_port ); + + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsQA: Change QP state to INIT failed = %s\n", + ib_get_err_str(ib_status)); + return (DAT_INVALID_HANDLE); + } + ib_status = ib_query_qp ( ep_ptr->qp_handle, &qp_attr ); + + ep_ptr->qp_state = qp_attr.state; + ep_ptr->qpn = qp_attr.num; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQAQA: EP:%p new_QP %p state %s\n", + ep_ptr, + ep_ptr->qp_handle, + ib_get_port_state_str(ep_ptr->qp_state)); + + return (DAT_SUCCESS); +} + + +/* + * dapls_ib_qp_free + * + * Free a QP + * + * Input: + * *ia_ptr pointer to IA structure + * *ep_ptr pointer to EP structure + * + * Output: + * none + * + * Returns: + * none + * + */ +DAT_RETURN +dapls_ib_qp_free ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr ) +{ + + ib_qp_handle_t qp_handle; + UNREFERENCED_PARAMETER(ia_ptr); + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQF: free %p, state %s\n", + ep_ptr->qp_handle, + ib_get_port_state_str(ep_ptr->qp_state)); + + if (( ep_ptr->qp_handle != IB_INVALID_HANDLE ) && + ( ep_ptr->qp_state != DAPL_QP_STATE_UNATTACHED )) + { + qp_handle = ep_ptr->qp_handle; + ep_ptr->qp_handle = IB_INVALID_HANDLE; + ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED; + ib_destroy_qp ( qp_handle, NULL /* callback */); + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQF: freed QP %p\n", + qp_handle ); + } + + return DAT_SUCCESS; +} + + +/* + * dapls_ib_qp_modify + * + * Set the QP to the parameters specified in an EP_PARAM + * + * We can't be sure what state the QP is in so we first obtain the state + * from the driver. The EP_PARAM structure that is provided has been + * sanitized such that only non-zero values are valid. + * + * Input: + * *ia_ptr pointer to DAPL IA + * *ep_ptr pointer to DAPL EP + * *ep_attr pointer to DAT EP attribute + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_qp_modify ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr, + IN DAT_EP_ATTR *ep_attr ) +{ + ib_qp_attr_t qp_attr; + ib_api_status_t ib_status; + ib_qp_handle_t qp_handle; + ib_qp_state_t qp_state; + ib_qp_mod_t qp_mod; + ib_av_attr_t *p_av_attr; + ib_qp_opts_t *p_qp_opts; + uint32_t *p_sq_depth, *p_rq_depth; + DAT_BOOLEAN need_modify; + DAT_RETURN dat_status; + + qp_handle = ep_ptr->qp_handle; + need_modify = DAT_FALSE; + dat_status = DAT_SUCCESS; + if ( ia_ptr == NULL || ia_ptr->header.magic != DAPL_MAGIC_IA ) + { + dat_status = DAT_INVALID_HANDLE; + goto bail; + } + /* + * Query the QP to get the current state. + */ + ib_status = ib_query_qp ( qp_handle, &qp_attr ); + + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsIQM: Query QP failed = %s\n", + ib_get_err_str(ib_status)); + dat_status = DAT_INTERNAL_ERROR; + goto bail; + } + + qp_state = qp_attr.state; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM: modify qp state=%d\n",qp_state); + /* + * Check if we have the right qp_state or not + */ + if ( (qp_state != IB_QPS_RTR ) && (qp_state != IB_QPS_RTS ) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM: postpone to modify qp to EP values later\n"); + dat_status = DAT_SUCCESS; + goto bail; + } + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + if (qp_state == IB_QPS_RTR) + { + p_av_attr = &qp_mod.state.rtr.primary_av; + p_qp_opts = &qp_mod.state.rtr.opts; + p_sq_depth = &qp_mod.state.rtr.sq_depth; + p_rq_depth = &qp_mod.state.rtr.rq_depth; + } + else + { + /* + * RTS does not have primary_av field + */ + p_av_attr = &qp_mod.state.rts.alternate_av; + p_qp_opts = &qp_mod.state.rts.opts; + p_sq_depth = &qp_mod.state.rts.sq_depth; + p_rq_depth = &qp_mod.state.rts.rq_depth; + } + + if ( (ep_attr->max_recv_dtos > 0) && + ((DAT_UINT32)ep_attr->max_recv_dtos != qp_attr.rq_depth) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_EP,"--> DsIQM: rq_depth modified (%d,%d)\n", + qp_attr.rq_depth, ep_attr->max_recv_dtos); + + *p_rq_depth = ep_attr->max_recv_dtos; + *p_qp_opts |= IB_MOD_QP_RQ_DEPTH; + need_modify = DAT_TRUE; + } + + if ( (ep_attr->max_request_dtos > 0) && + ((DAT_UINT32)ep_attr->max_request_dtos != qp_attr.sq_depth) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM: sq_depth modified (%d,%d)\n", + qp_attr.sq_depth, ep_attr->max_request_dtos); + + *p_sq_depth = ep_attr->max_request_dtos; + *p_qp_opts |= IB_MOD_QP_SQ_DEPTH; + need_modify = DAT_TRUE; + } + + qp_mod.req_state = qp_state; + + if ( need_modify == DAT_TRUE ) + { + ib_status = ib_modify_qp (qp_handle, &qp_mod); + if ( ib_status != IB_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: ib_status = %d\n", + "DsIQM", ib_status); + dat_status = DAT_INTERNAL_ERROR; + } + } + +bail: + + return dat_status; +} + + +ib_api_status_t +dapls_modify_qp_state_to_error ( ib_qp_handle_t qp_handle ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_Err: QP state change --> Err\n"); + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_ERROR; + + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + return (ib_status); +} + + +ib_api_status_t +dapls_modify_qp_state_to_reset ( ib_qp_handle_t qp_handle ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_RESET: QP state change\n"); + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_RESET; + + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + return (ib_status); +} + + +ib_api_status_t +dapls_modify_qp_state_to_init ( + IN ib_qp_handle_t qp_handle, + IN DAT_EP_ATTR *p_attr, + IN dapl_ibal_port_t *p_port ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_INIT; + qp_mod.state.init.primary_port = p_port->p_attr->port_num; + qp_mod.state.init.qkey = DAPL_IBAL_QKEY; + qp_mod.state.init.pkey_index = 0; + qp_mod.state.init.access_ctrl = IB_AC_LOCAL_WRITE | + IB_AC_RDMA_WRITE | + IB_AC_MW_BIND | + IB_AC_ATOMIC; + if ((p_attr->max_rdma_read_in > 0) || (p_attr->max_rdma_read_out > 0)) + { + qp_mod.state.init.access_ctrl |= IB_AC_RDMA_READ; + } + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_INIT: QP(%p) state change, %s\n", + qp_handle, ib_get_err_str(ib_status)); + + return (ib_status); +} + + +ib_api_status_t +dapls_modify_qp_state_to_rtr ( + ib_qp_handle_t qp_handle, + ib_net32_t dest_qp, + ib_lid_t dest_lid, + dapl_ibal_port_t *p_port) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_RTR; + qp_mod.state.rtr.rq_psn = DAPL_IBAL_START_PSN; + qp_mod.state.rtr.dest_qp = dest_qp; + qp_mod.state.rtr.primary_av.port_num = p_port->p_attr->port_num; + qp_mod.state.rtr.primary_av.sl = 0; + qp_mod.state.rtr.primary_av.dlid = dest_lid; + qp_mod.state.rtr.primary_av.grh_valid = 0; /* FALSE */ + qp_mod.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS; + qp_mod.state.rtr.primary_av.path_bits = 0; + qp_mod.state.rtr.primary_av.conn.path_mtu = p_port->p_attr->mtu; + qp_mod.state.rtr.primary_av.conn.local_ack_timeout = 7; + qp_mod.state.rtr.primary_av.conn.seq_err_retry_cnt = 7; + qp_mod.state.rtr.primary_av.conn.rnr_retry_cnt = IB_RNR_RETRY_CNT; + qp_mod.state.rtr.resp_res = 4; // in-flight RDMAs + qp_mod.state.rtr.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT; + + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_RTR: QP(%p) state change %s\n", + qp_handle, ib_get_err_str(ib_status)); + + return (ib_status); +} + +ib_api_status_t +dapls_modify_qp_state_to_rts ( ib_qp_handle_t qp_handle ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_RTS; + qp_mod.state.rts.sq_psn = DAPL_IBAL_START_PSN; + qp_mod.state.rts.retry_cnt = 7; + qp_mod.state.rts.rnr_retry_cnt = IB_RNR_RETRY_CNT; + qp_mod.state.rtr.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT; + qp_mod.state.rts.local_ack_timeout = 7; + qp_mod.state.rts.init_depth = 4; + + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_RTS: QP(%p) state change %s\n", + qp_handle, ib_get_err_str(ib_status)); + + return (ib_status); +} + + +/* + * dapls_ib_reinit_ep + * + * Move the QP to INIT state again. + * + * Input: + * ep_ptr DAPL_EP + * + * Output: + * none + * + * Returns: + * void + * + */ +void +dapls_ib_reinit_ep ( IN DAPL_EP *ep_ptr ) +{ + DAPL_IA *ia_ptr; + ib_api_status_t ib_status; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM_REINIT: EP(%p) QP(%p) state change\n", + ep_ptr, ep_ptr->qp_handle ); + + if ( ep_ptr->param.ep_state != DAT_EP_STATE_DISCONNECTED ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsIRE: EP invalid state(%d)\n", + ep_ptr->param.ep_state); + return /*DAT_INVALID_STATE*/; + } + + ia_ptr = ep_ptr->header.owner_ia; + + /* Re-create QP if cleaned up, alloc will return init state */ + if ( ep_ptr->qp_handle == IB_INVALID_HANDLE ) + { + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIRE: !EP(%p)->qp_handle, re-create QP\n",ep_ptr); + ib_status = dapls_ib_qp_alloc ( ia_ptr, ep_ptr, ep_ptr ); + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsIRE: failed to move qp to RESET status = %s\n", + ib_get_err_str(ib_status)); + } + return /*ib_status*/; + } + + ib_status = dapls_modify_qp_state_to_reset (ep_ptr->qp_handle); + + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsIRE: failed to move qp to RESET status = %s\n", + ib_get_err_str(ib_status)); + return /*DAT_INTERNAL_ERROR*/; + } + + ep_ptr->qp_state = IB_QPS_RESET; + + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + p_active_port = dapli_ibal_get_port ( p_ca, + (uint8_t)ia_ptr->hca_ptr->port_num ); + if (NULL == p_active_port) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsIRE: Port %d is not available = %d\n", + ia_ptr->hca_ptr->port_num, __LINE__); + return /*DAT_INTERNAL_ERROR*/; + } + + /* May fail if QP still RESET and in timewait, keep in reset state */ + ib_status = dapls_modify_qp_state_to_init ( ep_ptr->qp_handle, + &ep_ptr->param.ep_attr, + p_active_port); + if ( ib_status != IB_SUCCESS ) + { + ep_ptr->qp_state = IB_QPS_RESET; + + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsIRE: failed to move qp to INIT status %s\n", + ib_get_err_str(ib_status)); + return /*DAT_INTERNAL_ERROR*/; + } + ep_ptr->qp_state = IB_QPS_INIT; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_util.c b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_util.c new file mode 100644 index 00000000..ad4acf0e --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_util.c @@ -0,0 +1,2380 @@ +/* + * 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_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: +#ifdef DAPL_DBG + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"%s() unknown IB_COMP_ST %x(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-1/ulp/dapl2/dapl/ibal/dapl_ibal_util.h b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_util.h new file mode 100644 index 00000000..52dd879c --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/ibal/dapl_ibal_util.h @@ -0,0 +1,584 @@ + +/* + * 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 +typedef ib_cm_handle_t *dp_ib_cm_handle_t; +typedef ib_listen_handle_t ib_cm_srvc_handle_t; +#endif + +typedef ib_net64_t IB_HCA_NAME; +typedef ib_ca_handle_t ib_hca_handle_t; +typedef DAT_PVOID ib_cqd_handle_t; +typedef ib_async_event_rec_t ib_error_record_t; +typedef ib_wr_type_t ib_send_op_type_t; +typedef ib_wc_t ib_work_completion_t; +typedef uint32_t ib_hca_port_t; +typedef uint32_t ib_uint32_t; +typedef 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 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-1/ulp/dapl2/dapl/ibal/makefile b/branches/WOF2-1/ulp/dapl2/dapl/ibal/makefile new file mode 100644 index 00000000..e26e1c04 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/ibal/udapl.rc b/branches/WOF2-1/ulp/dapl2/dapl/ibal/udapl.rc new file mode 100644 index 00000000..7c2505a2 --- /dev/null +++ b/branches/WOF2-1/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 (Debug)" +#define VER_INTERNALNAME_STR "dapl2d.dll" +#define VER_ORIGINALFILENAME_STR "dapl2d.dll" +#else +#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v2.0" +#define VER_INTERNALNAME_STR "dapl2.dll" +#define VER_ORIGINALFILENAME_STR "dapl2.dll" +#endif + +#include diff --git a/branches/WOF2-1/ulp/dapl2/dapl/ibal/udapl_exports.src b/branches/WOF2-1/ulp/dapl2/dapl/ibal/udapl_exports.src new file mode 100644 index 00000000..54b403bc --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/include/dapl.h b/branches/WOF2-1/ulp/dapl2/dapl/include/dapl.h new file mode 100644 index 00000000..b13c9631 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/include/dapl.h @@ -0,0 +1,1275 @@ +/* + * 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; + + /* 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; + + DAT_COUNT cno_active_count; + DAPL_CNO *cno_ptr; + + DAPL_OS_WAIT_OBJECT wait_object; + +#ifdef CQ_WAIT_OBJECT + /* Some providers support a direct CQ wait object */ + ib_wait_obj_handle_t cq_wait_obj_handle; +#endif + + DAT_COUNT threshold; + DAPL_EVD_COMPLETION completion_type; + +#ifdef DAPL_COUNTERS + void *cntrs; +#endif +}; + +/* DAPL_PRIVATE used to pass private data in a connection */ +struct dapl_private +{ +#ifdef IBHOSTS_NAMING + DAT_SOCK_ADDR6 hca_address; /* local address of HCA*/ +#endif /* IBHOSTS_NAMING */ + unsigned char private_data[DAPL_MAX_PRIVATE_DATA_SIZE]; +}; + +/* uDAPL timer entry, used to queue timeouts */ +struct dapl_timer_entry +{ + DAPL_LLIST_ENTRY list_entry; /* link entry on ia struct */ + DAPL_OS_TIMEVAL expires; + void (*function) (uintptr_t); + void *data; +}; + +#ifdef DAPL_DBG_IO_TRC + +#define DBG_IO_TRC_QLEN 32 /* length of trace buffer */ +#define DBG_IO_TRC_IOV 3 /* iov elements we keep track of */ + +struct io_buf_track +{ + Ib_send_op_type op_type; + DAPL_COOKIE *cookie; + DAT_LMR_TRIPLET iov[DBG_IO_TRC_IOV]; + DAT_RMR_TRIPLET remote_iov; + unsigned int done; /* count to track completion ordering */ + int status; + void *wqe; +}; + +#endif /* DAPL_DBG_IO_TRC */ + +/* DAPL_EP maps to DAT_EP_HANDLE */ +struct dapl_ep +{ + DAPL_HEADER header; + /* What the DAT Consumer asked for */ + DAT_EP_PARAM param; + + /* The RC Queue Pair (IBM OS API) */ + ib_qp_handle_t qp_handle; + unsigned int qpn; /* qp number */ + ib_qp_state_t qp_state; + + /* communications manager handle (IBM OS API) */ + dp_ib_cm_handle_t cm_handle; + + /* store the remote IA address here, reference from the param + * struct which only has a pointer, no storage + */ + DAT_SOCK_ADDR6 remote_ia_address; + + /* For passive connections we maintain a back pointer to the CR */ + void * cr_ptr; + + /* pointer to connection timer, if set */ + struct dapl_timer_entry *cxn_timer; + + /* private data container */ + DAPL_PRIVATE private; + + /* DTO data */ + DAPL_ATOMIC req_count; + DAPL_ATOMIC recv_count; + + DAPL_COOKIE_BUFFER req_buffer; + DAPL_COOKIE_BUFFER recv_buffer; + +#ifdef DAPL_DBG_IO_TRC + int ibt_dumped; + struct io_buf_track *ibt_base; + DAPL_RING_BUFFER ibt_queue; +#endif /* DAPL_DBG_IO_TRC */ +#if defined(_WIN32) || defined(_WIN64) + DAT_BOOLEAN recv_discreq; + DAT_BOOLEAN sent_discreq; + dp_ib_cm_handle_t ibal_cm_handle; +#endif +#ifdef DAPL_COUNTERS + void *cntrs; +#endif +}; + +/* DAPL_SRQ maps to DAT_SRQ_HANDLE */ +struct dapl_srq +{ + DAPL_HEADER header; + DAT_SRQ_PARAM param; + DAPL_ATOMIC srq_ref_count; + DAPL_COOKIE_BUFFER recv_buffer; + DAPL_ATOMIC recv_count; +}; + +/* DAPL_PZ maps to DAT_PZ_HANDLE */ +struct dapl_pz +{ + DAPL_HEADER header; + ib_pd_handle_t pd_handle; + DAPL_ATOMIC pz_ref_count; +}; + +/* DAPL_LMR maps to DAT_LMR_HANDLE */ +struct dapl_lmr +{ + DAPL_HEADER header; + DAT_LMR_PARAM param; + ib_mr_handle_t mr_handle; + DAPL_ATOMIC lmr_ref_count; +#if !defined(__KDAPL__) + char shmid[DAT_LMR_COOKIE_SIZE]; /* shared memory ID */ + ib_shm_transport_t ib_trans; /* provider specific data */ +#endif /* !__KDAPL__ */ +}; + +/* DAPL_RMR maps to DAT_RMR_HANDLE */ +struct dapl_rmr +{ + DAPL_HEADER header; + DAT_RMR_PARAM param; + DAPL_EP *ep; + DAPL_PZ *pz; + DAPL_LMR *lmr; + ib_mw_handle_t mw_handle; +}; + +/* SP types, indicating the state and queue */ +typedef enum dapl_sp_state +{ + DAPL_SP_STATE_FREE, + DAPL_SP_STATE_PSP_LISTENING, + DAPL_SP_STATE_PSP_PENDING, + DAPL_SP_STATE_RSP_LISTENING, + DAPL_SP_STATE_RSP_PENDING +} DAPL_SP_STATE; + +/* DAPL_SP maps to DAT_PSP_HANDLE and DAT_RSP_HANDLE */ +struct dapl_sp +{ + DAPL_HEADER header; + DAPL_SP_STATE state; /* type and queue of the SP */ + + /* PSP/RSP PARAM fields */ + DAT_CONN_QUAL conn_qual; + DAT_EVD_HANDLE evd_handle; + DAT_PSP_FLAGS psp_flags; + DAT_EP_HANDLE ep_handle; + + /* maintenence fields */ + DAT_BOOLEAN listening; /* PSP is registered & active */ + ib_cm_srvc_handle_t cm_srvc_handle; /* Used by Mellanox CM */ + DAPL_LLIST_HEAD cr_list_head; /* CR pending queue */ + DAT_COUNT cr_list_count; /* count of CRs on queue */ +#if defined(_VENDOR_IBAL_) + DAPL_OS_WAIT_OBJECT wait_object; /* cancel & destroy. */ +#endif +}; + +/* DAPL_CR maps to DAT_CR_HANDLE */ +struct dapl_cr +{ + DAPL_HEADER header; + + /* for convenience the data is kept as a DAT_CR_PARAM. + * however, the "local_endpoint" field is always NULL + * so this wastes a pointer. This is probably ok to + * simplify code, espedially dat_cr_query. + */ + DAT_CR_PARAM param; + /* IB specific fields */ + dp_ib_cm_handle_t ib_cm_handle; + + DAT_SOCK_ADDR6 remote_ia_address; + /* Assuming that the maximum private data size is small. + * If it gets large, use of a pointer may be appropriate. + */ + unsigned char private_data[DAPL_MAX_PRIVATE_DATA_SIZE]; + /* + * Need to be able to associate the CR back to the PSP for + * dapl_cr_reject. + */ + DAPL_SP *sp_ptr; +}; + +typedef enum dapl_dto_type +{ + DAPL_DTO_TYPE_SEND, + DAPL_DTO_TYPE_RECV, + DAPL_DTO_TYPE_RDMA_WRITE, + DAPL_DTO_TYPE_RDMA_READ, +#ifdef DAT_EXTENSIONS + DAPL_DTO_TYPE_EXTENSION, +#endif +} DAPL_DTO_TYPE; + +typedef enum dapl_cookie_type +{ + DAPL_COOKIE_TYPE_NULL, + DAPL_COOKIE_TYPE_DTO, + DAPL_COOKIE_TYPE_RMR, +} DAPL_COOKIE_TYPE; + +/* DAPL_DTO_COOKIE used as context for DTO WQEs */ +struct dapl_dto_cookie +{ + DAPL_DTO_TYPE type; + DAT_DTO_COOKIE cookie; + DAT_COUNT size; /* used for SEND and RDMA write */ +}; + +/* DAPL_RMR_COOKIE used as context for bind WQEs */ +struct dapl_rmr_cookie +{ + DAPL_RMR *rmr; + DAT_RMR_COOKIE cookie; +}; + +/* DAPL_COOKIE used as context for WQEs */ +struct dapl_cookie +{ + DAPL_COOKIE_TYPE type; /* Must be first, to define struct. */ + DAPL_EP *ep; + DAT_COUNT index; + union + { + DAPL_DTO_COOKIE dto; + DAPL_RMR_COOKIE rmr; + } val; +}; + +/* + * Private Data operations. Used to obtain the size of the private + * data from the provider layer. + */ +typedef enum dapl_private_data_op +{ + DAPL_PDATA_CONN_REQ = 0, /* connect request */ + DAPL_PDATA_CONN_REP = 1, /* connect reply */ + DAPL_PDATA_CONN_REJ = 2, /* connect reject */ + DAPL_PDATA_CONN_DREQ = 3, /* disconnect request */ + DAPL_PDATA_CONN_DREP = 4, /* disconnect reply */ +} DAPL_PDATA_OP; + + +/* + * Generic HCA name field + */ +#define DAPL_HCA_NAME_MAX_LEN 260 +typedef char DAPL_HCA_NAME[DAPL_HCA_NAME_MAX_LEN+1]; + +#ifdef IBHOSTS_NAMING + +/* + * Simple mapping table to match IP addresses to GIDs. Loaded + * by dapl_init. + */ +typedef struct _dapl_gid_map_table +{ + uint32_t ip_address; + ib_gid_t gid; +} DAPL_GID_MAP; + +#endif /* IBHOSTS_NAMING */ + +/* + * IBTA defined reason for reject message: See IBTA 1.1 specification, + * 12.6.7.2 REJECTION REASON section. + */ +#define IB_CM_REJ_REASON_CONSUMER_REJ 0x001C + + +#if defined(DAPL_DBG_IO_TRC) +/********************************************************************* + * * + * Debug I/O tracing support prototypes * + * * + *********************************************************************/ +/* + * I/O tracing support + */ +void dapls_io_trc_alloc ( + DAPL_EP *ep_ptr); + +void dapls_io_trc_update_completion ( + DAPL_EP *ep_ptr, + DAPL_COOKIE *cookie, + ib_uint32_t ib_status ); + +void dapls_io_trc_dump ( + DAPL_EP *ep_ptr, + ib_work_completion_t *cqe_ptr, + ib_uint32_t ib_status); + +#else /* DAPL_DBG_IO_TRC */ + +#define dapls_io_trc_alloc(a) +#define dapls_io_trc_update_completion(a, b, c) +#define dapls_io_trc_dump(a, b, c) + +#endif /* DAPL_DBG_IO_TRC */ + + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +typedef void (*DAPL_CONNECTION_STATE_HANDLER) ( + IN DAPL_EP *, + IN ib_cm_events_t, + IN const void *, + OUT DAT_EVENT *); + +/* + * DAT Mandated functions + */ + +extern DAT_RETURN DAT_API dapl_ia_open ( + IN const DAT_NAME_PTR, /* name */ + IN DAT_COUNT, /* asynch_evd_qlen */ + INOUT DAT_EVD_HANDLE *, /* asynch_evd_handle */ + OUT DAT_IA_HANDLE *); /* ia_handle */ + +extern DAT_RETURN DAT_API dapl_ia_close ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CLOSE_FLAGS ); /* ia_flags */ + + +extern DAT_RETURN DAT_API dapl_ia_query ( + IN DAT_IA_HANDLE, /* ia handle */ + OUT DAT_EVD_HANDLE *, /* async_evd_handle */ + IN DAT_IA_ATTR_MASK, /* ia_params_mask */ + OUT DAT_IA_ATTR *, /* ia_params */ + IN DAT_PROVIDER_ATTR_MASK, /* provider_params_mask */ + OUT DAT_PROVIDER_ATTR * ); /* provider_params */ + + +/* helper functions */ + +extern DAT_RETURN DAT_API dapl_set_consumer_context ( + IN DAT_HANDLE, /* dat handle */ + IN DAT_CONTEXT); /* context */ + +extern DAT_RETURN DAT_API dapl_get_consumer_context ( + IN DAT_HANDLE, /* dat handle */ + OUT DAT_CONTEXT * ); /* context */ + +extern DAT_RETURN DAT_API dapl_get_handle_type ( + IN DAT_HANDLE, + OUT DAT_HANDLE_TYPE * ); + +/* CNO functions */ + +#if !defined(__KERNEL__) +extern DAT_RETURN DAT_API dapl_cno_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_OS_WAIT_PROXY_AGENT, /* agent */ + OUT DAT_CNO_HANDLE *); /* cno_handle */ + +extern DAT_RETURN DAT_API dapl_cno_modify_agent ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_OS_WAIT_PROXY_AGENT); /* agent */ + +extern DAT_RETURN DAT_API dapl_cno_query ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_CNO_PARAM_MASK, /* cno_param_mask */ + OUT DAT_CNO_PARAM * ); /* cno_param */ + +extern DAT_RETURN DAT_API dapl_cno_free ( + IN DAT_CNO_HANDLE); /* cno_handle */ + +extern DAT_RETURN DAT_API dapl_cno_wait ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_TIMEOUT, /* timeout */ + OUT DAT_EVD_HANDLE *); /* evd_handle */ + +extern DAT_RETURN DAT_API dapl_cno_fd_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_FD *, /* file_descriptor */ + OUT DAT_CNO_HANDLE *); /* cno_handle */ + +extern DAT_RETURN DAT_API dapl_cno_trigger ( + IN DAT_CNO_HANDLE, /* cno_handle */ + OUT DAT_EVD_HANDLE *); /* evd_handle */ + +#endif /* !defined(__KERNEL__) */ + +/* CR Functions */ + +extern DAT_RETURN DAT_API dapl_cr_query ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_CR_PARAM_MASK, /* cr_args_mask */ + OUT DAT_CR_PARAM * ); /* cwr_args */ + +extern DAT_RETURN DAT_API dapl_cr_accept ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID ); /* private_data */ + +extern DAT_RETURN DAT_API dapl_cr_reject ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID ); /* private_data */ + +extern DAT_RETURN DAT_API dapl_cr_handoff ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_CONN_QUAL); /* handoff */ + +/* EVD Functions */ + +#if defined(__KERNEL__) +extern DAT_RETURN DAT_API dapl_ia_memtype_hint ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_VLEN, /* length */ + IN DAT_MEM_OPT, /* mem_optimization */ + OUT DAT_VLEN *, /* suggested_length */ + OUT DAT_VADDR *); /* suggested_alignment */ + +extern DAT_RETURN DAT_API dapl_evd_kcreate ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COUNT, /* evd_min_qlen */ + IN DAT_UPCALL_POLICY, /* upcall_policy */ + IN const DAT_UPCALL_OBJECT *, /* upcall */ + IN DAT_EVD_FLAGS, /* evd_flags */ + OUT DAT_EVD_HANDLE * ); /* evd_handle */ + +extern DAT_RETURN DAT_API dapl_evd_kquery ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_EVD_PARAM_MASK, /* evd_args_mask */ + OUT DAT_EVD_PARAM * ); /* evd_args */ + +#else +extern DAT_RETURN DAT_API dapl_evd_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COUNT, /* evd_min_qlen */ + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_EVD_FLAGS, /* evd_flags */ + OUT DAT_EVD_HANDLE * ); /* evd_handle */ + +extern DAT_RETURN DAT_API dapl_evd_query ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_EVD_PARAM_MASK, /* evd_args_mask */ + OUT DAT_EVD_PARAM * ); /* evd_args */ +#endif /* defined(__KERNEL__) */ + +#if defined(__KERNEL__) +extern DAT_RETURN DAT_API dapl_evd_modify_upcall ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_UPCALL_POLICY, /* upcall_policy */ + IN const DAT_UPCALL_OBJECT * ); /* upcall */ + +#else + +extern DAT_RETURN DAT_API dapl_evd_modify_cno ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_CNO_HANDLE); /* cno_handle */ +#endif + +extern DAT_RETURN DAT_API dapl_evd_enable ( + IN DAT_EVD_HANDLE); /* evd_handle */ + +extern DAT_RETURN DAT_API dapl_evd_disable ( + IN DAT_EVD_HANDLE); /* evd_handle */ + +#if !defined(__KERNEL__) +extern DAT_RETURN DAT_API dapl_evd_wait ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* threshold */ + OUT DAT_EVENT *, /* event */ + OUT DAT_COUNT *); /* nmore */ +#endif /* !defined(__KERNEL__) */ + +extern DAT_RETURN DAT_API dapl_evd_resize ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_COUNT ); /* evd_qlen */ + +extern DAT_RETURN DAT_API dapl_evd_post_se ( + DAT_EVD_HANDLE, /* evd_handle */ + const DAT_EVENT * ); /* event */ + +extern DAT_RETURN DAT_API dapl_evd_dequeue ( + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_EVENT * ); /* event */ + +extern DAT_RETURN DAT_API dapl_evd_free ( + IN DAT_EVD_HANDLE ); + +extern DAT_RETURN DAT_API +dapl_evd_set_unwaitable ( + IN DAT_EVD_HANDLE evd_handle ); + +extern DAT_RETURN DAT_API +dapl_evd_clear_unwaitable ( + IN DAT_EVD_HANDLE evd_handle ); + +/* EP functions */ + +extern DAT_RETURN DAT_API dapl_ep_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_EVD_HANDLE, /* in_dto_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* out_dto_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* connect_evd_handle */ + IN const DAT_EP_ATTR *, /* ep_parameters */ + OUT DAT_EP_HANDLE * ); /* ep_handle */ + +extern DAT_RETURN DAT_API dapl_ep_query ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_PARAM_MASK, /* ep_args_mask */ + OUT DAT_EP_PARAM * ); /* ep_args */ + +extern DAT_RETURN DAT_API dapl_ep_modify ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_PARAM_MASK, /* ep_args_mask */ + IN const DAT_EP_PARAM * ); /* ep_args */ + +extern DAT_RETURN DAT_API dapl_ep_connect ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_IA_ADDRESS_PTR, /* remote_ia_address */ + IN DAT_CONN_QUAL, /* remote_conn_qual */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID, /* private_data */ + IN DAT_QOS, /* quality_of_service */ + IN DAT_CONNECT_FLAGS ); /* connect_flags */ + +extern DAT_RETURN DAT_API dapl_ep_common_connect ( + IN DAT_EP_HANDLE ep, /* ep_handle */ + IN DAT_IA_ADDRESS_PTR remote_addr, /* remote_ia_address */ + IN DAT_TIMEOUT timeout, /* timeout */ + IN DAT_COUNT pdata_size, /* private_data_size */ + IN const DAT_PVOID pdata ); /* private_data */ + +extern DAT_RETURN DAT_API dapl_ep_dup_connect ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_HANDLE, /* ep_dup_handle */ + IN DAT_TIMEOUT, /* timeout*/ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID, /* private_data */ + IN DAT_QOS); /* quality_of_service */ + +extern DAT_RETURN DAT_API dapl_ep_disconnect ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_CLOSE_FLAGS ); /* close_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_send ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_recv ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_rdma_read ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *, /* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_rdma_read_to_rmr ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN const DAT_RMR_TRIPLET *,/* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *,/* remote_iov */ + IN DAT_COMPLETION_FLAGS); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_rdma_write ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *, /* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_send_with_invalidate ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS, /* completion_flags */ + IN DAT_BOOLEAN, /* invalidate_flag */ + IN DAT_RMR_CONTEXT); /* RMR context */ + +extern DAT_RETURN DAT_API dapl_ep_get_status ( + IN DAT_EP_HANDLE, /* ep_handle */ + OUT DAT_EP_STATE *, /* ep_state */ + OUT DAT_BOOLEAN *, /* in_dto_idle */ + OUT DAT_BOOLEAN * ); /* out_dto_idle */ + +extern DAT_RETURN DAT_API dapl_ep_free ( + IN DAT_EP_HANDLE); /* ep_handle */ + +extern DAT_RETURN DAT_API dapl_ep_reset ( + IN DAT_EP_HANDLE); /* ep_handle */ + +extern DAT_RETURN DAT_API dapl_ep_create_with_srq ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_EVD_HANDLE, /* recv_evd_handle */ + IN DAT_EVD_HANDLE, /* request_evd_handle */ + IN DAT_EVD_HANDLE, /* connect_evd_handle */ + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN const DAT_EP_ATTR *, /* ep_attributes */ + OUT DAT_EP_HANDLE *); /* ep_handle */ + +extern DAT_RETURN DAT_API dapl_ep_recv_query ( + IN DAT_EP_HANDLE, /* ep_handle */ + OUT DAT_COUNT *, /* nbufs_allocated */ + OUT DAT_COUNT *); /* bufs_alloc_span */ + +extern DAT_RETURN DAT_API dapl_ep_set_watermark ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* soft_high_watermark */ + IN DAT_COUNT); /* hard_high_watermark */ + +/* LMR functions */ + +#if defined(__KERNEL__) +extern DAT_RETURN DAT_API dapl_lmr_kcreate ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_REGION_DESCRIPTION, /* region_description */ + IN DAT_VLEN, /* length */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_MEM_PRIV_FLAGS, /* privileges */ + IN DAT_VA_TYPE, /* va_type */ + IN DAT_MEM_OPT, /* optimization */ + OUT DAT_LMR_HANDLE *, /* lmr_handle */ + OUT DAT_LMR_CONTEXT *, /* lmr_context */ + OUT DAT_RMR_CONTEXT *, /* rmr_context */ + OUT DAT_VLEN *, /* registered_length */ + OUT DAT_VADDR * ); /* registered_address */ +#else +extern DAT_RETURN DAT_API dapl_lmr_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_REGION_DESCRIPTION, /* region_description */ + IN DAT_VLEN, /* length */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_MEM_PRIV_FLAGS, /* privileges */ + IN DAT_VA_TYPE, /* va_type */ + OUT DAT_LMR_HANDLE *, /* lmr_handle */ + OUT DAT_LMR_CONTEXT *, /* lmr_context */ + OUT DAT_RMR_CONTEXT *, /* rmr_context */ + OUT DAT_VLEN *, /* registered_length */ + OUT DAT_VADDR * ); /* registered_address */ +#endif /* defined(__KERNEL__) */ + +extern DAT_RETURN DAT_API dapl_lmr_query ( + IN DAT_LMR_HANDLE, + IN DAT_LMR_PARAM_MASK, + OUT DAT_LMR_PARAM *); + +extern DAT_RETURN DAT_API dapl_lmr_free ( + IN DAT_LMR_HANDLE); + +extern DAT_RETURN DAT_API dapl_lmr_sync_rdma_read ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN const DAT_LMR_TRIPLET *, /* local_segments */ + IN DAT_VLEN); /* num_segments */ + +extern DAT_RETURN DAT_API dapl_lmr_sync_rdma_write ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN const DAT_LMR_TRIPLET *, /* local_segments */ + IN DAT_VLEN); /* num_segments */ + +/* RMR Functions */ + +extern DAT_RETURN DAT_API dapl_rmr_create ( + IN DAT_PZ_HANDLE, /* pz_handle */ + OUT DAT_RMR_HANDLE *); /* rmr_handle */ + +extern DAT_RETURN DAT_API dapl_rmr_create_for_ep ( + IN DAT_PZ_HANDLE pz_handle, /* pz_handle */ + OUT DAT_RMR_HANDLE *rmr_handle); /* rmr_handle */ + +extern DAT_RETURN DAT_API dapl_rmr_query ( + IN DAT_RMR_HANDLE, /* rmr_handle */ + IN DAT_RMR_PARAM_MASK, /* rmr_args_mask */ + OUT DAT_RMR_PARAM *); /* rmr_args */ + +extern DAT_RETURN DAT_API dapl_rmr_bind ( + IN DAT_RMR_HANDLE, /* rmr_handle */ + IN DAT_LMR_HANDLE, /* lmr_handle */ + IN const DAT_LMR_TRIPLET *, /* lmr_triplet */ + IN DAT_MEM_PRIV_FLAGS, /* mem_priv */ + IN DAT_VA_TYPE, /* va_type */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_RMR_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS, /* completion_flags */ + INOUT DAT_RMR_CONTEXT * ); /* context */ + +extern DAT_RETURN DAT_API dapl_rmr_free ( + IN DAT_RMR_HANDLE); + +/* PSP Functions */ + +extern DAT_RETURN DAT_API dapl_psp_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CONN_QUAL, /* conn_qual */ + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_PSP_FLAGS, /* psp_flags */ + OUT DAT_PSP_HANDLE * ); /* psp_handle */ + +extern DAT_RETURN DAT_API dapl_psp_create_any ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_CONN_QUAL *, /* conn_qual */ + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_PSP_FLAGS, /* psp_flags */ + OUT DAT_PSP_HANDLE *); /* psp_handle */ + +extern DAT_RETURN DAT_API dapl_psp_query ( + IN DAT_PSP_HANDLE, + IN DAT_PSP_PARAM_MASK, + OUT DAT_PSP_PARAM * ); + +extern DAT_RETURN DAT_API dapl_psp_free ( + IN DAT_PSP_HANDLE ); /* psp_handle */ + +/* RSP Functions */ + +extern DAT_RETURN DAT_API dapl_rsp_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CONN_QUAL, /* conn_qual */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_RSP_HANDLE * ); /* rsp_handle */ + +extern DAT_RETURN DAT_API dapl_rsp_query ( + IN DAT_RSP_HANDLE, + IN DAT_RSP_PARAM_MASK, + OUT DAT_RSP_PARAM * ); + +extern DAT_RETURN DAT_API dapl_rsp_free ( + IN DAT_RSP_HANDLE ); /* rsp_handle */ + +/* PZ Functions */ + +extern DAT_RETURN DAT_API dapl_pz_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_PZ_HANDLE * ); /* pz_handle */ + +extern DAT_RETURN DAT_API dapl_pz_query ( + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_PZ_PARAM_MASK, /* pz_args_mask */ + OUT DAT_PZ_PARAM * ); /* pz_args */ + +extern DAT_RETURN DAT_API dapl_pz_free ( + IN DAT_PZ_HANDLE ); /* pz_handle */ + +/* SRQ functions */ + +extern DAT_RETURN DAT_API dapl_srq_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_SRQ_ATTR *, /* srq_attr */ + OUT DAT_SRQ_HANDLE *); /* srq_handle */ + +extern DAT_RETURN DAT_API dapl_srq_free ( + IN DAT_SRQ_HANDLE); /* srq_handle */ + +extern DAT_RETURN DAT_API dapl_srq_post_recv ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE); /* user_cookie */ + +extern DAT_RETURN DAT_API dapl_srq_query ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_SRQ_PARAM_MASK, /* srq_param_mask */ + OUT DAT_SRQ_PARAM *); /* srq_param */ + +extern DAT_RETURN DAT_API dapl_srq_resize ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_COUNT); /* srq_max_recv_dto */ + +extern DAT_RETURN DAT_API dapl_srq_set_lw ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_COUNT); /* low_watermark */ + +/* CSP functions */ +extern DAT_RETURN DAT_API dapl_csp_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COMM *, /* communicator */ + IN DAT_IA_ADDRESS_PTR, /* address */ + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_CSP_HANDLE *); /* csp_handle */ + +extern DAT_RETURN DAT_API dapl_csp_query ( + IN DAT_CSP_HANDLE, /* csp_handle */ + IN DAT_CSP_PARAM_MASK, /* csp_param_mask */ + OUT DAT_CSP_PARAM *); /* csp_param */ + +extern DAT_RETURN DAT_API dapl_csp_free ( + IN DAT_CSP_HANDLE); /* csp_handle */ + +/* HA functions */ +DAT_RETURN DAT_API dapl_ia_ha ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN const DAT_NAME_PTR, /* provider */ + OUT DAT_BOOLEAN *); /* answer */ + +#ifdef DAT_EXTENSIONS +#include +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-1/ulp/dapl2/dapl/include/dapl_debug.h b/branches/WOF2-1/ulp/dapl2/dapl/include/dapl_debug.h new file mode 100644 index 00000000..37edf90d --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/include/dapl_debug.h @@ -0,0 +1,114 @@ +/* + * 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; + +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-1/ulp/dapl2/dapl/include/dapl_ipoib_names.h b/branches/WOF2-1/ulp/dapl2/dapl/include/dapl_ipoib_names.h new file mode 100644 index 00000000..23df8d5c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/include/dapl_vendor.h b/branches/WOF2-1/ulp/dapl2/dapl/include/dapl_vendor.h new file mode 100644 index 00000000..f6d3cc01 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/openib_cma/README b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/README new file mode 100644 index 00000000..2cd4b007 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/openib_cma/SOURCES b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/SOURCES new file mode 100644 index 00000000..d6b97a2d --- /dev/null +++ b/branches/WOF2-1/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;..\..\..\..\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-1/ulp/dapl2/dapl/openib_cma/cm.c b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/cm.c new file mode 100644 index 00000000..5631fe78 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/cm.c @@ -0,0 +1,1340 @@ +/* + * Copyright (c) 2005 Voltaire Inc. All rights reserved. + * Copyright (c) 2005-2007 Intel Corporation. All rights reserved. + * Copyright (c) 2004-2005, Mellanox Technologies, Inc. All rights reserved. + * Copyright (c) 2003 Topspin Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ib_cm.c + * + * PURPOSE: The OFED provider - uCMA, name and route resolution + * + * $Id: $ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_cr_util.h" +#include "dapl_name_service.h" +#include "dapl_ib_util.h" +#include "dapl_vendor.h" +#include "dapl_osd.h" + +extern struct rdma_event_channel *g_cm_events; + +/* local prototypes */ +static struct dapl_cm_id *dapli_req_recv(struct dapl_cm_id *conn, + struct rdma_cm_event *event); +static void dapli_cm_active_cb(struct dapl_cm_id *conn, + struct rdma_cm_event *event); +static void dapli_cm_passive_cb(struct dapl_cm_id *conn, + struct rdma_cm_event *event); +static void dapli_addr_resolve(struct dapl_cm_id *conn); +static void dapli_route_resolve(struct dapl_cm_id *conn); + +/* cma requires 16 bit SID, in network order */ +#define IB_PORT_MOD 32001 +#define IB_PORT_BASE (65535 - IB_PORT_MOD) +#define SID_TO_PORT(SID) \ + (SID > 0xffff ? \ + htons((unsigned short)((SID % IB_PORT_MOD) + IB_PORT_BASE)) :\ + htons((unsigned short)SID)) + +#define PORT_TO_SID(p) ntohs(p) + +/* private data header to validate consumer rejects versus abnormal events */ +struct dapl_pdata_hdr { + DAT_UINT32 version; +}; + +static void dapli_addr_resolve(struct dapl_cm_id *conn) +{ + int ret; +#ifdef DAPL_DBG + struct rdma_addr *ipaddr = &conn->cm_id->route.addr; +#endif + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " addr_resolve: cm_id %p SRC %x DST %x\n", + conn->cm_id, ntohl(((struct sockaddr_in *) + &ipaddr->src_addr)->sin_addr.s_addr), + ntohl(((struct sockaddr_in *) + &ipaddr->dst_addr)->sin_addr.s_addr)); + + ret = rdma_resolve_route(conn->cm_id, conn->route_timeout); + if (ret) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapl_cma_connect: rdma_resolve_route ERR 0x%x %s\n", + ret, strerror(errno)); + dapl_evd_connection_callback(conn, + IB_CME_LOCAL_FAILURE, + NULL, conn->ep); + } +} + +static void dapli_route_resolve(struct dapl_cm_id *conn) +{ + int ret; +#ifdef DAPL_DBG + struct rdma_addr *ipaddr = &conn->cm_id->route.addr; + struct ib_addr *ibaddr = &conn->cm_id->route.addr.addr.ibaddr; +#endif + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " route_resolve: cm_id %p SRC %x DST %x PORT %d\n", + conn->cm_id, ntohl(((struct sockaddr_in *) + &ipaddr->src_addr)->sin_addr.s_addr), + ntohl(((struct sockaddr_in *) + &ipaddr->dst_addr)->sin_addr.s_addr), + ntohs(((struct sockaddr_in *) + &ipaddr->dst_addr)->sin_port)); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " route_resolve: SRC GID subnet %016llx id %016llx\n", + (unsigned long long) + ntohll(ibaddr->sgid.global.subnet_prefix), + (unsigned long long) + ntohll(ibaddr->sgid.global.interface_id)); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " route_resolve: DST GID subnet %016llx id %016llx\n", + (unsigned long long) + ntohll(ibaddr->dgid.global.subnet_prefix), + (unsigned long long) + ntohll(ibaddr->dgid.global.interface_id)); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " route_resolve: cm_id %p pdata %p plen %d rr %d ind %d\n", + conn->cm_id, + conn->params.private_data, + conn->params.private_data_len, + conn->params.responder_resources, + conn->params.initiator_depth); + + ret = rdma_connect(conn->cm_id, &conn->params); + if (ret) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapl_cma_connect: rdma_connect ERR %d %s\n", + ret, strerror(errno)); + goto bail; + } + return; + + bail: + dapl_evd_connection_callback(conn, + IB_CME_LOCAL_FAILURE, NULL, conn->ep); +} + +dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep) +{ + dp_ib_cm_handle_t conn; + struct rdma_cm_id *cm_id; + + /* Allocate CM and initialize lock */ + if ((conn = dapl_os_alloc(sizeof(*conn))) == NULL) + return NULL; + + dapl_os_memzero(conn, sizeof(*conn)); + dapl_os_lock_init(&conn->lock); + + /* create CM_ID, bind to local device, create QP */ + if (rdma_create_id(g_cm_events, &cm_id, (void *)conn, RDMA_PS_TCP)) { + dapl_os_free(conn, sizeof(*conn)); + return NULL; + } + conn->cm_id = cm_id; + + /* setup timers for address and route resolution */ + conn->arp_timeout = dapl_os_get_env_val("DAPL_CM_ARP_TIMEOUT_MS", + IB_ARP_TIMEOUT); + conn->arp_retries = dapl_os_get_env_val("DAPL_CM_ARP_RETRY_COUNT", + IB_ARP_RETRY_COUNT); + conn->route_timeout = dapl_os_get_env_val("DAPL_CM_ROUTE_TIMEOUT_MS", + IB_ROUTE_TIMEOUT); + conn->route_retries = dapl_os_get_env_val("DAPL_CM_ROUTE_RETRY_COUNT", + IB_ROUTE_RETRY_COUNT); + if (ep != NULL) { + conn->ep = ep; + conn->hca = ((DAPL_IA *)ep->param.ia_handle)->hca_ptr; + } + + return conn; +} + +/* + * Called from consumer thread via dat_ep_free(). + * CANNOT be called from the async event processing thread + * dapli_cma_event_cb() since a cm_id reference is held and + * a deadlock will occur. + */ + +void dapls_ib_cm_free(dp_ib_cm_handle_t conn, DAPL_EP *ep) +{ + struct rdma_cm_id *cm_id; + + if (conn == NULL) + return; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " destroy_conn: conn %p id %d\n", conn, conn->cm_id); + + dapl_os_lock(&conn->lock); + conn->destroy = 1; + + if (ep != NULL) { + ep->cm_handle = NULL; + ep->qp_handle = NULL; + ep->qp_state = IB_QP_STATE_ERROR; + } + + cm_id = conn->cm_id; + conn->cm_id = NULL; + dapl_os_unlock(&conn->lock); + + /* + * rdma_destroy_id will force synchronization with async CM event + * thread since it blocks until the in-process event reference + * is cleared during our event processing call exit. + */ + if (cm_id) { + if (cm_id->qp) + rdma_destroy_qp(cm_id); + + rdma_destroy_id(cm_id); + } + dapl_os_free(conn, sizeof(*conn)); +} + +static struct dapl_cm_id *dapli_req_recv(struct dapl_cm_id *conn, + struct rdma_cm_event *event) +{ + struct dapl_cm_id *new_conn; +#ifdef DAPL_DBG + struct rdma_addr *ipaddr = &event->id->route.addr; +#endif + + if (conn->sp == NULL) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " dapli_rep_recv: on invalid listen " "handle\n"); + return NULL; + } + + /* allocate new cm_id and merge listen parameters */ + new_conn = dapl_os_alloc(sizeof(*new_conn)); + if (new_conn) { + (void)dapl_os_memzero(new_conn, sizeof(*new_conn)); + dapl_os_lock_init(&new_conn->lock); + new_conn->cm_id = event->id; /* provided by uCMA */ + event->id->context = new_conn; /* update CM_ID context */ + new_conn->sp = conn->sp; + new_conn->hca = conn->hca; + + /* 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_dbg_log(DAPL_DBG_TYPE_CM, + " active_cb: conn %p id %d event %d\n", + conn, conn->cm_id, event->event); + + dapl_os_lock(&conn->lock); + if (conn->destroy) { + dapl_os_unlock(&conn->lock); + return; + } + dapl_os_unlock(&conn->lock); + + /* 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); + + 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 */ + dapl_evd_connection_callback(conn, + IB_CME_DESTINATION_UNREACHABLE, + NULL, conn->ep); + break; + } + case RDMA_CM_EVENT_REJECTED: + { + ib_cm_events_t cm_event; + unsigned char *pdata = NULL; + + 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) { + cm_event = + IB_CME_DESTINATION_REJECT_PRIVATE_DATA; + pdata = + (unsigned char *)event->param.conn. + private_data + + sizeof(struct dapl_pdata_hdr); + } else { + 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)); + } + dapl_evd_connection_callback(conn, cm_event, pdata, + conn->ep); + break; + } + case RDMA_CM_EVENT_ESTABLISHED: + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " active_cb: cm_id %d PORT %d CONNECTED to %s!\n", + conn->cm_id, ntohs(((struct sockaddr_in *) + &conn->cm_id->route.addr. + dst_addr)->sin_port), + inet_ntoa(((struct sockaddr_in *) + &conn->cm_id->route.addr.dst_addr)-> + sin_addr)); + + /* setup local and remote ports for ep query */ + conn->ep->param.remote_port_qual = + PORT_TO_SID(rdma_get_dst_port(conn->cm_id)); + conn->ep->param.local_port_qual = + PORT_TO_SID(rdma_get_src_port(conn->cm_id)); + + dapl_evd_connection_callback(conn, IB_CME_CONNECTED, + event->param.conn.private_data, + conn->ep); + 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 */ + /* validate EP handle */ + if (!DAPL_BAD_HANDLE(conn->ep, DAPL_MAGIC_EP)) + dapl_evd_connection_callback(conn, + IB_CME_DISCONNECTED, + NULL, conn->ep); + 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); + break; + } + + return; +} + +static void dapli_cm_passive_cb(struct dapl_cm_id *conn, + struct rdma_cm_event *event) +{ + struct dapl_cm_id *new_conn; + + 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); + if (conn->destroy) { + dapl_os_unlock(&conn->lock); + return; + } + dapl_os_unlock(&conn->lock); + + switch (event->event) { + case RDMA_CM_EVENT_CONNECT_REQUEST: + /* create new conn object with new conn_id from event */ + new_conn = dapli_req_recv(conn, event); + + if (new_conn) + dapls_cr_callback(new_conn, + IB_CME_CONNECTION_REQUEST_PENDING, + event->param.conn.private_data, + new_conn->sp); + 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)); + + dapls_cr_callback(conn, IB_CME_DESTINATION_UNREACHABLE, + NULL, conn->sp); + 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)); + + dapls_cr_callback(conn, IB_CME_DESTINATION_REJECT, + NULL, conn->sp); + break; + } + case RDMA_CM_EVENT_ESTABLISHED: + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " passive_cb: cm_id %p PORT %d CONNECTED from 0x%x!\n", + conn->cm_id, ntohs(((struct sockaddr_in *) + &conn->cm_id->route.addr. + src_addr)->sin_port), + ntohl(((struct sockaddr_in *) + &conn->cm_id->route.addr.dst_addr)-> + sin_addr.s_addr)); + + dapls_cr_callback(conn, IB_CME_CONNECTED, NULL, conn->sp); + + break; + case RDMA_CM_EVENT_DISCONNECTED: + rdma_disconnect(conn->cm_id); /* required for DREP */ + /* validate SP handle context */ + if (!DAPL_BAD_HANDLE(conn->sp, DAPL_MAGIC_PSP) || + !DAPL_BAD_HANDLE(conn->sp, DAPL_MAGIC_RSP)) + dapls_cr_callback(conn, + IB_CME_DISCONNECTED, NULL, conn->sp); + 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); + break; + } + + return; +} + +/************************ DAPL provider entry points **********************/ + +/* + * dapls_ib_connect + * + * Initiate a connection with the passive listener on another node + * + * Input: + * ep_handle, + * remote_ia_address, + * remote_conn_qual, + * prd_size size of private data and structure + * prd_prt pointer to private data structure + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN dapls_ib_connect(IN DAT_EP_HANDLE ep_handle, + IN DAT_IA_ADDRESS_PTR r_addr, + IN DAT_CONN_QUAL r_qual, + IN DAT_COUNT p_size, IN void *p_data) +{ + struct dapl_ep *ep_ptr = ep_handle; + struct dapl_cm_id *conn = ep_ptr->cm_handle; + int ret; + + /* Sanity check */ + if (NULL == ep_ptr) + return DAT_SUCCESS; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " connect: rSID 0x%llx rPort %d, pdata %p, ln %d\n", + r_qual, ntohs(SID_TO_PORT(r_qual)), p_data, p_size); + + /* rdma conn and cm_id pre-bound; reference via ep_ptr->cm_handle */ + + /* Setup QP/CM parameters and private data in cm_id */ + (void)dapl_os_memzero(&conn->params, sizeof(conn->params)); + conn->params.responder_resources = + ep_ptr->param.ep_attr.max_rdma_read_in; + conn->params.initiator_depth = ep_ptr->param.ep_attr.max_rdma_read_out; + conn->params.flow_control = 1; + conn->params.rnr_retry_count = IB_RNR_RETRY_COUNT; + conn->params.retry_count = IB_RC_RETRY_COUNT; + if (p_size) { + dapl_os_memcpy(conn->p_data, p_data, p_size); + conn->params.private_data = conn->p_data; + conn->params.private_data_len = p_size; + } + + /* copy in remote address, need a copy for retry attempts */ + dapl_os_memcpy(&conn->r_addr, r_addr, sizeof(*r_addr)); + + /* Resolve remote address, src already bound during QP create */ + ((struct sockaddr_in *)&conn->r_addr)->sin_port = SID_TO_PORT(r_qual); + ((struct sockaddr_in *)&conn->r_addr)->sin_family = AF_INET; + + ret = rdma_resolve_addr(conn->cm_id, NULL, + (struct sockaddr *)&conn->r_addr, + conn->arp_timeout); + if (ret) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapl_cma_connect: rdma_resolve_addr ERR 0x%x %s\n", + ret, strerror(errno)); + return dapl_convert_errno(errno, "ib_connect"); + } + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " connect: resolve_addr: cm_id %p -> %s port %d\n", + conn->cm_id, + inet_ntoa(((struct sockaddr_in *)&conn->r_addr)->sin_addr), + ((struct sockaddr_in *)&conn->r_addr)->sin_port); + + return DAT_SUCCESS; +} + +/* + * dapls_ib_disconnect + * + * Disconnect an EP + * + * Input: + * ep_handle, + * disconnect_flags + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * + */ +DAT_RETURN +dapls_ib_disconnect(IN DAPL_EP * ep_ptr, IN DAT_CLOSE_FLAGS close_flags) +{ + dp_ib_cm_handle_t conn = ep_ptr->cm_handle; + int ret; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " disconnect(ep %p, conn %p, id %d flags %x)\n", + ep_ptr, conn, (conn ? conn->cm_id : 0), close_flags); + + if ((conn == IB_INVALID_HANDLE) || (conn->cm_id == NULL)) + return DAT_SUCCESS; + + /* no graceful half-pipe disconnect option */ + ret = rdma_disconnect(conn->cm_id); + if (ret) + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " disconnect: ID %p ret 0x%x\n", + ep_ptr->cm_handle, ret); + + /* + * DAT event notification occurs from the callback + * Note: will fire even if DREQ goes unanswered on timeout + */ + return DAT_SUCCESS; +} + +/* + * dapls_ib_disconnect_clean + * + * Clean up outstanding connection data. This routine is invoked + * after the final disconnect callback has occurred. Only on the + * ACTIVE side of a connection. + * + * Input: + * ep_ptr DAPL_EP + * active Indicates active side of connection + * + * Output: + * none + * + * Returns: + * void + * + */ +void +dapls_ib_disconnect_clean(IN DAPL_EP * ep_ptr, + IN DAT_BOOLEAN active, + IN const ib_cm_events_t ib_cm_event) +{ + /* nothing to do */ + return; +} + +/* + * dapl_ib_setup_conn_listener + * + * Have the CM set up a connection listener. + * + * Input: + * ibm_hca_handle HCA handle + * qp_handle QP handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INTERNAL_ERROR + * DAT_CONN_QUAL_UNAVAILBLE + * DAT_CONN_QUAL_IN_USE + * + */ +DAT_RETURN +dapls_ib_setup_conn_listener(IN DAPL_IA * ia_ptr, + IN DAT_UINT64 ServiceID, IN DAPL_SP * sp_ptr) +{ + DAT_RETURN dat_status = DAT_SUCCESS; + ib_cm_srvc_handle_t conn; + DAT_SOCK_ADDR6 addr; /* local binding address */ + + /* Allocate CM and initialize lock */ + if ((conn = dapl_os_alloc(sizeof(*conn))) == NULL) + return DAT_INSUFFICIENT_RESOURCES; + + dapl_os_memzero(conn, sizeof(*conn)); + dapl_os_lock_init(&conn->lock); + + /* create CM_ID, bind to local device, create QP */ + if (rdma_create_id + (g_cm_events, &conn->cm_id, (void *)conn, RDMA_PS_TCP)) { + dapl_os_free(conn, sizeof(*conn)); + return (dapl_convert_errno(errno, "setup_listener")); + } + + /* open identifies the local device; per DAT specification */ + /* Get family and address then set port to consumer's ServiceID */ + dapl_os_memcpy(&addr, &ia_ptr->hca_ptr->hca_address, sizeof(addr)); + ((struct sockaddr_in *)&addr)->sin_port = SID_TO_PORT(ServiceID); + + if (rdma_bind_addr(conn->cm_id, (struct sockaddr *)&addr)) { + if ((errno == EBUSY) || (errno == EADDRINUSE)) + dat_status = DAT_CONN_QUAL_IN_USE; + else + dat_status = + dapl_convert_errno(errno, "setup_listener"); + goto bail; + } + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " listen(ia_ptr %p SID 0x%llx Port %d sp %p conn %p id %d)\n", + ia_ptr, ServiceID, ntohs(SID_TO_PORT(ServiceID)), + sp_ptr, conn, conn->cm_id); + + sp_ptr->cm_srvc_handle = conn; + conn->sp = sp_ptr; + conn->hca = ia_ptr->hca_ptr; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " listen(conn=%p cm_id=%d)\n", + sp_ptr->cm_srvc_handle, conn->cm_id); + + if (rdma_listen(conn->cm_id, 0)) { /* max cma backlog */ + + if ((errno == EBUSY) || (errno == EADDRINUSE)) + dat_status = DAT_CONN_QUAL_IN_USE; + else + dat_status = + dapl_convert_errno(errno, "setup_listener"); + goto bail; + } + + /* success */ + return DAT_SUCCESS; + + bail: + rdma_destroy_id(conn->cm_id); + dapl_os_free(conn, sizeof(*conn)); + return dat_status; +} + +/* + * dapl_ib_remove_conn_listener + * + * Have the CM remove a connection listener. + * + * Input: + * ia_handle IA handle + * ServiceID IB Channel Service ID + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_STATE + * + */ +DAT_RETURN +dapls_ib_remove_conn_listener(IN DAPL_IA * ia_ptr, IN DAPL_SP * sp_ptr) +{ + ib_cm_srvc_handle_t conn = sp_ptr->cm_srvc_handle; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " remove_listen(ia_ptr %p sp_ptr %p cm_ptr %p)\n", + ia_ptr, sp_ptr, conn); + + if (conn != IB_INVALID_HANDLE) { + sp_ptr->cm_srvc_handle = NULL; + dapls_ib_cm_free(conn, NULL); + } + return DAT_SUCCESS; +} + +/* + * dapls_ib_accept_connection + * + * Perform necessary steps to accept a connection + * + * Input: + * cr_handle + * ep_handle + * private_data_size + * private_data + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INTERNAL_ERROR + * + */ +DAT_RETURN +dapls_ib_accept_connection(IN DAT_CR_HANDLE cr_handle, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT p_size, IN const DAT_PVOID p_data) +{ + DAPL_CR *cr_ptr = (DAPL_CR *) cr_handle; + DAPL_EP *ep_ptr = (DAPL_EP *) ep_handle; + DAPL_IA *ia_ptr = ep_ptr->header.owner_ia; + struct dapl_cm_id *cr_conn = cr_ptr->ib_cm_handle; + int ret; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " accept(cr %p conn %p, id %p, p_data %p, p_sz=%d)\n", + cr_ptr, cr_conn, cr_conn->cm_id, p_data, p_size); + + /* Obtain size of private data structure & contents */ + if (p_size > IB_MAX_REP_PDATA_SIZE) { + dat_status = DAT_ERROR(DAT_LENGTH_ERROR, DAT_NO_SUBTYPE); + goto bail; + } + + if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) { + /* + * If we are lazy attaching the QP then we may need to + * hook it up here. Typically, we run this code only for + * DAT_PSP_PROVIDER_FLAG + */ + dat_status = dapls_ib_qp_alloc(ia_ptr, ep_ptr, NULL); + if (dat_status != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapl_cma_accept: qp_alloc ERR %d\n", + dat_status); + goto bail; + } + } + + /* + * Validate device and port in EP cm_id against inbound + * CR cm_id. The pre-allocated EP cm_id is already bound to + * a local device (cm_id and QP) when created. Move the QP + * to the new cm_id only if device and port numbers match. + */ + if (ep_ptr->cm_handle->cm_id->verbs == cr_conn->cm_id->verbs && + ep_ptr->cm_handle->cm_id->port_num == cr_conn->cm_id->port_num) { + /* move QP to new cr_conn, remove QP ref in EP cm_id */ + cr_conn->cm_id->qp = ep_ptr->cm_handle->cm_id->qp; + ep_ptr->cm_handle->cm_id->qp = NULL; + dapls_ib_cm_free(ep_ptr->cm_handle, NULL); + } else { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapl_cma_accept: ERR dev(%p!=%p) or" + " port mismatch(%d!=%d)\n", + ep_ptr->cm_handle->cm_id->verbs, cr_conn->cm_id->verbs, + ntohs(ep_ptr->cm_handle->cm_id->port_num), + ntohs(cr_conn->cm_id->port_num)); + dat_status = DAT_INTERNAL_ERROR; + goto bail; + } + + cr_ptr->param.local_ep_handle = ep_handle; + cr_conn->params.private_data = p_data; + cr_conn->params.private_data_len = p_size; + + ret = rdma_accept(cr_conn->cm_id, &cr_conn->params); + if (ret) { + dapl_log(DAPL_DBG_TYPE_ERR, " dapl_cma_accept: ERR %d %s\n", + ret, strerror(errno)); + dat_status = dapl_convert_errno(ret, "accept"); + goto bail; + } + + /* save accepted conn and EP reference, qp_handle unchanged */ + ep_ptr->cm_handle = cr_conn; + cr_conn->ep = ep_ptr; + + /* setup local and remote ports for ep query */ + /* Note: port qual in network order */ + ep_ptr->param.remote_port_qual = + PORT_TO_SID(rdma_get_dst_port(cr_conn->cm_id)); + ep_ptr->param.local_port_qual = + PORT_TO_SID(rdma_get_src_port(cr_conn->cm_id)); + + return DAT_SUCCESS; + bail: + rdma_reject(cr_conn->cm_id, NULL, 0); + dapls_ib_cm_free(cr_conn, NULL); + return dat_status; +} + +/* + * dapls_ib_reject_connection + * + * Reject a connection + * + * Input: + * cr_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INTERNAL_ERROR + * + */ +DAT_RETURN +dapls_ib_reject_connection(IN dp_ib_cm_handle_t cm_handle, + IN int reason, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data) +{ + int ret; + int offset = sizeof(struct dapl_pdata_hdr); + struct dapl_pdata_hdr pdata_hdr; + + memset(&pdata_hdr, 0, sizeof pdata_hdr); + pdata_hdr.version = htonl((DAT_VERSION_MAJOR << 24) | + (DAT_VERSION_MINOR << 16) | + (VN_PROVIDER_MAJOR << 8) | + (VN_PROVIDER_MINOR)); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " reject: handle %p reason %x, ver=%x, data %p, sz=%d\n", + cm_handle, reason, ntohl(pdata_hdr.version), + private_data, private_data_size); + + if (cm_handle == IB_INVALID_HANDLE) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " reject: invalid handle: reason %d\n", reason); + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR); + } + + if (private_data_size > + dapls_ib_private_data_size(NULL, DAPL_PDATA_CONN_REJ, + cm_handle->hca)) + return DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + + /* setup pdata_hdr and users data, in CR pdata buffer */ + dapl_os_memcpy(cm_handle->p_data, &pdata_hdr, offset); + if (private_data_size) + dapl_os_memcpy(cm_handle->p_data + offset, + private_data, private_data_size); + + /* + * Always some private data with reject so active peer can + * determine real application reject from an abnormal + * application termination + */ + ret = rdma_reject(cm_handle->cm_id, + cm_handle->p_data, offset + private_data_size); + + dapls_ib_cm_free(cm_handle, NULL); + return dapl_convert_errno(ret, "reject"); +} + +/* + * dapls_ib_cm_remote_addr + * + * Obtain the remote IP address given a connection + * + * Input: + * cr_handle + * + * Output: + * remote_ia_address: where to place the remote address + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * + */ +DAT_RETURN +dapls_ib_cm_remote_addr(IN DAT_HANDLE dat_handle, OUT DAT_SOCK_ADDR6 * raddr) +{ + DAPL_HEADER *header; + dp_ib_cm_handle_t ib_cm_handle; + struct rdma_addr *ipaddr; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " remote_addr(cm_handle=%p, r_addr=%p)\n", + dat_handle, raddr); + + header = (DAPL_HEADER *) dat_handle; + + if (header->magic == DAPL_MAGIC_EP) + ib_cm_handle = ((DAPL_EP *) dat_handle)->cm_handle; + else if (header->magic == DAPL_MAGIC_CR) + ib_cm_handle = ((DAPL_CR *) dat_handle)->ib_cm_handle; + else + return DAT_INVALID_HANDLE; + + /* get remote IP address from cm_id route */ + ipaddr = &ib_cm_handle->cm_id->route.addr; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " remote_addr: conn %p id %p SRC %x DST %x PORT %d\n", + ib_cm_handle, ib_cm_handle->cm_id, + ntohl(((struct sockaddr_in *) + &ipaddr->src_addr)->sin_addr.s_addr), + ntohl(((struct sockaddr_in *) + &ipaddr->dst_addr)->sin_addr.s_addr), + ntohs(((struct sockaddr_in *) + &ipaddr->dst_addr)->sin_port)); + + dapl_os_memcpy(raddr, &ipaddr->dst_addr, sizeof(DAT_SOCK_ADDR)); + return DAT_SUCCESS; +} + +/* + * dapls_ib_private_data_size + * + * Return the size of private data given a connection op type + * + * Input: + * prd_ptr private data pointer + * conn_op connection operation type + * hca_ptr hca pointer, needed for transport type + * + * If prd_ptr is NULL, this is a query for the max size supported by + * the provider, otherwise it is the actual size of the private data + * contained in prd_ptr. + * + * + * Output: + * None + * + * Returns: + * length of private data + * + */ +int dapls_ib_private_data_size(IN DAPL_PRIVATE * prd_ptr, + IN DAPL_PDATA_OP conn_op, IN DAPL_HCA * hca_ptr) +{ + int size; + + if (hca_ptr->ib_hca_handle->device->transport_type + == IBV_TRANSPORT_IWARP) + return (IWARP_MAX_PDATA_SIZE - sizeof(struct dapl_pdata_hdr)); + + switch (conn_op) { + + case DAPL_PDATA_CONN_REQ: + size = IB_MAX_REQ_PDATA_SIZE; + break; + case DAPL_PDATA_CONN_REP: + size = IB_MAX_REP_PDATA_SIZE; + break; + case DAPL_PDATA_CONN_REJ: + size = IB_MAX_REJ_PDATA_SIZE - sizeof(struct dapl_pdata_hdr); + break; + case DAPL_PDATA_CONN_DREQ: + size = IB_MAX_DREQ_PDATA_SIZE; + break; + case DAPL_PDATA_CONN_DREP: + size = IB_MAX_DREP_PDATA_SIZE; + break; + default: + size = 0; + + } /* end case */ + + return size; +} + +/* + * Map all CMA event codes to the DAT equivelent. + */ +#define DAPL_IB_EVENT_CNT 13 + +static struct ib_cm_event_map { + const ib_cm_events_t ib_cm_event; + DAT_EVENT_NUMBER dat_event_num; +} ib_cm_event_map[DAPL_IB_EVENT_CNT] = { + /* 00 */ { + IB_CME_CONNECTED, DAT_CONNECTION_EVENT_ESTABLISHED}, + /* 01 */ { + IB_CME_DISCONNECTED, DAT_CONNECTION_EVENT_DISCONNECTED}, + /* 02 */ { + IB_CME_DISCONNECTED_ON_LINK_DOWN, + DAT_CONNECTION_EVENT_DISCONNECTED}, + /* 03 */ { + IB_CME_CONNECTION_REQUEST_PENDING, DAT_CONNECTION_REQUEST_EVENT}, + /* 04 */ { + IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA, + DAT_CONNECTION_REQUEST_EVENT}, + /* 05 */ { + IB_CME_CONNECTION_REQUEST_ACKED, DAT_CONNECTION_REQUEST_EVENT}, + /* 06 */ { + IB_CME_DESTINATION_REJECT, + DAT_CONNECTION_EVENT_NON_PEER_REJECTED}, + /* 07 */ { + IB_CME_DESTINATION_REJECT_PRIVATE_DATA, + DAT_CONNECTION_EVENT_PEER_REJECTED}, + /* 08 */ { + IB_CME_DESTINATION_UNREACHABLE, DAT_CONNECTION_EVENT_UNREACHABLE}, + /* 09 */ { + IB_CME_TOO_MANY_CONNECTION_REQUESTS, + DAT_CONNECTION_EVENT_NON_PEER_REJECTED}, + /* 10 */ { + IB_CME_LOCAL_FAILURE, DAT_CONNECTION_EVENT_BROKEN}, + /* 11 */ { + IB_CME_BROKEN, DAT_CONNECTION_EVENT_BROKEN}, + /* 12 */ { +IB_CME_TIMEOUT, DAT_CONNECTION_EVENT_TIMED_OUT},}; + +/* + * dapls_ib_get_cm_event + * + * Return a DAT connection event given a provider CM event. + * + * Input: + * dat_event_num DAT event we need an equivelent CM event for + * + * Output: + * none + * + * Returns: + * ib_cm_event of translated DAPL value + */ +DAT_EVENT_NUMBER +dapls_ib_get_dat_event(IN const ib_cm_events_t ib_cm_event, + IN DAT_BOOLEAN active) +{ + DAT_EVENT_NUMBER dat_event_num; + int i; + + active = active; + + dat_event_num = 0; + for (i = 0; i < DAPL_IB_EVENT_CNT; i++) { + if (ib_cm_event == ib_cm_event_map[i].ib_cm_event) { + dat_event_num = ib_cm_event_map[i].dat_event_num; + break; + } + } + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK, + "dapls_ib_get_dat_event: event(%s) ib=0x%x dat=0x%x\n", + active ? "active" : "passive", ib_cm_event, dat_event_num); + + return dat_event_num; +} + +/* + * dapls_ib_get_dat_event + * + * Return a DAT connection event given a provider CM event. + * + * Input: + * ib_cm_event event provided to the dapl callback routine + * active switch indicating active or passive connection + * + * Output: + * none + * + * Returns: + * DAT_EVENT_NUMBER of translated provider value + */ +ib_cm_events_t dapls_ib_get_cm_event(IN DAT_EVENT_NUMBER dat_event_num) +{ + ib_cm_events_t ib_cm_event; + int i; + + ib_cm_event = 0; + for (i = 0; i < DAPL_IB_EVENT_CNT; i++) { + if (dat_event_num == ib_cm_event_map[i].dat_event_num) { + ib_cm_event = ib_cm_event_map[i].ib_cm_event; + break; + } + } + return ib_cm_event; +} + +void dapli_cma_event_cb(void) +{ + struct rdma_cm_event *event; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_event()\n"); + + /* process one CM event, fairness */ + if (!rdma_get_cm_event(g_cm_events, &event)) { + struct dapl_cm_id *conn; + + /* set proper conn from cm_id context */ + if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) + conn = (struct dapl_cm_id *)event->listen_id->context; + else + conn = (struct dapl_cm_id *)event->id->context; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " cm_event: EVENT=%d ID=%p LID=%p CTX=%p\n", + event->event, event->id, event->listen_id, conn); + + switch (event->event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + dapli_addr_resolve(conn); + break; + + case RDMA_CM_EVENT_ROUTE_RESOLVED: + dapli_route_resolve(conn); + break; + + case RDMA_CM_EVENT_ADDR_ERROR: + dapl_log(DAPL_DBG_TYPE_WARN, + "dapl_cma_active: CM ADDR ERROR: ->" + " DST %s retry (%d)..\n", + inet_ntoa(((struct sockaddr_in *) + &conn->r_addr)->sin_addr), + conn->arp_retries); + + /* retry address resolution */ + if ((--conn->arp_retries) && + (event->status == -ETIMEDOUT)) { + int ret; + ret = rdma_resolve_addr(conn->cm_id, NULL, + (struct sockaddr *) + &conn->r_addr, + conn->arp_timeout); + if (!ret) + break; + else { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + " ERROR: rdma_resolve_addr = " + "%d %s\n", + ret, strerror(errno)); + } + } + /* retries exhausted or resolve_addr failed */ + dapl_log(DAPL_DBG_TYPE_ERR, + "dapl_cma_active: ARP_ERR, retries(%d)" + " exhausted -> DST %s,%d\n", + IB_ARP_RETRY_COUNT, + inet_ntoa(((struct sockaddr_in *) + &conn->cm_id->route.addr.dst_addr)-> + sin_addr), + ntohs(((struct sockaddr_in *) + &conn->cm_id->route.addr.dst_addr)-> + sin_port)); + + dapl_evd_connection_callback(conn, + IB_CME_DESTINATION_UNREACHABLE, + NULL, conn->ep); + break; + + case RDMA_CM_EVENT_ROUTE_ERROR: + dapl_log(DAPL_DBG_TYPE_WARN, + "dapl_cma_active: CM ROUTE ERROR: ->" + " DST %s retry (%d)..\n", + inet_ntoa(((struct sockaddr_in *) + &conn->r_addr)->sin_addr), + conn->route_retries); + + /* retry route resolution */ + if ((--conn->route_retries) && + (event->status == -ETIMEDOUT)) + dapli_addr_resolve(conn); + else { + dapl_log(DAPL_DBG_TYPE_ERR, + "dapl_cma_active: PATH_RECORD_ERR," + " retries(%d) exhausted, DST %s,%d\n", + IB_ROUTE_RETRY_COUNT, + inet_ntoa(((struct sockaddr_in *) + &conn->cm_id->route.addr. + dst_addr)->sin_addr), + ntohs(((struct sockaddr_in *) + &conn->cm_id->route.addr. + dst_addr)->sin_port)); + + dapl_evd_connection_callback(conn, + IB_CME_DESTINATION_UNREACHABLE, + NULL, conn->ep); + } + break; + + case RDMA_CM_EVENT_DEVICE_REMOVAL: + dapl_evd_connection_callback(conn, + IB_CME_LOCAL_FAILURE, + NULL, conn->ep); + break; + case RDMA_CM_EVENT_CONNECT_REQUEST: + case RDMA_CM_EVENT_CONNECT_ERROR: + case RDMA_CM_EVENT_UNREACHABLE: + case RDMA_CM_EVENT_REJECTED: + case RDMA_CM_EVENT_ESTABLISHED: + case RDMA_CM_EVENT_DISCONNECTED: + /* passive or active */ + if (conn->sp) + dapli_cm_passive_cb(conn, event); + else + dapli_cm_active_cb(conn, event); + break; + case RDMA_CM_EVENT_CONNECT_RESPONSE: + case RDMA_CM_EVENT_TIMEWAIT_EXIT: + break; + default: + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + " 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); + } +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/dapl_ib_util.h b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/dapl_ib_util.h new file mode 100644 index 00000000..f466c068 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/dapl_ib_util.h @@ -0,0 +1,134 @@ +/* + * 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 +#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 */ +#define CMA_PDATA_HDR 36 +#define IB_MAX_REQ_PDATA_SIZE (92-CMA_PDATA_HDR) +#define IB_MAX_REP_PDATA_SIZE (196-CMA_PDATA_HDR) +#define IB_MAX_REJ_PDATA_SIZE (148-CMA_PDATA_HDR) +#define IB_MAX_DREQ_PDATA_SIZE (220-CMA_PDATA_HDR) +#define IB_MAX_DREP_PDATA_SIZE (224-CMA_PDATA_HDR) +#define IWARP_MAX_PDATA_SIZE (512-CMA_PDATA_HDR) + +struct dapl_cm_id { + DAPL_OS_LOCK lock; + int destroy; + int arp_retries; + int arp_timeout; + int route_retries; + int route_timeout; + int in_callback; + struct rdma_cm_id *cm_id; + struct dapl_hca *hca; + struct dapl_sp *sp; + 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_qp_cm_t dst; /* dapls_modify_qp_state */ + struct ibv_ah *ah; /* dapls_modify_qp_state */ +}; + +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 dapl_hca *d_hca; + 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_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; + +} 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 *hca); +dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep); +void dapls_ib_cm_free(dp_ib_cm_handle_t cm, DAPL_EP *ep); +DAT_RETURN dapls_modify_qp_state(IN ib_qp_handle_t qp_handle, + IN ib_qp_state_t qp_state, + IN dp_ib_cm_handle_t cm); + +STATIC _INLINE_ void dapls_print_cm_list(IN DAPL_IA * ia_ptr) +{ + return; +} + +#endif /* _DAPL_IB_UTIL_H_ */ diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/device.c b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/device.c new file mode 100644 index 00000000..3c9d1354 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/device.c @@ -0,0 +1,847 @@ +/* + * 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 "..\..\..\..\..\etc\user\comp_channel.cpp" +#include + +struct ibvw_windata windata; + +static int getipaddr_netdev(char *name, char *addr, int addr_len) +{ + IWVProvider *prov; + WV_DEVICE_ADDRESS devaddr; + struct addrinfo *res, *ai; + HRESULT hr; + int index; + + if (strncmp(name, "rdma_dev", 8)) { + return EINVAL; + } + + index = atoi(name + 8); + + hr = WvGetObject(&IID_IWVProvider, (LPVOID *) &prov); + if (FAILED(hr)) { + return hr; + } + + hr = getaddrinfo("..localmachine", NULL, NULL, &res); + if (hr) { + goto release; + } + + for (ai = res; ai; ai = ai->ai_next) { + hr = prov->lpVtbl->TranslateAddress(prov, ai->ai_addr, &devaddr); + if (SUCCEEDED(hr) && (ai->ai_addrlen <= addr_len) && (index-- == 0)) { + memcpy(addr, ai->ai_addr, ai->ai_addrlen); + goto free; + } + } + hr = ENODEV; + +free: + freeaddrinfo(res); +release: + prov->lpVtbl->Release(prov); + return hr; +} + +static int dapls_os_init(void) +{ + return ibvw_get_windata(&windata, IBVW_WINDATA_VERSION); +} + +static void dapls_os_release(void) +{ + if (windata.comp_mgr) + ibvw_release_windata(&windata, IBVW_WINDATA_VERSION); + windata.comp_mgr = NULL; +} + +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_thread_signal(void) +{ + CompManagerCancel(windata.comp_mgr); + return 0; +} +#else // _WIN64 || WIN32 +int g_ib_pipe[2]; + +static int dapls_os_init(void) +{ + /* create pipe for waking up work thread */ + return pipe(g_ib_pipe); +} + +static void dapls_os_release(void) +{ + /* close pipe? */ +} + +/* Get IP address using network device name */ +static int getipaddr_netdev(char *name, char *addr, int addr_len) +{ + struct ifreq ifr; + int skfd, ret, len; + + /* Fill in the structure */ + snprintf(ifr.ifr_name, IFNAMSIZ, "%s", name); + ifr.ifr_hwaddr.sa_family = ARPHRD_INFINIBAND; + + /* Create a socket fd */ + skfd = socket(PF_INET, SOCK_STREAM, 0); + ret = ioctl(skfd, SIOCGIFADDR, &ifr); + if (ret) + goto bail; + + switch (ifr.ifr_addr.sa_family) { +#ifdef AF_INET6 + case AF_INET6: + len = sizeof(struct sockaddr_in6); + break; +#endif + case AF_INET: + default: + len = sizeof(struct sockaddr); + break; + } + + if (len <= addr_len) + memcpy(addr, &ifr.ifr_addr, len); + else + ret = EINVAL; + + bail: + close(skfd); + return ret; +} + +static int dapls_config_fd(int fd) +{ + int opts; + + opts = fcntl(fd, F_GETFL); + if (opts < 0 || fcntl(fd, F_SETFL, opts | O_NONBLOCK) < 0) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapls_config_fd: fcntl on fd %d ERR %d %s\n", + fd, opts, strerror(errno)); + return errno; + } + + return 0; +} + +static int dapls_config_cm_channel(struct rdma_event_channel *channel) +{ + return dapls_config_fd(channel->fd); +} + +static int dapls_config_verbs(struct ibv_context *verbs) +{ + return dapls_config_fd(verbs->async_fd); +} + +static int dapls_thread_signal(void) +{ + return write(g_ib_pipe[1], "w", sizeof "w"); +} +#endif + +/* Get IP address using network name, address, or device name */ +static int getipaddr(char *name, char *addr, int len) +{ + struct addrinfo *res; + + /* assume netdev for first attempt, then network and address type */ + if (getipaddr_netdev(name, addr, len)) { + if (getaddrinfo(name, NULL, NULL, &res)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: getaddr_netdev ERROR:" + " %s. Is %s configured?\n", + strerror(errno), name); + return 1; + } else { + if (len >= res->ai_addrlen) + memcpy(addr, res->ai_addr, res->ai_addrlen); + else { + freeaddrinfo(res); + return 1; + } + freeaddrinfo(res); + } + } + + dapl_dbg_log( + DAPL_DBG_TYPE_UTIL, + " getipaddr: family %d port %d addr %d.%d.%d.%d\n", + ((struct sockaddr_in *)addr)->sin_family, + ((struct sockaddr_in *)addr)->sin_port, + ((struct sockaddr_in *)addr)->sin_addr.s_addr >> 0 & 0xff, + ((struct sockaddr_in *)addr)->sin_addr.s_addr >> 8 & 0xff, + ((struct sockaddr_in *)addr)->sin_addr.s_addr >> 16 & 0xff, + ((struct sockaddr_in *)addr)->sin_addr. + s_addr >> 24 & 0xff); + + return 0; +} + +/* + * dapls_ib_init, dapls_ib_release + * + * Initialize Verb related items for device open + * + * Input: + * none + * + * Output: + * none + * + * Returns: + * 0 success, -1 error + * + */ +int32_t dapls_ib_init(void) +{ + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " dapl_ib_init: \n"); + + /* initialize hca_list lock */ + dapl_os_lock_init(&g_hca_lock); + + /* initialize hca list for CQ events */ + dapl_llist_init_head(&g_hca_list); + + if (dapls_os_init()) + return 1; + + return 0; +} + +int32_t dapls_ib_release(void) +{ + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " dapl_ib_release: \n"); + dapli_ib_thread_destroy(); + if (g_cm_events != NULL) + rdma_destroy_event_channel(g_cm_events); + dapls_os_release(); + return 0; +} + +/* + * dapls_ib_open_hca + * + * Open HCA + * + * Input: + * *hca_name pointer to provider device name + * *ib_hca_handle_p pointer to provide HCA handle + * + * Output: + * none + * + * Return: + * DAT_SUCCESS + * dapl_convert_errno + * + */ +DAT_RETURN dapls_ib_open_hca(IN IB_HCA_NAME hca_name, IN DAPL_HCA * hca_ptr) +{ + struct rdma_cm_id *cm_id = NULL; + union ibv_gid *gid; + int ret; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " open_hca: %s - %p\n", hca_name, hca_ptr); + + /* Setup the global cm event channel */ + dapl_os_lock(&g_hca_lock); + if (g_cm_events == NULL) { + g_cm_events = rdma_create_event_channel(); + if (g_cm_events == NULL) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " open_hca: ERR - RDMA channel %s\n", + strerror(errno)); + dapl_os_unlock(&g_hca_lock); + return DAT_INTERNAL_ERROR; + } + } + dapl_os_unlock(&g_hca_lock); + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " open_hca: RDMA channel created (%p)\n", g_cm_events); + + dat_status = dapli_ib_thread_init(); + if (dat_status != DAT_SUCCESS) + return dat_status; + + /* 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); + 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; + 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)); + + /* 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); + + /* + * 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); + + hca_ptr->ib_trans.d_hca = hca_ptr; + 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); + + 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; + } + + 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: + 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) +{ + int retries = 10; + + 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; + if (dapls_thread_signal() == -1) + dapl_log(DAPL_DBG_TYPE_UTIL, + " destroy: thread wakeup error = %s\n", + strerror(errno)); + while ((g_ib_thread_state != IB_THREAD_EXIT) && (retries--)) { + 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()); +} + +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->cm_id->verbs, &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->cm_id->verbs, + 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->cm_id->verbs, + 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->cm_id-> + verbs, &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); + } +} + +#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)) { + + idx = 0; + hca = dapl_llist_is_empty(&g_hca_list) ? NULL : + dapl_llist_peek_head(&g_hca_list); + + while (hca) { + 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 = CompManagerPoll(windata.comp_mgr, INFINITE, &channel); + + 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_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->cm_id->verbs->async_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 ASYNC events, per device */ + for (idx = 2; idx < fds; idx++) { + if (ufds[idx].revents == POLLIN) { + 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 = 2; 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-1/ulp/dapl2/dapl/openib_cma/libdaplcma.map b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/libdaplcma.map new file mode 100644 index 00000000..de06305f --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/libdaplcma.map @@ -0,0 +1,7 @@ +DAPL_CMA_2.0 { + global: + dat_provider_fini; + dat_provider_init; + dapl_extensions; + local: *; +}; diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/linux/openib_osd.h b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/linux/openib_osd.h new file mode 100644 index 00000000..309972f9 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/linux/openib_osd.h @@ -0,0 +1,15 @@ +#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 + +#endif // OPENIB_OSD_H diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/makefile b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/openib_cma/udapl.rc b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/udapl.rc new file mode 100644 index 00000000..c0533298 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/openib_cma/udapl_ofa_cma_exports.src b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/udapl_ofa_cma_exports.src new file mode 100644 index 00000000..32e74d24 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/openib_cma/windows/openib_osd.h b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/windows/openib_osd.h new file mode 100644 index 00000000..d008fc0a --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_cma/windows/openib_osd.h @@ -0,0 +1,5 @@ +#include +#include + +#define ntohll _byteswap_uint64 +#define htonll _byteswap_uint64 diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_common.c b/branches/WOF2-1/ulp/dapl2/dapl/openib_common.c new file mode 100644 index 00000000..336eff96 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/openib_common/cq.c b/branches/WOF2-1/ulp/dapl2/dapl/openib_common/cq.c new file mode 100644 index 00000000..aedfd712 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_common/cq.c @@ -0,0 +1,491 @@ +/* + * 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 = evd_ptr->cq_wait_obj_handle; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + "dapls_ib_cq_alloc: evd %p cqlen=%d \n", evd_ptr, *cqlen); + + /* Call IB verbs to create CQ */ + 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) + return DAT_INSUFFICIENT_RESOURCES; + + /* 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; +} + +/* + * 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 new_cq; + struct ibv_comp_channel *channel = evd_ptr->cq_wait_obj_handle; + + /* IB verbs DOES support resize. REDO THIS. + * Try to re-create CQ + * with new size. Can only be done if QP is not attached. + * destroy EBUSY == QP still attached. + */ + + /* Call IB verbs to create CQ */ + new_cq = ibv_create_cq(ia_ptr->hca_ptr->ib_hca_handle, *cqlen, + evd_ptr, channel, 0); + + if (new_cq == IB_INVALID_HANDLE) + return DAT_INSUFFICIENT_RESOURCES; + + /* destroy the original and replace if successful */ + if (ibv_destroy_cq(evd_ptr->ib_cq_handle)) { + ibv_destroy_cq(new_cq); + return (dapl_convert_errno(errno, "resize_cq")); + } + + /* update EVD with new cq handle and size */ + evd_ptr->ib_cq_handle = new_cq; + *cqlen = new_cq->cqe; + + /* arm cq for events */ + dapls_set_cq_notify(ia_ptr, evd_ptr); + + return DAT_SUCCESS; +} + +/* + * 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; + + 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) ; + if (ibv_destroy_cq(evd_ptr->ib_cq_handle)) + return (dapl_convert_errno(errno, "ibv_destroy_cq")); + evd_ptr->ib_cq_handle = IB_INVALID_HANDLE; + } + return DAT_SUCCESS; +} + +/* + * 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; +} + +/* NEW common wait objects for providers with direct CQ wait objects */ +DAT_RETURN +dapls_ib_wait_object_create(IN DAPL_EVD * evd_ptr, + IN ib_wait_obj_handle_t * p_cq_wait_obj_handle) +{ + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " cq_object_create: (%p,%p)\n", + evd_ptr, p_cq_wait_obj_handle); + + /* set cq_wait object to evd_ptr */ + *p_cq_wait_obj_handle = + ibv_create_comp_channel(evd_ptr->header.owner_ia->hca_ptr-> + ib_hca_handle); + + return DAT_SUCCESS; +} + +DAT_RETURN +dapls_ib_wait_object_destroy(IN ib_wait_obj_handle_t p_cq_wait_obj_handle) +{ + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " cq_object_destroy: wait_obj=%p\n", p_cq_wait_obj_handle); + + ibv_destroy_comp_channel(p_cq_wait_obj_handle); + + return DAT_SUCCESS; +} + +DAT_RETURN +dapls_ib_wait_object_wakeup(IN ib_wait_obj_handle_t p_cq_wait_obj_handle) +{ + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " cq_object_wakeup: wait_obj=%p\n", p_cq_wait_obj_handle); + + /* no wake up mechanism */ + return DAT_SUCCESS; +} + +#if defined(_WIN32) || defined(_WIN64) +DAT_RETURN +dapls_ib_wait_object_wait(IN ib_wait_obj_handle_t p_cq_wait_obj_handle, + IN uint32_t timeout) +{ + struct dapl_evd *evd_ptr; + struct ibv_cq *ibv_cq = NULL; + int status = 0; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " cq_object_wait: CQ channel %p time %d\n", + p_cq_wait_obj_handle, timeout); + + /* uDAPL timeout values in usecs */ + p_cq_wait_obj_handle->comp_channel.Milliseconds = timeout / 1000; + + /* returned event */ + status = ibv_get_cq_event(p_cq_wait_obj_handle, &ibv_cq, + (void *)&evd_ptr); + if (status == 0) { + 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")); +} +#else //_WIN32 || _WIN64 +DAT_RETURN +dapls_ib_wait_object_wait(IN ib_wait_obj_handle_t p_cq_wait_obj_handle, + IN uint32_t timeout) +{ + struct dapl_evd *evd_ptr; + struct ibv_cq *ibv_cq = NULL; + int status = 0; + int timeout_ms = -1; + struct pollfd cq_fd = { + .fd = p_cq_wait_obj_handle->fd, + .events = POLLIN, + .revents = 0 + }; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " cq_object_wait: CQ channel %p time %d\n", + p_cq_wait_obj_handle, timeout); + + /* uDAPL timeout values in usecs */ + if (timeout != DAT_TIMEOUT_INFINITE) + timeout_ms = timeout / 1000; + + status = poll(&cq_fd, 1, timeout_ms); + + /* returned event */ + if (status > 0) { + if (!ibv_get_cq_event(p_cq_wait_obj_handle, + &ibv_cq, (void *)&evd_ptr)) { + ibv_ack_cq_events(ibv_cq, 1); + } + status = 0; + + /* timeout */ + } else if (status == 0) + status = ETIMEDOUT; + + 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")); + +} +#endif //_WIN32 || _WIN64 + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_common/dapl_ib_common.h b/branches/WOF2-1/ulp/dapl2/dapl/openib_common/dapl_ib_common.h new file mode 100644 index 00000000..2ed5ea1a --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_common/dapl_ib_common.h @@ -0,0 +1,299 @@ +/* + * 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; + +/* 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 4 +typedef struct _ib_qp_cm +{ + uint16_t ver; + uint16_t rej; + uint16_t lid; + uint16_t port; + uint32_t qpn; + uint32_t p_size; + union ibv_gid gid; + DAT_SOCK_ADDR6 ia_address; + uint16_t qp_type; +} ib_qp_cm_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; +typedef uint32_t ib_comp_handle_t; + +typedef struct ibv_comp_channel *ib_wait_obj_handle_t; + +/* Definitions */ +#define IB_INVALID_HANDLE NULL + +/* inline send rdma threshold */ +#define INLINE_SEND_IWARP_DEFAULT 64 +#define INLINE_SEND_IB_DEFAULT 200 + +/* qkey for UD QP's */ +#define DAT_UD_QKEY 0x78654321 + +/* 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; + + +/* 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); +enum ibv_mtu dapl_ib_mtu(int mtu); +char *dapl_ib_mtu_str(enum ibv_mtu mtu); +DAT_RETURN getlocalipaddr(DAT_SOCK_ADDR *addr, int addr_len); + +/* 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; + } + } + +typedef enum dapl_cm_state +{ + DCM_INIT, + DCM_LISTEN, + DCM_CONN_PENDING, + DCM_RTU_PENDING, + DCM_ACCEPTING, + DCM_ACCEPTING_DATA, + DCM_ACCEPTED, + DCM_REJECTED, + DCM_CONNECTED, + DCM_RELEASED, + DCM_DISCONNECTED, + DCM_DESTROY +} DAPL_CM_STATE; + +STATIC _INLINE_ char * dapl_cm_state_str(IN int st) +{ + static char *state[] = { + "CM_INIT", + "CM_LISTEN", + "CM_CONN_PENDING", + "CM_RTU_PENDING", + "CM_ACCEPTING", + "CM_ACCEPTING_DATA", + "CM_ACCEPTED", + "CM_REJECTED", + "CM_CONNECTED", + "CM_RELEASED", + "CM_DISCONNECTED", + "CM_DESTROY" + }; + return ((st < 0 || st > 11) ? "Invalid CM state?" : state[st]); +} + +#endif /* _DAPL_IB_COMMON_H_ */ diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_common/dapl_ib_dto.h b/branches/WOF2-1/ulp/dapl2/dapl/openib_common/dapl_ib_dto.h new file mode 100644 index 00000000..1e741130 --- /dev/null +++ b/branches/WOF2-1/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, 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-1/ulp/dapl2/dapl/openib_common/ib_extensions.c b/branches/WOF2-1/ulp/dapl2/dapl/openib_common/ib_extensions.c new file mode 100644 index 00000000..4dc46ffa --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/openib_common/mem.c b/branches/WOF2-1/ulp/dapl2/dapl/openib_common/mem.c new file mode 100644 index 00000000..2e33cac5 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_common/mem.c @@ -0,0 +1,370 @@ +/* + * 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; + if (DAT_MEM_PRIV_REMOTE_READ_FLAG & privileges) + access |= IBV_ACCESS_REMOTE_READ; + if (DAT_MEM_PRIV_REMOTE_READ_FLAG & privileges) + access |= IBV_ACCESS_REMOTE_READ; +#ifdef DAT_EXTENSIONS + if (DAT_IB_MEM_PRIV_REMOTE_ATOMIC & privileges) + access |= IBV_ACCESS_REMOTE_ATOMIC; +#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) { + if (ibv_dealloc_pd(pz->pd_handle)) + return (dapl_convert_errno(errno, "ibv_dealloc_pd")); + 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-1/ulp/dapl2/dapl/openib_common/qp.c b/branches/WOF2-1/ulp/dapl2/dapl/openib_common/qp.c new file mode 100644 index 00000000..ffff25b4 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_common/qp.c @@ -0,0 +1,515 @@ +/* + * This Software 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" + +/* + * 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 = + rcv_evd->cq_wait_obj_handle; + + /* 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) + 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, "create_cq")); + + /* open identifies the local device; per DAT specification */ + if (rdma_bind_addr(conn->cm_id, + (struct sockaddr *)&ia_ptr->hca_ptr->hca_address)) + return (dapl_convert_errno(EAFNOSUPPORT, "create_cq")); +#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_ib_cm_free(conn, ep_ptr); + return (dapl_convert_errno(errno, "create_qp")); + } + ep_ptr->qp_handle = conn->cm_id->qp; + ep_ptr->cm_handle = conn; + ep_ptr->qp_state = IBV_QPS_INIT; + + /* setup up ep->param to reference the bound local address and port */ + ep_ptr->param.local_ia_address_ptr = + &conn->cm_id->route.addr.src_addr; + 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, NULL) != DAT_SUCCESS) { + ibv_destroy_qp(ep_ptr->qp_handle); + ep_ptr->qp_handle = IB_INVALID_HANDLE; + return DAT_INTERNAL_ERROR; + } +#endif + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " qp_alloc: qpn %p sq %d,%d rq %d,%d\n", + ep_ptr->qp_handle->qp_num, + qp_create.cap.max_send_wr, qp_create.cap.max_send_sge, + qp_create.cap.max_recv_wr, qp_create.cap.max_recv_sge); + + return DAT_SUCCESS; +} + +/* + * dapl_ib_qp_free + * + * Free a QP + * + * Input: + * ia_handle IA handle + * *ep_ptr pointer to EP INFO + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * dapl_convert_errno + * + */ +DAT_RETURN dapls_ib_qp_free(IN DAPL_IA * ia_ptr, IN DAPL_EP * ep_ptr) +{ + dapl_dbg_log(DAPL_DBG_TYPE_EP, " qp_free: ep_ptr %p qp %p\n", + ep_ptr, ep_ptr->qp_handle); + + if (ep_ptr->cm_handle != NULL) { + dapls_ib_cm_free(ep_ptr->cm_handle, ep_ptr); + } + + 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, NULL); + + if (ibv_destroy_qp(ep_ptr->qp_handle)) + return (dapl_convert_errno(errno, "destroy_qp")); + + ep_ptr->qp_handle = NULL; + } + +#ifdef DAT_EXTENSIONS + /* UD endpoints can have many CR associations and will not + * set ep->cm_handle. Call provider with cm_ptr null to incidate + * UD type multi CR's for this EP. It will parse internal list + * and cleanup all associations. + */ + if (ep_ptr->param.ep_attr.service_type == DAT_IB_SERVICE_TYPE_UD) + dapls_ib_cm_free(NULL, ep_ptr); +#endif + + 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, NULL)); + } + + /* + * 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) +void dapls_ib_reinit_ep(IN DAPL_EP * ep_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); + 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); + dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_INIT, 0); + } +} +#endif // _WIN32 || _WIN64 + +/* + * Generic QP modify for init, reset, error, RTS, RTR + * For UD, create_ah on RTR, qkey on INIT + */ +DAT_RETURN +dapls_modify_qp_state(IN ib_qp_handle_t qp_handle, + IN ib_qp_state_t qp_state, + IN dp_ib_cm_handle_t cm_ptr) +{ + 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; + ib_qp_cm_t *qp_cm = &cm_ptr->dst; + int ret; + + dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr)); + qp_attr.qp_state = qp_state; + switch (qp_state) { + /* additional attributes with RTR and RTS */ + case IBV_QPS_RTR: + { + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " QPS_RTR: type %d state %d qpn %x lid %x" + " port %x ep %p qp_state %d\n", + qp_handle->qp_type, qp_handle->qp_type, + qp_cm->qpn, qp_cm->lid, qp_cm->port, + 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 = qp_cm->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 = qp_cm->lid; + if (ia_ptr->hca_ptr->ib_trans.global) { + qp_attr.ah_attr.is_global = 1; + qp_attr.ah_attr.grh.dgid = qp_cm->gid; + qp_attr.ah_attr.grh.hop_limit = + ia_ptr->hca_ptr->ib_trans.hop_limit; + qp_attr.ah_attr.grh.traffic_class = + ia_ptr->hca_ptr->ib_trans.tclass; + } + qp_attr.ah_attr.sl = 0; + qp_attr.ah_attr.src_path_bits = 0; + qp_attr.ah_attr.port_num = ia_ptr->hca_ptr->port_num; +#ifdef DAT_EXTENSIONS + /* UD: create AH for remote side */ + if (qp_handle->qp_type == IBV_QPT_UD) { + ib_pd_handle_t pz; + pz = ((DAPL_PZ *) + ep_ptr->param.pz_handle)->pd_handle; + mask = IBV_QP_STATE; + cm_ptr->ah = ibv_create_ah(pz, + &qp_attr.ah_attr); + if (!cm_ptr->ah) + return (dapl_convert_errno(errno, + "ibv_ah")); + + /* already RTR, multi remote AH's on QP */ + if (ep_ptr->qp_state == IBV_QPS_RTR || + ep_ptr->qp_state == IBV_QPS_RTS) + return DAT_SUCCESS; + } +#endif + break; + } + case IBV_QPS_RTS: + { + /* RC only */ + 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); +#ifdef DAT_EXTENSIONS + 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; + } +#endif + 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; + } +#ifdef DAT_EXTENSIONS + 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; + } +#endif + qp_attr.pkey_index = 0; + qp_attr.port_num = ia_ptr->hca_ptr->port_num; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " QPS_INIT: pi %x port %x acc %x qkey 0x%x\n", + qp_attr.pkey_index, qp_attr.port_num, + qp_attr.qp_access_flags, qp_attr.qkey); + break; + } + default: + break; + + } + + ret = ibv_modify_qp(qp_handle, &qp_attr, mask); + if (ret == 0) { + ep_ptr->qp_state = qp_state; + return DAT_SUCCESS; + } else { + return (dapl_convert_errno(errno, "modify_qp_state")); + } +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_common/util.c b/branches/WOF2-1/ulp/dapl2/dapl/openib_common/util.c new file mode 100644 index 00000000..0922e9ba --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_common/util.c @@ -0,0 +1,375 @@ +/* + * This Software 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; + +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(DAT_SOCK_ADDR * addr, int addr_len) +{ + struct sockaddr_in *sin; + struct addrinfo *res, hint, *ai; + int ret; + char hostname[256]; + + 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); + + dapl_log(DAPL_DBG_TYPE_UTIL, + " query_hca: (%x.%x) eps %d, sz %d evds %d," + " sz %d mtu %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); + + 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; +} + +/* + * 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; +} diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/SOURCES b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/SOURCES new file mode 100644 index 00000000..6e4ad30c --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/SOURCES @@ -0,0 +1,50 @@ +!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;..\..\..\..\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)\*\libibverbs.lib +!else + $(TARGETPATH)\*\dat2d.lib \ + $(TARGETPATH)\*\libibverbsd.lib +!endif + +MSC_WARNING_LEVEL = /W1 /wd4113 diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/cm.c b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/cm.c new file mode 100644 index 00000000..3639f157 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/cm.c @@ -0,0 +1,1865 @@ +/* + * This Software 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_osd.h" + +#if defined(_WIN32) || defined(_WIN64) +enum DAPL_FD_EVENTS { + DAPL_FD_READ = 0x1, + DAPL_FD_WRITE = 0x2, + DAPL_FD_ERROR = 0x4 +}; + +static int dapl_config_socket(DAPL_SOCKET s) +{ + unsigned long nonblocking = 1; + return ioctlsocket(s, FIONBIO, &nonblocking); +} + +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 WSAGetLastError(); + 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_CM, + " dapl_select: error 0x%x\n", WSAGetLastError()); + + return ret; +} +#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; + + ret = fcntl(s, F_GETFL); + if (ret >= 0) + ret = fcntl(s, F_SETFL, ret | O_NONBLOCK); + 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_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 ret; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: sleep, fds=%d\n", + set->index); + ret = poll(set->set, set->index, -1); + dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: wakeup, ret=0x%x\n", ret); + return ret; +} +#endif + +dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep) +{ + 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; + + cm_ptr->dst.ver = htons(DCM_VER); + cm_ptr->socket = DAPL_INVALID_SOCKET; + cm_ptr->ep = ep; + return cm_ptr; +bail: + dapl_os_free(cm_ptr, sizeof(*cm_ptr)); + return NULL; +} + +/* mark for destroy, remove all references, schedule cleanup */ +/* cm_ptr == NULL (UD), then multi CR's, kill all associated with EP */ +void dapls_ib_cm_free(dp_ib_cm_handle_t cm_ptr, DAPL_EP *ep) +{ + DAPL_IA *ia_ptr; + DAPL_HCA *hca_ptr = NULL; + dp_ib_cm_handle_t cr, next_cr; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " cm_destroy: cm %p ep %p\n", cm_ptr, ep); + + if (cm_ptr == NULL) + goto multi_cleanup; + + /* to notify cleanup thread */ + hca_ptr = cm_ptr->hca; + + /* cleanup, never made it to work queue */ + dapl_os_lock(&cm_ptr->lock); + if (cm_ptr->state == DCM_INIT) { + if (cm_ptr->socket != DAPL_INVALID_SOCKET) { + shutdown(cm_ptr->socket, SHUT_RDWR); + closesocket(cm_ptr->socket); + } + dapl_os_unlock(&cm_ptr->lock); + dapl_os_free(cm_ptr, sizeof(*cm_ptr)); + return; + } + + /* free could be called before disconnect, disc_clean will destroy */ + if (cm_ptr->state == DCM_CONNECTED) { + dapl_os_unlock(&cm_ptr->lock); + dapli_socket_disconnect(cm_ptr); + return; + } + + cm_ptr->state = DCM_DESTROY; + if ((cm_ptr->ep) && (cm_ptr->ep->cm_handle == cm_ptr)) { + cm_ptr->ep->cm_handle = IB_INVALID_HANDLE; + cm_ptr->ep = NULL; + } + + /* close socket if still active */ + if (cm_ptr->socket != DAPL_INVALID_SOCKET) { + shutdown(cm_ptr->socket, SHUT_RDWR); + closesocket(cm_ptr->socket); + cm_ptr->socket = DAPL_INVALID_SOCKET; + } + dapl_os_unlock(&cm_ptr->lock); + goto notify_thread; + +multi_cleanup: + + /* + * 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. 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, cr_thread will + * complete the cleanup with state == DCM_DESTROY. + */ + ia_ptr = ep->header.owner_ia; + 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; + + 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->entry); + if (cr->ep == ep) { + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " qp_free CR: ep %p cr %p\n", ep, cr); + dapli_socket_disconnect(cr); + dapl_os_lock(&cr->lock); + hca_ptr = cr->hca; + cr->ep = NULL; + cr->state = DCM_DESTROY; + dapl_os_unlock(&cr->lock); + } + } + dapl_os_unlock(&ia_ptr->hca_ptr->ib_trans.lock); + +notify_thread: + + /* wakeup work thread, if something destroyed */ + if (hca_ptr != NULL) { + if (send(hca_ptr->ib_trans.scm[1], + "w", sizeof "w", 0) == -1) + dapl_log(DAPL_DBG_TYPE_CM, + " cm_destroy: thread wakeup error = %s\n", + strerror(errno)); + } +} + +/* queue socket for processing CM work */ +static void dapli_cm_queue(struct ib_cm_handle *cm_ptr) +{ + /* add to work queue for cr thread processing */ + dapl_llist_init_entry((DAPL_LLIST_ENTRY *) & cm_ptr->entry); + dapl_os_lock(&cm_ptr->hca->ib_trans.lock); + dapl_llist_add_tail(&cm_ptr->hca->ib_trans.list, + (DAPL_LLIST_ENTRY *) & cm_ptr->entry, cm_ptr); + dapl_os_unlock(&cm_ptr->hca->ib_trans.lock); + + /* wakeup CM work thread */ + if (send(cm_ptr->hca->ib_trans.scm[1], "w", sizeof "w", 0) == -1) + dapl_log(DAPL_DBG_TYPE_CM, + " cm_queue: thread wakeup error = %s\n", + strerror(errno)); +} + +/* + * 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) +{ + DAPL_EP *ep_ptr = cm_ptr->ep; + DAT_UINT32 disc_data = htonl(0xdead); + + if (ep_ptr == NULL) + return DAT_SUCCESS; + + dapl_os_lock(&cm_ptr->lock); + if ((cm_ptr->state == DCM_INIT) || + (cm_ptr->state == DCM_DISCONNECTED) || + (cm_ptr->state == DCM_DESTROY)) { + dapl_os_unlock(&cm_ptr->lock); + return DAT_SUCCESS; + } else { + /* send disc date, close socket, schedule destroy */ + if (cm_ptr->socket != DAPL_INVALID_SOCKET) { + if (send(cm_ptr->socket, (char *)&disc_data, + sizeof(disc_data), 0) == -1) + dapl_log(DAPL_DBG_TYPE_WARN, + " cm_disc: write error = %s\n", + strerror(errno)); + shutdown(cm_ptr->socket, SHUT_RDWR); + closesocket(cm_ptr->socket); + cm_ptr->socket = DAPL_INVALID_SOCKET; + } + cm_ptr->state = DCM_DISCONNECTED; + } + dapl_os_unlock(&cm_ptr->lock); + + /* disconnect events for RC's only */ + if (ep_ptr->param.ep_attr.service_type == DAT_SERVICE_TYPE_RC) { + if (ep_ptr->cr_ptr) { + dapls_cr_callback(cm_ptr, + IB_CME_DISCONNECTED, + NULL, + ((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr); + } else { + dapl_evd_connection_callback(ep_ptr->cm_handle, + IB_CME_DISCONNECTED, + NULL, ep_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 ret, len, opt = 1; + struct iovec iov[2]; + struct dapl_ep *ep_ptr = cm_ptr->ep; + + if (err) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_PENDING: %s ERR %s -> %s %d\n", + err == -1 ? "POLL" : "SOCKOPT", + err == -1 ? strerror(errno) : strerror(err), + inet_ntoa(((struct sockaddr_in *) + ep_ptr->param. + remote_ia_address_ptr)->sin_addr), + ntohs(((struct sockaddr_in *) + &cm_ptr->dst.ia_address)->sin_port)); + goto bail; + } + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " socket connected, write QP and private data\n"); + + /* no delay for small packets */ + ret = setsockopt(cm_ptr->socket, IPPROTO_TCP, TCP_NODELAY, + (char *)&opt, sizeof(opt)); + if (ret) + dapl_log(DAPL_DBG_TYPE_WARN, + " connected: NODELAY setsockopt: %s\n", + strerror(errno)); + + /* send qp info and pdata to remote peer */ + iov[0].iov_base = (void *)&cm_ptr->dst; + iov[0].iov_len = sizeof(ib_qp_cm_t); + if (cm_ptr->dst.p_size) { + iov[1].iov_base = cm_ptr->p_data; + iov[1].iov_len = ntohl(cm_ptr->dst.p_size); + len = writev(cm_ptr->socket, iov, 2); + } else { + len = writev(cm_ptr->socket, iov, 1); + } + + if (len != (ntohl(cm_ptr->dst.p_size) + sizeof(ib_qp_cm_t))) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_PENDING write: ERR %s, wcnt=%d -> %s\n", + strerror(errno), len, inet_ntoa(((struct sockaddr_in *) + ep_ptr->param. + remote_ia_address_ptr)-> + sin_addr)); + goto bail; + } + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " connected: sending SRC port=0x%x lid=0x%x," + " qpn=0x%x, psize=%d\n", + ntohs(cm_ptr->dst.port), ntohs(cm_ptr->dst.lid), + ntohl(cm_ptr->dst.qpn), ntohl(cm_ptr->dst.p_size)); + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " connected: sending SRC GID subnet %016llx id %016llx\n", + (unsigned long long) + htonll(cm_ptr->dst.gid.global.subnet_prefix), + (unsigned long long) + htonll(cm_ptr->dst.gid.global.interface_id)); + + /* queue up to work thread to avoid blocking consumer */ + cm_ptr->state = DCM_RTU_PENDING; + return; + bail: + /* close socket, free cm structure and post error event */ + dapls_ib_cm_free(cm_ptr, cm_ptr->ep); + dapl_evd_connection_callback(NULL, IB_CME_LOCAL_FAILURE, NULL, ep_ptr); +} + +/* + * ACTIVE: Create socket, connect, defer exchange QP information to CR thread + * to avoid blocking. + */ +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; + DAPL_IA *ia_ptr = ep_ptr->header.owner_ia; + struct sockaddr_in addr; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, " connect: r_qual %d p_size=%d\n", + r_qual, p_size); + + cm_ptr = dapls_ib_cm_create(ep_ptr); + if (cm_ptr == NULL) + return DAT_INSUFFICIENT_RESOURCES; + + /* create, connect, sockopt, and exchange QP information */ + if ((cm_ptr->socket = + socket(AF_INET, SOCK_STREAM, 0)) == DAPL_INVALID_SOCKET) { + dapl_os_free(cm_ptr, sizeof(*cm_ptr)); + return DAT_INSUFFICIENT_RESOURCES; + } + + ret = dapl_config_socket(cm_ptr->socket); + if (ret < 0) { + dapl_log(DAPL_DBG_TYPE_ERR, + " socket connect: config socket %d ERR %d %s\n", + cm_ptr->socket, ret, strerror(errno)); + goto bail; + } + + dapl_os_memcpy(&addr, r_addr, sizeof(addr)); + addr.sin_port = htons(r_qual); + ret = dapl_connect_socket(cm_ptr->socket, (struct sockaddr *)&addr, + sizeof(addr)); + if (ret && ret != EAGAIN) { + dapl_log(DAPL_DBG_TYPE_ERR, + " socket connect ERROR: %s -> %s r_qual %d\n", + strerror(errno), + inet_ntoa(addr.sin_addr), (unsigned int)r_qual); + dapls_ib_cm_free(cm_ptr, cm_ptr->ep); + return DAT_INVALID_ADDRESS; + } + + /* Send QP info, IA address, and private data */ + cm_ptr->dst.qpn = htonl(ep_ptr->qp_handle->qp_num); +#ifdef DAT_EXTENSIONS + cm_ptr->dst.qp_type = htons(ep_ptr->qp_handle->qp_type); +#endif + cm_ptr->dst.port = htons(ia_ptr->hca_ptr->port_num); + cm_ptr->dst.lid = ia_ptr->hca_ptr->ib_trans.lid; + cm_ptr->dst.gid = ia_ptr->hca_ptr->ib_trans.gid; + + /* save references */ + cm_ptr->hca = ia_ptr->hca_ptr; + cm_ptr->ep = ep_ptr; + cm_ptr->dst.ia_address = ia_ptr->hca_ptr->hca_address; + ((struct sockaddr_in *) + &cm_ptr->dst.ia_address)->sin_port = ntohs(r_qual); + + if (p_size) { + cm_ptr->dst.p_size = htonl(p_size); + dapl_os_memcpy(cm_ptr->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: socket %d to %s r_qual %d pending\n", + cm_ptr->socket, + inet_ntoa(addr.sin_addr), (unsigned int)r_qual); + + dapli_cm_queue(cm_ptr); + return DAT_SUCCESS; + bail: + dapl_log(DAPL_DBG_TYPE_ERR, + " socket connect ERROR: %s query lid(0x%x)/gid" + " -> %s r_qual %d\n", + strerror(errno), ntohs(cm_ptr->dst.lid), + inet_ntoa(((struct sockaddr_in *)r_addr)->sin_addr), + (unsigned int)r_qual); + + /* close socket, free cm structure */ + dapls_ib_cm_free(cm_ptr, cm_ptr->ep); + return DAT_INTERNAL_ERROR; +} + +/* + * 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; + short rtu_data = htons(0x0E0F); + ib_cm_events_t event = IB_CME_DESTINATION_REJECT; + + /* 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->dst, sizeof(ib_qp_cm_t), 0); + if (len != sizeof(ib_qp_cm_t) || ntohs(cm_ptr->dst.ver) != DCM_VER) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_RTU read: ERR %s, rcnt=%d, ver=%d -> %s\n", + strerror(errno), len, cm_ptr->dst.ver, + inet_ntoa(((struct sockaddr_in *) + ep_ptr->param.remote_ia_address_ptr)-> + sin_addr)); + goto bail; + } + + /* convert peer response values to host order */ + cm_ptr->dst.port = ntohs(cm_ptr->dst.port); + cm_ptr->dst.lid = ntohs(cm_ptr->dst.lid); + cm_ptr->dst.qpn = ntohl(cm_ptr->dst.qpn); +#ifdef DAT_EXTENSIONS + cm_ptr->dst.qp_type = ntohs(cm_ptr->dst.qp_type); +#endif + cm_ptr->dst.p_size = ntohl(cm_ptr->dst.p_size); + + /* save remote address information */ + dapl_os_memcpy(&ep_ptr->remote_ia_address, + &cm_ptr->dst.ia_address, + sizeof(ep_ptr->remote_ia_address)); + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " CONN_RTU: DST %s port=0x%x lid=0x%x," + " qpn=0x%x, qp_type=%d, psize=%d\n", + inet_ntoa(((struct sockaddr_in *) + &cm_ptr->dst.ia_address)->sin_addr), + cm_ptr->dst.port, cm_ptr->dst.lid, + cm_ptr->dst.qpn, cm_ptr->dst.qp_type, cm_ptr->dst.p_size); + + /* validate private data size before reading */ + if (cm_ptr->dst.p_size > IB_MAX_REP_PDATA_SIZE) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_RTU read: psize (%d) wrong -> %s\n", + cm_ptr->dst.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, + " socket connected, read private data\n"); + if (cm_ptr->dst.p_size) { + len = + recv(cm_ptr->socket, cm_ptr->p_data, cm_ptr->dst.p_size, 0); + if (len != cm_ptr->dst.p_size) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_RTU read pdata: ERR %s, rcnt=%d -> %s\n", + strerror(errno), len, + inet_ntoa(((struct sockaddr_in *) + ep_ptr->param. + remote_ia_address_ptr)->sin_addr)); + goto bail; + } + } + + /* check for consumer reject */ + if (cm_ptr->dst.rej) { + dapl_log(DAPL_DBG_TYPE_CM, + " CONN_RTU read: PEER REJ reason=0x%x -> %s\n", + ntohs(cm_ptr->dst.rej), + inet_ntoa(((struct sockaddr_in *) + ep_ptr->param.remote_ia_address_ptr)-> + sin_addr)); + event = IB_CME_DESTINATION_REJECT_PRIVATE_DATA; +#ifdef DAT_EXTENSIONS + if (cm_ptr->dst.qp_type == IBV_QPT_UD) + goto ud_bail; + else +#endif + 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) != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_RTU: QPS_RTR ERR %s -> %s\n", + strerror(errno), inet_ntoa(((struct sockaddr_in *) + ep_ptr->param. + remote_ia_address_ptr)-> + 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) != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_RTU: QPS_RTS ERR %s -> %s\n", + strerror(errno), inet_ntoa(((struct sockaddr_in *) + ep_ptr->param. + remote_ia_address_ptr)-> + sin_addr)); + 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 */ + if (send(cm_ptr->socket, (char *)&rtu_data, sizeof(rtu_data), 0) == -1) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_RTU: write error = %s\n", strerror(errno)); + goto bail; + } + /* init cm_handle and post the event with private data */ + cm_ptr->state = DCM_CONNECTED; + event = IB_CME_CONNECTED; + dapl_dbg_log(DAPL_DBG_TYPE_EP, " ACTIVE: connected!\n"); + +#ifdef DAT_EXTENSIONS +ud_bail: + if (cm_ptr->dst.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_REMOTE_AH; + xevent.remote_ah.ah = cm_ptr->ah; + xevent.remote_ah.qpn = cm_ptr->dst.qpn; + dapl_os_memcpy(&xevent.remote_ah.ia_addr, + &cm_ptr->dst.ia_address, + sizeof(cm_ptr->dst.ia_address)); + + if (event == IB_CME_CONNECTED) + event = DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED; + 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) cm_ptr->dst.p_size, + (DAT_PVOID *) cm_ptr->p_data, + (DAT_PVOID *) &xevent); + + /* done with socket, don't destroy cm_ptr, need pdata */ + closesocket(cm_ptr->socket); + cm_ptr->socket = DAPL_INVALID_SOCKET; + cm_ptr->state = DCM_RELEASED; + } else +#endif + { + ep_ptr->cm_handle = cm_ptr; /* only RC, multi CR's on UD */ + dapl_evd_connection_callback(cm_ptr, + IB_CME_CONNECTED, + cm_ptr->p_data, ep_ptr); + } + return; + +bail: + /* close socket, and post error event */ + dapls_ib_reinit_ep(ep_ptr); /* reset QP state */ + closesocket(cm_ptr->socket); + cm_ptr->socket = DAPL_INVALID_SOCKET; + dapl_evd_connection_callback(NULL, event, cm_ptr->p_data, ep_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; + int opt = 1; + DAT_RETURN dat_status = DAT_SUCCESS; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " listen(ia_ptr %p ServiceID %d sp_ptr %p)\n", + ia_ptr, serviceID, sp_ptr); + + cm_ptr = dapls_ib_cm_create(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, 0)) == DAPL_INVALID_SOCKET) { + dapl_log(DAPL_DBG_TYPE_ERR, " ERR: listen socket create: %s\n", + strerror(errno)); + dat_status = DAT_INSUFFICIENT_RESOURCES; + goto bail; + } + + setsockopt(cm_ptr->socket, SOL_SOCKET, SO_REUSEADDR, + (char *)&opt, sizeof(opt)); + + addr.sin_port = htons(serviceID); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + + if ((bind(cm_ptr->socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) + || (listen(cm_ptr->socket, 128) < 0)) { + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " listen: ERROR %s on conn_qual 0x%x\n", + strerror(errno), serviceID); + if (errno == EADDRINUSE) + dat_status = DAT_CONN_QUAL_IN_USE; + else + dat_status = DAT_CONN_QUAL_UNAVAILABLE; + goto bail; + } + + /* set cm_handle for this service point, save listen socket */ + sp_ptr->cm_srvc_handle = cm_ptr; + + /* 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, + " listen: qual 0x%x cr %p s_fd %d\n", + ntohs(serviceID), cm_ptr, cm_ptr->socket); + + return dat_status; + bail: + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " listen: ERROR on conn_qual 0x%x\n", serviceID); + dapls_ib_cm_free(cm_ptr, cm_ptr->ep); + 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; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, " socket_accept\n"); + + /* + * 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 = dapls_ib_cm_create(NULL)) == NULL) + return; + + acm_ptr->sp = cm_ptr->sp; + acm_ptr->hca = cm_ptr->hca; + + len = sizeof(acm_ptr->dst.ia_address); + acm_ptr->socket = accept(cm_ptr->socket, + (struct sockaddr *) + &acm_ptr->dst.ia_address, + (socklen_t *) & len); + if (acm_ptr->socket == DAPL_INVALID_SOCKET) { + dapl_log(DAPL_DBG_TYPE_ERR, + " accept: ERR %s on FD %d l_cr %p\n", + strerror(errno), cm_ptr->socket, cm_ptr); + dapls_ib_cm_free(acm_ptr, acm_ptr->ep); + return; + } + + /* no delay for small packets */ + ret = setsockopt(acm_ptr->socket, IPPROTO_TCP, TCP_NODELAY, + (char *)&opt, sizeof(opt)); + if (ret) + dapl_log(DAPL_DBG_TYPE_WARN, + " accept: NODELAY setsockopt: %s\n", + strerror(errno)); + + 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; + 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->dst, sizeof(ib_qp_cm_t), 0); + if (len != sizeof(ib_qp_cm_t) || ntohs(acm_ptr->dst.ver) != DCM_VER) { + dapl_log(DAPL_DBG_TYPE_ERR, + " accept read: ERR %s, rcnt=%d, ver=%d\n", + strerror(errno), len, ntohs(acm_ptr->dst.ver)); + goto bail; + } + + /* convert accepted values to host order */ + acm_ptr->dst.port = ntohs(acm_ptr->dst.port); + acm_ptr->dst.lid = ntohs(acm_ptr->dst.lid); + acm_ptr->dst.qpn = ntohl(acm_ptr->dst.qpn); +#ifdef DAT_EXTENSIONS + acm_ptr->dst.qp_type = ntohs(acm_ptr->dst.qp_type); +#endif + acm_ptr->dst.p_size = ntohl(acm_ptr->dst.p_size); + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " accept: DST %s port=0x%x lid=0x%x, qpn=0x%x, psize=%d\n", + inet_ntoa(((struct sockaddr_in *)&acm_ptr->dst. + ia_address)->sin_addr), acm_ptr->dst.port, + acm_ptr->dst.lid, acm_ptr->dst.qpn, acm_ptr->dst.p_size); + + /* validate private data size before reading */ + if (acm_ptr->dst.p_size > IB_MAX_REQ_PDATA_SIZE) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " accept read: psize (%d) wrong\n", + acm_ptr->dst.p_size); + goto bail; + } + + dapl_dbg_log(DAPL_DBG_TYPE_EP, " socket accepted, read private data\n"); + + /* read private data into cm_handle if any present */ + if (acm_ptr->dst.p_size) { + len = + recv(acm_ptr->socket, acm_ptr->p_data, acm_ptr->dst.p_size, + 0); + if (len != acm_ptr->dst.p_size) { + dapl_log(DAPL_DBG_TYPE_ERR, + " accept read pdata: ERR %s, rcnt=%d\n", + strerror(errno), len); + goto bail; + } + dapl_dbg_log(DAPL_DBG_TYPE_EP, " accept: psize=%d read\n", len); + p_data = acm_ptr->p_data; + } + + acm_ptr->state = DCM_ACCEPTING_DATA; + +#ifdef DAT_EXTENSIONS + if (acm_ptr->dst.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) acm_ptr->dst.p_size, + (DAT_PVOID *) acm_ptr->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, acm_ptr->sp); + return; + bail: + /* close socket, free cm structure, active will see socket close as reject */ + dapls_ib_cm_free(acm_ptr, acm_ptr->ep); + return; +} + +/* + * 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_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_qp_cm_t local; + struct iovec iov[2]; + int len; + + if (p_size > IB_MAX_REP_PDATA_SIZE) + return DAT_LENGTH_ERROR; + + /* must have a accepted socket */ + if (cm_ptr->socket == DAPL_INVALID_SOCKET) + return DAT_INTERNAL_ERROR; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " ACCEPT_USR: remote port=0x%x lid=0x%x" + " qpn=0x%x qp_type %d, psize=%d\n", + cm_ptr->dst.port, cm_ptr->dst.lid, + cm_ptr->dst.qpn, cm_ptr->dst.qp_type, cm_ptr->dst.p_size); + +#ifdef DAT_EXTENSIONS + if (cm_ptr->dst.qp_type == IBV_QPT_UD && + ep_ptr->qp_handle->qp_type != IBV_QPT_UD) { + dapl_dbg_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_ptr->header.lock); + if (dapls_modify_qp_state(ep_ptr->qp_handle, + IBV_QPS_RTR, cm_ptr) != 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->dst.ia_address)-> + 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) != 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->dst.ia_address)-> + 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->dst.ia_address, + sizeof(ep_ptr->remote_ia_address)); + + /* send our QP info, IA address, pdata. Don't overwrite dst data */ + local.ver = htons(DCM_VER); + local.rej = 0; + local.qpn = htonl(ep_ptr->qp_handle->qp_num); + local.qp_type = htons(ep_ptr->qp_handle->qp_type); + local.port = htons(ia_ptr->hca_ptr->port_num); + local.lid = ia_ptr->hca_ptr->ib_trans.lid; + local.gid = ia_ptr->hca_ptr->ib_trans.gid; + local.ia_address = ia_ptr->hca_ptr->hca_address; + ((struct sockaddr_in *)&local.ia_address)->sin_port = + ntohs(cm_ptr->sp->conn_qual); + + local.p_size = htonl(p_size); + iov[0].iov_base = (void *)&local; + iov[0].iov_len = sizeof(ib_qp_cm_t); + 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 + sizeof(ib_qp_cm_t))) { + dapl_log(DAPL_DBG_TYPE_ERR, + " ACCEPT_USR: ERR %s, wcnt=%d -> %s\n", + strerror(errno), len, inet_ntoa(((struct sockaddr_in *) + &cm_ptr->dst. + ia_address)-> + sin_addr)); + goto bail; + } + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " ACCEPT_USR: local port=0x%x lid=0x%x" + " qpn=0x%x psize=%d\n", + ntohs(local.port), ntohs(local.lid), + ntohl(local.qpn), ntohl(local.p_size)); + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " ACCEPT_USR SRC GID subnet %016llx id %016llx\n", + (unsigned long long) + htonll(local.gid.global.subnet_prefix), + (unsigned long long) + htonll(local.gid.global.interface_id)); + + /* save state and reference to EP, queue for RTU data */ + cm_ptr->ep = ep_ptr; + cm_ptr->hca = ia_ptr->hca_ptr; + cm_ptr->state = DCM_ACCEPTED; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, " PASSIVE: accepted!\n"); + return DAT_SUCCESS; + bail: + dapls_ib_cm_free(cm_ptr, cm_ptr->ep); + dapls_ib_reinit_ep(ep_ptr); /* reset QP state */ + return DAT_INTERNAL_ERROR; +} + +/* + * PASSIVE: read RTU from active peer, post CONN event + */ +void dapli_socket_accept_rtu(dp_ib_cm_handle_t cm_ptr) +{ + int len; + short rtu_data = 0; + + /* complete handshake after final QP state change */ + len = recv(cm_ptr->socket, (char *)&rtu_data, sizeof(rtu_data), 0); + if (len != sizeof(rtu_data) || ntohs(rtu_data) != 0x0e0f) { + dapl_log(DAPL_DBG_TYPE_ERR, + " ACCEPT_RTU: ERR %s, rcnt=%d rdata=%x\n", + strerror(errno), len, ntohs(rtu_data), + inet_ntoa(((struct sockaddr_in *) + &cm_ptr->dst.ia_address)->sin_addr)); + goto bail; + } + + /* save state and reference to EP, queue for disc event */ + cm_ptr->state = DCM_CONNECTED; + + /* final data exchange if remote QP state is good to go */ + dapl_dbg_log(DAPL_DBG_TYPE_EP, " PASSIVE: connected!\n"); + +#ifdef DAT_EXTENSIONS + if (cm_ptr->dst.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_PASSIVE_REMOTE_AH; + xevent.remote_ah.ah = cm_ptr->ah; + xevent.remote_ah.qpn = cm_ptr->dst.qpn; + dapl_os_memcpy(&xevent.remote_ah.ia_addr, + &cm_ptr->dst.ia_address, + sizeof(cm_ptr->dst.ia_address)); + + dapls_evd_post_connection_event_ext((DAPL_EVD *) cm_ptr->ep-> + param.connect_evd_handle, + DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED, + (DAT_EP_HANDLE) cm_ptr->ep, + (DAT_COUNT) cm_ptr->dst.p_size, + (DAT_PVOID *) cm_ptr->p_data, + (DAT_PVOID *) &xevent); + + /* done with socket, don't destroy cm_ptr, need pdata */ + closesocket(cm_ptr->socket); + cm_ptr->socket = DAPL_INVALID_SOCKET; + cm_ptr->state = DCM_RELEASED; + } else { +#endif + cm_ptr->ep->cm_handle = cm_ptr; /* only RC, multi CR's on UD */ + dapls_cr_callback(cm_ptr, IB_CME_CONNECTED, NULL, cm_ptr->sp); + } + return; + +bail: + dapls_ib_reinit_ep(cm_ptr->ep); /* reset QP state */ + dapls_ib_cm_free(cm_ptr, cm_ptr->ep); + dapls_cr_callback(cm_ptr, IB_CME_DESTINATION_REJECT, NULL, cm_ptr->sp); +} + +/* + * 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; + ib_qp_handle_t qp_ptr; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " connect(ep_handle %p ....)\n", ep_handle); + + ep_ptr = (DAPL_EP *) ep_handle; + qp_ptr = ep_ptr->qp_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) +{ + dapl_dbg_log(DAPL_DBG_TYPE_EP, + "dapls_ib_disconnect(ep_handle %p ....)\n", ep_ptr); + + /* reinit to modify QP state */ + dapls_ib_reinit_ep(ep_ptr); + + if (ep_ptr->cm_handle == NULL || + ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED) + return DAT_SUCCESS; + else + return (dapli_socket_disconnect(ep_ptr->cm_handle)); +} + +/* + * 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) +{ + /* NOTE: SCM will only initialize cm_handle with RC type + * + * For UD there can many in-flight CR's so you + * cannot cleanup timed out CR's with EP reference + * alone since they share the same EP. The common + * code that handles connection timeout logic needs + * updated for UD support. + */ + if (ep_ptr->cm_handle) + dapls_ib_cm_free(ep_ptr->cm_handle, ep_ptr); + + return; +} + +/* + * dapl_ib_setup_conn_listener + * + * Have the CM set up a connection listener. + * + * Input: + * ibm_hca_handle HCA handle + * qp_handle QP handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INTERNAL_ERROR + * DAT_CONN_QUAL_UNAVAILBLE + * DAT_CONN_QUAL_IN_USE + * + */ +DAT_RETURN +dapls_ib_setup_conn_listener(IN DAPL_IA * ia_ptr, + IN DAT_UINT64 ServiceID, IN DAPL_SP * sp_ptr) +{ + 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; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + "dapls_ib_remove_conn_listener(ia_ptr %p sp_ptr %p cm_ptr %p)\n", + ia_ptr, sp_ptr, cm_ptr); + + /* close accepted socket, free cm_srvc_handle and return */ + if (cm_ptr != NULL) { + if (cm_ptr->socket != DAPL_INVALID_SOCKET) { + shutdown(cm_ptr->socket, SHUT_RDWR); + closesocket(cm_ptr->socket); + cm_ptr->socket = DAPL_INVALID_SOCKET; + } + /* cr_thread will free */ + cm_ptr->state = DCM_DESTROY; + sp_ptr->cm_srvc_handle = NULL; + if (send(cm_ptr->hca->ib_trans.scm[1], + "w", sizeof "w", 0) == -1) + dapl_log(DAPL_DBG_TYPE_CM, + " cm_destroy: thread wakeup error = %s\n", + strerror(errno)); + } + 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 > IB_MAX_REJ_PDATA_SIZE) + return DAT_LENGTH_ERROR; + + /* write reject data to indicate reject */ + if (cm_ptr->socket != DAPL_INVALID_SOCKET) { + cm_ptr->dst.rej = (uint16_t) reason; + cm_ptr->dst.rej = htons(cm_ptr->dst.rej); + cm_ptr->dst.p_size = htonl(psize); + /* get qp_type from request */ + cm_ptr->dst.qp_type = ntohs(cm_ptr->dst.qp_type); + + iov[0].iov_base = (void *)&cm_ptr->dst; + iov[0].iov_len = sizeof(ib_qp_cm_t); + 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); + } + + shutdown(cm_ptr->socket, SHUT_RDWR); + closesocket(cm_ptr->socket); + cm_ptr->socket = DAPL_INVALID_SOCKET; + } + + /* cr_thread will destroy CR */ + cm_ptr->state = DCM_DESTROY; + if (send(cm_ptr->hca->ib_trans.scm[1], "w", sizeof "w", 0) == -1) + dapl_log(DAPL_DBG_TYPE_CM, + " cm_destroy: thread wakeup error = %s\n", + strerror(errno)); + 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 ib_cm_handle; + + 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) + ib_cm_handle = ((DAPL_EP *) dat_handle)->cm_handle; + else if (header->magic == DAPL_MAGIC_CR) + ib_cm_handle = ((DAPL_CR *) dat_handle)->ib_cm_handle; + else + return DAT_INVALID_HANDLE; + + dapl_os_memcpy(remote_ia_address, + &ib_cm_handle->dst.ia_address, sizeof(DAT_SOCK_ADDR6)); + + 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. + * + * + * Output: + * None + * + * Returns: + * length of private data + * + */ +int dapls_ib_private_data_size(IN DAPL_PRIVATE * prd_ptr, + IN DAPL_PDATA_OP conn_op, IN DAPL_HCA * hca_ptr) +{ + int size; + + 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; +} + +/* + * Map all socket CM event codes to the DAT equivelent. + */ +#define DAPL_IB_EVENT_CNT 10 + +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_DESTINATION_REJECT, + DAT_CONNECTION_EVENT_NON_PEER_REJECTED}, +/* 06 */ {IB_CME_DESTINATION_REJECT_PRIVATE_DATA, + DAT_CONNECTION_EVENT_PEER_REJECTED}, +/* 07 */ {IB_CME_DESTINATION_UNREACHABLE, + DAT_CONNECTION_EVENT_UNREACHABLE}, +/* 08 */ {IB_CME_TOO_MANY_CONNECTION_REQUESTS, + DAT_CONNECTION_EVENT_NON_PEER_REJECTED}, +/* 09 */ {IB_CME_LOCAL_FAILURE, + 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; +} + +/* 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->entry); + if (cr->state == DCM_DESTROY + || hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) { + dapl_llist_remove_entry(&hca_ptr->ib_trans.list, + (DAPL_LLIST_ENTRY *) & + cr->entry); + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " CR FREE: %p ep=%p st=%d sock=%d\n", + cr, cr->ep, cr->state, cr->socket); + dapl_os_free(cr, sizeof(*cr)); + continue; + } + if (cr->socket == DAPL_INVALID_SOCKET) + 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: DESTROY CR st=%d fd %d" + " -> %s\n", cr->state, cr->socket, + inet_ntoa(((struct sockaddr_in *) + &cr->dst.ia_address)-> + sin_addr)); + dapls_ib_cm_free(cr, cr->ep); + continue; + } + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " poll cr=%p, socket=%d\n", cr, + cr->socket); + dapl_os_unlock(&hca_ptr->ib_trans.lock); + + ret = dapl_poll(cr->socket, event); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " poll ret=0x%x cr->state=%d socket=%d\n", + ret, cr->state, cr->socket); + + /* data on listen, qp exchange, and on disc req */ + if (ret == DAPL_FD_READ) { + if (cr->socket != DAPL_INVALID_SOCKET) { + switch (cr->state) { + case DCM_LISTEN: + dapli_socket_accept(cr); + break; + case DCM_ACCEPTING: + dapli_socket_accept_data(cr); + break; + case DCM_ACCEPTED: + dapli_socket_accept_rtu(cr); + break; + case DCM_RTU_PENDING: + dapli_socket_connect_rtu(cr); + break; + case DCM_CONNECTED: + dapli_socket_disconnect(cr); + break; + default: + break; + } + } + /* connect socket is writable, 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); + if (!ret) + dapli_socket_connected(cr, opt); + else + dapli_socket_connected(cr, errno); + + /* POLLUP, ERR, NVAL, or poll error - DISC */ + } else if (ret < 0 || ret == DAPL_FD_ERROR) { + dapl_log(DAPL_DBG_TYPE_CM, + " poll=%d cr->st=%s sk=%d ep %p, %d\n", + ret, dapl_cm_state_str(cr->state), + cr->socket, cr->ep, + cr->ep ? cr->ep->param.ep_state:0); + dapli_socket_disconnect(cr); + } + 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_CM, + " 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); + free(set); + out: + hca_ptr->ib_trans.cr_state = IB_THREAD_EXIT; + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " 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->entry); + + printf( " CONN[%d]: sp %p ep %p sock %d %s %s %s %s %d\n", + i, cr->sp, cr->ep, cr->socket, + cr->dst.qp_type == IBV_QPT_RC ? "RC" : "UD", + dapl_cm_state_str(cr->state), + cr->sp ? "<-" : "->", + cr->state == DCM_LISTEN ? + inet_ntoa(((struct sockaddr_in *) + &ia_ptr->hca_ptr->hca_address)->sin_addr) : + inet_ntoa(((struct sockaddr_in *) + &cr->dst.ia_address)->sin_addr), + cr->sp ? (int)cr->sp->conn_qual : + ntohs(((struct sockaddr_in *) + &cr->dst.ia_address)->sin_port)); + i++; + } + printf("\n"); + dapl_os_unlock(&ia_ptr->hca_ptr->ib_trans.lock); +} +#endif diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/dapl_ib_util.h b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/dapl_ib_util.h new file mode 100644 index 00000000..e83c5ae3 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/dapl_ib_util.h @@ -0,0 +1,125 @@ +/* + * This Software 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" + +struct ib_cm_handle +{ + struct dapl_llist_entry entry; + DAPL_OS_LOCK lock; + int state; + DAPL_SOCKET socket; + struct dapl_hca *hca; + struct dapl_sp *sp; + struct dapl_ep *ep; + ib_qp_cm_t dst; + unsigned char p_data[256]; /* must follow ib_qp_cm_t */ + struct ibv_ah *ah; +}; + +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 + +/* CM private data areas */ +#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 +#define IB_MAX_RTU_PDATA_SIZE 224 + + +/* ib_hca_transport_t, specific to this implementation */ +typedef struct _ib_hca_transport +{ + union ibv_gid gid; + struct ibv_device *ib_dev; + 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]; +} 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); +DAT_RETURN dapli_socket_disconnect(dp_ib_cm_handle_t cm_ptr); +void dapls_print_cm_list(IN DAPL_IA *ia_ptr); +dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep); +void dapls_ib_cm_free(dp_ib_cm_handle_t cm, DAPL_EP *ep); +DAT_RETURN dapls_modify_qp_state(IN ib_qp_handle_t qp_handle, + IN ib_qp_state_t qp_state, + IN dp_ib_cm_handle_t cm); + +#endif /* _DAPL_IB_UTIL_H_ */ diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/device.c b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/device.c new file mode 100644 index 00000000..293e028d --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/device.c @@ -0,0 +1,412 @@ +/* + * This Software 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 + +static int32_t create_cr_pipe(IN DAPL_HCA * hca_ptr) +{ + DAPL_SOCKET listen_socket; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + int ret; + + listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listen_socket == DAPL_INVALID_SOCKET) + return 1; + + memset(&addr, 0, sizeof addr); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(0x7f000001); + ret = bind(listen_socket, (struct sockaddr *)&addr, sizeof addr); + if (ret) + goto err1; + + ret = getsockname(listen_socket, (struct sockaddr *)&addr, &addrlen); + if (ret) + goto err1; + + ret = listen(listen_socket, 0); + if (ret) + goto err1; + + hca_ptr->ib_trans.scm[1] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (hca_ptr->ib_trans.scm[1] == DAPL_INVALID_SOCKET) + goto err1; + + ret = connect(hca_ptr->ib_trans.scm[1], + (struct sockaddr *)&addr, sizeof(addr)); + if (ret) + goto err2; + + hca_ptr->ib_trans.scm[0] = accept(listen_socket, NULL, NULL); + if (hca_ptr->ib_trans.scm[0] == DAPL_INVALID_SOCKET) + goto err2; + + closesocket(listen_socket); + return 0; + + err2: + closesocket(hca_ptr->ib_trans.scm[1]); + err1: + closesocket(listen_socket); + return 1; +} + +static void destroy_cr_pipe(IN DAPL_HCA * hca_ptr) +{ + closesocket(hca_ptr->ib_trans.scm[0]); + closesocket(hca_ptr->ib_trans.scm[1]); +} + + +/* + * dapls_ib_init, dapls_ib_release + * + * Initialize Verb related items for device open + * + * Input: + * none + * + * Output: + * none + * + * Returns: + * 0 success, -1 error + * + */ +int32_t dapls_ib_init(void) +{ + return 0; +} + +int32_t dapls_ib_release(void) +{ + return 0; +} + +#if defined(_WIN64) || defined(_WIN32) +int dapls_config_comp_channel(struct ibv_comp_channel *channel) +{ + return 0; +} +#else // _WIN64 || WIN32 +int dapls_config_comp_channel(struct ibv_comp_channel *channel) +{ + int opts; + + opts = fcntl(channel->fd, F_GETFL); /* uCQ */ + if (opts < 0 || fcntl(channel->fd, F_SETFL, opts | O_NONBLOCK) < 0) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapls_create_comp_channel: fcntl on ib_cq->fd %d ERR %d %s\n", + channel->fd, opts, strerror(errno)); + return errno; + } + + return 0; +} +#endif + +/* + * dapls_ib_open_hca + * + * Open HCA + * + * Input: + * *hca_name pointer to provider device name + * *ib_hca_handle_p pointer to provide HCA handle + * + * Output: + * none + * + * Return: + * DAT_SUCCESS + * dapl_convert_errno + * + */ +DAT_RETURN dapls_ib_open_hca(IN IB_HCA_NAME hca_name, IN DAPL_HCA * hca_ptr) +{ + struct ibv_device **dev_list; + struct ibv_port_attr port_attr; + int i; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " open_hca: %s - %p\n", hca_name, hca_ptr); + + /* get the IP address of the device */ + dat_status = getlocalipaddr((DAT_SOCK_ADDR *) &hca_ptr->hca_address, + sizeof(DAT_SOCK_ADDR6)); + if (dat_status != DAT_SUCCESS) + return dat_status; + + /* 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; + } + + /* 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)); + +#ifndef CQ_WAIT_OBJECT + /* initialize cq_lock */ + dat_status = dapl_os_lock_init(&hca_ptr->ib_trans.cq_lock); + if (dat_status != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: failed to init cq_lock\n"); + goto bail; + } + /* EVD events without direct CQ channels, non-blocking */ + 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; + } + + if (dapls_config_comp_channel(hca_ptr->ib_trans.ib_cq)) { + goto bail; + } + + if (dapli_cq_thread_init(hca_ptr)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: cq_thread_init failed for %s\n", + ibv_get_device_name(hca_ptr->ib_trans.ib_dev)); + goto bail; + } +#endif /* CQ_WAIT_OBJECT */ + + /* 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(2000); + } + + 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); + +#ifndef CQ_WAIT_OBJECT + dapli_cq_thread_destroy(hca_ptr); + dapl_os_lock_destroy(&hca_ptr->ib_trans.cq_lock); +#endif /* CQ_WAIT_OBJECT */ + + 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; + } + + /* destroy cr_thread and lock */ + hca_ptr->ib_trans.cr_state = IB_THREAD_CANCEL; + if (send(hca_ptr->ib_trans.scm[1], "w", sizeof "w", 0) == -1) + dapl_log(DAPL_DBG_TYPE_UTIL, + " thread_destroy: thread wakeup err = %s\n", + strerror(errno)); + while (hca_ptr->ib_trans.cr_state != IB_THREAD_EXIT) { + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " close_hca: waiting for cr_thread\n"); + if (send(hca_ptr->ib_trans.scm[1], "w", sizeof "w", 0) == -1) + dapl_log(DAPL_DBG_TYPE_UTIL, + " thread_destroy: thread wakeup err = %s\n", + strerror(errno)); + dapl_os_sleep_usec(2000); + } + dapl_os_lock_destroy(&hca_ptr->ib_trans.lock); + destroy_cr_pipe(hca_ptr); /* no longer need pipe */ + return (DAT_SUCCESS); +} diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/libdaplscm.map b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/libdaplscm.map new file mode 100644 index 00000000..b5dec4ef --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/libdaplscm.map @@ -0,0 +1,6 @@ +DAPL_SCM_1.2 { + global: + dat_provider_fini; + dat_provider_init; + local: *; +}; diff --git a/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/linux/openib_osd.h b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/linux/openib_osd.h new file mode 100644 index 00000000..41001d57 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/openib_scm/makefile b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/openib_scm/udapl.rc b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/udapl.rc new file mode 100644 index 00000000..85502564 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/openib_scm/udapl_ofa_scm_exports.src b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/udapl_ofa_scm_exports.src new file mode 100644 index 00000000..cc1a7a37 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/openib_scm/windows/openib_osd.h b/branches/WOF2-1/ulp/dapl2/dapl/openib_scm/windows/openib_osd.h new file mode 100644 index 00000000..31fe32f1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/udapl/dapl_cno_create.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_cno_create.c new file mode 100644 index 00000000..a214c338 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/udapl/dapl_cno_free.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_cno_free.c new file mode 100644 index 00000000..572fb98a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/udapl/dapl_cno_modify_agent.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_cno_modify_agent.c new file mode 100644 index 00000000..887e9845 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/udapl/dapl_cno_query.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_cno_query.c new file mode 100644 index 00000000..5112e337 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/udapl/dapl_cno_wait.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_cno_wait.c new file mode 100644 index 00000000..e89317df --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_cno_wait.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_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); + 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_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-1/ulp/dapl2/dapl/udapl/dapl_evd_clear_unwaitable.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_clear_unwaitable.c new file mode 100644 index 00000000..ab24c043 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/udapl/dapl_evd_create.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_create.c new file mode 100644 index 00000000..548c2aee --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/udapl/dapl_evd_disable.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_disable.c new file mode 100644 index 00000000..78f1b0e1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/udapl/dapl_evd_enable.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_enable.c new file mode 100644 index 00000000..b5991c74 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/udapl/dapl_evd_modify_cno.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_modify_cno.c new file mode 100644 index 00000000..955a835d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/udapl/dapl_evd_query.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_query.c new file mode 100644 index 00000000..09abcad1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/udapl/dapl_evd_set_unwaitable.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_set_unwaitable.c new file mode 100644 index 00000000..bf41662f --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_set_unwaitable.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_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) { +#ifdef CQ_WAIT_OBJECT + if (evd_ptr->cq_wait_obj_handle) + dapls_ib_wait_object_wakeup(evd_ptr-> + cq_wait_obj_handle); + else +#endif + 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-1/ulp/dapl2/dapl/udapl/dapl_evd_wait.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_wait.c new file mode 100644 index 00000000..8d82d63a --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_evd_wait.c @@ -0,0 +1,277 @@ +/* + * 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) || + (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, + (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); + +#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); + + 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-1/ulp/dapl2/dapl/udapl/dapl_init.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_init.c new file mode 100644 index 00000000..e0af8f75 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_init.c @@ -0,0 +1,306 @@ +/* + * 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); + /* 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(); + + 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-1/ulp/dapl2/dapl/udapl/dapl_lmr_create.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_lmr_create.c new file mode 100644 index 00000000..849f4fe7 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/udapl/dapl_lmr_create.c @@ -0,0 +1,506 @@ +/* + * 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; + } + + /* 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); + *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_HASH_DATA hash_lmr; + + 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); + + dat_status = dapls_hash_search(ia->hca_ptr->lmr_hash_table, + original_lmr->param.lmr_context, + &hash_lmr); + if (dat_status != DAT_SUCCESS) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + lmr = (DAPL_LMR *) hash_lmr; + 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; + } + + /* 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); + *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; + } + + /* 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_SUCCESS == dat_status) { + (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); + *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-1/ulp/dapl2/dapl/udapl/libdaplofa.map b/branches/WOF2-1/ulp/dapl2/dapl/udapl/libdaplofa.map new file mode 100644 index 00000000..97d3a22b --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/udapl/libdaplofa.map @@ -0,0 +1,7 @@ +DAPL_CMA_2.0 { + global: + dat_provider_fini; + dat_provider_init; + dapl_extensions; + local: *; +}; diff --git a/branches/WOF2-1/ulp/dapl2/dapl/udapl/libdaploscm.map b/branches/WOF2-1/ulp/dapl2/dapl/udapl/libdaploscm.map new file mode 100644 index 00000000..45edb4d8 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/udapl/libdaploscm.map @@ -0,0 +1,7 @@ +DAPL_SCM_2.0 { + global: + dat_provider_fini; + dat_provider_init; + dapl_extensions; + local: *; +}; diff --git a/branches/WOF2-1/ulp/dapl2/dapl/udapl/libdaplscm.map b/branches/WOF2-1/ulp/dapl2/dapl/udapl/libdaplscm.map new file mode 100644 index 00000000..b5dec4ef --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/udapl/libdaplscm.map @@ -0,0 +1,6 @@ +DAPL_SCM_1.2 { + global: + dat_provider_fini; + dat_provider_init; + local: *; +}; diff --git a/branches/WOF2-1/ulp/dapl2/dapl/udapl/linux/dapl_osd.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/linux/dapl_osd.c new file mode 100644 index 00000000..78d7735e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/udapl/linux/dapl_osd.h b/branches/WOF2-1/ulp/dapl2/dapl/udapl/linux/dapl_osd.h new file mode 100644 index 00000000..cb61cae6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dapl/udapl/windows/dapl_osd.c b/branches/WOF2-1/ulp/dapl2/dapl/udapl/windows/dapl_osd.c new file mode 100644 index 00000000..80975606 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/udapl/windows/dapl_osd.c @@ -0,0 +1,268 @@ +/* + * 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() */ + + + +/* + * 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) + { +#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 + 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-1/ulp/dapl2/dapl/udapl/windows/dapl_osd.h b/branches/WOF2-1/ulp/dapl2/dapl/udapl/windows/dapl_osd.h new file mode 100644 index 00000000..6266f1f8 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dapl/udapl/windows/dapl_osd.h @@ -0,0 +1,525 @@ +/* + * 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 +#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 + */ + +/* 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 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); // 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-1/ulp/dapl2/dat/common/dat_api.c b/branches/WOF2-1/ulp/dapl2/dat/common/dat_api.c new file mode 100644 index 00000000..781c9a65 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/common/dat_dictionary.c b/branches/WOF2-1/ulp/dapl2/dat/common/dat_dictionary.c new file mode 100644 index 00000000..6716ff63 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/common/dat_dictionary.h b/branches/WOF2-1/ulp/dapl2/dat/common/dat_dictionary.h new file mode 100644 index 00000000..b496266d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/common/dat_dr.c b/branches/WOF2-1/ulp/dapl2/dat/common/dat_dr.c new file mode 100644 index 00000000..0460e814 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/common/dat_dr.h b/branches/WOF2-1/ulp/dapl2/dat/common/dat_dr.h new file mode 100644 index 00000000..30122525 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/common/dat_init.c b/branches/WOF2-1/ulp/dapl2/dat/common/dat_init.c new file mode 100644 index 00000000..71a56a08 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/common/dat_init.h b/branches/WOF2-1/ulp/dapl2/dat/common/dat_init.h new file mode 100644 index 00000000..4596b017 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/common/dat_sr.c b/branches/WOF2-1/ulp/dapl2/dat/common/dat_sr.c new file mode 100644 index 00000000..95b9333a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/common/dat_sr.h b/branches/WOF2-1/ulp/dapl2/dat/common/dat_sr.h new file mode 100644 index 00000000..86be8a08 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/common/dat_strerror.c b/branches/WOF2-1/ulp/dapl2/dat/common/dat_strerror.c new file mode 100644 index 00000000..4480bef5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/dirs b/branches/WOF2-1/ulp/dapl2/dat/dirs new file mode 100644 index 00000000..90c97ac8 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dat/dirs @@ -0,0 +1 @@ +DIRS=udat diff --git a/branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat.h new file mode 100644 index 00000000..cf0b7ec1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/include/dat2/dat_error.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_error.h new file mode 100644 index 00000000..251e6c4f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/include/dat2/dat_ib_extensions.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_ib_extensions.h new file mode 100644 index 00000000..59df1de1 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_ib_extensions.h @@ -0,0 +1,506 @@ +/* + * 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 + * + */ +#define DAT_IB_EXTENSION_VERSION 204 /* 2.0.4 */ +#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_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_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-1/ulp/dapl2/dat/include/dat2/dat_iw_extensions.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_iw_extensions.h new file mode 100644 index 00000000..59de0b33 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/include/dat2/dat_platform_specific.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_platform_specific.h new file mode 100644 index 00000000..79e8d3af --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_platform_specific.h @@ -0,0 +1,271 @@ +/* + * 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 */ + +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-1/ulp/dapl2/dat/include/dat2/dat_redirection.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_redirection.h new file mode 100644 index 00000000..ea61eff9 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/include/dat2/dat_registry.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_registry.h new file mode 100644 index 00000000..2c0edcbd --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/include/dat2/dat_vendor_specific.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/dat_vendor_specific.h new file mode 100644 index 00000000..844fc7e4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/include/dat2/kdat.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/kdat.h new file mode 100644 index 00000000..704c1cb5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/include/dat2/kdat_config.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/kdat_config.h new file mode 100644 index 00000000..855a629a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/include/dat2/kdat_redirection.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/kdat_redirection.h new file mode 100644 index 00000000..d7e56287 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/include/dat2/kdat_vendor_specific.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/kdat_vendor_specific.h new file mode 100644 index 00000000..3a89d198 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/include/dat2/udat.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/udat.h new file mode 100644 index 00000000..4ea491e5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/include/dat2/udat_config.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/udat_config.h new file mode 100644 index 00000000..eb92f140 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/include/dat2/udat_redirection.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/udat_redirection.h new file mode 100644 index 00000000..f1804170 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/include/dat2/udat_vendor_specific.h b/branches/WOF2-1/ulp/dapl2/dat/include/dat2/udat_vendor_specific.h new file mode 100644 index 00000000..dd955f8b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/udat/SOURCES b/branches/WOF2-1/ulp/dapl2/dat/udat/SOURCES new file mode 100644 index 00000000..7d37f652 --- /dev/null +++ b/branches/WOF2-1/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; +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-1/ulp/dapl2/dat/udat/libdat2.map b/branches/WOF2-1/ulp/dapl2/dat/udat/libdat2.map new file mode 100644 index 00000000..3ab4e0c8 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dat/udat/libdat2.map @@ -0,0 +1,78 @@ +DAT_2.0 { + global: + dat_cno_create; + dat_cno_free; + dat_cno_modify_agent; + dat_cno_query; + dat_cno_wait; + dat_cr_accept; + dat_cr_handoff; + dat_cr_query; + dat_cr_reject; + dat_ep_connect; + dat_ep_create; + dat_ep_create_with_srq; + dat_ep_disconnect; + dat_ep_dup_connect; + dat_ep_free; + dat_ep_get_status; + dat_ep_modify; + dat_ep_post_rdma_read; + dat_ep_post_rdma_write; + dat_ep_post_recv; + dat_ep_post_send; + dat_ep_query; + dat_ep_recv_query; + dat_ep_reset; + dat_ep_set_watermark; + dat_evd_clear_unwaitable; + dat_evd_create; + dat_evd_dequeue; + dat_evd_disable; + dat_evd_enable; + dat_evd_free; + dat_evd_modify_cno; + dat_evd_post_se; + dat_evd_query; + dat_evd_resize; + dat_evd_set_unwaitable; + dat_evd_wait; + dat_get_consumer_context; + dat_get_handle_type; + dat_ia_close; + dat_ia_openv; + dat_ia_query; + dat_lmr_create; + dat_lmr_free; + dat_lmr_query; + dat_lmr_sync_rdma_read; + dat_lmr_sync_rdma_write; + dat_psp_create; + dat_psp_create_any; + dat_psp_free; + dat_psp_query; + dat_pz_create; + dat_pz_free; + dat_pz_query; + dat_registry_add_provider; + dat_registry_list_providers; + dat_registry_remove_provider; + dat_rmr_bind; + dat_rmr_create; + dat_rmr_free; + dat_rmr_query; + dat_rsp_create; + dat_rsp_free; + dat_rsp_query; + dat_set_consumer_context; + dat_srq_create; + dat_srq_free; + dat_srq_post_recv; + dat_srq_query; + dat_srq_resize; + dat_srq_set_lw; + dats_get_ia_handle; + dat_strerror; + dat_extension_op; + local: *; +}; diff --git a/branches/WOF2-1/ulp/dapl2/dat/udat/linux/dat-registry-1.1.spec b/branches/WOF2-1/ulp/dapl2/dat/udat/linux/dat-registry-1.1.spec new file mode 100644 index 00000000..690726f4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/udat/linux/dat_osd.c b/branches/WOF2-1/ulp/dapl2/dat/udat/linux/dat_osd.c new file mode 100644 index 00000000..28ac9fa8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/udat/linux/dat_osd.h b/branches/WOF2-1/ulp/dapl2/dat/udat/linux/dat_osd.h new file mode 100644 index 00000000..40b5b1ca --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/udat/makefile b/branches/WOF2-1/ulp/dapl2/dat/udat/makefile new file mode 100644 index 00000000..e26e1c04 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/udat/udat.c b/branches/WOF2-1/ulp/dapl2/dat/udat/udat.c new file mode 100644 index 00000000..03edcf9c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/udat/udat.rc b/branches/WOF2-1/ulp/dapl2/dat/udat/udat.rc new file mode 100644 index 00000000..8fa97f0f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/udat/udat_api.c b/branches/WOF2-1/ulp/dapl2/dat/udat/udat_api.c new file mode 100644 index 00000000..5948a4fe --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/udat/udat_exports.src b/branches/WOF2-1/ulp/dapl2/dat/udat/udat_exports.src new file mode 100644 index 00000000..32b29ff7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/udat/udat_sources.c b/branches/WOF2-1/ulp/dapl2/dat/udat/udat_sources.c new file mode 100644 index 00000000..264ab4f7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/udat/udat_sr_parser.c b/branches/WOF2-1/ulp/dapl2/dat/udat/udat_sr_parser.c new file mode 100644 index 00000000..126fb9f5 --- /dev/null +++ b/branches/WOF2-1/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_ERROR, + "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-1/ulp/dapl2/dat/udat/udat_sr_parser.h b/branches/WOF2-1/ulp/dapl2/dat/udat/udat_sr_parser.h new file mode 100644 index 00000000..82a027a7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dat/udat/windows/dat_osd.c b/branches/WOF2-1/ulp/dapl2/dat/udat/windows/dat_osd.c new file mode 100644 index 00000000..5b57f432 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dat/udat/windows/dat_osd.c @@ -0,0 +1,203 @@ +/* + * 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 */ + } +} + + +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: + DisableThreadLibraryCalls( h_module ); + udat_check_state(); + break; + + case DLL_PROCESS_DETACH: + dat_fini(); + } + + 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-1/ulp/dapl2/dat/udat/windows/dat_osd.h b/branches/WOF2-1/ulp/dapl2/dat/udat/windows/dat_osd.h new file mode 100644 index 00000000..d78fe44d --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dat/udat/windows/dat_osd.h @@ -0,0 +1,426 @@ +/* + * 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 + +#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 * + * * + *********************************************************************/ + +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_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-1/ulp/dapl2/dat/udat/windows/dat_osd_sr.h b/branches/WOF2-1/ulp/dapl2/dat/udat/windows/dat_osd_sr.h new file mode 100644 index 00000000..e64a743c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/dirs b/branches/WOF2-1/ulp/dapl2/dirs new file mode 100644 index 00000000..21aa2261 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/dirs @@ -0,0 +1,4 @@ +DIRS=\ + dat \ + dapl \ + test diff --git a/branches/WOF2-1/ulp/dapl2/doc/dapl_coding_style.txt b/branches/WOF2-1/ulp/dapl2/doc/dapl_coding_style.txt new file mode 100644 index 00000000..74e44f1d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/doc/dapl_end_point_design.txt b/branches/WOF2-1/ulp/dapl2/doc/dapl_end_point_design.txt new file mode 100644 index 00000000..d351d961 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/doc/dapl_environ.txt b/branches/WOF2-1/ulp/dapl2/doc/dapl_environ.txt new file mode 100644 index 00000000..17aabd19 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/doc/dapl_event_design.txt b/branches/WOF2-1/ulp/dapl2/doc/dapl_event_design.txt new file mode 100644 index 00000000..247c7ef5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/doc/dapl_ibm_api_variations.txt b/branches/WOF2-1/ulp/dapl2/doc/dapl_ibm_api_variations.txt new file mode 100644 index 00000000..764e552b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/doc/dapl_memory_management_design.txt b/branches/WOF2-1/ulp/dapl2/doc/dapl_memory_management_design.txt new file mode 100644 index 00000000..09ff153e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/doc/dapl_patch.txt b/branches/WOF2-1/ulp/dapl2/doc/dapl_patch.txt new file mode 100644 index 00000000..5bc5f9d2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/doc/dapl_registry_design.txt b/branches/WOF2-1/ulp/dapl2/doc/dapl_registry_design.txt new file mode 100644 index 00000000..7215cc0b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/doc/dapl_shared_memory_design.txt b/branches/WOF2-1/ulp/dapl2/doc/dapl_shared_memory_design.txt new file mode 100644 index 00000000..f4f35240 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/doc/dapl_vendor_specific_changes.txt b/branches/WOF2-1/ulp/dapl2/doc/dapl_vendor_specific_changes.txt new file mode 100644 index 00000000..19bbbf89 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/doc/dat_environ.txt b/branches/WOF2-1/ulp/dapl2/doc/dat_environ.txt new file mode 100644 index 00000000..7c32037e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/doc/uDAPL_release_notes.txt b/branches/WOF2-1/ulp/dapl2/doc/uDAPL_release_notes.txt new file mode 100644 index 00000000..4d15a8b4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/man/dapltest.1 b/branches/WOF2-1/ulp/dapl2/man/dapltest.1 new file mode 100644 index 00000000..c1c46829 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/man/dat.conf.5 b/branches/WOF2-1/ulp/dapl2/man/dat.conf.5 new file mode 100644 index 00000000..6dee6683 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/man/dat.conf.5 @@ -0,0 +1,62 @@ +.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 Example netdev entries for OpenFabrics rdma_cm providers, both v1.2 and v2.0 +\br + 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" "" + + NOTE: The OpenFabrics providers use to specify the device with one of the following: + network address, network hostname, or netdev name; along with port number. + + The 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. +The file location may be overridden with the environment variable DAT_OVERRIDE=/your_own_directory/your_dat.conf. +.PP +.SH "SEE ALSO" +.PP diff --git a/branches/WOF2-1/ulp/dapl2/man/dtest.1 b/branches/WOF2-1/ulp/dapl2/man/dtest.1 new file mode 100644 index 00000000..1e227e50 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/Makefile.am b/branches/WOF2-1/ulp/dapl2/test/dapltest/Makefile.am new file mode 100644 index 00000000..bfc25338 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/README b/branches/WOF2-1/ulp/dapl2/test/dapltest/README new file mode 100644 index 00000000..98f66569 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/cmd/dapl_fft_cmd.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_fft_cmd.c new file mode 100644 index 00000000..a604e936 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/cmd/dapl_getopt.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_getopt.c new file mode 100644 index 00000000..293ab67b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/cmd/dapl_limit_cmd.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_limit_cmd.c new file mode 100644 index 00000000..69b8b7c9 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/cmd/dapl_main.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_main.c new file mode 100644 index 00000000..9ac6f120 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/cmd/dapl_netaddr.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_netaddr.c new file mode 100644 index 00000000..e54dec94 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/cmd/dapl_params.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_params.c new file mode 100644 index 00000000..9d5e510f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/cmd/dapl_performance_cmd.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_performance_cmd.c new file mode 100644 index 00000000..5f9b9f1e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/cmd/dapl_qos_util.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_qos_util.c new file mode 100644 index 00000000..42995dc5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/cmd/dapl_quit_cmd.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_quit_cmd.c new file mode 100644 index 00000000..d8536a7f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/cmd/dapl_server_cmd.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_server_cmd.c new file mode 100644 index 00000000..5859471d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/cmd/dapl_test_data.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_test_data.c new file mode 100644 index 00000000..5f13cc37 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/cmd/dapl_transaction_cmd.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/cmd/dapl_transaction_cmd.c new file mode 100644 index 00000000..5bdcab8c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/common/dapl_endian.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/common/dapl_endian.c new file mode 100644 index 00000000..d93fbb92 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/common/dapl_global.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/common/dapl_global.c new file mode 100644 index 00000000..ecd61e7e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/common/dapl_performance_cmd_util.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/common/dapl_performance_cmd_util.c new file mode 100644 index 00000000..5321809f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/common/dapl_quit_cmd_util.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/common/dapl_quit_cmd_util.c new file mode 100644 index 00000000..b629ae02 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/common/dapl_transaction_cmd_util.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/common/dapl_transaction_cmd_util.c new file mode 100644 index 00000000..30301b1c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/configure.in b/branches/WOF2-1/ulp/dapl2/test/dapltest/configure.in new file mode 100644 index 00000000..c6b5a266 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/dirs b/branches/WOF2-1/ulp/dapl2/test/dapltest/dirs new file mode 100644 index 00000000..f3b2bb0b --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dapltest/dirs @@ -0,0 +1 @@ +dirs = windows diff --git a/branches/WOF2-1/ulp/dapl2/test/dapltest/dt_cmd.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/dt_cmd.c new file mode 100644 index 00000000..ea07f161 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/dt_common.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/dt_common.c new file mode 100644 index 00000000..bd939e53 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/dt_mdep.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/dt_mdep.c new file mode 100644 index 00000000..d4a92336 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dapltest/dt_mdep.c @@ -0,0 +1,2 @@ + +#include "mdep/windows/dapl_mdep_user.c" diff --git a/branches/WOF2-1/ulp/dapl2/test/dapltest/dt_test.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/dt_test.c new file mode 100644 index 00000000..d63dbba7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/dt_udapl.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/dt_udapl.c new file mode 100644 index 00000000..274be4e0 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dapltest/dt_udapl.c @@ -0,0 +1,2 @@ + +#include "udapl/udapl_tdep.c" diff --git a/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_bpool.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_bpool.h new file mode 100644 index 00000000..33ba4854 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_client_info.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_client_info.h new file mode 100644 index 00000000..6431f8df --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_common.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_common.h new file mode 100644 index 00000000..df3e0009 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_execute.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_execute.h new file mode 100644 index 00000000..eb2d54a2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_fft_cmd.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_fft_cmd.h new file mode 100644 index 00000000..0989a2e7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_fft_util.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_fft_util.h new file mode 100644 index 00000000..17675cf4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_getopt.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_getopt.h new file mode 100644 index 00000000..e8874b67 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_global.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_global.h new file mode 100644 index 00000000..562404f0 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_limit_cmd.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_limit_cmd.h new file mode 100644 index 00000000..03bc7739 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_mdep.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_mdep.h new file mode 100644 index 00000000..72f4aec3 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_memlist.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_memlist.h new file mode 100644 index 00000000..b383610b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_params.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_params.h new file mode 100644 index 00000000..dc500b78 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_performance_cmd.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_performance_cmd.h new file mode 100644 index 00000000..93fb3215 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_performance_stats.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_performance_stats.h new file mode 100644 index 00000000..44c117ca --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_performance_test.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_performance_test.h new file mode 100644 index 00000000..82040a2f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_proto.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_proto.h new file mode 100644 index 00000000..fb5a293b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_quit_cmd.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_quit_cmd.h new file mode 100644 index 00000000..8aba24e1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_server_cmd.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_server_cmd.h new file mode 100644 index 00000000..244103a8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_server_info.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_server_info.h new file mode 100644 index 00000000..de038c5e --- /dev/null +++ b/branches/WOF2-1/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[80]; + 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-1/ulp/dapl2/test/dapltest/include/dapl_tdep.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_tdep.h new file mode 100644 index 00000000..ccddce5c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_tdep_print.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_tdep_print.h new file mode 100644 index 00000000..0a1a1b07 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_test_data.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_test_data.h new file mode 100644 index 00000000..4ac00209 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_transaction_cmd.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_transaction_cmd.h new file mode 100644 index 00000000..afd59c01 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_transaction_stats.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_transaction_stats.h new file mode 100644 index 00000000..3fd3a957 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_transaction_test.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_transaction_test.h new file mode 100644 index 00000000..7401cdf6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/include/dapl_version.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/include/dapl_version.h new file mode 100644 index 00000000..20222504 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.c new file mode 100644 index 00000000..e2c6da31 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.h new file mode 100644 index 00000000..c0734e94 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.c new file mode 100644 index 00000000..d2b45bd8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.h new file mode 100644 index 00000000..c39d3d69 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.h @@ -0,0 +1,203 @@ +/* + * 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) + +#endif diff --git a/branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.c new file mode 100644 index 00000000..fc52861c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.h new file mode 100644 index 00000000..3a1e6281 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.h @@ -0,0 +1,151 @@ +/* + * 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) + + +/* + * 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-1/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.c new file mode 100644 index 00000000..afc12d37 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.h b/branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.h new file mode 100644 index 00000000..7b7a845c --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.h @@ -0,0 +1,185 @@ + +/* + * 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) + +/* + * 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-1/ulp/dapl2/test/dapltest/scripts/cl.sh b/branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/cl.sh new file mode 100644 index 00000000..9a8d64f6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/scripts/dt-cli.bat b/branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/dt-cli.bat new file mode 100644 index 00000000..c445d5a8 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/dt-cli.bat @@ -0,0 +1,372 @@ +@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) + +if EXIST "%ProgramFiles(x86)%" ( + set PF="%ProgramFiles(x86)%\WinOF" +) else ( + set PF="%ProgramFiles%\WinOF" +) + +if NOT EXIST %PF%\dapl2test.exe ( + echo Missing file %PF%\dapl2test.exe ? + exit /B 1 +) +set DT=dapl2test.exe +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-1/ulp/dapl2/test/dapltest/scripts/dt-svr.bat b/branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/dt-svr.bat new file mode 100644 index 00000000..c876d413 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/dt-svr.bat @@ -0,0 +1,68 @@ +@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 + +if EXIST "%ProgramFiles(x86)%" ( + set PF="%ProgramFiles(x86)%\WinOF" +) else ( + set PF="%ProgramFiles%\WinOF" +) + +if NOT EXIST %PF%\dapl2test.exe ( + echo Missing file %PF%\dapl2test.exe ? + exit /B 1 +) + +set DT=dapl2test.exe +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-1/ulp/dapl2/test/dapltest/scripts/kregress.sh b/branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/kregress.sh new file mode 100644 index 00000000..8e5dfc99 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/scripts/ksrv.sh b/branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/ksrv.sh new file mode 100644 index 00000000..9727e6c4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/scripts/lim.sh b/branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/lim.sh new file mode 100644 index 00000000..09b938b6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/scripts/regress.sh b/branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/regress.sh new file mode 100644 index 00000000..7659257f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/scripts/srv.sh b/branches/WOF2-1/ulp/dapl2/test/dapltest/scripts/srv.sh new file mode 100644 index 00000000..78e8f631 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_bpool.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_bpool.c new file mode 100644 index 00000000..e06f2fc2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_client.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_client.c new file mode 100644 index 00000000..91ebd7dc --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_client_info.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_client_info.c new file mode 100644 index 00000000..f060bbcc --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_cnxn.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_cnxn.c new file mode 100644 index 00000000..36d538ce --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_execute.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_execute.c new file mode 100644 index 00000000..c117b2aa --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_fft_connmgt.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_connmgt.c new file mode 100644 index 00000000..c1c9e600 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer.c new file mode 100644 index 00000000..d14071f0 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer_client.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer_client.c new file mode 100644 index 00000000..f31bb55e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_fft_endpoint.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_endpoint.c new file mode 100644 index 00000000..81e2c983 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_fft_hwconn.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_hwconn.c new file mode 100644 index 00000000..ccde7332 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_fft_mem.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_mem.c new file mode 100644 index 00000000..4a89d4e2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_fft_pz.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_pz.c new file mode 100644 index 00000000..77f818b9 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_fft_queryinfo.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_queryinfo.c new file mode 100644 index 00000000..5bbee36f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_fft_test.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_test.c new file mode 100644 index 00000000..1ef1a87a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_fft_util.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_fft_util.c new file mode 100644 index 00000000..eeb32998 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_limit.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_limit.c new file mode 100644 index 00000000..6b299fab --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_memlist.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_memlist.c new file mode 100644 index 00000000..03e8d88a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_performance_client.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_performance_client.c new file mode 100644 index 00000000..96d5b47a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_performance_server.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_performance_server.c new file mode 100644 index 00000000..5083967e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_performance_stats.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_performance_stats.c new file mode 100644 index 00000000..95fa202f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_performance_util.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_performance_util.c new file mode 100644 index 00000000..5023be0b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_quit_util.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_quit_util.c new file mode 100644 index 00000000..a0524c4a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_server.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_server.c new file mode 100644 index 00000000..443425c5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_server_info.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_server_info.c new file mode 100644 index 00000000..6041ba8e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_test_data.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_test_data.c new file mode 100644 index 00000000..59d5d1a1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_test_util.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_test_util.c new file mode 100644 index 00000000..db9b6721 --- /dev/null +++ b/branches/WOF2-1/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 (;;) { + 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-1/ulp/dapl2/test/dapltest/test/dapl_thread.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_thread.c new file mode 100644 index 00000000..9a56558d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_transaction_stats.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_transaction_stats.c new file mode 100644 index 00000000..f9d63778 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_transaction_test.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_transaction_test.c new file mode 100644 index 00000000..14c14b4c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/test/dapl_transaction_util.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_transaction_util.c new file mode 100644 index 00000000..ffe5d7df --- /dev/null +++ b/branches/WOF2-1/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" + +/* ----------------------------------------------------------- + * 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; + + 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(); + 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 + (phead, ep_context[i].reqt_evd_hdl, poll, &dto_stat)) { + DT_Mdep_Free(completion_reaped); + return false; + } + + 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(); + 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(phead, + &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_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(); + DT_Mdep_Free(completion_reaped); + return (false); + } + 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(); + 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(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; + + 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 + (phead, ep_context[i].recv_evd_hdl, poll, &dto_stat)) { + DT_Mdep_Free(recv_completion_reaped); + DT_Mdep_Free(send_completion_reaped); + return false; + } + + 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(); + 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(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(); + DT_Mdep_Free(recv_completion_reaped); + DT_Mdep_Free(send_completion_reaped); + return false; + } + + 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(); + 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_Tdep_PT_Printf(phead, + "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 + (phead, ep_context[i].reqt_evd_hdl, poll, + &dto_stat)) { + DT_Mdep_Free(recv_completion_reaped); + DT_Mdep_Free(send_completion_reaped); + return false; + } + + 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(); + 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(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(); + DT_Mdep_Free(recv_completion_reaped); + DT_Mdep_Free(send_completion_reaped); + return false; + } + + 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(); + 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_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(); + 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_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(); + 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 + (phead, ep_context, num_eps, op_indx)) { + DT_Tdep_PT_Printf(phead, + "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(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; + + 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(); + DT_Mdep_Free(completion_reaped); + return (false); + } else { + DT_Tdep_PT_Debug(3, (phead, + "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 + (phead, ep_context[i].reqt_evd_hdl, poll, &dto_stat)) { + DT_Mdep_Free(completion_reaped); + return (false); + } + + 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(); + 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(phead, + &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_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(); + DT_Mdep_Free(completion_reaped); + return (false); + } + 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(); + 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, 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-1/ulp/dapl2/test/dapltest/test/dapl_util.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/test/dapl_util.c new file mode 100644 index 00000000..39cc1a3b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/udapl/udapl_tdep.c b/branches/WOF2-1/ulp/dapl2/test/dapltest/udapl/udapl_tdep.c new file mode 100644 index 00000000..af5522cb --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/windows/SOURCES b/branches/WOF2-1/ulp/dapl2/test/dapltest/windows/SOURCES new file mode 100644 index 00000000..9aee05b0 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/windows/dapltest.rc b/branches/WOF2-1/ulp/dapl2/test/dapltest/windows/dapltest.rc new file mode 100644 index 00000000..09fef620 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dapltest/windows/makefile b/branches/WOF2-1/ulp/dapl2/test/dapltest/windows/makefile new file mode 100644 index 00000000..b931d6c8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dirs b/branches/WOF2-1/ulp/dapl2/test/dirs new file mode 100644 index 00000000..b6232e98 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dirs @@ -0,0 +1 @@ +DIRS = dapltest dtest diff --git a/branches/WOF2-1/ulp/dapl2/test/dtest/Makefile.am b/branches/WOF2-1/ulp/dapl2/test/dtest/Makefile.am new file mode 100644 index 00000000..6d92345e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dtest/README b/branches/WOF2-1/ulp/dapl2/test/dtest/README new file mode 100644 index 00000000..34eeeb95 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dtest/configure.in b/branches/WOF2-1/ulp/dapl2/test/dtest/configure.in new file mode 100644 index 00000000..2fca0577 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dtest/dirs b/branches/WOF2-1/ulp/dapl2/test/dtest/dirs new file mode 100644 index 00000000..f3b2bb0b --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dtest/dirs @@ -0,0 +1 @@ +dirs = windows diff --git a/branches/WOF2-1/ulp/dapl2/test/dtest/dtc.bat b/branches/WOF2-1/ulp/dapl2/test/dtest/dtc.bat new file mode 100644 index 00000000..7c2c0fce --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dtest/dtest.c b/branches/WOF2-1/ulp/dapl2/test/dtest/dtest.c new file mode 100644 index 00000000..77d78b2b --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dtest/dtest.c @@ -0,0 +1,2148 @@ +/* + * 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 + +#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 DTO_FLUSH_TIMEOUT (1000*1000*2) +#define CONN_TIMEOUT (1000*1000*10) +#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 time; + +/* 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; + +/* 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); +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); + } +} + +int main(int argc, char **argv) +{ + int i, c; + DAT_RETURN ret; + DAT_EP_PARAM ep_param; + + /* parse arguments */ + while ((c = getopt(argc, argv, "tscvpb: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 '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(&time, 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(); + time.open += ((stop - start) * 1.0e6); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d: Error Adaptor open: %s\n", + getpid(), DT_RetToString(ret)); + exit(1); + } else + LOGPRINTF("%d Opened Interface Adaptor\n", getpid()); + + /* Create Protection Zone */ + start = get_time(); + LOGPRINTF("%d Create Protection Zone\n", getpid()); + ret = dat_pz_create(h_ia, &h_pz); + stop = get_time(); + time.pzc += ((stop - start) * 1.0e6); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error creating Protection Zone: %s\n", + getpid(), DT_RetToString(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_RetToString(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_RetToString(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(); + time.epc += ((stop - start) * 1.0e6); + time.total += time.epc; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_ep_create: %s\n", + getpid(), DT_RetToString(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_RetToString(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_RetToString(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_RetToString(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_RetToString(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_RetToString(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(); + time.epf += ((stop - start) * 1.0e6); + time.total += time.epf; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error freeing EP: %s\n", + getpid(), DT_RetToString(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_RetToString(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_RetToString(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(); + time.pzf += ((stop - start) * 1.0e6); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error freeing PZ: %s\n", + getpid(), DT_RetToString(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(); + time.close += ((stop - start) * 1.0e6); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d: Error Adaptor close: %s\n", + getpid(), DT_RetToString(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(), time.rtt, burst, time.rtt / burst, poll_count); + printf("%d: RDMA write: Total=%10.2lf usec, %d bursts, itime=%10.2lf" + " usec, pc=%d\n", + getpid(), time.rdma_wr, burst, + time.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(), time.rdma_rd_total, MAX_RDMA_RD, + time.rdma_rd[i], rdma_rd_poll_count[i]); + } + printf("%d: open: %10.2lf usec\n", getpid(), time.open); + printf("%d: close: %10.2lf usec\n", getpid(), time.close); + printf("%d: PZ create: %10.2lf usec\n", getpid(), time.pzc); + printf("%d: PZ free: %10.2lf usec\n", getpid(), time.pzf); + printf("%d: LMR create:%10.2lf usec\n", getpid(), time.reg); + printf("%d: LMR free: %10.2lf usec\n", getpid(), time.unreg); + printf("%d: EVD create:%10.2lf usec\n", getpid(), time.evdc); + printf("%d: EVD free: %10.2lf usec\n", getpid(), time.evdf); + if (use_cno) { + printf("%d: CNO create: %10.2lf usec\n", getpid(), time.cnoc); + printf("%d: CNO free: %10.2lf usec\n", getpid(), time.cnof); + } + printf("%d: EP create: %10.2lf usec\n", getpid(), time.epc); + printf("%d: EP free: %10.2lf usec\n", getpid(), time.epf); + if (!server) + printf("%d: connect: %10.2lf usec, poll_cnt=%d\n", + getpid(), time.conn, conn_poll_count); + printf("%d: TOTAL: %10.2lf usec\n", getpid(), time.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_COUNT nmore; + 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_RetToString(ret)); + return ret; + } + + if (!(flags & DAT_COMPLETION_SUPPRESS_FLAG)) { + if (polling) { + printf("%d Polling post send completion...\n", + getpid()); + while (dat_evd_dequeue(h_dto_req_evd, &event) == + DAT_QUEUE_EMPTY) ; + } else { + LOGPRINTF("%d waiting for post_send completion event\n", + getpid()); + if (use_cno) { + DAT_EVD_HANDLE evd = DAT_HANDLE_NULL; + ret = + dat_cno_wait(h_dto_cno, DTO_TIMEOUT, &evd); + LOGPRINTF("%d cno wait return evd_handle=%p\n", + getpid(), evd); + if (evd != h_dto_req_evd) { + fprintf(stderr, + "%d Error waiting on h_dto_cno: evd != h_dto_req_evd\n", + getpid()); + return (DAT_ABORT); + } + } + /* use wait to dequeue */ + ret = + dat_evd_wait(h_dto_req_evd, DTO_TIMEOUT, 1, &event, + &nmore); + if (ret != DAT_SUCCESS) { + fprintf(stderr, + "%d: ERROR: DTO dat_evd_wait() %s\n", + getpid(), DT_RetToString(ret)); + return ret; + } + } + + /* 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_RetToString(ret)); + return (DAT_ABORT); + } + } + + return DAT_SUCCESS; +} + +DAT_RETURN connect_ep(char *hostname, DAT_CONN_QUAL conn_id) +{ + DAT_SOCK_ADDR remote_addr; + 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_RetToString(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_RetToString(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_RetToString(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_RetToString(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_RetToString(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_RetToString(ret)); + return (ret); + } else + LOGPRINTF("%d dat_cr_accept completed\n", getpid()); + } else { /* CLIENT */ + struct addrinfo *target; + int rval; + +#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); + freeaddrinfo(target); + + 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_RetToString(ret)); + return (ret); + } else + LOGPRINTF("%d dat_ep_connect completed\n", getpid()); + } + + 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(); + time.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_RetToString(ret)); + return (ret); + } else + LOGPRINTF("%d send_msg completed\n", getpid()); + + /* + * Wait for remote RMR information for RDMA + */ + if (polling) { + printf("%d Polling for remote to send RMR data\n", getpid()); + while (dat_evd_dequeue(h_dto_rcv_evd, &event) == + DAT_QUEUE_EMPTY) ; + } else { + printf("%d Waiting for remote to send RMR data\n", getpid()); + if (use_cno) { + DAT_EVD_HANDLE evd = DAT_HANDLE_NULL; + ret = dat_cno_wait(h_dto_cno, DTO_TIMEOUT, &evd); + LOGPRINTF("%d cno wait return evd_handle=%p\n", + getpid(), evd); + if (evd != h_dto_rcv_evd) { + fprintf(stderr, + "%d Error waiting on h_dto_cno: evd != h_dto_rcv_evd\n", + getpid()); + return (DAT_ABORT); + } + } + /* use wait to dequeue */ + ret = + dat_evd_wait(h_dto_rcv_evd, DTO_TIMEOUT, 1, &event, &nmore); + if (ret != DAT_SUCCESS) { + fprintf(stderr, + "%d Error waiting on h_dto_rcv_evd: %s\n", + getpid(), DT_RetToString(ret)); + return (ret); + } else { + LOGPRINTF("%d dat_evd_wait h_dto_rcv_evd completed\n", + getpid()); + } + } + + 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_RetToString(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_RetToString(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_RetToString(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_RetToString(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_RetToString(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_COUNT nmore; + 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_RetToString(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_RetToString(ret)); + return (ret); + } else { + LOGPRINTF("%d send_msg completed\n", getpid()); + } + + /* + * Collect first event, write completion or the inbound recv + */ + if (polling) { + while (dat_evd_dequeue(h_dto_rcv_evd, &event) == + DAT_QUEUE_EMPTY) + rdma_wr_poll_count++; + } else { + LOGPRINTF("%d waiting for message receive event\n", getpid()); + if (use_cno) { + DAT_EVD_HANDLE evd = DAT_HANDLE_NULL; + ret = dat_cno_wait(h_dto_cno, DTO_TIMEOUT, &evd); + LOGPRINTF("%d cno wait return evd_handle=%p\n", + getpid(), evd); + if (evd != h_dto_rcv_evd) { + fprintf(stderr, + "%d Error waiting on h_dto_cno: " + "evd != h_dto_rcv_evd\n", getpid()); + return (ret); + } + } + /* use wait to dequeue */ + ret = + dat_evd_wait(h_dto_rcv_evd, DTO_TIMEOUT, 1, &event, &nmore); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d: ERROR: DTO dat_evd_wait() %s\n", + getpid(), DT_RetToString(ret)); + return (ret); + } + } + stop = get_time(); + time.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_COUNT nmore; + 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_RetToString(ret)); + return (DAT_ABORT); + } + + if (polling) { + while (dat_evd_dequeue(h_dto_req_evd, &event) == + DAT_QUEUE_EMPTY) + rdma_rd_poll_count[i]++; + } else { + LOGPRINTF("%d waiting for rdma_read completion event\n", + getpid()); + if (use_cno) { + DAT_EVD_HANDLE evd = DAT_HANDLE_NULL; + ret = + dat_cno_wait(h_dto_cno, DTO_TIMEOUT, &evd); + LOGPRINTF("%d cno wait return evd_handle=%p\n", + getpid(), evd); + if (evd != h_dto_req_evd) { + fprintf(stderr, + "%d Error waiting on h_dto_cno: evd != h_dto_req_evd\n", + getpid()); + return (DAT_ABORT); + } + } + /* use wait to dequeue */ + ret = + dat_evd_wait(h_dto_req_evd, DTO_TIMEOUT, 1, &event, + &nmore); + if (ret != DAT_SUCCESS) { + fprintf(stderr, + "%d: ERROR: DTO dat_evd_wait() %s\n", + getpid(), DT_RetToString(ret)); + return ret; + } + } + /* 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_RetToString(ret)); + return (DAT_ABORT); + } + stop = get_time(); + time.rdma_rd[i] = ((stop - start) * 1.0e6); + time.rdma_rd_total += time.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()); + + 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_RetToString(ret)); + return (ret); + } else { + LOGPRINTF("%d send_msg completed\n", getpid()); + } + + /* + * Collect first event, write completion or the inbound recv with immed + */ + printf("%d Waiting for inbound message....\n", getpid()); + if (polling) { + while (dat_evd_dequeue(h_dto_rcv_evd, &event) == + DAT_QUEUE_EMPTY) ; + } else { + LOGPRINTF("%d waiting for message receive event\n", getpid()); + if (use_cno) { + DAT_EVD_HANDLE evd = DAT_HANDLE_NULL; + ret = dat_cno_wait(h_dto_cno, DTO_TIMEOUT, &evd); + LOGPRINTF("%d cno wait return evd_handle=%p\n", + getpid(), evd); + if (evd != h_dto_rcv_evd) { + fprintf(stderr, + "%d Error waiting on h_dto_cno: evd != h_dto_rcv_evd\n", + getpid()); + return (ret); + } + } + /* use wait to dequeue */ + ret = + dat_evd_wait(h_dto_rcv_evd, DTO_TIMEOUT, 1, &event, &nmore); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d: ERROR: DTO dat_evd_wait() %s\n", + getpid(), DT_RetToString(ret)); + return (ret); + } + } + + /* 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_COUNT nmore; + 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_RetToString(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_RetToString(ret)); + return (ret); + } else { + LOGPRINTF("%d send_msg completed\n", getpid()); + } + } + + /* Wait for recv message */ + if (polling) { + poll_count = 0; + LOGPRINTF("%d Polling for message receive event\n", + getpid()); + while (dat_evd_dequeue(h_dto_rcv_evd, &event) == + DAT_QUEUE_EMPTY) + poll_count++; + } else { + LOGPRINTF("%d waiting for message receive event\n", + getpid()); + if (use_cno) { + DAT_EVD_HANDLE evd = DAT_HANDLE_NULL; + ret = + dat_cno_wait(h_dto_cno, DTO_TIMEOUT, &evd); + LOGPRINTF("%d cno wait return evd_handle=%p\n", + getpid(), evd); + if (evd != h_dto_rcv_evd) { + fprintf(stderr, + "%d Error waiting on h_dto_cno: evd != h_dto_rcv_evd\n", + getpid()); + return (ret); + } + } + /* use wait to dequeue */ + ret = + dat_evd_wait(h_dto_rcv_evd, DTO_TIMEOUT, 1, &event, + &nmore); + if (ret != DAT_SUCCESS) { + fprintf(stderr, + "%d: ERROR: DTO dat_evd_wait() %s\n", + getpid(), DT_RetToString(ret)); + return (ret); + } + } + /* 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_RetToString(ret)); + return (ret); + } else { + LOGPRINTF("%d send_msg completed\n", getpid()); + } + } + + /* next buffers */ + rcv_buf += buf_len; + snd_buf += buf_len; + } + stop = get_time(); + time.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(); + time.reg += ((stop - start) * 1.0e6); + time.total += time.reg; + + if (ret != DAT_SUCCESS) { + fprintf(stderr, + "%d Error registering Receive RDMA buffer: %s\n", + getpid(), DT_RetToString(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_RetToString(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(); + time.unreg += ((stop - start) * 1.0e6); + time.total += time.unreg; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error deregistering recv mr: %s\n", + getpid(), DT_RetToString(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_RetToString(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(); + time.cnoc += ((stop - start) * 1.0e6); + time.total += time.cnoc; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_cno_create: %s\n", + getpid(), DT_RetToString(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(); + time.evdc += ((stop - start) * 1.0e6); + time.total += time.evdc; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_evd_create: %s\n", + getpid(), DT_RetToString(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_RetToString(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_RetToString(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_RetToString(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_RetToString(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_RetToString(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_RetToString(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(); + time.evdf += ((stop - start) * 1.0e6); + time.total += time.evdf; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error freeing dto EVD: %s\n", + getpid(), DT_RetToString(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_RetToString(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(); + time.cnof += ((stop - start) * 1.0e6); + time.total += time.cnof; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error freeing dto CNO: %s\n", + getpid(), DT_RetToString(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_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("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("\n"); +} + diff --git a/branches/WOF2-1/ulp/dapl2/test/dtest/dtestcm.c b/branches/WOF2-1/ulp/dapl2/test/dtest/dtestcm.c new file mode 100644 index 00000000..b6dcccfa --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dtest/dtestcm.c @@ -0,0 +1,1112 @@ +/* + * 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 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 + +#define DAPL_PROVIDER "ofa-v2-mlx4_0-1" + +#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 time; + +/* 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; + +/* 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); + } +} + +int main(int argc, char **argv) +{ + int i, c, len; + DAT_RETURN ret; + + /* parse arguments */ + while ((c = getopt(argc, argv, "smwvub:c:d:h:P:p:")) != -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; + 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(&time, 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(); + time.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"); + + /* Create Protection Zone */ + start = get_time(); + LOGPRINTF(" Create Protection Zone\n"); + ret = dat_pz_create(h_ia, &h_pz); + stop = get_time(); + time.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(); + time.epc += ((stop - start) * 1.0e6); + time.total += time.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(); + time.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(); + time.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", time.open); + printf(" close: %10.2lf usec\n", time.close); + printf(" PZ create: %10.2lf usec\n", time.pzc); + printf(" PZ free: %10.2lf usec\n", time.pzf); + printf(" LMR create:%10.2lf usec\n", time.reg); + printf(" LMR free: %10.2lf usec\n", time.unreg); + printf(" EVD create:%10.2lf usec\n", time.evdc); + printf(" EVD free: %10.2lf usec\n", time.evdf); + printf(" EP create: %10.2lf usec avg\n", time.epc/connections); + printf(" EP free: %10.2lf usec avg\n", time.epf/connections); + if (!server) { + printf(" Connections: %8.2lf usec, CPS %7.2lf " + "Total %4.2lf secs, poll_cnt=%u, Num=%d\n", + (double)(time.conn/connections), + (double)(1/(time.conn/1000000/connections)), + (double)(time.conn/1000000), + conn_poll_count, connections); + } + printf(" TOTAL: %4.2lf sec\n", time.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); + freeaddrinfo(target); + + 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(); + time.conn += ((stop - start) * 1.0e6); + + 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(); + time.epf += ((stop - start) * 1.0e6); + time.total += time.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(); + time.epf += ((stop - start) * 1.0e6); + time.total += time.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(); + time.evdc += ((stop - start) * 1.0e6); + time.total += time.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(); + time.evdf += ((stop - start) * 1.0e6); + time.total += time.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-1/ulp/dapl2/test/dtest/dtestx.c b/branches/WOF2-1/ulp/dapl2/test/dtest/dtestx.c new file mode 100644 index 00000000..2945a741 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dtest/dtestx.c @@ -0,0 +1,1299 @@ +/* + * 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 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; + +#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 + +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; + 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); + + /* Waiting on CR's or CONN_EST */ + if (event.event_number != DAT_CONNECTION_EVENT_ESTABLISHED || + (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_SOCK_ADDR remote_addr; + DAT_EP_ATTR ep_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, 0, NULL, + DAT_PROVIDER_FIELD_ALL, &prov_attrs); + _OK(status, "dat_ia_query"); + + /* 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 (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)); + + remote_addr = *((DAT_IA_ADDRESS_PTR) target->ai_addr); + freeaddrinfo(target); + strcpy((char *)buf[SND_RDMA_BUF_INDEX], "Client written data"); + + /* 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"); + } + } + + /* 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 (!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"); + + 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); + } + 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:")) != -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; + 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-1/ulp/dapl2/test/dtest/dts.bat b/branches/WOF2-1/ulp/dapl2/test/dtest/dts.bat new file mode 100644 index 00000000..3e802073 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dtest/windows/dirs b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dirs new file mode 100644 index 00000000..50f01314 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dirs @@ -0,0 +1 @@ +dirs = dtest dtestx dtestcm diff --git a/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtest/SOURCES b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtest/SOURCES new file mode 100644 index 00000000..e880beb1 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtest/SOURCES @@ -0,0 +1,33 @@ +!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; + +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-1/ulp/dapl2/test/dtest/windows/dtest/dtest.c b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtest/dtest.c new file mode 100644 index 00000000..2bdfae3d --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtest/dtest.c @@ -0,0 +1,3 @@ +#include "..\..\..\..\..\..\etc\user\gtod.c" +#include "..\..\dtest.c" + diff --git a/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtest/dtest.rc b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtest/dtest.rc new file mode 100644 index 00000000..9253096e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dtest/windows/dtest/makefile b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtest/makefile new file mode 100644 index 00000000..5fb2ee8f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dtest/windows/dtestcm/SOURCES b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestcm/SOURCES new file mode 100644 index 00000000..662da89a --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestcm/SOURCES @@ -0,0 +1,33 @@ +!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; + +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-1/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.c b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.c new file mode 100644 index 00000000..c734a6ba --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.c @@ -0,0 +1,3 @@ +#include "..\..\..\..\..\..\etc\user\gtod.c" +#include "..\..\dtestcm.c" + diff --git a/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.rc b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.rc new file mode 100644 index 00000000..a1674857 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dtest/windows/dtestcm/makefile b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestcm/makefile new file mode 100644 index 00000000..5fb2ee8f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dtest/windows/dtestx/SOURCES b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestx/SOURCES new file mode 100644 index 00000000..2a7f1f60 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestx/SOURCES @@ -0,0 +1,31 @@ +!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; + +# 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-1/ulp/dapl2/test/dtest/windows/dtestx/dtestx.c b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestx/dtestx.c new file mode 100644 index 00000000..4cc23c13 --- /dev/null +++ b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestx/dtestx.c @@ -0,0 +1 @@ +#include "..\..\dtestx.c" diff --git a/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestx/dtestx.rc b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestx/dtestx.rc new file mode 100644 index 00000000..98659e0a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dapl2/test/dtest/windows/dtestx/makefile b/branches/WOF2-1/ulp/dapl2/test/dtest/windows/dtestx/makefile new file mode 100644 index 00000000..5fb2ee8f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/dirs b/branches/WOF2-1/ulp/dirs new file mode 100644 index 00000000..31a7d720 --- /dev/null +++ b/branches/WOF2-1/ulp/dirs @@ -0,0 +1,14 @@ +DIRS = \ + opensm \ + dapl \ + dapl2 \ + ipoib \ + srp \ + wsd \ + qlgcvnic \ + libibverbs \ + libibumad \ + libibmad \ + libibnetdisc\ + librdmacm \ + nd diff --git a/branches/WOF2-1/ulp/ipoib/dirs b/branches/WOF2-1/ulp/ipoib/dirs new file mode 100644 index 00000000..ed41dcf4 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/dirs @@ -0,0 +1,2 @@ +DIRS=\ + kernel diff --git a/branches/WOF2-1/ulp/ipoib/ip_stats.h b/branches/WOF2-1/ulp/ipoib/ip_stats.h new file mode 100644 index 00000000..0182475c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/SOURCES b/branches/WOF2-1/ulp/ipoib/kernel/SOURCES new file mode 100644 index 00000000..ffd58fef --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel/SOURCES @@ -0,0 +1,58 @@ +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 + +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-1/ulp/ipoib/kernel/ipoib.cdf b/branches/WOF2-1/ulp/ipoib/kernel/ipoib.cdf new file mode 100644 index 00000000..eb21da98 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/ipoib.rc b/branches/WOF2-1/ulp/ipoib/kernel/ipoib.rc new file mode 100644 index 00000000..525372fd --- /dev/null +++ b/branches/WOF2-1/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 Miniport (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "IP over InfiniBand NDIS Miniport" +#endif + +#define VER_INTERNALNAME_STR "ipoib.sys" +#define VER_ORIGINALFILENAME_STR "ipoib.sys" + +#include +#include "ipoib_log.rc" diff --git a/branches/WOF2-1/ulp/ipoib/kernel/ipoib32-xp.cdf b/branches/WOF2-1/ulp/ipoib/kernel/ipoib32-xp.cdf new file mode 100644 index 00000000..faf8ea6f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/ipoib32.cdf b/branches/WOF2-1/ulp/ipoib/kernel/ipoib32.cdf new file mode 100644 index 00000000..50225ba6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/ipoib_adapter.c b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_adapter.c new file mode 100644 index 00000000..1115bc5d --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_adapter.c @@ -0,0 +1,1455 @@ +/* + * 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( (status == NDIS_STATUS_SUCCESS) && (len == HW_ADDR_LEN) ) + { + 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 ); + } + } + + *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 ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_adapter ); + + /* + * 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_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; + + 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; + 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; + 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-1/ulp/ipoib/kernel/ipoib_adapter.h b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_adapter.h new file mode 100644 index 00000000..f6600a2e --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_adapter.h @@ -0,0 +1,436 @@ +/* + * 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" + + +/* + * 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; + 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; + +} 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-1/ulp/ipoib/kernel/ipoib_debug.h b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_debug.h new file mode 100644 index 00000000..93701142 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/ipoib_driver.c b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_driver.c new file mode 100644 index 00000000..2a490aa4 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_driver.c @@ -0,0 +1,2581 @@ +/* + * 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 ); + + 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_EXIT( IPOIB_DBG_INIT ); + 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 ); + + + 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_EXIT( IPOIB_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 +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_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->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 ); + } + + IPOIB_EXIT( IPOIB_DBG_PNP ); +} + + +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, p_net_addr_oid = + (PNETWORK_ADDRESS)((uint8_t *)p_net_addr_oid + + FIELD_OFFSET(NETWORK_ADDRESS, Address) + + p_net_addr_oid->AddressLength) ) + { + + if( p_net_addr_oid->AddressType != NDIS_PROTOCOL_ID_TCP_IP ) + { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong type of 0x%.4X, " + "should be 0x%.4X\n", port_num, i, p_net_addr_oid->AddressType, + NDIS_PROTOCOL_ID_TCP_IP)); + continue; + } + + if( p_net_addr_oid->AddressLength != NETWORK_ADDRESS_LENGTH_IP) + { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_OID, + ("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)); + continue; + } + + 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++, p_net_addr_oid = + (PNETWORK_ADDRESS)((uint8_t *)p_net_addr_oid + + FIELD_OFFSET(NETWORK_ADDRESS, Address) + p_net_addr_oid->AddressLength) ) + { + + if( p_net_addr_oid->AddressType != NDIS_PROTOCOL_ID_TCP_IP ) + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong type of 0x%.4X, " + "should be 0x%.4X\n", port_num, i, p_net_addr_oid->AddressType, + NDIS_PROTOCOL_ID_TCP_IP)); + continue; + } + + if( p_net_addr_oid->AddressLength != NETWORK_ADDRESS_LENGTH_IP) + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("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)); + continue; + } + + 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 = 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-1/ulp/ipoib/kernel/ipoib_driver.h b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_driver.h new file mode 100644 index 00000000..7f2725c2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/ipoib_endpoint.c b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_endpoint.c new file mode 100644 index 00000000..53903a05 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/ipoib_endpoint.h b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_endpoint.h new file mode 100644 index 00000000..ae1f1468 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/ipoib_ibat.c b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_ibat.c new file mode 100644 index 00000000..01fc02a8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/ipoib_ibat.h b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_ibat.h new file mode 100644 index 00000000..83d01951 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/ipoib_log.mc b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_log.mc new file mode 100644 index 00000000..193e368a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/ipoib_port.c b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_port.c new file mode 100644 index 00000000..da36393a --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_port.c @@ -0,0 +1,6480 @@ +/* + * 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 ); + + +static void __recv_cb_dpc(KDPC *p_gc_dpc,void *context,void *s_arg1, void *s_arg2); + + +/****************************************************************************** +* +* 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 intn_t +__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 ); + + 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; + + 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; + } + + KeInitializeDpc(&p_port->recv_dpc,(PKDEFERRED_ROUTINE)__recv_cb_dpc,p_port); + + + /* 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 ); + + 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 void __recv_cb_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); + + + __recv_cb(NULL, p_port); + ipoib_port_deref( p_port, ref_recv_cb ); + + +} + + +static void +__recv_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_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; + 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 ); + + UNUSED_PARAM( h_cq ); + + 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)); + + /* 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. + */ + 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 ); + + ipoib_port_deref( p_port, ref_recv_cb ); + } else { + // Please note the reference is still up + KeInsertQueueDpc(&p_port->recv_dpc, NULL, NULL); + } + + cl_perf_stop( &p_port->p_adapter->perf, RecvCb ); + + IPOIB_EXIT( IPOIB_DBG_RECV ); +} + + +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 + { + 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 ); + } + } + + 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) ); + } + 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 ); + cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts, + &p_port->p_local_endpt->lid_item ); + + 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 ); + } + + 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-1/ulp/ipoib/kernel/ipoib_port.h b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_port.h new file mode 100644 index 00000000..955a5d8a --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_port.h @@ -0,0 +1,652 @@ +/* + * 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; + + KDPC recv_dpc; + + 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; + 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-1/ulp/ipoib/kernel/ipoib_xfr_mgr.c b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_xfr_mgr.c new file mode 100644 index 00000000..0fc4f102 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/ipoib_xfr_mgr.h b/branches/WOF2-1/ulp/ipoib/kernel/ipoib_xfr_mgr.h new file mode 100644 index 00000000..b2a4cd55 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/makefile b/branches/WOF2-1/ulp/ipoib/kernel/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/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-1/ulp/ipoib/kernel/makefile.inc b/branches/WOF2-1/ulp/ipoib/kernel/makefile.inc new file mode 100644 index 00000000..4f29f500 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel/netipoib-xp32.inf b/branches/WOF2-1/ulp/ipoib/kernel/netipoib-xp32.inf new file mode 100644 index 00000000..e24f2076 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel/netipoib-xp32.inf @@ -0,0 +1,269 @@ +; 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=10/10/2008,2.0.0000.2159 +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 = WOW64WsdCopyFiles + +[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 +ndinstall.exe,,,0x00000002 + +[WOW64CopyFiles] +ibwsd.dll,ibwsd32.dll,,0x00000002 +ibndprov.dll,ibndprov32.dll,,0x00000002 + +[WOW64WsdCopyFiles] +ibwsd.dll,ibwsd32.dll,,0x00000002 + +[SourceDisksNames.x86] +1 = %IcsDisk1%,,,"" + +[SourceDisksNames.amd64] +1 = %IcsDisk1%,,,"" + +[SourceDisksNames.ia64] +1 = %IcsDisk1%,,,"" + +[SourceDisksFiles.x86] +ipoib.sys = 1 +ibndprov.dll = 1 +ndinstall.exe = 1 + +[SourceDisksFiles.amd64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +ibndprov.dll = 1 +ibndprov32.dll = 1 +ndinstall.exe = 1 + +[SourceDisksFiles.ia64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 + +[DestinationDirs] +IpoibCopyFiles = %DIRID_DRIVERS% +WsdCopyFiles = %DIRID_SYSTEM% +NdCopyFiles = %DIRID_SYSTEM% +WOW64CopyFiles = %DIRID_SYSTEM_X86% +WOW64WsdCopyFiles = %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" \ No newline at end of file diff --git a/branches/WOF2-1/ulp/ipoib/kernel/netipoib.inx b/branches/WOF2-1/ulp/ipoib/kernel/netipoib.inx new file mode 100644 index 00000000..1a7a6db2 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel/netipoib.inx @@ -0,0 +1,271 @@ +; 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 = WOW64WsdCopyFiles + +[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 +ndinstall.exe,,,0x00000002 + +[WOW64CopyFiles] +ibwsd.dll,ibwsd32.dll,,0x00000002 +ibndprov.dll,ibndprov32.dll,,0x00000002 + +[WOW64WsdCopyFiles] +ibwsd.dll,ibwsd32.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 +ndinstall.exe = 1 + +[SourceDisksFiles.amd64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +ibndprov.dll = 1 +ibndprov32.dll = 1 +ndinstall.exe = 1 + +[SourceDisksFiles.ia64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 + +[DestinationDirs] +IpoibCopyFiles = %DIRID_DRIVERS% +WsdCopyFiles = %DIRID_SYSTEM% +NdCopyFiles = %DIRID_SYSTEM% +WOW64CopyFiles = %DIRID_SYSTEM_X86% +WOW64WsdCopyFiles = %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" \ No newline at end of file diff --git a/branches/WOF2-1/ulp/ipoib/kernel/offload.h b/branches/WOF2-1/ulp/ipoib/kernel/offload.h new file mode 100644 index 00000000..de696c6a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib/kernel6/SOURCES b/branches/WOF2-1/ulp/ipoib/kernel6/SOURCES new file mode 100644 index 00000000..a528904b --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/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_cm.c \ + ipoib_xfr_mgr.c + +INCLUDES=..;..\..\..\inc;..\..\..\inc\kernel; + +C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DNDIS_WDM=1 \ + -DDEPRECATE_DDK_FUNCTIONS -DNDIS60_MINIPORT=1 -DNEED_CL_OBJ -DBINARY_COMPATIBLE=0 -DVER_FILEREV=42 + +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-1/ulp/ipoib/kernel6/ipoib.cdf b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib.cdf new file mode 100644 index 00000000..eb21da98 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/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-1/ulp/ipoib/kernel6/ipoib.rc b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib.rc new file mode 100644 index 00000000..330f19e7 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/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 Miniport (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "IP over InfiniBand NDIS Miniport" +#endif + +#define VER_INTERNALNAME_STR "ipoib.sys" +#define VER_ORIGINALFILENAME_STR "ipoib.sys" + +#include +#include "ipoib_log.rc" diff --git a/branches/WOF2-1/ulp/ipoib/kernel6/ipoib32-xp.cdf b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib32-xp.cdf new file mode 100644 index 00000000..faf8ea6f --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/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-1/ulp/ipoib/kernel6/ipoib32.cdf b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib32.cdf new file mode 100644 index 00000000..50225ba6 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/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-1/ulp/ipoib/kernel6/ipoib_adapter.c b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_adapter.c new file mode 100644 index 00000000..78eff263 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_adapter.c @@ -0,0 +1,1632 @@ +/* + * 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 4226 2009-04-06 06:01:03Z xalex $ + */ + + + +#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( (status == NDIS_STATUS_SUCCESS) && (len == HW_ADDR_LEN) ) + { + 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 ); + } + } + + *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 ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_adapter ); + + /* + * 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_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; + 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; + + 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; + 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 ) + { + 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 = IPOIB_MEDIA_MAX_SPEED; + + 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 ); + } + 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 = IPOIB_MEDIA_MAX_SPEED; + + 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 = IPOIB_MEDIA_MAX_SPEED; + + 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 ); + + 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; + 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; + 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_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 ) + { + 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 = IPOIB_MEDIA_MAX_SPEED; + 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 = IPOIB_MEDIA_MAX_SPEED; + + 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_INIT ); + 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-1/ulp/ipoib/kernel6/ipoib_adapter.h b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_adapter.h new file mode 100644 index 00000000..f8ab4c47 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_adapter.h @@ -0,0 +1,483 @@ +/* + * 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 4226 2009-04-06 06:01:03Z xalex $ + */ + + +#ifndef _IPOIB_ADAPTER_H_ +#define _IPOIB_ADAPTER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ip_stats.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_PAUSED, + IPOIB_PAUSING, + IPOIB_RUNNING +} ipoib_state_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 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. + + 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 +* 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; + PNDIS_OID_REQUEST p_pending_oid; +} pending_oid_t; + + +typedef struct _ipoib_adapter +{ + cl_obj_t obj; + NDIS_HANDLE h_adapter; + 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; + NDIS_HANDLE NdisMiniportDmaHandle; + ipoib_state_t ipoib_state; + ib_al_ifc_t *p_ifc; + + ULONG sg_list_size; + +} 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_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; \ + } + +//TODO rename to 4 +#define IPOIB_MEDIA_MAX_SPEED 10000000000 + +#endif /* _IPOIB_ADAPTER_H_ */ diff --git a/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_cm.c b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_cm.c new file mode 100644 index 00000000..e69de29b diff --git a/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_debug.h b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_debug.h new file mode 100644 index 00000000..69ec3c5a --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/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, + 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-1/ulp/ipoib/kernel6/ipoib_driver.c b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_driver.c new file mode 100644 index 00000000..95d67cdf --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_driver.c @@ -0,0 +1,4057 @@ +/* + * 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 4226 2009-04-06 06:01:03Z xalex $ + */ + +#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 + + + +#define MAJOR_DRIVER_VERSION 2 +#define MINOR_DRIVER_VERSION 1 +#if defined(NDIS60_MINIPORT) +#define MAJOR_NDIS_VERSION 6 +#define MINOR_NDIS_VERSION 0 + +#else +#error NDIS Version not defined, try defining NDIS60_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}; +NDIS_HANDLE g_IpoibMiniportDriverHandle = NULL; +NDIS_HANDLE g_IpoibDriverContext = NULL; + + + +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); + +} + + + +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 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( + IN NDIS_HANDLE adapter_context, + OUT PBOOLEAN p_addr_reset); + +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 ); + +//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 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, + 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 +*/ +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 ); + + NdisZeroMemory(&characteristics, sizeof(characteristics)); + + characteristics.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS, + characteristics.Header.Size = sizeof(NDIS_MINIPORT_DRIVER_CHARACTERISTICS); + characteristics.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1; + + 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; + + + +//TODO NDIS60 set g_ prefix to global variables + 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 = 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 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_OBJECT config_obj; + NDIS_CONFIGURATION_PARAMETER *p_param; + UINT value; + PIPOIB_REG_ENTRY pRegEntry; + UINT i; + PUCHAR structPointer; + + int sq_depth_step = 128; + + UNUSED_PARAM(wrapper_config_context); + 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, p_mac, p_len, h_config ); + + 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; + //TODO NDIS60 Port or adapter + atr.MiniportAdapterContext = (NDIS_HANDLE)p_adapter; //(NDIS_HANDLE)pPort->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 = IPOIB_MEDIA_MAX_SPEED; //TODO NDIS60 NDIS_LINK_SPEED_UNKNOWN + gat.RcvLinkSpeed = IPOIB_MEDIA_MAX_SPEED; // TODO NDIS60 NDIS_LINK_SPEED_UNKNOWN ??? + + gat.MediaConnectState = MediaConnectStateConnected; //TODO NDIS60 Check the current state + gat.MediaDuplexState = MediaDuplexStateFull; + + gat.MtuSize = MAX_IB_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; + //TODO NDIS60 This value is absent for ETH driver + 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; // 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->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); //TODO NDIS60 + + + 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; + + p_offload->LsoV2.IPv6.Encapsulation = ulEncapsulation; + p_offload->LsoV2.IPv6.MaxOffLoadSize = LARGE_SEND_OFFLOAD_SIZE; + p_offload->LsoV2.IPv6.MinSegmentCount = LSO_MIN_SEG_COUNT; + + p_offload->LsoV2.IPv6.IpExtensionHeadersSupported = NDIS_OFFLOAD_NOT_SUPPORTED; + p_offload->LsoV2.IPv6.TcpOptionsSupported = NDIS_OFFLOAD_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( + 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 = TRUE; + p_offload->Checksum.IPv4Transmit.TcpOptionsSupported = TRUE; + p_offload->Checksum.IPv4Transmit.TcpChecksum = TRUE; + p_offload->Checksum.IPv4Transmit.UdpChecksum = TRUE; + p_offload->Checksum.IPv4Transmit.IpChecksum = TRUE; + + p_offload->Checksum.IPv4Receive.Encapsulation = ulEncapsulation; + p_offload->Checksum.IPv4Receive.IpOptionsSupported = TRUE; + p_offload->Checksum.IPv4Receive.TcpOptionsSupported = TRUE; + p_offload->Checksum.IPv4Receive.TcpChecksum = TRUE; + p_offload->Checksum.IPv4Receive.UdpChecksum = TRUE; + p_offload->Checksum.IPv4Receive.IpChecksum = TRUE; + + + // + // 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 = TRUE; + p_offload->Checksum.IPv6Transmit.TcpOptionsSupported = TRUE; + p_offload->Checksum.IPv6Transmit.TcpChecksum = TRUE; + p_offload->Checksum.IPv6Transmit.UdpChecksum = TRUE; + + + p_offload->Checksum.IPv6Receive.Encapsulation = ulEncapsulation; + p_offload->Checksum.IPv6Receive.IpExtensionHeadersSupported = TRUE; + p_offload->Checksum.IPv6Receive.TcpOptionsSupported = TRUE; + p_offload->Checksum.IPv6Receive.TcpChecksum = TRUE; + p_offload->Checksum.IPv6Receive.UdpChecksum = TRUE; + + 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; + + 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_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(&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); + 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); + return Status; + } + + Status = SetOffloadAttributes(p_adapter, h_adapter); + if (Status != NDIS_STATUS_SUCCESS) + { + //ETH_PRINT(TRACE_LEVEL_ERROR, ETH_INIT, "Set OFFLOAD attributes failed Error=0x%x\n", 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; +} + + +//TODO Don't pass h_adapter inside the function, use pPort->p_adapter->h_adapter +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 + // + 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; + + DmaDescription.ProcessSGListHandler = ipoib_process_sg_list; + DmaDescription.SharedMemAllocateCompleteHandler = NULL; + + status = NdisMRegisterScatterGatherDma( + h_adapter, + &DmaDescription, + &p_adapter->NdisMiniportDmaHandle); + + if( status != NDIS_STATUS_SUCCESS ) + { + //TODO NDIS60 + //ipoib_destroy_adapter( p_adapter ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisMRegisterScatterGatherDma returned 0x%.8x.\n", 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; +} + + +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; + //NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES RegistrationAttributes; + //NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES GeneralAttributes; +#if IPOIB_USE_DMA + //NDIS_SG_DMA_DESCRIPTION DmaDescription; +#endif + IPOIB_ENTER( IPOIB_DBG_INIT ); + +#ifdef _DEBUG_ + PAGED_CODE(); +#endif + + UNUSED_PARAM( config_context ); + UNUSED_PARAM( MiniportInitParameters ); + + //foo1(100); + /* Create the adapter adapter */ + ib_status = ipoib_create_adapter(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; + } + p_adapter->ipoib_state = IPOIB_PAUSED; + status = SetAttributes(p_adapter, h_adapter); + if (status != NDIS_STATUS_SUCCESS) { + ASSERT(FALSE); + } +#if 0 + NdisZeroMemory(&RegistrationAttributes, sizeof(NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES)); + NdisZeroMemory(&GeneralAttributes, sizeof(NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES)); + + /* setting registration attributes */ + RegistrationAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES; + RegistrationAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; + RegistrationAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; + + RegistrationAttributes.MiniportAdapterContext = (NDIS_HANDLE)p_adapter; + RegistrationAttributes.AttributeFlags = NDIS_MINIPORT_ATTRIBUTES_BUS_MASTER; + + RegistrationAttributes.CheckForHangTimeInSeconds = 10; + RegistrationAttributes.InterfaceType = NdisInterfacePNPBus; + + status = NdisMSetMiniportAttributes(h_adapter, + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&RegistrationAttributes); + + if (status != NDIS_STATUS_SUCCESS) + { + ipoib_destroy_adapter( p_adapter ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisMSetMiniportAttributes returned 0x%.8x.\n", status) ); + return status; + } + + /* set up generic attributes */ + + GeneralAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES; + GeneralAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; + GeneralAttributes.Header.Size = sizeof(NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES); + + GeneralAttributes.MediaType = NdisMedium802_3; + //TODO + GeneralAttributes.MtuSize = MAX_IB_MTU; + GeneralAttributes.MaxXmitLinkSpeed = IPOIB_MEDIA_MAX_SPEED; + GeneralAttributes.MaxRcvLinkSpeed = IPOIB_MEDIA_MAX_SPEED; + GeneralAttributes.XmitLinkSpeed = NDIS_LINK_SPEED_UNKNOWN; + GeneralAttributes.RcvLinkSpeed = NDIS_LINK_SPEED_UNKNOWN; + GeneralAttributes.MediaConnectState = MediaConnectStateUnknown; + GeneralAttributes.MediaDuplexState = MediaDuplexStateUnknown; + GeneralAttributes.LookaheadSize = MAX_XFER_BLOCK_SIZE; + + GeneralAttributes.PowerManagementCapabilities = NULL; + + GeneralAttributes.MacOptions = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | + NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | + NDIS_MAC_OPTION_NO_LOOPBACK | + NDIS_MAC_OPTION_FULL_DUPLEX; + + GeneralAttributes.SupportedPacketFilters = NDIS_PACKET_TYPE_DIRECTED | + NDIS_PACKET_TYPE_MULTICAST | + NDIS_PACKET_TYPE_ALL_MULTICAST | + NDIS_PACKET_TYPE_BROADCAST; + + GeneralAttributes.MaxMulticastListSize = MAX_MCAST; + GeneralAttributes.MacAddressLength = HW_ADDR_LEN; + + NdisMoveMemory(GeneralAttributes.PermanentMacAddress, + p_adapter->mac.addr, + HW_ADDR_LEN); + + NdisMoveMemory(GeneralAttributes.CurrentMacAddress, + p_adapter->params.conf_mac.addr, + HW_ADDR_LEN); + + + GeneralAttributes.PhysicalMediumType = NdisPhysicalMediumUnspecified; + GeneralAttributes.RecvScaleCapabilities = NULL; + GeneralAttributes.AccessType = NET_IF_ACCESS_BROADCAST; // NET_IF_ACCESS_BROADCAST for a typical ethernet adapter + GeneralAttributes.DirectionType = NET_IF_DIRECTION_SENDRECEIVE; // NET_IF_DIRECTION_SENDRECEIVE for a typical ethernet adapter + GeneralAttributes.ConnectionType = NET_IF_CONNECTION_DEDICATED; // NET_IF_CONNECTION_DEDICATED for a typical ethernet adapter + GeneralAttributes.IfType = IF_TYPE_ETHERNET_CSMACD; // IF_TYPE_ETHERNET_CSMACD for a typical ethernet adapter (regardless of speed) + GeneralAttributes.IfConnectorPresent = TRUE; // RFC 2665 TRUE if physical adapter + + GeneralAttributes.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 | + NDIS_STATISTICS_GEN_STATISTICS_SUPPORTED; + + GeneralAttributes.SupportedOidList = (PNDIS_OID)SUPPORTED_OIDS; + GeneralAttributes.SupportedOidListLength = sizeof(SUPPORTED_OIDS); + + status = NdisMSetMiniportAttributes(h_adapter, + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&GeneralAttributes); + + if (status != NDIS_STATUS_SUCCESS) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisMSetMiniportAttributes returned 0x%.8x.\n", status) ); + } + +#if IPOIB_USE_DMA + + 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);//NDIS_SIZEOF_SG_DMA_DESCRIPTION_REVISION_1; + + DmaDescription.Flags = NDIS_SG_DMA_64_BIT_ADDRESS; + DmaDescription.MaximumPhysicalMapping = p_adapter->params.xfer_block_size; + + DmaDescription.ProcessSGListHandler = ipoib_process_sg_list; + DmaDescription.SharedMemAllocateCompleteHandler = NULL; + + status = NdisMRegisterScatterGatherDma( + p_adapter->h_adapter, + &DmaDescription, + &p_adapter->NdisMiniportDmaHandle); + + if( status != NDIS_STATUS_SUCCESS ) + { + ipoib_destroy_adapter( p_adapter ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisMRegisterScatterGatherDma returned 0x%.8x.\n", status) ); + return status; + } + + + +#endif +#endif //if 0 + + + +#if IPOIB_USE_DMA + + InitNdisScatterGatherDma(p_adapter, h_adapter); + + + +#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 ); +#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; + } + + 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->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 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) ); + if( p_adapter->params.cm_enabled ) + { + info = p_adapter->params.cm_payload_mtu; + } + else + { + 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) ); + if (info_buf_len < buf_len) + { + break; + } + + cl_obj_lock( &p_adapter->obj ); + switch( p_adapter->state ) + { + case IB_PNP_PORT_ADD: + /* Mark the adapter as pending an OID */ + p_adapter->pending_query = TRUE; + + /* Save the request parameters. */ + 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_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: + CL_ASSERT( p_adapter->p_port ); + info = p_adapter->port_rate; + break; + } + 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) ); + 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: + 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) ); + if( p_adapter->params.cm_enabled ) + info = p_adapter->params.cm_xfer_block_size; + else + 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_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 (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_TASK_OFFLOAD: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_TCP_TASK_OFFLOAD\n", port_num) ); + 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: + 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_UPn", port_num) ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Number of OID: 0x%.8X!\n", 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_PNP_QUERY_POWER\n", port_num) ); + //ulBytesAvailable = ulInfoLen = sizeof(NDIS_OFFLOAD); + if (info_buf_len < sizeof(NDIS_OFFLOAD)) + { + status = NDIS_STATUS_BUFFER_TOO_SHORT; + *p_bytes_needed = sizeof(NDIS_OFFLOAD) ; + break; + } + + //ipoib_offload_config(pPort, &offload); + //pInfo = &offload; + break; + + default: + status = NDIS_STATUS_INVALID_OID; + // IPOIB_PRINT( TRACE_LEVEL_ERROR,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 ); + return status; + } + + 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; + } + + 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 ); +} + + +static NDIS_STATUS +__ipoib_get_tcp_task_offload( + IN ipoib_adapter_t* p_adapter, + OUT pending_oid_t *pNdisRequest ) +{ +#ifndef NDIS60_MINIPORT + 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); + + pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = buf_len; + + if( pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength < buf_len ) + return NDIS_STATUS_INVALID_LENGTH; + + p_offload_hdr = (NDIS_TASK_OFFLOAD_HEADER*)pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer; + 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; + } + + pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten = buf_len + + return NDIS_STATUS_SUCCESS; +#endif + UNUSED_PARAM(p_adapter); + UNUSED_PARAM(pNdisRequest); + return NDIS_STATUS_NOT_SUPPORTED; + +} + + +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 ) +{ +#ifndef NDIS60_MINIPORT + 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; +#endif + UNUSED_PARAM(p_adapter); + UNUSED_PARAM(p_info_buf); + UNUSED_PARAM(p_info_len); + return NDIS_STATUS_NOT_SUPPORTED; +} + + +//! 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 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; + + 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->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; +} + +#ifdef NNN +NDIS_STATUS +ipoib_set_info( + ipoib_adapter_t* p_adapter, + IN PNDIS_OID_REQUEST pNdisRequest) +{ + NDIS_STATUS status; + NDIS_OID oid; + UINT info_buf_len; + UINT buf_len; + uint8_t port_num; + PVOID info_buf; + UINT *p_bytes_needed; + KLOCK_QUEUE_HANDLE hdl; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + oid = pNdisRequest->DATA.SET_INFORMATION.Oid; + info_buf = pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer; + info_buf_len = pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength; + p_bytes_needed = &pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded; + status = NDIS_STATUS_SUCCESS; + + buf_len = sizeof(UINT); + 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->p_oid_request = pNdisRequest; + 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, pNdisRequest); + break; + + 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; + + + /* 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, pNdisRequest ); + 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 ) + { + pNdisRequest->DATA.SET_INFORMATION.BytesRead = buf_len; + } + else + { + if( status == NDIS_STATUS_INVALID_LENGTH ) + { + if ( !*p_bytes_needed ) + { + *p_bytes_needed = buf_len; + } + } + + pNdisRequest->DATA.SET_INFORMATION.BytesRead = 0; + } + + IPOIB_EXIT( IPOIB_DBG_OID ); + return status; +} +#endif +static NDIS_STATUS +ipoib_oid_handler( + IN NDIS_HANDLE adapter_context, + IN 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->DATA.SET_INFORMATION.Oid, + pNdisRequest->DATA.SET_INFORMATION.InformationBuffer, + pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength, + (PULONG)&pNdisRequest->DATA.SET_INFORMATION.BytesRead, + (PULONG)&pNdisRequest->DATA.SET_INFORMATION.BytesNeeded); + break; + + case NdisRequestQueryInformation: + case NdisRequestQueryStatistics: + status = ipoib_query_info(adapter_context, + pNdisRequest->DATA.QUERY_INFORMATION.Oid, + pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer, + pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength, + (PULONG)&pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten, + (PULONG)&pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded); + + 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 packet_array Array of packets to send +@param numPackets Number of packets in the array +*/ +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; + p_port = p_adapter->p_port; + + cl_obj_lock( &p_adapter->obj ); + if( p_adapter->ipoib_state == IPOIB_PAUSING || + p_adapter->ipoib_state == IPOIB_PAUSED) + { + status = NDIS_STATUS_PAUSED; + 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 ); + 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 ); + //IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + // ("Starting NET BUFFER LIST \n") ); + for (curr_net_buffer_list = net_buffer_list; + curr_net_buffer_list != NULL; + curr_net_buffer_list = next_net_buffer_list) + { + next_net_buffer_list = NET_BUFFER_LIST_NEXT_NBL(curr_net_buffer_list); + cl_perf_start( PortSend ); + + ipoib_port_send( p_port, curr_net_buffer_list, send_flags); + cl_perf_stop( &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 ); + +compl_status: + if (status != NDIS_STATUS_SUCCESS) + { + //ASSERT(FALSE); //???? + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Got bad status \n") ); + 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) + { + 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 ); + } + + + if (NDIS_TEST_SEND_AT_DISPATCH_LEVEL(send_flags)) + { + NDIS_SET_SEND_COMPLETE_FLAG(send_complete_flags, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); + } + + NdisMSendNetBufferListsComplete( + p_adapter->h_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 ); + } + + 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( adapter_context ); + UNUSED_PARAM( shutdown_action ); + 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, p_net_addr_oid = + (PNETWORK_ADDRESS)((uint8_t *)p_net_addr_oid + + FIELD_OFFSET(NETWORK_ADDRESS, Address) + + p_net_addr_oid->AddressLength) ) + { + + if( p_net_addr_oid->AddressType != NDIS_PROTOCOL_ID_TCP_IP ) + { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong type of 0x%.4X, " + "should be 0x%.4X\n", port_num, i, p_net_addr_oid->AddressType, + NDIS_PROTOCOL_ID_TCP_IP)); + continue; + } + + if( p_net_addr_oid->AddressLength != NETWORK_ADDRESS_LENGTH_IP) + { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_OID, + ("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)); + continue; + } + + 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++, p_net_addr_oid = + (PNETWORK_ADDRESS)((uint8_t *)p_net_addr_oid + + FIELD_OFFSET(NETWORK_ADDRESS, Address) + p_net_addr_oid->AddressLength) ) + { + + if( p_net_addr_oid->AddressType != NDIS_PROTOCOL_ID_TCP_IP ) + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong type of 0x%.4X, " + "should be 0x%.4X\n", port_num, i, p_net_addr_oid->AddressType, + NDIS_PROTOCOL_ID_TCP_IP)); + continue; + } + + if( p_net_addr_oid->AddressLength != NETWORK_ADDRESS_LENGTH_IP) + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("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)); + continue; + } + + 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 = 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 ); +} + + +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 ); + } +} + + +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 ); +} + +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 ); + + //TODO: + ipoib_port_resume(p_adapter->p_port,FALSE); +// ASSERT(FALSE); + + 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 + } + + 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-1/ulp/ipoib/kernel6/ipoib_driver.h b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_driver.h new file mode 100644 index 00000000..5ba79d91 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_driver.h @@ -0,0 +1,162 @@ +/* + * 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 4226 2009-04-06 06:01:03Z 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_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 (8) + +/* 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; + 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-1/ulp/ipoib/kernel6/ipoib_endpoint.c b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_endpoint.c new file mode 100644 index 00000000..1e82e5a5 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_endpoint.c @@ -0,0 +1,1170 @@ +/* + * 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 "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 +#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 = 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_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 for cm 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->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_pkt_array ) + { + //NDIS60 + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_zalloc for 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_pkt_array ) + { + cl_free( p_port->cm_recv_mgr.recv_pkt_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 receive 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_pkt_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; + size_t i; + + 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( i = 0; i < MAX_RECV_WC; i++ ) + wc[i].p_next = &wc[i + 1]; + wc[MAX_RECV_WC - 1].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\n") ); + 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\n") ); + 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-1/ulp/ipoib/kernel6/ipoib_endpoint.h b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_endpoint.h new file mode 100644 index 00000000..547d4652 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_endpoint.h @@ -0,0 +1,257 @@ +/* + * 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_pkt_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 ); + /* + * 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 ); + +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-1/ulp/ipoib/kernel6/ipoib_ibat.c b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_ibat.c new file mode 100644 index 00000000..ba89e00f --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_ibat.c @@ -0,0 +1,666 @@ +/* + * 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 4226 2009-04-06 06:01:03Z xalex $ + */ + + +#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 + +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 = 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() +{ + NTSTATUS status; + NDIS_STRING DeviceName; + NDIS_STRING DeviceLinkUnicodeString; + + IPOIB_ENTER( IPOIB_DBG_IOCTL ); + + if( InterlockedIncrement( &g_ipoib.ibat_ref ) == 1 ) + { + NdisInitUnicodeString( &DeviceName, IBAT_DEV_NAME ); + NdisInitUnicodeString( &DeviceLinkUnicodeString, IBAT_DOS_DEV_NAME ); + + g_p_drv_obj->MajorFunction[IRP_MJ_CREATE] = __ipoib_create; + g_p_drv_obj->MajorFunction[IRP_MJ_CLEANUP] = __ipoib_cleanup; + g_p_drv_obj->MajorFunction[IRP_MJ_CLOSE] = __ipoib_close; + g_p_drv_obj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = __ipoib_dispatch; + g_p_drv_obj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = __ipoib_dispatch; + status = IoCreateDevice(g_p_drv_obj, 0,&DeviceName, + FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &g_ipoib.h_ibat_dev); + + if( status != 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 ) + { + IoDeleteDevice( 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-1/ulp/ipoib/kernel6/ipoib_ibat.h b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_ibat.h new file mode 100644 index 00000000..efcb0a6b --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/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-1/ulp/ipoib/kernel6/ipoib_log.mc b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_log.mc new file mode 100644 index 00000000..bb7d1c1d --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_log.mc @@ -0,0 +1,334 @@ +;/*++ +;============================================================================= +;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. +. + diff --git a/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_port.c b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_port.c new file mode 100644 index 00000000..da57d2cc --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_port.c @@ -0,0 +1,8098 @@ +/* + * 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 4226 2009-04-06 06:01:03Z xalex $ + */ + + + +#include "ipoib_endpoint.h" +#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 + +#include "wdm.h" +#include + + + +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 ); + + +static void __recv_cb_dpc(KDPC *p_gc_dpc,void *context,void *s_arg1, void *s_arg2); + + +/****************************************************************************** +* +* 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 /* 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 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_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 NET_BUFFER_LIST** const pp_net_buffer_list ); + +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 SCATTER_GATHER_LIST *p_sgl, + 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 MDL* p_mdl, + IN size_t buf_len, + IN SCATTER_GATHER_LIST *p_sgl, + 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 MDL* p_mdl, + 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 MDL* p_mdl, + IN size_t buf_len, + IN SCATTER_GATHER_LIST *p_sgl, + 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 MDL* p_mdl, + 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 MDL* p_mdl, + 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, + IN ULONG send_complete_flags ); + +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 ipoib_port_t* const p_port, + IN eth_hdr_t* const p_eth_hdr, + IN MDL* const p_mdl, + IN const size_t mdl_len, + IN SCATTER_GATHER_LIST *p_sgl, + IN OUT ipoib_send_desc_t* const p_desc ); + + +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 OUT ipoib_send_desc_t* const p_desc, + IN ULONG mss, + IN SCATTER_GATHER_LIST *p_sgl, + IN int32_t hdr_idx, + IN PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO p_lso_info ); + +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 ); +/****************************************************************************** +* +* 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 intn_t +__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 + 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 = 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 ); + + 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; + + 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; + } + + KeInitializeDpc(&p_port->recv_dpc,(PKDEFERRED_ROUTINE)__recv_cb_dpc,p_port); + + + /* 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 ); + +#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 + ASSERT(FALSE); + //TODO NDIS6.0 + ipoib_port_resume( p_port, FALSE ); + + 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 ); + } + 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; + + 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; + } + + 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; + } + + 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 = 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 ) +{ + 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; + + NdisInitializeNPagedLookasideList( &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; + 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, +#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 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'; + + 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; + } +/* + 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 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; + } +/* + 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 ) + 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 ) +{ + //IPOIB_ENTER( IPOIB_DBG_RECV ); + cl_qpool_put_list( &p_port->buf_mgr.recv_pool, p_list ); + //IPOIB_EXIT( IPOIB_DBG_RECV ); +} + + +static inline NET_BUFFER_LIST* +__buf_mgr_get_ndis_pkt( + 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_PACKET( p_net_buffer_list ) = p_port; + IPOIB_RECV_FROM_PACKET( 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 ) +{ + 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(NET_BUFFER_LIST*) * 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_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; +} + +void +ipoib_return_net_buffer_list( + IN NDIS_HANDLE adapter_context, + IN NET_BUFFER_LIST *p_net_buffer_lists, + IN ULONG return_flags) +{ + cl_list_item_t *p_item; + ipoib_port_t *p_port; + ipoib_recv_desc_t *p_desc; + NET_BUFFER_LIST *cur_net_buffer_list,*next_net_buffer_list; + ib_api_status_t status = IB_NOT_DONE; + int32_t shortage; + ULONG complete_flags = 0; + PERF_DECLARE( ReturnPacket ); + PERF_DECLARE( ReturnPutRecv ); + PERF_DECLARE( ReturnRepostRecv ); + PERF_DECLARE( ReturnPreparePkt ); + PERF_DECLARE( ReturnNdisIndicate ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + p_port = ((ipoib_adapter_t*)adapter_context)->p_port; + CL_ASSERT( p_net_buffer_lists ); + + cl_perf_start( ReturnPacket ); + cl_spinlock_acquire( &p_port->recv_lock ); + for (cur_net_buffer_list = p_net_buffer_lists; + cur_net_buffer_list != NULL; + cur_net_buffer_list = next_net_buffer_list) + { + next_net_buffer_list = NET_BUFFER_LIST_NEXT_NBL(cur_net_buffer_list); + + /* Get the port and descriptor from the packet. */ + CL_ASSERT(p_port == IPOIB_PORT_FROM_PACKET( cur_net_buffer_list )); + p_desc = IPOIB_RECV_FROM_PACKET( cur_net_buffer_list ); + + + //TODO: NDIS60, rewrite this block + /* Get descriptor from the packet. */ +#if 0 + if( p_desc->type == PKT_TYPE_CM_UCAST ) + { + 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 ); + } +#if 0 + /* 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, &cur_net_buffer_list ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnPreparePkt ); + if( status == IB_SUCCESS ) + { + if( shortage > 0 ) + NET_BUFFER_LIST_STATUS( cur_net_buffer_list) = NDIS_STATUS_RESOURCES; + else + NET_BUFFER_LIST_STATUS( cur_net_buffer_list) = NDIS_STATUS_SUCCESS; + + cl_spinlock_release( &p_port->recv_lock ); + NET_BUFFER_LIST_NEXT_NBL(cur_net_buffer_list) = NULL; + cl_perf_start( ReturnNdisIndicate ); + NdisMRecvIndicate( p_port->p_adapter->h_adapter, + cur_net_buffer_list, complete_flags ); + 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, cur_net_buffer_list ); + 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; + } + } + #endif + cl_spinlock_release( &p_port->recv_lock ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnPacket ); + + IPOIB_EXIT( IPOIB_DBG_RECV ); +} + +static void __recv_cb_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); + + + __recv_cb(NULL, p_port); + ipoib_port_deref( p_port, ref_recv_cb ); + + +} + + +static void +__recv_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_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; + ULONG recv_complete_flags = 0; + + 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 ); +//return ; + UNUSED_PARAM( h_cq ); + + 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( 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)); + + /* 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 ); + 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 ); + for( cnt = 0; cnt < pkt_cnt -1; cnt++) + { + NET_BUFFER_LIST_NEXT_NBL(p_port->recv_mgr.recv_pkt_array[cnt]) = + p_port->recv_mgr.recv_pkt_array[cnt + 1]; + } + cl_perf_start( RecvNdisIndicate ); +#ifndef NDIS_DEFAULT_PORT_NUMBER +#define NDIS_DEFAULT_PORT_NUMBER 0 +#endif + /*IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Indicate NDIS with %d received NBs\n", + pkt_cnt) );*/ + NdisMIndicateReceiveNetBufferLists( + p_port->p_adapter->h_adapter, + p_port->recv_mgr.recv_pkt_array[0], + NDIS_DEFAULT_PORT_NUMBER, + pkt_cnt, + recv_complete_flags); + + 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_desc_t *)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_net_buffer_list( NULL, p_port->recv_mgr.recv_pkt_array[0],recv_complete_flags ); + } + 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. + */ + 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 ); + + ipoib_port_deref( p_port, ref_recv_cb ); + } else { + // Please note the reference is still up + KeInsertQueueDpc(&p_port->recv_dpc, NULL, NULL); + } + + cl_perf_stop( &p_port->p_adapter->perf, RecvCb ); + + IPOIB_EXIT( IPOIB_DBG_RECV ); +} + + +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_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 ); + 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) ) + { + 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; + ib_gid_t gid; + 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[4]; + 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. + */ + cl_memcpy( &gid, &p_cid[7], sizeof(ib_gid_t) ); + p_cid[1] = HW_ADDR_LEN +1;// CID length + p_cid[2] = DHCP_HW_TYPE_ETH;// CID type + status = ipoib_mac_from_guid( gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, (mac_addr_t*)&p_cid[3] ); + 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); + status = IB_SUCCESS; + } + p_cid[HW_ADDR_LEN + 3] = DHCP_OPT_END; //terminate tag + } + 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); + } + 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 + * 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 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 NET_BUFFER_LIST** const pp_net_buffer_list ) +{ + NDIS_STATUS status; + uint32_t pkt_filter; + ip_stat_sel_t type; + //NDIS60 + NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO chksum; + //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; + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, + ("Received UCAST PKT.\n")); + } + else + { + type = IP_STAT_DROPPED; + status = NDIS_STATUS_FAILURE; + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, 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. */ + type = IP_STAT_BCAST_BYTES; + status = NDIS_STATUS_SUCCESS; + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, + ("Received BCAST PKT.\n")); + } + else + { + type = IP_STAT_DROPPED; + status = NDIS_STATUS_FAILURE; + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received BCAST PKT with ERROR !!!!\n")); + } + 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; + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, + ("Received UCAST PKT.\n")); + } + else + { + type = IP_STAT_DROPPED; + status = NDIS_STATUS_FAILURE; + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received MCAST PKT with ERROR !!!!\n")); + } + break; + } + + if( status != NDIS_STATUS_SUCCESS ) + { + ipoib_inc_recv_stat( p_port->p_adapter, type, 0, 0 ); + /* Return the receive descriptor to the pool. */ + __buf_mgr_put_recv( p_port, p_desc, NULL ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, 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_net_buffer_list = __buf_mgr_get_ndis_pkt( 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_ndis_pkt failed\n") ); + return IB_INSUFFICIENT_RESOURCES; + } + + chksum.Value = 0; + switch( p_port->p_adapter->params.recv_chksum_offload ) + { + default: + CL_ASSERT( FALSE ); + case CSUM_DISABLED: + //NDIS60 + //NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) = + //(void*)(uintn_t)chksum.Value; + 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 */ + //NDIS60 + //NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) = + 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 = TRUE; + chksum.Receive.UdpChecksumSucceeded = TRUE; + chksum.Receive.IpChecksumSucceeded = TRUE; + //NDIS60 + //NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) = + NET_BUFFER_LIST_INFO(*pp_net_buffer_list, TcpIpChecksumNetBufferListInfo) = + (void*)(uintn_t)chksum.Value; + break; + } + ipoib_inc_recv_stat( p_port->p_adapter, type, p_desc->len, 1 ); + + 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 ) + { + NET_BUFFER_LIST_STATUS(p_port->recv_mgr.recv_pkt_array[i])= NDIS_STATUS_RESOURCES; + } + else + { + NET_BUFFER_LIST_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; + NET_BUFFER_LIST **pp_net_buffer_list, *p_head; + + p_head = NULL; + cl_spinlock_acquire( &p_port->send_lock ); + /* Complete any pending packets. */ + pp_net_buffer_list = &p_head; + 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 ) ) + { + *pp_net_buffer_list = IPOIB_PACKET_FROM_LIST_ITEM( p_item ); + NET_BUFFER_LIST_STATUS(*pp_net_buffer_list) = NDIS_STATUS_RESET_IN_PROGRESS; + pp_net_buffer_list = &(NET_BUFFER_LIST_NEXT_NBL(*pp_net_buffer_list)); + } + cl_spinlock_release( &p_port->send_lock ); + if(p_head) + NdisMSendNetBufferListsComplete( + p_port->p_adapter->h_adapter, + p_head, + 0); +} + +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 MDL* const p_mdl, + IN size_t buf_len, + IN SCATTER_GATHER_LIST *p_sgl, + 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_mdl, buf_len, p_sgl, 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_mdl, buf_len, p_desc ); + 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( p_port, p_desc, p_sgl, 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 ) +{ + NET_BUFFER_LIST *p_net_buffer_list; + NET_BUFFER *p_netbuffer; + MDL *p_mdl; + UINT tot_len = 0; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + UNREFERENCED_PARAMETER(p_port); + UNREFERENCED_PARAMETER(p_desc); + + p_desc->p_buf = + NdisAllocateFromNPagedLookasideList( &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; + } + + p_mdl = NdisAllocateMdl(p_port->p_adapter->h_adapter, + p_desc->p_buf, + p_port->p_adapter->params.xfer_block_size ); + if( !p_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate MDL\n") ); + return NDIS_STATUS_RESOURCES; + } + + p_net_buffer_list = NdisAllocateNetBufferAndNetBufferList( + p_port->buf_mgr.h_send_buf_pool, + 0, + 0, + p_mdl, + 0, + 0); + + if( !p_net_buffer_list ) + { + NdisFreeMdl(p_mdl); + IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND, + ("Failed to allocate NDIS_PACKET for copy.\n") ); + return NDIS_STATUS_RESOURCES; + } + + for (p_netbuffer = NET_BUFFER_LIST_FIRST_NB(p_net_buffer_list); + p_netbuffer != NULL; + p_netbuffer = NET_BUFFER_NEXT_NB(p_netbuffer)) + { + tot_len +=NET_BUFFER_DATA_LENGTH(p_netbuffer); + } + + /* Setup the work request. */ + p_desc->send_wr[0].local_ds[1].vaddr = cl_get_physaddr( + ((uint8_t*)p_desc->p_buf) + sizeof(eth_hdr_t) ); + p_desc->send_wr[0].local_ds[1].length = tot_len - sizeof(eth_hdr_t); + p_desc->send_wr[0].local_ds[1].lkey = p_port->ib_mgr.lkey; + p_desc->send_wr[0].wr.num_ds = 2; + + /* Free our temp packet now that the data is copied. */ + NdisFreeMdl(p_mdl); + NdisFreeNetBufferList(p_net_buffer_list); + + 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; + } + + 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 + NET_BUFFER_CURRENT_MDL_OFFSET(p_net_buffer)); + + 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 + + +void +ipoib_process_sg_list1( + IN PDEVICE_OBJECT pDO, + IN PVOID pIrp, + IN PSCATTER_GATHER_LIST p_sgl, + IN PVOID context + ) +{ + int i; + char temp[200]; + for (i = 0 ; i < 1;i++) + temp[i] = 5; +} + + +void +ipoib_process_sg_list( + 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; + static ipoib_send_desc_t *p_desc = NULL; + 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_ENTER( IPOIB_DBG_SEND ); + + 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 ); + + + p_netbuf = (NET_BUFFER*)context; + p_net_buffer_list = (NET_BUFFER_LIST*)IPOIB_NET_BUFFER_LIST_FROM_NETBUFFER(p_netbuf); + p_port = (ipoib_port_t*)IPOIB_PORT_FROM_PACKET(p_net_buffer_list); + NDIS_SET_SEND_COMPLETE_FLAG(complete_flags, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); + + + cl_spinlock_acquire( &p_port->send_lock ); + if (p_desc == NULL) { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_SEND, ("Allocating send_desc First Time\n") ); + p_desc = ExAllocatePoolWithTag(NonPagedPool ,sizeof (ipoib_send_desc_t), 'XMXA'); + } + ASSERT(p_desc); + p_desc->p_netbuf_list = p_net_buffer_list; + p_desc->p_endpt = NULL; + p_desc->p_buf = NULL; + p_desc->num_wrs = 1; + + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_SEND, + ("\n*******\nRECEIVED NB= %x with SG= %x\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 list */ + __process_failed_send( p_port, p_desc, status, complete_flags); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + goto send_end; + } + //from_queue = (boolean_t)(IPOIB_FROM_QUEUE(p_netbuf) == (void*)1); + from_queue = (boolean_t)(IPOIB_FROM_QUEUE(p_netbuf) != NULL); + if (from_queue) + { + cl_perf_start( GetEndpt ); + status = __endpt_mgr_ref( p_port, p_eth_hdr->dst, &p_desc->p_endpt ); + cl_perf_stop( &p_port->p_adapter->perf, GetEndpt ); + if( status == NDIS_STATUS_PENDING ) + { + IPOIB_FROM_QUEUE(p_netbuf) = p_sgl; + cl_qlist_insert_head( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET( p_desc->p_netbuf_list ) ); + 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 ) ) + { + 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") ); + IPOIB_FROM_QUEUE(p_netbuf) = p_sgl; + cl_qlist_insert_head( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET( p_desc->p_netbuf_list ) ); + goto send_end; + } + } + /* + * 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, p_desc, NDIS_STATUS_SUCCESS,complete_flags ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + goto send_end; + } + } + else + { + 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; + + 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: + status = __send_mgr_queue( p_port, p_eth_hdr, &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 ); + NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL; + IPOIB_FROM_QUEUE(p_netbuf) = p_sgl; + cl_qlist_insert_tail( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET(p_net_buffer_list) ); + cl_perf_stop( &p_port->p_adapter->perf, QueuePacket ); + 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. + */ + cl_perf_start( ProcessFailedSends ); + __process_failed_send( p_port, p_desc, NDIS_STATUS_SUCCESS, complete_flags ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + goto send_end; + } + } + cl_perf_start( BuildSendDesc ); + status = __build_send_desc( p_port, p_eth_hdr, p_mdl, mdl_len, p_sgl, p_desc ); + cl_perf_stop( &p_port->p_adapter->perf, BuildSendDesc ); + + if( status != NDIS_STATUS_SUCCESS ) + { + cl_perf_start( ProcessFailedSends ); + __process_failed_send( p_port, p_desc, status, complete_flags ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + goto send_end; + } + + /* Post the WR. */ + cl_perf_start( PostSend ); + cl_msg_out("sending packet with wr-id =0x%x\n",&p_desc->send_wr[0].wr.wr_id ); + ib_status = p_port->p_adapter->p_ifc->post_send( p_port->ib_mgr.h_qp, &p_desc->send_wr[0].wr, &p_wr_failed ); + 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, p_desc, NDIS_STATUS_FAILURE, complete_flags ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + /* Flag the adapter as hung since posting is busted. */ + p_port->p_adapter->hung = TRUE; + } + cl_atomic_inc( &p_port->send_mgr.depth ); + +send_end: + if (status != NDIS_STATUS_SUCCESS) { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_SEND, + ("Free S/G List: 0x%x.\n", p_sgl) ); + /*NdisMFreeNetBufferSGList( + p_port->p_adapter->NdisMiniportDmaHandle, + p_sgl, + p_netbuf);*/ + + } + + + cl_spinlock_release( &p_port->send_lock ); + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + +static NDIS_STATUS +__send_gen( + IN ipoib_port_t* const p_port, + IN ipoib_send_desc_t* const p_desc, + IN SCATTER_GATHER_LIST *p_sgl, + IN INT lso_data_index + ) +{ + ib_api_status_t status; + uint32_t i, j = 1; + uint32_t offset = sizeof(eth_hdr_t); + PERF_DECLARE( SendCopy ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + 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)) ) + { + + 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 ) ); + status = NDIS_STATUS_RESOURCES; + if( !p_port->p_adapter->params.cm_enabled ) + { + 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->send_wr[0].local_ds[j].vaddr = + p_sgl->Elements[i].Address.QuadPart + offset; + p_desc->send_wr[0].local_ds[j].length = + p_sgl->Elements[i].Length - offset; + p_desc->send_wr[0].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->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 = 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 ipoib_port_t* const p_port, + IN const eth_hdr_t* const p_eth_hdr, + IN MDL* p_mdl, + IN size_t buf_len, + IN SCATTER_GATHER_LIST *p_sgl, + IN OUT ipoib_send_desc_t* const p_desc ) +{ + 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 ); + + 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_port, p_ip_hdr, p_mdl, (buf_len - sizeof(ip_hdr_t)), p_sgl, p_desc ); + 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( 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( !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 > 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 + ASSERT(FALSE); + } + } + +send_gen: + cl_perf_start( SendTcp ); + status = __send_gen( p_port, p_desc, p_sgl, 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 = 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 MDL* p_mdl, + IN size_t buf_len, + IN SCATTER_GATHER_LIST *p_sgl, + 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 ); + //TODO NDIS60 remove this param + UNUSED_PARAM(p_sgl); + 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( &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. */ + 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_mdl, 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_mdl, + 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 ) + { + 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 = &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 + { + 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 */ + //if( !p_port->p_adapter->params.send_chksum_offload ) + //{ //TODO ? + 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)); + //} TODO ?? + 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->send_wr[0].local_ds[1].vaddr = cl_get_physaddr( p_desc->p_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 = 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 ipoib_port_t* const p_port, + IN const eth_hdr_t* const p_eth_hdr, + IN MDL* p_mdl, + 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 ) + { + 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. */ + p_desc->p_buf = (send_buf_t*) + NdisAllocateFromNPagedLookasideList( &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; + + ipoib_addr_set_qpn( &p_ib_arp->src_hw, 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, + 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( 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, p_desc->p_buf ); + cl_qlist_insert_tail( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET( p_desc->p_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, p_desc->p_buf ); + cl_qlist_insert_tail( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET( p_desc->p_pkt ) ); + 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 = 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. */ + 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 MDL* const p_mdl, + IN const size_t mdl_len, + IN SCATTER_GATHER_LIST *p_sgl, + IN OUT ipoib_send_desc_t* const p_desc ) +{ + NDIS_STATUS status; + int32_t hdr_idx; + uint32_t mss; + //PVOID* pp_tmp; + PNDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO p_checksum_list_info; + PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO p_lso_info; + PERF_DECLARE( SendMgrFilter ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + /* Format the send descriptor. */ + p_checksum_list_info = NET_BUFFER_LIST_INFO( p_desc->p_netbuf_list,TcpIpChecksumNetBufferListInfo); + //pp_tmp = &NET_BUFFER_LIST_INFO(p_desc->p_netbuf_list, TcpIpChecksumNetBufferListInfo); + //p_checksum_list_info = ( ) ((PULONG)pp_tmp); + p_lso_info = NET_BUFFER_LIST_INFO( p_desc->p_netbuf_list, TcpLargeSendNetBufferListInfo ); + + /* 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; + + p_desc->send_wr[0].local_ds[0].vaddr = cl_get_physaddr( &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 = p_port->ib_mgr.lkey; + p_desc->send_wr[0].wr.send_opt = 0; + + //TODO: first check params.lso, and thereafter calculate LSO + if( p_port->p_adapter->params.lso && + (mss = (p_lso_info->LsoV1Transmit.MSS | p_lso_info->LsoV2Transmit.MSS)) ) + { + ASSERT( mss == (p_lso_info->LsoV1Transmit.MSS & p_lso_info->LsoV2Transmit.MSS)); + ASSERT ( (mss & (1<<20)) == mss); + status = __build_lso_desc( p_port, p_desc, mss, p_sgl, hdr_idx, p_lso_info ); + 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_port, p_eth_hdr, p_mdl, mdl_len,p_sgl, 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; + } + + if( p_desc->send_dir == SEND_UD_QP ) + { + p_desc->send_qp = 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 = 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 = p_port->pkey_index; + p_desc->send_wr[i].wr.dgrm.ud.rsvd = NULL; + p_desc->send_wr[i].wr.send_opt = 0; + + if( p_port->p_adapter->params.send_chksum_offload && + ( 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_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; + } + } + //TODO p_net_buf or p_buf +// p_desc->send_wr[p_desc->num_wrs - 1].wr.wr_id = (uintn_t)NET_BUFFER_LIST_FIRST_NB(p_desc->p_netbuf_list ); +//???? IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, ("WR_ID was set to NBL 0x%x \n",p_desc->p_netbuf_list )); + p_desc->send_wr[p_desc->num_wrs - 1].wr.wr_id = (uintn_t)p_desc->p_netbuf_list ; + + 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; + } + + /* Store context in our reserved area of the packet. */ + IPOIB_PORT_FROM_PACKET( p_desc->p_netbuf_list ) = p_port; + IPOIB_ENDPT_FROM_PACKET( p_desc->p_netbuf_list ) = p_desc->p_endpt; + IPOIB_SEND_FROM_NETBUFFER( NET_BUFFER_LIST_FIRST_NB(p_desc->p_netbuf_list ))= p_desc->p_buf; + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} + +static NDIS_STATUS +__build_lso_desc( + IN ipoib_port_t* const p_port, + IN OUT ipoib_send_desc_t* const p_desc, + IN ULONG mss, + IN SCATTER_GATHER_LIST *p_sgl, + IN int32_t hdr_idx, + IN PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO p_lso_info) +{ + NDIS_STATUS status; + LsoData TheLsoData; + UINT IndexOfData = 0; + + PNET_BUFFER FirstBuffer = NET_BUFFER_LIST_FIRST_NB (p_desc->p_netbuf_list); + ULONG PacketLength = NET_BUFFER_DATA_LENGTH(FirstBuffer); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + + + 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; + + 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; + + //TODO: Should be NBL or p_desc + p_desc->send_wr[0].wr.wr_id = (uintn_t)p_desc->p_netbuf_list; + 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(p_port, p_desc, p_sgl, IndexOfData ); + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; +} + +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, + IN ULONG compl_flags) +{ + IPOIB_ENTER( IPOIB_DBG_SEND ); + + /* Complete the packet. */ + NET_BUFFER_LIST_NEXT_NBL(p_desc->p_netbuf_list) = NULL; + NET_BUFFER_LIST_STATUS(p_desc->p_netbuf_list) = status; + NdisMSendNetBufferListsComplete( p_port->p_adapter->h_adapter, + p_desc->p_netbuf_list, compl_flags ); + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_ERROR, 0 ); + /* Deref the endpoint. */ + if( p_desc->p_endpt ) + ipoib_endpt_deref( p_desc->p_endpt ); + + if( p_desc->p_buf ) + { + NdisFreeToNPagedLookasideList( + &p_port->buf_mgr.send_buf_list, p_desc->p_buf ); + } + + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + +// 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 + ) +{ +// ETH_ENTER(ETH_SND); + + 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); + ASSERT(PhysBufCount <= MAX_PHYS_BUF_FRAG_ELEMENTS); + + ASSERT(buf_len > 0); + UNREFERENCED_PARAMETER(PacketLength); + + +// ETH_PRINT(TRACE_LEVEL_VERBOSE, ETH_SND, "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) ); + +// ETH_PRINT(TRACE_LEVEL_VERBOSE, ETH_SND, "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; + } + +// ETH_PRINT(TRACE_LEVEL_VERBOSE, ETH_SND, "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; + } + +// ETH_PRINT(TRACE_LEVEL_VERBOSE, ETH_SND, "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; +// ETH_PRINT(TRACE_LEVEL_ERROR, ETH_SND, "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 + +// ETH_EXIT(ETH_SND); +} + + + + +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; + UINT buf_cnt = 0; + //ipoib_send_desc_t *p_desc; + ULONG send_complete_flags = 0; + KIRQL old_irql; + PVOID p_sgl; + + 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); + NDIS_SET_SEND_COMPLETE_FLAG(send_complete_flags, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); + } else { + //ASSERT (KeGetCurrentIRQL() == PASSIVE_LEVEL); + } + + cl_obj_lock( &p_port->obj ); + if( p_port->state != IB_QPS_RTS ) + { + + + cl_obj_unlock( &p_port->obj ); + + + NET_BUFFER_LIST_STATUS(p_net_buffer_list) = NDIS_STATUS_FAILURE; + NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL; + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_DROPPED, 0 ); + + NdisMSendNetBufferListsComplete( + p_port->p_adapter->h_adapter, + p_net_buffer_list, + send_complete_flags); + + return; + } + cl_obj_unlock( &p_port->obj ); + + //IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + // ("Processing netbuffer list: %x\n", p_net_buffer_list)); + for (p_netbuf = NET_BUFFER_LIST_FIRST_NB(p_net_buffer_list); + p_netbuf != NULL; + p_netbuf = NET_BUFFER_NEXT_NB(p_netbuf)) + { + IPOIB_PORT_FROM_PACKET(p_net_buffer_list) = p_port; + IPOIB_NET_BUFFER_LIST_FROM_NETBUFFER(p_netbuf) = p_net_buffer_list; + IPOIB_FROM_QUEUE(p_netbuf) = NULL; + /*p_desc = &p_port->send_mgr.desc; + p_desc->p_buf = p_netbuf; + p_desc->p_endpt = NULL; + p_desc->p_buf = NULL; + p_desc->send_qp = NULL; + p_desc->num_wrs = 1; + p_desc->send_dir = 0;*/ + + old_irql = KeGetCurrentIrql(); + if (old_irql < DISPATCH_LEVEL) + { + KeRaiseIrqlToDpcLevel(); + } + ++buf_cnt; + //IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + // ("[%d] Netbuf = %x\n",buf_cnt, p_netbuf) ); + if (cl_is_item_in_qlist( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET( p_net_buffer_list ))) { + p_sgl = IPOIB_FROM_QUEUE(p_netbuf); + //IPOIB_FROM_QUEUE(p_net_buffer) = (void*)1; + ASSERT (p_sgl); + //IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + // ("[%d] FROM_QUEUE Netbuf = %x, found SGL = %x\n",buf_cnt, p_netbuf, p_sgl) ); + status = NDIS_STATUS_SUCCESS; + } else { + + + CHAR *pTemp = ExAllocatePoolWithTag(NonPagedPool , p_port->p_adapter->sg_list_size, 'abcd'); + CL_ASSERT(pTemp != NULL); + status = NDIS_STATUS_SUCCESS; + p_sgl = pTemp; + CreateFragList(NdisQueryNetBufferPhysicalCount(p_netbuf), p_netbuf, NET_BUFFER_DATA_LENGTH(p_netbuf), 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, p_sgl, p_netbuf); + status = NDIS_STATUS_SUCCESS; + +#if 0 + status = NdisMAllocateNetBufferSGList( + p_port->p_adapter->NdisMiniportDmaHandle, + p_netbuf, + p_netbuf, + NDIS_SG_LIST_WRITE_TO_DEVICE, + NULL, + 0); +#endif + } + KeLowerIrql (old_irql); + + if( status != NDIS_STATUS_SUCCESS ) + { + /* fail net buffer list */ + NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL; + NET_BUFFER_LIST_STATUS(p_net_buffer_list) = NDIS_STATUS_RESOURCES; + NdisMSendNetBufferListsComplete( + p_port->p_adapter->h_adapter, + p_net_buffer_list, + send_complete_flags); + break; + } + ASSERT(buf_cnt); + IPOIB_GET_NET_BUFFER_LIST_REF_COUNT(p_net_buffer_list) = (PVOID)(ULONG_PTR)buf_cnt; + } + + /* Post the WR. * + cl_perf_start( PostSend ); + ib_status = p_port->p_adapter->p_ifc->post_send( p_desc->send_qp, &p_desc->send_wr[0].wr, &p_wr_failed ); + 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, p_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, + IN boolean_t b_pending ) +{ + NDIS_STATUS status; + cl_list_item_t *p_item; + NET_BUFFER *p_net_buffer; + NET_BUFFER_LIST *p_net_buffer_list; + //ipoib_send_desc_t *p_desc; + KIRQL old_irql; + UINT buf_cnt = 0; + NET_BUFFER_LIST *p_prev_nbl = NULL; + PVOID p_sgl; + static PVOID p_prev_sgl = NULL; + + 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 ); + +//TODO NDIS60 +////?????????????? 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; + } + + p_net_buffer_list = IPOIB_PACKET_FROM_LIST_ITEM( + cl_qlist_remove_head( &p_port->send_mgr.pending_list ) ); + if (p_prev_nbl == p_net_buffer_list) { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("TRYING TO PROCESS ONCE AGAIN, EXITING: %x\n", p_net_buffer_list)); + break; //TODO more sophisticated mechanism to avoid starvation + } + old_irql = KeGetCurrentIrql(); + if (old_irql < DISPATCH_LEVEL) + { + KeRaiseIrqlToDpcLevel(); + } + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Processing netbuffer list from queue: %x\n", p_net_buffer_list)); + + for( p_net_buffer = NET_BUFFER_LIST_FIRST_NB(p_net_buffer_list); + p_net_buffer != NULL; + p_net_buffer = NET_BUFFER_NEXT_NB(p_net_buffer), buf_cnt++) + { + + + p_sgl = IPOIB_FROM_QUEUE(p_net_buffer); + //IPOIB_FROM_QUEUE(p_net_buffer) = (void*)1; + ASSERT (p_sgl); + IPOIB_PORT_FROM_PACKET(p_net_buffer_list) = p_port; + IPOIB_NET_BUFFER_LIST_FROM_NETBUFFER(p_net_buffer) = p_net_buffer_list; + /*p_desc = &p_port->send_mgr.desc; + p_desc->p_buf = p_net_buffer; + p_desc->p_endpt = NULL; + p_desc->p_buf = NULL; + p_desc->send_qp = NULL; + p_desc->num_wrs = 1; + p_desc->send_dir = 0;*/ + + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("[%d] Netbuf = %x, p_sgl = %x\n",buf_cnt, p_net_buffer, p_sgl) ); + ASSERT(p_sgl); + if (p_sgl != (void*) 1) { + ipoib_process_sg_list(NULL, NULL, p_sgl, p_net_buffer); + status = NDIS_STATUS_SUCCESS; + } + else { + ASSERT(FALSE); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Getting strange flow\n") ); + NdisMFreeNetBufferSGList( + p_port->p_adapter->NdisMiniportDmaHandle, + p_sgl, + p_net_buffer ); + status = NdisMAllocateNetBufferSGList( + p_port->p_adapter->NdisMiniportDmaHandle, + p_net_buffer, + p_net_buffer, + NDIS_SG_LIST_WRITE_TO_DEVICE, + NULL, + 0 /*p_port->p_adapter->sg_list_size*/ ); + } + p_prev_sgl = p_sgl; + if( status != NDIS_STATUS_SUCCESS ) + { + /* fail net buffer list */ + NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL; + NET_BUFFER_LIST_STATUS(p_net_buffer_list) = NDIS_STATUS_RESOURCES; + NdisMSendNetBufferListsComplete( + p_port->p_adapter->h_adapter, + p_net_buffer_list, + 0); + break; + } + } + + KeLowerIrql (old_irql); + + + p_prev_nbl = p_net_buffer_list; + + } + 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; + NET_BUFFER_LIST *p_nbl; + uint32_t length; + ipoib_endpt_t *p_endpt; + send_buf_t *p_send_buf; + ip_stat_sel_t type; + size_t i; + NET_BUFFER *p_netbuffer = NULL; + + PERF_DECLARE( SendCompBundle ); + PERF_DECLARE( SendCb ); + PERF_DECLARE( PollSend ); + PERF_DECLARE( SendComp ); + PERF_DECLARE( FreeSendBuf ); + PERF_DECLARE( RearmSend ); + PERF_DECLARE( PortResume ); +//return;//??????????? + 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_nbl = (NET_BUFFER_LIST*)(uintn_t)p_wc->wr_id; + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_SEND, + ("[1]Successfull send completion for NBL=0x%x .\n", p_nbl )); + CL_ASSERT( p_nbl ); + CL_ASSERT( IPOIB_PORT_FROM_PACKET( p_nbl ) == p_port ); + length = 0; + p_endpt = IPOIB_ENDPT_FROM_PACKET( p_nbl ); + p_send_buf = IPOIB_SEND_FROM_NETBUFFER( NET_BUFFER_LIST_FIRST_NB (p_nbl )); + + 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; + } + for (p_netbuffer = NET_BUFFER_LIST_FIRST_NB(p_nbl); + p_netbuffer != NULL; + p_netbuffer = NET_BUFFER_NEXT_NB(p_netbuffer)) + { + length += NET_BUFFER_DATA_LENGTH(p_netbuffer); + } + ipoib_inc_send_stat( p_port->p_adapter, type, length ); + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_SEND, + ("Successfull send completion for NBL=0x%x .\n", p_nbl) ); + NET_BUFFER_LIST_STATUS(p_nbl) = NDIS_STATUS_SUCCESS; + IPOIB_DEC_NET_BUFFER_LIST_REF_COUNT(p_nbl); + if (IPOIB_GET_NET_BUFFER_LIST_REF_COUNT(p_nbl) == 0) + NdisMSendNetBufferListsComplete(p_port->p_adapter->h_adapter, + p_nbl, + 0); + 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 ); + NET_BUFFER_LIST_STATUS(p_nbl) = NDIS_STATUS_RESET_IN_PROGRESS; + NdisMSendNetBufferListsComplete(p_port->p_adapter->h_adapter, + p_nbl, + 0); + 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 ); + NET_BUFFER_LIST_STATUS(p_nbl) = NDIS_STATUS_FAILURE; + NdisMSendNetBufferListsComplete(p_port->p_adapter->h_adapter, + p_nbl, + 0); + 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 ); + NdisFreeToNPagedLookasideList( &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, TRUE ); + 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 void +__endpt_cm_mgr_thread( +IN void* p_context ); + +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; +} + +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_EXIT( 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 thread is done\n", p_port->port_num ) ); +} + +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 ) ); +#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 = IPOIB_MEDIA_MAX_SPEED; + + 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 ); + cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts, + &p_port->p_local_endpt->lid_item ); + + 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 ); + + //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->resv0 = 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, + 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 *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; + //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 ); + } + + cl_obj_unlock( &p_port->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) ); + + 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, + (" 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 ); + 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_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; + } +#if 0 //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_EXIT( 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 ); + + 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 , FALSE); + + 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 ); +} + +/*++ +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); + //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; + } + //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)); + 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_VERBOSE, 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 = 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; + PNET_BUFFER_LIST p_nbl; + PVOID nbl_id; + cl_qlist_t cancel_list; + ULONG send_complete_flags = 0; + IPOIB_ENTER( IPOIB_DBG_SEND ); + + cl_qlist_init( &cancel_list ); + + 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_next( p_item ) ) + { + p_nbl = IPOIB_PACKET_FROM_LIST_ITEM( p_item ); + nbl_id = NDIS_GET_NET_BUFFER_LIST_CANCEL_ID( p_nbl ); + if( nbl_id == cancel_id ) + { + cl_qlist_remove_item( &p_port->send_mgr.pending_list, p_item ); + NET_BUFFER_LIST_STATUS( p_nbl) = NDIS_STATUS_REQUEST_ABORTED ; + cl_qlist_insert_tail( &cancel_list, IPOIB_LIST_ITEM_FROM_PACKET( p_nbl ) ); + } + } + 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 )) + { + p_nbl = IPOIB_PACKET_FROM_LIST_ITEM( p_item ); + NET_BUFFER_LIST_STATUS( p_nbl) = NDIS_STATUS_SEND_ABORTED; + send_complete_flags = 0; + if (NDIS_CURRENT_IRQL() == DISPATCH_LEVEL) + { + NDIS_SET_SEND_COMPLETE_FLAG(send_complete_flags, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); + } + NdisMSendNetBufferListsComplete( p_port->p_adapter->h_adapter, + p_nbl, send_complete_flags ); + } + } + 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; + } + p_desc->p_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; +} +#endif + +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; +} diff --git a/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_port.h b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_port.h new file mode 100644 index 00000000..602389b5 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_port.h @@ -0,0 +1,827 @@ +/* + * 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 + + +#define IPOIB_PORT_FROM_PACKET( P ) \ + (((ipoib_port_t**)NET_BUFFER_LIST_MINIPORT_RESERVED(P))[0]) +#define IPOIB_ENDPT_FROM_PACKET( P ) \ + (((ipoib_endpt_t**)NET_BUFFER_LIST_MINIPORT_RESERVED(P))[1]) +#define IPOIB_RECV_FROM_PACKET( P ) \ + (((ipoib_recv_desc_t**)NET_BUFFER_LIST_MINIPORT_RESERVED(P))[1]) + +//TODO to be renamed: IPOIB_NBL_FROM_LIST_ITEM +#define IPOIB_PACKET_FROM_LIST_ITEM( I ) \ + (PARENT_STRUCT( I, NET_BUFFER_LIST, MiniportReserved )) +#define IPOIB_LIST_ITEM_FROM_PACKET( P ) \ + ((cl_list_item_t*)NET_BUFFER_LIST_MINIPORT_RESERVED(P)) + +#define IPOIB_NET_BUFFER_LIST_FROM_NETBUFFER( P ) \ + (((NET_BUFFER_LIST**)NET_BUFFER_MINIPORT_RESERVED(P))[0]) +#define IPOIB_FROM_QUEUE( P ) \ + (((void**)NET_BUFFER_MINIPORT_RESERVED(P))[1]) +#define IPOIB_SEND_FROM_NETBUFFER( P ) \ + (((send_buf_t**)NET_BUFFER_MINIPORT_RESERVED(P))[2]) + + +#define IPOIB_GET_NET_BUFFER_LIST_REF_COUNT(_NetBufferList) ((_NetBufferList->FirstNetBuffer)->MiniportReserved[3]) +#define IPOIB_DEC_NET_BUFFER_LIST_REF_COUNT(_NetBufferList) (*(PULONG)&(_NetBufferList->FirstNetBuffer)->MiniportReserved[3])-- + + +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_UD_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, + 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; + 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_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_desc_t desc; + +} 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. +*********/ + + +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; + + KDPC recv_dpc; + + 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; + 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. +*********/ +typedef struct _sgl_context +{ + MDL *p_mdl; + NET_BUFFER_LIST *p_netbuffer_list; + ipoib_port_t *p_port; +}sgl_context_t; + +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; + } +} +#endif /* _IPOIB_PORT_H_ */ diff --git a/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_xfr_mgr.c b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_xfr_mgr.c new file mode 100644 index 00000000..ce0650f1 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_xfr_mgr.c @@ -0,0 +1,74 @@ +/* + * 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}, + + {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}, + {0x30, 0x48, 0xE7}, + {0x80, 0x5F, 0xE7}, + + {0x00, 0x00, 0x00}, +}; + diff --git a/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_xfr_mgr.h b/branches/WOF2-1/ulp/ipoib/kernel6/ipoib_xfr_mgr.h new file mode 100644 index 00000000..9e38b609 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/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-1/ulp/ipoib/kernel6/makefile b/branches/WOF2-1/ulp/ipoib/kernel6/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/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-1/ulp/ipoib/kernel6/makefile.inc b/branches/WOF2-1/ulp/ipoib/kernel6/makefile.inc new file mode 100644 index 00000000..4f29f500 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/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-1/ulp/ipoib/kernel6/netipoib-xp32.inf b/branches/WOF2-1/ulp/ipoib/kernel6/netipoib-xp32.inf new file mode 100644 index 00000000..fd29521f --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/netipoib-xp32.inf @@ -0,0 +1,280 @@ +; 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 = %MTL% +DriverVer=10/10/2008,2.0.0000.1630 +CatalogFile=ipoib.cat + +[Manufacturer] +%MTL% = MTL,ntx86,ntamd64,ntia64 + +[ControlFlags] +ExcludeFromSelect = IBA\IPoIB + +[MTL] +; empty since we don't support W9x/Me + +[MTL.ntx86] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[MTL.ntamd64] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[MTL.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 = NdCopyFiles +CopyFiles = WOW64CopyFiles + +[Ipoib.DDInstall.ntia64] +Characteristics = 0x81 ; NCF_HAS_UI | NCF_VIRTUAL +AddReg = IpoibAddReg +CopyFiles = IpoibCopyFiles +CopyFiles = NdCopyFiles +CopyFiles = WOW64CopyFiles + +[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, "1" +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 + +[NdCopyFiles] +ibndprov.dll,,,0x00000002 +ndinstall.exe,,,0x00000002 + +[WOW64CopyFiles] +ibwsd.dll,ibwsd32.dll,,0x00000002 +ibndprov.dll,ibndprov32.dll,,0x00000002 + +[SourceDisksNames.x86] +1 = %IcsDisk1%,,,"" + +[SourceDisksNames.amd64] +1 = %IcsDisk1%,,,"" + +[SourceDisksNames.ia64] +1 = %IcsDisk1%,,,"" + +[SourceDisksFiles.x86] +ipoib.sys = 1 +ibndprov.dll = 1 +ndinstall.exe = 1 + +[SourceDisksFiles.amd64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +ibndprov.dll = 1 +ibndprov32.dll = 1 +ndinstall.exe = 1 + +[SourceDisksFiles.ia64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +ibndprov.dll = 1 +ibndprov32.dll = 1 +ndinstall.exe = 1 + +[DestinationDirs] +IpoibCopyFiles = %DIRID_DRIVERS% +WsdCopyFiles = %DIRID_SYSTEM% +NdCopyFiles = %DIRID_SYSTEM% +WOW64CopyFiles = %DIRID_SYSTEM_X86% +DefaultDestDir = %DIRID_SYSTEM% + +[Strings] +OPENIB = "OpenFabrics Alliance" +MTL = "Mellanox Technologies Ltd." +IpoibDesc = "Mellanox IPoIB Adapter" +IpoibDescP = "Mellanox IPoIB Adapter Partition" +IpoibServiceDispName = "IPoIB" +IcsDisk1 = "Mellanox 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-1/ulp/ipoib/kernel6/netipoib.inx b/branches/WOF2-1/ulp/ipoib/kernel6/netipoib.inx new file mode 100644 index 00000000..ca3126b5 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/netipoib.inx @@ -0,0 +1,295 @@ +; 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 = %MTL% +DriverVer=06/11/2008,1.0.0000.1207 +CatalogFile=ipoib.cat + +[Manufacturer] +%MTL% = MTL,ntx86,ntamd64,ntia64 + +[ControlFlags] +ExcludeFromSelect = IBA\IPoIB + +[MTL] +; empty since we don't support W9x/Me + +[MTL.ntx86] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[MTL.ntamd64] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[MTL.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 = NdCopyFiles +CopyFiles = WOW64CopyFiles +*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 +ndinstall.exe,,,0x00000002 + +[WOW64CopyFiles] +ibwsd.dll,ibwsd32.dll,,0x00000002 +ibndprov.dll,ibndprov32.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 +ndinstall.exe = 1 + +[SourceDisksFiles.amd64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +ibndprov.dll = 1 +ibndprov32.dll = 1 +ndinstall.exe = 1 + +[SourceDisksFiles.ia64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +ibndprov.dll = 1 +ibndprov32.dll = 1 +ndinstall.exe = 1 + +[DestinationDirs] +IpoibCopyFiles = %DIRID_DRIVERS% +WsdCopyFiles = %DIRID_SYSTEM% +NdCopyFiles = %DIRID_SYSTEM% +WOW64CopyFiles = %DIRID_SYSTEM_X86% +DefaultDestDir = %DIRID_SYSTEM% + +[Strings] +OPENIB = "OpenFabrics Alliance" +MTL = "Mellanox Technologies Ltd." +IpoibDesc = "Mellanox IPoIB Adapter" +IpoibDescP = "Mellanox IPoIB Adapter Partition" +IpoibServiceDispName = "IPoIB" +IcsDisk1 = "Mellanox 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" \ No newline at end of file diff --git a/branches/WOF2-1/ulp/ipoib/kernel6/offload.h b/branches/WOF2-1/ulp/ipoib/kernel6/offload.h new file mode 100644 index 00000000..de696c6a --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib/kernel6/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-1/ulp/ipoib_NDIS6_CM/dirs b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/dirs new file mode 100644 index 00000000..ed41dcf4 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/dirs @@ -0,0 +1,2 @@ +DIRS=\ + kernel diff --git a/branches/WOF2-1/ulp/ipoib_NDIS6_CM/ip_stats.h b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/ip_stats.h new file mode 100644 index 00000000..2f93e41c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib_NDIS6_CM/kernel/SOURCES b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/SOURCES new file mode 100644 index 00000000..774f114b --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/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.cpp \ + ipoib_adapter.cpp \ + ipoib_endpoint.cpp \ + ipoib_port.cpp \ + ipoib_ibat.cpp \ +# ipoib_cm.cpp \ + ipoib_xfr_mgr.cpp + +INCLUDES=..;..\..\..\inc;..\..\..\inc\kernel; + +C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DNDIS_WDM=1 \ + -DDEPRECATE_DDK_FUNCTIONS -DNDIS60_MINIPORT=1 -DNEED_CL_OBJ -DBINARY_COMPATIBLE=0 -DVER_FILEREV=42 + +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 + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib.cdf b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib.cdf new file mode 100644 index 00000000..eb21da98 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib_NDIS6_CM/kernel/ipoib.rc b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib.rc new file mode 100644 index 00000000..330f19e7 --- /dev/null +++ b/branches/WOF2-1/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 Miniport (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "IP over InfiniBand NDIS Miniport" +#endif + +#define VER_INTERNALNAME_STR "ipoib.sys" +#define VER_ORIGINALFILENAME_STR "ipoib.sys" + +#include +#include "ipoib_log.rc" diff --git a/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib32.cdf b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib32.cdf new file mode 100644 index 00000000..50225ba6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.cpp b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.cpp new file mode 100644 index 00000000..6733a38d --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.cpp @@ -0,0 +1,1639 @@ +/* + * 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 "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 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( (status == NDIS_STATUS_SUCCESS) && (len == HW_ADDR_LEN) ) + { + 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 ); + } + } + + *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 ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_adapter ); + + /* + * 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_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 ) + { + 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_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, (ib_pfn_destroy_cb_t) 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; + 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; + + 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; + 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 ) + { + 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.MediaConnectState = MediaConnectStateConnected; + link_state.MediaDuplexState = MediaDuplexStateFull; + link_state.XmitLinkSpeed = link_state.RcvLinkSpeed = IPOIB_MEDIA_MAX_SPEED; + + 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 ); + } + 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.MediaConnectState = MediaConnectStateConnected; + link_state.MediaDuplexState = MediaDuplexStateFull; + link_state.XmitLinkSpeed = link_state.RcvLinkSpeed = IPOIB_MEDIA_MAX_SPEED; + + 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.MediaConnectState = MediaConnectStateConnected; + link_state.MediaDuplexState = MediaDuplexStateFull; + link_state.XmitLinkSpeed = link_state.RcvLinkSpeed = IPOIB_MEDIA_MAX_SPEED; + + 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") ); +// return; + 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; + 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; + 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_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 ) + { + 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 = IPOIB_MEDIA_MAX_SPEED; + 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.MediaConnectState = MediaConnectStateConnected; + + link_state.MediaDuplexState = MediaDuplexStateFull; + link_state.XmitLinkSpeed = link_state.RcvLinkSpeed = IPOIB_MEDIA_MAX_SPEED; + + 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_INIT ); + 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-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h new file mode 100644 index 00000000..0d3c106b --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h @@ -0,0 +1,482 @@ +/* + * 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" + + +/* + * 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_PAUSED, + IPOIB_PAUSING, + IPOIB_RUNNING +} ipoib_state_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 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. + + 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 +* 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; + PNDIS_OID_REQUEST p_pending_oid; +} pending_oid_t; + + +typedef struct _ipoib_adapter +{ + cl_obj_t obj; + NDIS_HANDLE h_adapter; + 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; + NDIS_HANDLE NdisMiniportDmaHandle; + ipoib_state_t ipoib_state; + ib_al_ifc_t *p_ifc; + + ULONG sg_list_size; + +} 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 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; \ + } + +//TODO rename to 4 +#define IPOIB_MEDIA_MAX_SPEED 40000000000 + +#endif /* _IPOIB_ADAPTER_H_ */ diff --git a/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h new file mode 100644 index 00000000..69ec3c5a --- /dev/null +++ b/branches/WOF2-1/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, + 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-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.cpp b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.cpp new file mode 100644 index 00000000..236a81f5 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.cpp @@ -0,0 +1,4570 @@ +/* + * 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 "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 + + + +#define MAJOR_DRIVER_VERSION 2 +#define MINOR_DRIVER_VERSION 1 +#if defined(NDIS60_MINIPORT) +#define MAJOR_NDIS_VERSION 6 +#define MINOR_NDIS_VERSION 0 + +#else +#error NDIS Version not defined, try defining NDIS60_MINIPORT +#endif + +PDRIVER_OBJECT g_p_drv_obj; + + +#if 0 +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 +}; +#endif + +NDIS_OID NICSupportedOidsTest[] = +{ + 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, + + +/* custom oid WMI support */ +// OID_CUSTOM_PERF_COUNTERS, + // OID_CUSTOM_STRING, + + 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, + +/* 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 + +}; + +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; + + + +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); + +NDIS_STATUS +MPInitializeTest( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE MiniportDriverContext, + 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 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( + IN NDIS_HANDLE adapter_context, + OUT PBOOLEAN p_addr_reset); + +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 ); + +//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 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, + 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 ); + + NdisZeroMemory(&characteristics, sizeof(characteristics)); + + characteristics.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS, + characteristics.Header.Size = sizeof(NDIS_MINIPORT_DRIVER_CHARACTERISTICS); + characteristics.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1; + + 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;// MPInitializeTest + 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; + + + +//TODO NDIS60 set g_ prefix to global variables + 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 ); + + 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; + //TODO NDIS60 Port or adapter + atr.MiniportAdapterContext = (NDIS_HANDLE)p_adapter; //(NDIS_HANDLE)pPort->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 = IPOIB_MEDIA_MAX_SPEED; //TODO NDIS60 NDIS_LINK_SPEED_UNKNOWN + gat.RcvLinkSpeed = IPOIB_MEDIA_MAX_SPEED; // TODO NDIS60 NDIS_LINK_SPEED_UNKNOWN ??? + + gat.MediaConnectState = MediaConnectStateConnected; //TODO NDIS60 Check the current state + gat.MediaDuplexState = MediaDuplexStateFull; + + gat.MtuSize = MAX_IB_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; + //TODO NDIS60 This value is absent for ETH driver + 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; // 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->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); //TODO NDIS60 + + + 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; + + p_offload->LsoV2.IPv6.Encapsulation = ulEncapsulation; + p_offload->LsoV2.IPv6.MaxOffLoadSize = LARGE_SEND_OFFLOAD_SIZE; + p_offload->LsoV2.IPv6.MinSegmentCount = LSO_MIN_SEG_COUNT; + + p_offload->LsoV2.IPv6.IpExtensionHeadersSupported = NDIS_OFFLOAD_NOT_SUPPORTED; + p_offload->LsoV2.IPv6.TcpOptionsSupported = NDIS_OFFLOAD_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( + 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 = TRUE; + p_offload->Checksum.IPv4Transmit.TcpOptionsSupported = TRUE; + p_offload->Checksum.IPv4Transmit.TcpChecksum = TRUE; + p_offload->Checksum.IPv4Transmit.UdpChecksum = TRUE; + p_offload->Checksum.IPv4Transmit.IpChecksum = TRUE; + + p_offload->Checksum.IPv4Receive.Encapsulation = ulEncapsulation; + p_offload->Checksum.IPv4Receive.IpOptionsSupported = TRUE; + p_offload->Checksum.IPv4Receive.TcpOptionsSupported = TRUE; + p_offload->Checksum.IPv4Receive.TcpChecksum = TRUE; + p_offload->Checksum.IPv4Receive.UdpChecksum = TRUE; + p_offload->Checksum.IPv4Receive.IpChecksum = TRUE; + + + // + // 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 = TRUE; + p_offload->Checksum.IPv6Transmit.TcpOptionsSupported = TRUE; + p_offload->Checksum.IPv6Transmit.TcpChecksum = TRUE; + p_offload->Checksum.IPv6Transmit.UdpChecksum = TRUE; + + + p_offload->Checksum.IPv6Receive.Encapsulation = ulEncapsulation; + p_offload->Checksum.IPv6Receive.IpExtensionHeadersSupported = TRUE; + p_offload->Checksum.IPv6Receive.TcpOptionsSupported = TRUE; + p_offload->Checksum.IPv6Receive.TcpChecksum = TRUE; + p_offload->Checksum.IPv6Receive.UdpChecksum = TRUE; + + 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; + + 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_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(&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); + 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); + return Status; + } + + Status = SetOffloadAttributes(p_adapter, h_adapter); + if (Status != NDIS_STATUS_SUCCESS) + { + //ETH_PRINT(TRACE_LEVEL_ERROR, ETH_INIT, "Set OFFLOAD attributes failed Error=0x%x\n", 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; +} + + + +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 + // + 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; + + DmaDescription.ProcessSGListHandler = ipoib_process_sg_list; + DmaDescription.SharedMemAllocateCompleteHandler = NULL; + + status = NdisMRegisterScatterGatherDma( + h_adapter, + &DmaDescription, + &p_adapter->NdisMiniportDmaHandle); + + if( status != NDIS_STATUS_SUCCESS ) + { + //TODO NDIS60 + //ipoib_destroy_adapter( p_adapter ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisMRegisterScatterGatherDma returned 0x%.8x.\n", 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; +} + + +NDIS_STATUS +MPInitializeTest( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE MiniportDriverContext, + IN PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters + ) +/*++ +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 Status = NDIS_STATUS_SUCCESS; + //PMP_PORT pPort = NULL; + ipoib_adapter_t *p_adapter; +// NDIS_MINIPORT_INTERRUPT_CHARACTERISTICS Interrupt; + NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES RegistrationAttributes; + NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES GeneralAttributes; + //NDIS_TIMER_CHARACTERISTICS Timer; + NDIS_PNP_CAPABILITIES PowerManagementCapabilities; + //PMP_ADAPTER Adapter = NULL; + //PVOID NetworkAddress; +// UINT index; +// UINT uiPnpCommandValue; +// ULONG ulInfoLen; + //ULONG InterruptVersion; +// LARGE_INTEGER liDueTime; + //BOOLEAN isTimerAlreadyInQueue = FALSE; +// uint8_t portId; + ib_api_status_t ib_status; +#if 0 +#if DBG + LARGE_INTEGER TS, TD, TE; +#endif +#endif + + cl_dbg_out ("====> MPInitialize\n"); + + UNREFERENCED_PARAMETER(MiniportDriverContext); + UNREFERENCED_PARAMETER(MiniportInitParameters); + + + + + + { + + ib_status = ipoib_create_adapter( MiniportAdapterHandle, &p_adapter ); + if( ib_status != IB_SUCCESS ) + { + ASSERT(FALSE); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_create_adapter returned status %d.\n", ib_status ) ); + return NDIS_STATUS_FAILURE; + } + + + + NdisZeroMemory(&RegistrationAttributes, sizeof(NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES)); + NdisZeroMemory(&GeneralAttributes, sizeof(NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES)); + + // + // setting registration attributes + // + RegistrationAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES; + RegistrationAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; + RegistrationAttributes.Header.Size = sizeof(NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES); + + RegistrationAttributes.MiniportAdapterContext = (NDIS_HANDLE)p_adapter; + RegistrationAttributes.AttributeFlags = NDIS_MINIPORT_ATTRIBUTES_HARDWARE_DEVICE | + NDIS_MINIPORT_ATTRIBUTES_BUS_MASTER; + + RegistrationAttributes.CheckForHangTimeInSeconds = 2; + RegistrationAttributes.InterfaceType = NdisInterfacePci; + + Status = NdisMSetMiniportAttributes(MiniportAdapterHandle, + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&RegistrationAttributes); + + if (Status != NDIS_STATUS_SUCCESS) + { + //break; + return Status; + } + +#if 0 + // + // Read the registry parameters + // + Status = NICReadRegParameters(Adapter); + + if (Status != NDIS_STATUS_SUCCESS) + { + break; + } + + + // + // Find the physical adapter + // + Status = MpFindAdapter(Adapter, MiniportInitParameters->AllocatedResources); + if (Status != NDIS_STATUS_SUCCESS) + { + break; + } + + // + // Map bus-relative IO range to system IO space + // + Status = NdisMRegisterIoPortRange( + (PVOID *)&Adapter->PortOffset, + Adapter->AdapterHandle, + Adapter->IoBaseAddress, + Adapter->IoRange); + if (Status != NDIS_STATUS_SUCCESS) + { + DBGPRINT(MP_ERROR, ("NdisMRegisterioPortRange failed\n")); + + NdisWriteErrorLogEntry( + Adapter->AdapterHandle, + NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS, + 0); + + break; + } + + // + // Read additional info from NIC such as MAC address + // + Status = NICReadAdapterInfo(Adapter); + if (Status != NDIS_STATUS_SUCCESS) + { + break; + } + +#endif + // + // set up generic attributes + // + + + GeneralAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES; + GeneralAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; + GeneralAttributes.Header.Size = sizeof(NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES); + + GeneralAttributes.MediaType = NdisMedium802_3; + + GeneralAttributes.MtuSize = DEFAULT_MTU; +#define LINE_SPEED_10_GBTS 10000000000 + GeneralAttributes.MaxXmitLinkSpeed = LINE_SPEED_10_GBTS; + GeneralAttributes.MaxRcvLinkSpeed = LINE_SPEED_10_GBTS; + GeneralAttributes.XmitLinkSpeed = NDIS_LINK_SPEED_UNKNOWN; + GeneralAttributes.RcvLinkSpeed = NDIS_LINK_SPEED_UNKNOWN; + GeneralAttributes.MediaConnectState = MediaConnectStateUnknown; + GeneralAttributes.MediaDuplexState = MediaDuplexStateUnknown; + GeneralAttributes.LookaheadSize = MAX_XFER_BLOCK_SIZE; +#if 0 + MPFillPoMgmtCaps (Adapter, + &PowerManagementCapabilities, + &Status, + &ulInfoLen); +#endif + NdisZeroMemory(&PowerManagementCapabilities, sizeof(NDIS_PNP_CAPABILITIES)); + Status = NDIS_STATUS_NOT_SUPPORTED; + // ulInfoLen = 0; + + if (Status == NDIS_STATUS_SUCCESS) + { + GeneralAttributes.PowerManagementCapabilities = &PowerManagementCapabilities; + } + else + { + GeneralAttributes.PowerManagementCapabilities = NULL; + } + + // + // do not fail the call because of failure to get PM caps + // + Status = NDIS_STATUS_SUCCESS; + + GeneralAttributes.MacOptions = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | + NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | + NDIS_MAC_OPTION_NO_LOOPBACK; + + GeneralAttributes.SupportedPacketFilters = NDIS_PACKET_TYPE_DIRECTED | + NDIS_PACKET_TYPE_MULTICAST | + NDIS_PACKET_TYPE_ALL_MULTICAST | + NDIS_PACKET_TYPE_BROADCAST; + + GeneralAttributes.MaxMulticastListSize = MAX_MCAST; + GeneralAttributes.MacAddressLength = HW_ADDR_LEN; + NdisMoveMemory(GeneralAttributes.PermanentMacAddress, + p_adapter->mac.addr, + HW_ADDR_LEN); + + NdisMoveMemory(GeneralAttributes.CurrentMacAddress, + p_adapter->params.conf_mac.addr, + HW_ADDR_LEN); + GeneralAttributes.RecvScaleCapabilities = NULL; + GeneralAttributes.AccessType = NET_IF_ACCESS_BROADCAST; // NET_IF_ACCESS_BROADCAST for a typical ethernet adapter + GeneralAttributes.DirectionType = NET_IF_DIRECTION_SENDRECEIVE; // NET_IF_DIRECTION_SENDRECEIVE for a typical ethernet adapter + GeneralAttributes.ConnectionType = NET_IF_CONNECTION_DEDICATED; // NET_IF_CONNECTION_DEDICATED for a typical ethernet adapter + GeneralAttributes.IfType = IF_TYPE_ETHERNET_CSMACD; // IF_TYPE_ETHERNET_CSMACD for a typical ethernet adapter (regardless of speed) + GeneralAttributes.IfConnectorPresent = TRUE; // RFC 2665 TRUE if physical adapter + + GeneralAttributes.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 | + NDIS_STATISTICS_GEN_STATISTICS_SUPPORTED; + + GeneralAttributes.SupportedOidList = NICSupportedOidsTest; + GeneralAttributes.SupportedOidListLength = sizeof(NICSupportedOidsTest); + + Status = NdisMSetMiniportAttributes(MiniportAdapterHandle, + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&GeneralAttributes); + + +#if 0 + // + // Allocate all other memory blocks including shared memory + // + Status = NICAllocAdapterMemory(Adapter); + if (Status != NDIS_STATUS_SUCCESS) + { + break; + } + // + // Init send data structures + // + NICInitSend(Adapter); + + // + // Init receive data structures + // + Status = NICInitRecv(Adapter); + if (Status != NDIS_STATUS_SUCCESS) + { + break; + } + // + // Map bus-relative registers to virtual system-space + // + Status = NdisMMapIoSpace( + (PVOID *) &(Adapter->CSRAddress), + Adapter->AdapterHandle, + Adapter->MemPhysAddress, + NIC_MAP_IOSPACE_LENGTH); + if (Status != NDIS_STATUS_SUCCESS) + { + DBGPRINT(MP_ERROR, ("NdisMMapIoSpace failed\n")); + + NdisWriteErrorLogEntry( + Adapter->AdapterHandle, + NDIS_ERROR_CODE_RESOURCE_CONFLICT, + 1, + ERRLOG_MAP_IO_SPACE); + + break; + } + + DBGPRINT(MP_INFO, ("CSRAddress="PTR_FORMAT"\n", Adapter->CSRAddress)); + + // + // Disable interrupts here which is as soon as possible + // + NICDisableInterrupt(Adapter); +#endif + + // + // Register the interrupt + // + // + + // + // the embeded NDIS interrupt structure is already zero'ed out + // as part of the adapter structure + // + #if 0 + NdisZeroMemory(&Interrupt, sizeof(NDIS_MINIPORT_INTERRUPT_CHARACTERISTICS)); + + Interrupt.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_INTERRUPT; + Interrupt.Header.Revision = NDIS_MINIPORT_INTERRUPT_REVISION_1; + Interrupt.Header.Size = sizeof(NDIS_MINIPORT_INTERRUPT_CHARACTERISTICS); + + Interrupt.InterruptHandler = MPIsr; + Interrupt.InterruptDpcHandler = MPHandleInterrupt; + Interrupt.DisableInterruptHandler = NULL; + Interrupt.EnableInterruptHandler = NULL; + + + + Status = NdisMRegisterInterruptEx(Adapter->AdapterHandle, + Adapter, + &Interrupt, + &Adapter->NdisInterruptHandle + ); + + + if (Status != NDIS_STATUS_SUCCESS) + { + DBGPRINT(MP_ERROR, ("NdisMRegisterInterrupt failed\n")); + + NdisWriteErrorLogEntry( + Adapter->AdapterHandle, + NDIS_ERROR_CODE_INTERRUPT_CONNECT, + 0); + + break; + } + + // + // If the driver support MSI + // + Adapter->InterruptType = Interrupt.InterruptType; + + if (Adapter->InterruptType == NDIS_CONNECT_MESSAGE_BASED) + { + Adapter->MessageInfoTable = Interrupt.MessageInfoTable; + } + + // + // If the driver supports MSI, here it should what kind of interrupt is granted. If MSI is granted, + // the driver can check Adapter->MessageInfoTable to get MSI information + // + + + MP_SET_FLAG(Adapter, fMP_ADAPTER_INTERRUPT_IN_USE); + + // + // Test our adapter hardware + // + Status = NICSelfTest(Adapter); + if (Status != NDIS_STATUS_SUCCESS) + { + break; + } + + // + // Init the hardware and set up everything + // + Status = NICInitializeAdapter(Adapter); + if (Status != NDIS_STATUS_SUCCESS) + { + break; + } + + // + // initial state is paused + // + Adapter->AdapterState = NicPaused; + + // + // Set the link detection flag + // + MP_SET_FLAG(Adapter, fMP_ADAPTER_LINK_DETECTION); + + // + // Increment the reference count so halt handler will wait + // + MP_INC_REF(Adapter); + + // + // Enable the interrupt + // + NICEnableInterrupt(Adapter); + + + NdisZeroMemory(&Timer, sizeof(NDIS_TIMER_CHARACTERISTICS)); + + Timer.Header.Type = NDIS_OBJECT_TYPE_TIMER_CHARACTERISTICS; + Timer.Header.Revision = NDIS_TIMER_CHARACTERISTICS_REVISION_1; + Timer.Header.Size = sizeof(NDIS_TIMER_CHARACTERISTICS); + + Timer.AllocationTag = NIC_TAG; + Timer.TimerFunction = MpLinkDetectionDpc; + Timer.FunctionContext = Adapter; + + // + // Minimize init-time + // + Status = NdisAllocateTimerObject( + Adapter->AdapterHandle, + &Timer, + &Adapter->LinkDetectionTimerHandle); + + if (Status != NDIS_STATUS_SUCCESS) + { + break; + } + + liDueTime.QuadPart = NIC_LINK_DETECTION_DELAY; + isTimerAlreadyInQueue =NdisSetTimerObject(Adapter->LinkDetectionTimerHandle, liDueTime, 0, NULL); + ASSERT(!isTimerAlreadyInQueue); +#endif + } +#if 0 + if (Adapter && (Status != NDIS_STATUS_SUCCESS)) + { + // + // Undo everything if it failed + // + MP_DEC_REF(Adapter); + MpFreeAdapter(Adapter); + } + + DBGPRINT_S(Status, ("<==== MPInitialize, Status=%x\n", Status)); +#endif + /* Create the adapter adapter */ + ib_status = ipoib_start_adapter( p_adapter ); + if( ib_status != IB_SUCCESS ) + { + ASSERT(FALSE); + + 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(); + return NDIS_STATUS_SUCCESS; +} + + + +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 ); + +#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); + 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_PAUSED; + status = SetAttributes(p_adapter, h_adapter); + if (status != NDIS_STATUS_SUCCESS) { + ASSERT(FALSE); + } + +#if IPOIB_USE_DMA + InitNdisScatterGatherDma(p_adapter, h_adapter); +#endif + + /* Create the adapter adapter */ + ib_status = ipoib_start_adapter( p_adapter ); + if( ib_status != IB_SUCCESS ) + { + ASSERT(FALSE); + NdisWriteErrorLogEntry( h_adapter, + NDIS_ERROR_CODE_HARDWARE_FAILURE, 0 ); +#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; + } + + 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); +//return; + 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 ); +//return FALSE; + 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); +} + + +/*++ +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 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) ); + if( p_adapter->params.cm_enabled ) + { + info = p_adapter->params.cm_payload_mtu; + } + else + { + 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) ); + if (info_buf_len < buf_len) + { + break; + } + + cl_obj_lock( &p_adapter->obj ); + switch( p_adapter->state ) + { + case IB_PNP_PORT_ADD: + /* Mark the adapter as pending an OID */ + p_adapter->pending_query = TRUE; + + /* Save the request parameters. */ + 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_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: + CL_ASSERT( p_adapter->p_port ); + info = p_adapter->port_rate; + break; + } + 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) ); + 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: + 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) ); + if( p_adapter->params.cm_enabled ) + info = p_adapter->params.cm_xfer_block_size; + else + 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_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 (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_TASK_OFFLOAD: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_TCP_TASK_OFFLOAD\n", port_num) ); + 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: + 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_UPn", port_num) ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Number of OID: 0x%.8X!\n", 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_PNP_QUERY_POWER\n", port_num) ); + //ulBytesAvailable = ulInfoLen = sizeof(NDIS_OFFLOAD); + if (info_buf_len < sizeof(NDIS_OFFLOAD)) + { + status = NDIS_STATUS_BUFFER_TOO_SHORT; + *p_bytes_needed = sizeof(NDIS_OFFLOAD) ; + break; + } + + //ipoib_offload_config(pPort, &offload); + //pInfo = &offload; + break; + + default: + status = NDIS_STATUS_INVALID_OID; + // IPOIB_PRINT( TRACE_LEVEL_ERROR,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 ); + return status; + } + + 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; + } + + 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 ); +} + + +static NDIS_STATUS +__ipoib_get_tcp_task_offload( + IN ipoib_adapter_t* p_adapter, + OUT pending_oid_t *pNdisRequest ) +{ +#ifndef NDIS60_MINIPORT + 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); + + pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = buf_len; + + if( pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength < buf_len ) + return NDIS_STATUS_INVALID_LENGTH; + + p_offload_hdr = (NDIS_TASK_OFFLOAD_HEADER*)pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer; + 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; + } + + pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten = buf_len + + return NDIS_STATUS_SUCCESS; +#endif + UNUSED_PARAM(p_adapter); + UNUSED_PARAM(pNdisRequest); + return NDIS_STATUS_NOT_SUPPORTED; + +} + + +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 ) +{ +#ifndef NDIS60_MINIPORT + 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; +#endif + UNUSED_PARAM(p_adapter); + UNUSED_PARAM(p_info_buf); + UNUSED_PARAM(p_info_len); + return NDIS_STATUS_NOT_SUPPORTED; +} + + +//! 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 ); +//return NDIS_STATUS_SUCCESS; + 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; + + 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->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; +} + +#ifdef NNN +NDIS_STATUS +ipoib_set_info( + ipoib_adapter_t* p_adapter, + IN PNDIS_OID_REQUEST pNdisRequest) +{ + NDIS_STATUS status; + NDIS_OID oid; + UINT info_buf_len; + UINT buf_len; + uint8_t port_num; + PVOID info_buf; + UINT *p_bytes_needed; + KLOCK_QUEUE_HANDLE hdl; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + oid = pNdisRequest->DATA.SET_INFORMATION.Oid; + info_buf = pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer; + info_buf_len = pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength; + p_bytes_needed = &pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded; + status = NDIS_STATUS_SUCCESS; + + buf_len = sizeof(UINT); + 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->p_oid_request = pNdisRequest; + 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, pNdisRequest); + break; + + 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; + + + /* 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, pNdisRequest ); + 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 ) + { + pNdisRequest->DATA.SET_INFORMATION.BytesRead = buf_len; + } + else + { + if( status == NDIS_STATUS_INVALID_LENGTH ) + { + if ( !*p_bytes_needed ) + { + *p_bytes_needed = buf_len; + } + } + + pNdisRequest->DATA.SET_INFORMATION.BytesRead = 0; + } + + IPOIB_EXIT( IPOIB_DBG_OID ); + return status; +} +#endif +static NDIS_STATUS +ipoib_oid_handler( + IN NDIS_HANDLE adapter_context, + IN 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->DATA.SET_INFORMATION.Oid, + pNdisRequest->DATA.SET_INFORMATION.InformationBuffer, + pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength, + (PULONG)&pNdisRequest->DATA.SET_INFORMATION.BytesRead, + (PULONG)&pNdisRequest->DATA.SET_INFORMATION.BytesNeeded); + break; + + case NdisRequestQueryInformation: + case NdisRequestQueryStatistics: + status = ipoib_query_info(adapter_context, + pNdisRequest->DATA.QUERY_INFORMATION.Oid, + pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer, + pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength, + (PULONG)&pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten, + (PULONG)&pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded); + + 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 packet_array Array of packets to send +@param numPackets Number of packets in the array +*/ +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; + p_port = p_adapter->p_port; + + cl_obj_lock( &p_adapter->obj ); + if( p_adapter->ipoib_state == IPOIB_PAUSING || + p_adapter->ipoib_state == IPOIB_PAUSED) + { + status = NDIS_STATUS_PAUSED; + 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 ); + 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 ); + //IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + // ("Starting NET BUFFER LIST \n") ); + for (curr_net_buffer_list = net_buffer_list; + curr_net_buffer_list != NULL; + curr_net_buffer_list = next_net_buffer_list) + { + next_net_buffer_list = NET_BUFFER_LIST_NEXT_NBL(curr_net_buffer_list); + cl_perf_start( PortSend ); + + ipoib_port_send( p_port, curr_net_buffer_list, send_flags); + cl_perf_stop( &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 ); + +compl_status: + if (status != NDIS_STATUS_SUCCESS) + { + //ASSERT(FALSE); //???? + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Got bad status \n") ); + 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) + { + 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 ); + } + + + if (NDIS_TEST_SEND_AT_DISPATCH_LEVEL(send_flags)) + { + NDIS_SET_SEND_COMPLETE_FLAG(send_complete_flags, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); + } + + NdisMSendNetBufferListsComplete( + p_adapter->h_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 ); + } + + 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( adapter_context ); + UNUSED_PARAM( shutdown_action ); + 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, p_net_addr_oid = + (PNETWORK_ADDRESS)((uint8_t *)p_net_addr_oid + + FIELD_OFFSET(NETWORK_ADDRESS, Address) + + p_net_addr_oid->AddressLength) ) + { + + if( p_net_addr_oid->AddressType != NDIS_PROTOCOL_ID_TCP_IP ) + { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong type of 0x%.4X, " + "should be 0x%.4X\n", port_num, i, p_net_addr_oid->AddressType, + NDIS_PROTOCOL_ID_TCP_IP)); + continue; + } + + if( p_net_addr_oid->AddressLength != NETWORK_ADDRESS_LENGTH_IP) + { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_OID, + ("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)); + continue; + } + + 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++, p_net_addr_oid = + (PNETWORK_ADDRESS)((uint8_t *)p_net_addr_oid + + FIELD_OFFSET(NETWORK_ADDRESS, Address) + p_net_addr_oid->AddressLength) ) + { + + if( p_net_addr_oid->AddressType != NDIS_PROTOCOL_ID_TCP_IP ) + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong type of 0x%.4X, " + "should be 0x%.4X\n", port_num, i, p_net_addr_oid->AddressType, + NDIS_PROTOCOL_ID_TCP_IP)); + continue; + } + + if( p_net_addr_oid->AddressLength != NETWORK_ADDRESS_LENGTH_IP) + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("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)); + continue; + } + + 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 = (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); + 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 ); +} + + +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 0 + if( p_adapter && p_adapter->p_port ) + { + ipoib_port_cancel_xmit( p_adapter->p_port, cancel_id ); + } +endif +*/ + + UNUSED_PARAM(adapter_context); + UNUSED_PARAM(cancel_id); + + return; //TODO return this functionality + +} + + +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_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 ); +//return NDIS_STATUS_SUCCESS; + 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 ); + + //TODO: + ipoib_port_resume(p_adapter->p_port,FALSE); +// ASSERT(FALSE); + + 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 + } + + 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-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.h b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.h new file mode 100644 index 00000000..0e3b7f28 --- /dev/null +++ b/branches/WOF2-1/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_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 (8) + +/* 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-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.cpp b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.cpp new file mode 100644 index 00000000..58a2b5c2 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.cpp @@ -0,0 +1,1170 @@ +/* + * 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 "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 +#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_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 for cm 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->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_pkt_array ) + { + //NDIS60 + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_zalloc for 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_pkt_array ) + { + cl_free( p_port->cm_recv_mgr.recv_pkt_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 receive 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_pkt_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; + size_t i; + + 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( i = 0; i < MAX_RECV_WC; i++ ) + wc[i].p_next = &wc[i + 1]; + wc[MAX_RECV_WC - 1].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\n") ); + 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\n") ); + 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-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.h b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.h new file mode 100644 index 00000000..547d4652 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.h @@ -0,0 +1,257 @@ +/* + * 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_pkt_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 ); + /* + * 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 ); + +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-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.cpp b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.cpp new file mode 100644 index 00000000..1e207bca --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.cpp @@ -0,0 +1,693 @@ +/* + * 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 "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 + +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-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.h b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.h new file mode 100644 index 00000000..efcb0a6b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc new file mode 100644 index 00000000..bb7d1c1d --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc @@ -0,0 +1,334 @@ +;/*++ +;============================================================================= +;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. +. + diff --git a/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp new file mode 100644 index 00000000..f6d7a25a --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp @@ -0,0 +1,8119 @@ +/* + * 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 "ipoib_endpoint.h" +#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 + +#include "wdm.h" +#include + + + +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 ); + + +static void __recv_cb_dpc(KDPC *p_gc_dpc,void *context,void *s_arg1, void *s_arg2); + + +/****************************************************************************** +* +* 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 /* 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 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_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. */ +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_pkt( + 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_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 SCATTER_GATHER_LIST *p_sgl, + 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 MDL* p_mdl, + IN size_t buf_len, + IN SCATTER_GATHER_LIST *p_sgl, + 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 MDL* p_mdl, + 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 MDL* p_mdl, + IN size_t buf_len, + IN SCATTER_GATHER_LIST *p_sgl, + 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 MDL* p_mdl, + 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 MDL* p_mdl, + 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, + IN ULONG send_complete_flags ); + +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 ipoib_port_t* const p_port, + IN eth_hdr_t* const p_eth_hdr, + IN MDL* const p_mdl, + IN const size_t mdl_len, + IN SCATTER_GATHER_LIST *p_sgl, + IN OUT ipoib_send_desc_t* const p_desc ); + + +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 OUT ipoib_send_desc_t* const p_desc, + IN ULONG mss, + IN SCATTER_GATHER_LIST *p_sgl, + IN int32_t hdr_idx, + IN PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO p_lso_info ); + +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 ); + +//TODO CM Restore +#if 0 +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 intn_t +__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] ); + 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) ); + //TODO remove + //ASSERT (p_port->obj.ref_cnt < 100); +#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] ); + 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 + 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 + 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 ); + + 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; + + 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; + } + + KeInitializeDpc(&p_port->recv_dpc,(PKDEFERRED_ROUTINE)__recv_cb_dpc,p_port); + + + /* 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 ); + +#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 + ASSERT(FALSE); + //TODO NDIS6.0 + ipoib_port_resume( p_port, FALSE ); + + 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 ); + } + 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; + + 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; + } + + 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; + } + + 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 ) +{ + 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; + + NdisInitializeNPagedLookasideList( &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; + 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, +#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 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'; + + 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; + } +/* + 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 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; + } +/* + 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 ) + 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 ) +{ + //IPOIB_ENTER( IPOIB_DBG_RECV ); + cl_qpool_put_list( &p_port->buf_mgr.recv_pool, p_list ); + //IPOIB_EXIT( IPOIB_DBG_RECV ); +} + + +static inline NET_BUFFER_LIST* +__buf_mgr_get_ndis_pkt( + 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_PACKET( p_net_buffer_list ) = p_port; + IPOIB_RECV_FROM_PACKET( 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 ) +{ + 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 = (NET_BUFFER_LIST **)cl_malloc( + sizeof(NET_BUFFER_LIST*) * 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. + */ +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; +} + +void +ipoib_return_net_buffer_list( + IN NDIS_HANDLE adapter_context, + IN NET_BUFFER_LIST *p_net_buffer_lists, + IN ULONG return_flags) +{ +// cl_list_item_t *p_item; + ipoib_port_t *p_port; + ipoib_recv_desc_t *p_desc; + NET_BUFFER_LIST *cur_net_buffer_list,*next_net_buffer_list; +// ib_api_status_t status = IB_NOT_DONE; +// int32_t shortage; +// ULONG complete_flags = 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 ); + + cl_perf_start( ReturnPacket ); + cl_spinlock_acquire( &p_port->recv_lock ); + for (cur_net_buffer_list = p_net_buffer_lists; + cur_net_buffer_list != NULL; + cur_net_buffer_list = next_net_buffer_list) + { + next_net_buffer_list = NET_BUFFER_LIST_NEXT_NBL(cur_net_buffer_list); + + /* Get the port and descriptor from the packet. */ + CL_ASSERT(p_port == IPOIB_PORT_FROM_PACKET( cur_net_buffer_list )); + p_desc = IPOIB_RECV_FROM_PACKET( cur_net_buffer_list ); + + + //TODO: NDIS60, rewrite this block + /* Get descriptor from the packet. */ +#if 0 + if( p_desc->type == PKT_TYPE_CM_UCAST ) + { + 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 ); + } +#if 0 + /* 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, &cur_net_buffer_list ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnPreparePkt ); + if( status == IB_SUCCESS ) + { + if( shortage > 0 ) + NET_BUFFER_LIST_STATUS( cur_net_buffer_list) = NDIS_STATUS_RESOURCES; + else + NET_BUFFER_LIST_STATUS( cur_net_buffer_list) = NDIS_STATUS_SUCCESS; + + cl_spinlock_release( &p_port->recv_lock ); + NET_BUFFER_LIST_NEXT_NBL(cur_net_buffer_list) = NULL; + cl_perf_start( ReturnNdisIndicate ); + NdisMRecvIndicate( p_port->p_adapter->h_adapter, + cur_net_buffer_list, complete_flags ); + 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, cur_net_buffer_list ); + 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; + } + } + #endif + cl_spinlock_release( &p_port->recv_lock ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnPacket ); + + IPOIB_EXIT( IPOIB_DBG_RECV ); +} + +static void __recv_cb_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); + + + __recv_cb(NULL, p_port); + ipoib_port_deref( p_port, ref_recv_cb ); + + +} + + +static void +__recv_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_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; + ULONG recv_complete_flags = 0; + + 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 ); +//return ; + UNUSED_PARAM( h_cq ); + + 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( 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)); + + /* 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 ); + 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 ); + for( cnt = 0; cnt < pkt_cnt -1; cnt++) + { + NET_BUFFER_LIST_NEXT_NBL(p_port->recv_mgr.recv_pkt_array[cnt]) = + p_port->recv_mgr.recv_pkt_array[cnt + 1]; + } + cl_perf_start( RecvNdisIndicate ); +#ifndef NDIS_DEFAULT_PORT_NUMBER +#define NDIS_DEFAULT_PORT_NUMBER 0 +#endif + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Indicate NDIS with %d received NBs\n", + pkt_cnt) ); + NdisMIndicateReceiveNetBufferLists( + p_port->p_adapter->h_adapter, + p_port->recv_mgr.recv_pkt_array[0], + NDIS_DEFAULT_PORT_NUMBER, + pkt_cnt, + recv_complete_flags); + + 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_desc_t *)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_net_buffer_list( NULL, p_port->recv_mgr.recv_pkt_array[0],recv_complete_flags ); + } + 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. + */ + 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 ); + + ipoib_port_deref( p_port, ref_recv_cb ); + } else { + // Please note the reference is still up + KeInsertQueueDpc(&p_port->recv_dpc, NULL, NULL); + } + + cl_perf_stop( &p_port->p_adapter->perf, RecvCb ); + + IPOIB_EXIT( IPOIB_DBG_RECV ); +} + + +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_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 /* 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) ) + { + 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; + ib_gid_t gid; + 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[4]; + 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. + */ + cl_memcpy( &gid, &p_cid[7], sizeof(ib_gid_t) ); + p_cid[1] = HW_ADDR_LEN +1;// CID length + p_cid[2] = DHCP_HW_TYPE_ETH;// CID type + status = ipoib_mac_from_guid( gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, (mac_addr_t*)&p_cid[3] ); + 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); + status = IB_SUCCESS; + } + p_cid[HW_ADDR_LEN + 3] = DHCP_OPT_END; //terminate tag + } + 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); + } + 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 + * 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 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 NET_BUFFER_LIST** const pp_net_buffer_list ) +{ + NDIS_STATUS status; + uint32_t pkt_filter; + ip_stat_sel_t type; + //NDIS60 + NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO chksum; + //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; + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, + ("Received UCAST PKT.\n")); + } + else + { + type = IP_STAT_DROPPED; + status = NDIS_STATUS_FAILURE; + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, 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. */ + type = IP_STAT_BCAST_BYTES; + status = NDIS_STATUS_SUCCESS; + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, + ("Received BCAST PKT.\n")); + } + else + { + type = IP_STAT_DROPPED; + status = NDIS_STATUS_FAILURE; + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received BCAST PKT with ERROR !!!!\n")); + } + 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; + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, + ("Received UCAST PKT.\n")); + } + else + { + type = IP_STAT_DROPPED; + status = NDIS_STATUS_FAILURE; + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received MCAST PKT with ERROR !!!!\n")); + } + break; + } + + if( status != NDIS_STATUS_SUCCESS ) + { + ipoib_inc_recv_stat( p_port->p_adapter, type, 0, 0 ); + /* Return the receive descriptor to the pool. */ + __buf_mgr_put_recv( p_port, p_desc, NULL ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, 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_net_buffer_list = __buf_mgr_get_ndis_pkt( 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_ndis_pkt 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: + //NDIS60 + //NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) = + //(void*)(uintn_t)chksum.Value; + 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 */ + //NDIS60 + //NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) = + 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 = TRUE; + chksum.Receive.UdpChecksumSucceeded = TRUE; + chksum.Receive.IpChecksumSucceeded = TRUE; + //NDIS60 + //NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) = + NET_BUFFER_LIST_INFO(*pp_net_buffer_list, TcpIpChecksumNetBufferListInfo) = + (void*)(uintn_t)chksum.Value; + break; + } + ipoib_inc_recv_stat( p_port->p_adapter, type, p_desc->len, 1 ); + + 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 ) + { + NET_BUFFER_LIST_STATUS(p_port->recv_mgr.recv_pkt_array[i])= NDIS_STATUS_RESOURCES; + } + else + { + NET_BUFFER_LIST_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; + NET_BUFFER_LIST **pp_net_buffer_list, *p_head; + + p_head = NULL; + cl_spinlock_acquire( &p_port->send_lock ); + /* Complete any pending packets. */ + pp_net_buffer_list = &p_head; + 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 ) ) + { + *pp_net_buffer_list = IPOIB_PACKET_FROM_LIST_ITEM( p_item ); + NET_BUFFER_LIST_STATUS(*pp_net_buffer_list) = NDIS_STATUS_RESET_IN_PROGRESS; + pp_net_buffer_list = &(NET_BUFFER_LIST_NEXT_NBL(*pp_net_buffer_list)); + } + cl_spinlock_release( &p_port->send_lock ); + if(p_head) + NdisMSendNetBufferListsComplete( + p_port->p_adapter->h_adapter, + p_head, + 0); +} + +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 MDL* const p_mdl, + IN size_t buf_len, + IN SCATTER_GATHER_LIST *p_sgl, + 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_mdl, buf_len, p_sgl, 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_mdl, buf_len, p_desc ); + 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( p_port, p_desc, p_sgl, 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 ) +{ + NET_BUFFER_LIST *p_net_buffer_list; + NET_BUFFER *p_netbuffer; + MDL *p_mdl; + UINT tot_len = 0; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + UNREFERENCED_PARAMETER(p_port); + UNREFERENCED_PARAMETER(p_desc); + + p_desc->p_buf = + (send_buf_t *) NdisAllocateFromNPagedLookasideList( &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; + } + + p_mdl = NdisAllocateMdl(p_port->p_adapter->h_adapter, + p_desc->p_buf, + p_port->p_adapter->params.xfer_block_size ); + if( !p_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate MDL\n") ); + return NDIS_STATUS_RESOURCES; + } + + p_net_buffer_list = NdisAllocateNetBufferAndNetBufferList( + p_port->buf_mgr.h_send_buf_pool, + 0, + 0, + p_mdl, + 0, + 0); + + if( !p_net_buffer_list ) + { + NdisFreeMdl(p_mdl); + IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND, + ("Failed to allocate NDIS_PACKET for copy.\n") ); + return NDIS_STATUS_RESOURCES; + } + + for (p_netbuffer = NET_BUFFER_LIST_FIRST_NB(p_net_buffer_list); + p_netbuffer != NULL; + p_netbuffer = NET_BUFFER_NEXT_NB(p_netbuffer)) + { + tot_len +=NET_BUFFER_DATA_LENGTH(p_netbuffer); + } + + /* Setup the work request. */ + p_desc->send_wr[0].local_ds[1].vaddr = cl_get_physaddr( + ((uint8_t*)p_desc->p_buf) + sizeof(eth_hdr_t) ); + p_desc->send_wr[0].local_ds[1].length = tot_len - sizeof(eth_hdr_t); + p_desc->send_wr[0].local_ds[1].lkey = p_port->ib_mgr.lkey; + p_desc->send_wr[0].wr.num_ds = 2; + + /* Free our temp packet now that the data is copied. */ + NdisFreeMdl(p_mdl); + NdisFreeNetBufferList(p_net_buffer_list); + + 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; + } + + 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 + NET_BUFFER_CURRENT_MDL_OFFSET(p_net_buffer)); + + 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 + +#if 0 +void +ipoib_process_sg_list1( + IN PDEVICE_OBJECT pDO, + IN PVOID pIrp, + IN PSCATTER_GATHER_LIST p_sgl, + IN PVOID context + ) +{ + int i; + char temp[200]; + for (i = 0 ; i < 1;i++) + temp[i] = 5; +} +#endif + +void +ipoib_process_sg_list( + 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; + static ipoib_send_desc_t *p_desc = NULL; + 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_ENTER( IPOIB_DBG_SEND ); + + 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 ); + + + p_netbuf = (NET_BUFFER*)context; + p_net_buffer_list = (NET_BUFFER_LIST*)IPOIB_NET_BUFFER_LIST_FROM_NETBUFFER(p_netbuf); + p_port = (ipoib_port_t*)IPOIB_PORT_FROM_PACKET(p_net_buffer_list); + NDIS_SET_SEND_COMPLETE_FLAG(complete_flags, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); + + + cl_spinlock_acquire( &p_port->send_lock ); + if (p_desc == NULL) { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_SEND, ("Allocating send_desc First Time\n") ); + p_desc = + (ipoib_send_desc_t *)ExAllocatePoolWithTag(NonPagedPool ,sizeof (ipoib_send_desc_t), 'XMXA'); + } + ASSERT(p_desc); + p_desc->p_netbuf_list = p_net_buffer_list; + p_desc->p_endpt = NULL; + p_desc->p_buf = NULL; + p_desc->num_wrs = 1; + + //IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND, + // ("\n*******\nRECEIVED NB= %x with SG= %x\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 list */ + __process_failed_send( p_port, p_desc, status, complete_flags); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + goto send_end; + } + //from_queue = (boolean_t)(IPOIB_FROM_QUEUE(p_netbuf) == (void*)1); + from_queue = (boolean_t)(IPOIB_FROM_QUEUE(p_netbuf) != NULL); + if (from_queue) + { + cl_perf_start( GetEndpt ); + status = __endpt_mgr_ref( p_port, p_eth_hdr->dst, &p_desc->p_endpt ); + cl_perf_stop( &p_port->p_adapter->perf, GetEndpt ); + if( status == NDIS_STATUS_PENDING ) + { + IPOIB_FROM_QUEUE(p_netbuf) = p_sgl; + cl_qlist_insert_head( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET( p_desc->p_netbuf_list ) ); + 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 ) ) + { + 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") ); + IPOIB_FROM_QUEUE(p_netbuf) = p_sgl; + cl_qlist_insert_head( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET( p_desc->p_netbuf_list ) ); + goto send_end; + } + } + /* + * 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, p_desc, NDIS_STATUS_SUCCESS,complete_flags ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + goto send_end; + } + } + else + { + 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; + + 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: + status = __send_mgr_queue( p_port, p_eth_hdr, &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 ); + NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL; + IPOIB_FROM_QUEUE(p_netbuf) = p_sgl; + cl_qlist_insert_tail( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET(p_net_buffer_list) ); + cl_perf_stop( &p_port->p_adapter->perf, QueuePacket ); + 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. + */ + cl_perf_start( ProcessFailedSends ); + __process_failed_send( p_port, p_desc, NDIS_STATUS_SUCCESS, complete_flags ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + goto send_end; + } + } + cl_perf_start( BuildSendDesc ); + status = __build_send_desc( p_port, p_eth_hdr, p_mdl, mdl_len, p_sgl, p_desc ); + cl_perf_stop( &p_port->p_adapter->perf, BuildSendDesc ); + + if( status != NDIS_STATUS_SUCCESS ) + { + cl_perf_start( ProcessFailedSends ); + __process_failed_send( p_port, p_desc, status, complete_flags ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + goto send_end; + } + + /* Post the WR. */ + cl_perf_start( PostSend ); + cl_msg_out("sending packet with wr-id =0x%x\n",&p_desc->send_wr[0].wr.wr_id ); + ib_status = p_port->p_adapter->p_ifc->post_send( p_port->ib_mgr.h_qp, &p_desc->send_wr[0].wr, &p_wr_failed ); + 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, p_desc, NDIS_STATUS_FAILURE, complete_flags ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + /* Flag the adapter as hung since posting is busted. */ + p_port->p_adapter->hung = TRUE; + } + cl_atomic_inc( &p_port->send_mgr.depth ); + +send_end: + if (status != NDIS_STATUS_SUCCESS) { +// IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_SEND, + // ("Free S/G List: 0x%x.\n", (UINT) (PVOID) p_sgl) ); + /*NdisMFreeNetBufferSGList( + p_port->p_adapter->NdisMiniportDmaHandle, + p_sgl, + p_netbuf);*/ + + } + + + cl_spinlock_release( &p_port->send_lock ); + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + +static NDIS_STATUS +__send_gen( + IN ipoib_port_t* const p_port, + IN ipoib_send_desc_t* const p_desc, + IN SCATTER_GATHER_LIST *p_sgl, + IN INT lso_data_index + ) +{ + NDIS_STATUS status; + uint32_t i, j = 1; + uint32_t offset = sizeof(eth_hdr_t); + PERF_DECLARE( SendCopy ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + 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)) ) + { + + 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 ) ); + status = NDIS_STATUS_RESOURCES; + if( !p_port->p_adapter->params.cm_enabled ) + { + 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->send_wr[0].local_ds[j].vaddr = + p_sgl->Elements[i].Address.QuadPart + offset; + p_desc->send_wr[0].local_ds[j].length = + p_sgl->Elements[i].Length - offset; + p_desc->send_wr[0].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->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 = 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 ipoib_port_t* const p_port, + IN const eth_hdr_t* const p_eth_hdr, + IN MDL* p_mdl, + IN size_t buf_len, + IN SCATTER_GATHER_LIST *p_sgl, + IN OUT ipoib_send_desc_t* const p_desc ) +{ + 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 ); + + 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_port, p_ip_hdr, p_mdl, (buf_len - sizeof(ip_hdr_t)), p_sgl, p_desc ); + 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( 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( !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 > 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 + ASSERT(FALSE); + } + } + +send_gen: + cl_perf_start( SendTcp ); + status = __send_gen( p_port, p_desc, p_sgl, 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, + ("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 MDL* p_mdl, + IN size_t buf_len, + IN SCATTER_GATHER_LIST *p_sgl, + IN OUT ipoib_send_desc_t* const p_desc ) +{ + NDIS_STATUS status; + udp_hdr_t *p_udp_hdr; + PERF_DECLARE( QueryUdp ); + PERF_DECLARE( SendUdp ); + PERF_DECLARE( FilterDhcp ); + //TODO NDIS60 remove this param + UNUSED_PARAM(p_sgl); + 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( &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. */ + 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_mdl, 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_mdl, + 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 ) + { + 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 = &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 + { + 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 */ + //if( !p_port->p_adapter->params.send_chksum_offload ) + //{ //TODO ? + 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)); + //} TODO ?? + 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->send_wr[0].local_ds[1].vaddr = cl_get_physaddr( p_desc->p_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 = 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 ipoib_port_t* const p_port, + IN const eth_hdr_t* const p_eth_hdr, + IN MDL* p_mdl, + 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 ) + { + 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. */ + p_desc->p_buf = (send_buf_t*) + NdisAllocateFromNPagedLookasideList( &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; + + ipoib_addr_set_qpn( &p_ib_arp->src_hw, 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, + 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( 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, p_desc->p_buf ); + cl_qlist_insert_tail( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET( p_desc->p_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, p_desc->p_buf ); + cl_qlist_insert_tail( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET( p_desc->p_pkt ) ); + 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 = 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. */ + 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 MDL* const p_mdl, + IN const size_t mdl_len, + IN SCATTER_GATHER_LIST *p_sgl, + IN OUT ipoib_send_desc_t* const p_desc ) +{ + NDIS_STATUS status; + int32_t hdr_idx; + uint32_t mss = 0; + + PNDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO p_checksum_list_info; + PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO p_lso_info; + PERF_DECLARE( SendMgrFilter ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + /* Format the send descriptor. */ + p_checksum_list_info = + (PNDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO) NET_BUFFER_LIST_INFO( p_desc->p_netbuf_list,TcpIpChecksumNetBufferListInfo); + + // Calculate LSO + if( p_port->p_adapter->params.lso ) { + p_lso_info = + (PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO) + NET_BUFFER_LIST_INFO( p_desc->p_netbuf_list, TcpLargeSendNetBufferListInfo ); + ASSERT(p_lso_info); + if (p_lso_info) { + mss = (p_lso_info->LsoV1Transmit.MSS | p_lso_info->LsoV2Transmit.MSS); + } + } + + /* 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; + + p_desc->send_wr[0].local_ds[0].vaddr = cl_get_physaddr( &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 = p_port->ib_mgr.lkey; + p_desc->send_wr[0].wr.send_opt = 0; + + + + if (mss) { //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( p_port, p_desc, mss, p_sgl, hdr_idx, p_lso_info ); + 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_port, p_eth_hdr, p_mdl, mdl_len,p_sgl, 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; + } + + if( p_desc->send_dir == SEND_UD_QP ) + { + p_desc->send_qp = 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 = 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 = p_port->pkey_index; + p_desc->send_wr[i].wr.dgrm.ud.rsvd = NULL; + p_desc->send_wr[i].wr.send_opt = 0; + + if( p_port->p_adapter->params.send_chksum_offload && + ( 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_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; + } + } + //TODO p_net_buf or p_buf +// p_desc->send_wr[p_desc->num_wrs - 1].wr.wr_id = (uintn_t)NET_BUFFER_LIST_FIRST_NB(p_desc->p_netbuf_list ); +//???? IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, ("WR_ID was set to NBL 0x%x \n",p_desc->p_netbuf_list )); + p_desc->send_wr[p_desc->num_wrs - 1].wr.wr_id = (uintn_t)p_desc->p_netbuf_list ; + + 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; + } + + /* Store context in our reserved area of the packet. */ + IPOIB_PORT_FROM_PACKET( p_desc->p_netbuf_list ) = p_port; + IPOIB_ENDPT_FROM_PACKET( p_desc->p_netbuf_list ) = p_desc->p_endpt; + IPOIB_SEND_FROM_NETBUFFER( NET_BUFFER_LIST_FIRST_NB(p_desc->p_netbuf_list ))= p_desc->p_buf; + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} + +static NDIS_STATUS +__build_lso_desc( + IN ipoib_port_t* const p_port, + IN OUT ipoib_send_desc_t* const p_desc, + IN ULONG mss, + IN SCATTER_GATHER_LIST *p_sgl, + IN int32_t hdr_idx, + IN PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO p_lso_info) +{ + NDIS_STATUS status; + LsoData TheLsoData; + UINT IndexOfData = 0; + + PNET_BUFFER FirstBuffer = NET_BUFFER_LIST_FIRST_NB (p_desc->p_netbuf_list); + ULONG PacketLength = NET_BUFFER_DATA_LENGTH(FirstBuffer); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + + + 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; + + 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; + + //TODO: Should be NBL or p_desc + p_desc->send_wr[0].wr.wr_id = (uintn_t)p_desc->p_netbuf_list; + 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(p_port, p_desc, p_sgl, IndexOfData ); + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; +} + +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, + IN ULONG compl_flags) +{ + IPOIB_ENTER( IPOIB_DBG_SEND ); + + /* Complete the packet. */ + NET_BUFFER_LIST_NEXT_NBL(p_desc->p_netbuf_list) = NULL; + NET_BUFFER_LIST_STATUS(p_desc->p_netbuf_list) = status; + NdisMSendNetBufferListsComplete( p_port->p_adapter->h_adapter, + p_desc->p_netbuf_list, compl_flags ); + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_ERROR, 0 ); + /* Deref the endpoint. */ + if( p_desc->p_endpt ) + ipoib_endpt_deref( p_desc->p_endpt ); + + if( p_desc->p_buf ) + { + NdisFreeToNPagedLookasideList( + &p_port->buf_mgr.send_buf_list, p_desc->p_buf ); + } + + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + +// 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 + ) +{ +// ETH_ENTER(ETH_SND); + + 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); + + +// ETH_PRINT(TRACE_LEVEL_VERBOSE, ETH_SND, "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) ); + +// ETH_PRINT(TRACE_LEVEL_VERBOSE, ETH_SND, "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; + } + +// ETH_PRINT(TRACE_LEVEL_VERBOSE, ETH_SND, "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; + } + +// ETH_PRINT(TRACE_LEVEL_VERBOSE, ETH_SND, "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; +// ETH_PRINT(TRACE_LEVEL_ERROR, ETH_SND, "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 + +// ETH_EXIT(ETH_SND); +} + + + + +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; + UINT buf_cnt = 0; + //ipoib_send_desc_t *p_desc; + ULONG send_complete_flags = 0; + KIRQL old_irql; + PVOID p_sgl; + + 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); + NDIS_SET_SEND_COMPLETE_FLAG(send_complete_flags, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); + } else { + //ASSERT (KeGetCurrentIRQL() == PASSIVE_LEVEL); + } + + cl_obj_lock( &p_port->obj ); + if( p_port->state != IB_QPS_RTS ) + { + + + cl_obj_unlock( &p_port->obj ); + + + NET_BUFFER_LIST_STATUS(p_net_buffer_list) = NDIS_STATUS_FAILURE; + NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL; + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_DROPPED, 0 ); + + NdisMSendNetBufferListsComplete( + p_port->p_adapter->h_adapter, + p_net_buffer_list, + send_complete_flags); + + return; + } + cl_obj_unlock( &p_port->obj ); + + //IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + // ("Processing netbuffer list: %x\n", p_net_buffer_list)); + for (p_netbuf = NET_BUFFER_LIST_FIRST_NB(p_net_buffer_list); + p_netbuf != NULL; + p_netbuf = NET_BUFFER_NEXT_NB(p_netbuf)) + { + IPOIB_PORT_FROM_PACKET(p_net_buffer_list) = p_port; + IPOIB_NET_BUFFER_LIST_FROM_NETBUFFER(p_netbuf) = p_net_buffer_list; + IPOIB_FROM_QUEUE(p_netbuf) = NULL; + /*p_desc = &p_port->send_mgr.desc; + p_desc->p_buf = p_netbuf; + p_desc->p_endpt = NULL; + p_desc->p_buf = NULL; + p_desc->send_qp = NULL; + p_desc->num_wrs = 1; + p_desc->send_dir = 0;*/ + + old_irql = KeGetCurrentIrql(); + if (old_irql < DISPATCH_LEVEL) + { + KeRaiseIrqlToDpcLevel(); + } + ++buf_cnt; + //IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + // ("[%d] Netbuf = %x\n",buf_cnt, p_netbuf) ); + if (cl_is_item_in_qlist( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET( p_net_buffer_list ))) { + p_sgl = IPOIB_FROM_QUEUE(p_netbuf); + //IPOIB_FROM_QUEUE(p_net_buffer) = (void*)1; + ASSERT (p_sgl); + //IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + // ("[%d] FROM_QUEUE Netbuf = %x, found SGL = %x\n",buf_cnt, p_netbuf, p_sgl) ); + status = NDIS_STATUS_SUCCESS; + } else { + +//#if 0 + CHAR *pTemp = (CHAR *) ExAllocatePoolWithTag(NonPagedPool , p_port->p_adapter->sg_list_size, 'abcd'); + CL_ASSERT(pTemp != NULL); + status = NDIS_STATUS_SUCCESS; + 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; +//#endif +#if 0 + status = NdisMAllocateNetBufferSGList( + p_port->p_adapter->NdisMiniportDmaHandle, + p_netbuf, + p_netbuf, + NDIS_SG_LIST_WRITE_TO_DEVICE, + NULL, + 0); +#endif + } + KeLowerIrql (old_irql); + + if( status != NDIS_STATUS_SUCCESS ) + { + /* fail net buffer list */ + NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL; + NET_BUFFER_LIST_STATUS(p_net_buffer_list) = NDIS_STATUS_RESOURCES; + NdisMSendNetBufferListsComplete( + p_port->p_adapter->h_adapter, + p_net_buffer_list, + send_complete_flags); + break; + } + ASSERT(buf_cnt); + IPOIB_GET_NET_BUFFER_LIST_REF_COUNT(p_net_buffer_list) = (PVOID)(ULONG_PTR)buf_cnt; + } + +} + + +void +ipoib_port_resume( + IN ipoib_port_t* const p_port, + IN boolean_t b_pending ) +{ + NDIS_STATUS status; + cl_list_item_t *p_item; + NET_BUFFER *p_net_buffer; + NET_BUFFER_LIST *p_net_buffer_list; + //ipoib_send_desc_t *p_desc; + KIRQL old_irql; + UINT buf_cnt = 0; + NET_BUFFER_LIST *p_prev_nbl = NULL; + PVOID p_sgl; + static PVOID p_prev_sgl = NULL; + + PERF_DECLARE( GetEndpt ); + PERF_DECLARE( BuildSendDesc ); + PERF_DECLARE( ProcessFailedSends ); + PERF_DECLARE( PostSend ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + UNUSED_PARAM(b_pending); + + 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 ); + +//TODO NDIS60 +////?????????????? 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; + } + + p_net_buffer_list = IPOIB_PACKET_FROM_LIST_ITEM( + cl_qlist_remove_head( &p_port->send_mgr.pending_list ) ); + if (p_prev_nbl == p_net_buffer_list) { +// IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + // ("TRYING TO PROCESS ONCE AGAIN, EXITING: %x\n", p_net_buffer_list)); + break; //TODO more sophisticated mechanism to avoid starvation + } + old_irql = KeGetCurrentIrql(); + if (old_irql < DISPATCH_LEVEL) + { + KeRaiseIrqlToDpcLevel(); + } +// IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + // ("Processing netbuffer list from queue: %x\n", (UINT) (PVOID) p_net_buffer_list)); + + for( p_net_buffer = NET_BUFFER_LIST_FIRST_NB(p_net_buffer_list); + p_net_buffer != NULL; + p_net_buffer = NET_BUFFER_NEXT_NB(p_net_buffer), buf_cnt++) + { + + + p_sgl = IPOIB_FROM_QUEUE(p_net_buffer); + //IPOIB_FROM_QUEUE(p_net_buffer) = (void*)1; + ASSERT (p_sgl); + IPOIB_PORT_FROM_PACKET(p_net_buffer_list) = p_port; + IPOIB_NET_BUFFER_LIST_FROM_NETBUFFER(p_net_buffer) = p_net_buffer_list; + /*p_desc = &p_port->send_mgr.desc; + p_desc->p_buf = p_net_buffer; + p_desc->p_endpt = NULL; + p_desc->p_buf = NULL; + p_desc->send_qp = NULL; + p_desc->num_wrs = 1; + p_desc->send_dir = 0;*/ + +// IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + // ("[%d] Netbuf = %x, p_sgl = %x\n",buf_cnt, p_net_buffer, p_sgl) ); + ASSERT(p_sgl); + if (p_sgl != (void*) 1) { + ipoib_process_sg_list(NULL, NULL, (PSCATTER_GATHER_LIST) p_sgl, p_net_buffer); + status = NDIS_STATUS_SUCCESS; + } + else { + ASSERT(FALSE); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Getting strange flow\n") ); + NdisMFreeNetBufferSGList( + p_port->p_adapter->NdisMiniportDmaHandle, + (PSCATTER_GATHER_LIST)p_sgl, + p_net_buffer ); + status = NdisMAllocateNetBufferSGList( + p_port->p_adapter->NdisMiniportDmaHandle, + p_net_buffer, + p_net_buffer, + NDIS_SG_LIST_WRITE_TO_DEVICE, + NULL, + 0 /*p_port->p_adapter->sg_list_size*/ ); + } + p_prev_sgl = p_sgl; + if( status != NDIS_STATUS_SUCCESS ) + { + /* fail net buffer list */ + NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL; + NET_BUFFER_LIST_STATUS(p_net_buffer_list) = NDIS_STATUS_RESOURCES; + NdisMSendNetBufferListsComplete( + p_port->p_adapter->h_adapter, + p_net_buffer_list, + 0); + break; + } + } + + KeLowerIrql (old_irql); + + + p_prev_nbl = p_net_buffer_list; + + } + 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; + NET_BUFFER_LIST *p_nbl; + uint32_t length; + ipoib_endpt_t *p_endpt; + send_buf_t *p_send_buf; + ip_stat_sel_t type; + size_t i; + NET_BUFFER *p_netbuffer = NULL; + + 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_nbl = (NET_BUFFER_LIST*)(uintn_t)p_wc->wr_id; + //IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_SEND, + //("[1]Successfull send completion for NBL=0x%x .\n", (UINT) (PVOID) p_nbl )); + CL_ASSERT( p_nbl ); + CL_ASSERT( IPOIB_PORT_FROM_PACKET( p_nbl ) == p_port ); + length = 0; + p_endpt = IPOIB_ENDPT_FROM_PACKET( p_nbl ); + p_send_buf = IPOIB_SEND_FROM_NETBUFFER( NET_BUFFER_LIST_FIRST_NB (p_nbl )); + + 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; + } + for (p_netbuffer = NET_BUFFER_LIST_FIRST_NB(p_nbl); + p_netbuffer != NULL; + p_netbuffer = NET_BUFFER_NEXT_NB(p_netbuffer)) + { + length += NET_BUFFER_DATA_LENGTH(p_netbuffer); + } + ipoib_inc_send_stat( p_port->p_adapter, type, length ); + // IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_SEND, + //("Successfull send completion for NBL=0x%x .\n", (UINT) (PVOID) p_nbl) ); + NET_BUFFER_LIST_STATUS(p_nbl) = NDIS_STATUS_SUCCESS; + IPOIB_DEC_NET_BUFFER_LIST_REF_COUNT(p_nbl); + if (IPOIB_GET_NET_BUFFER_LIST_REF_COUNT(p_nbl) == 0) + NdisMSendNetBufferListsComplete(p_port->p_adapter->h_adapter, + p_nbl, + 0); + 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 ); + NET_BUFFER_LIST_STATUS(p_nbl) = NDIS_STATUS_RESET_IN_PROGRESS; + NdisMSendNetBufferListsComplete(p_port->p_adapter->h_adapter, + p_nbl, + 0); + 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 ); + NET_BUFFER_LIST_STATUS(p_nbl) = NDIS_STATUS_FAILURE; + NdisMSendNetBufferListsComplete(p_port->p_adapter->h_adapter, + p_nbl, + 0); + 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 ); + NdisFreeToNPagedLookasideList( &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, TRUE ); + 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 ); +} + +//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_EXIT( 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 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 = IPOIB_MEDIA_MAX_SPEED; + + 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 ); + cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts, + &p_port->p_local_endpt->lid_item ); + + 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 ); + + //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 *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; + //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 ); + } + + cl_obj_unlock( &p_port->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) ); + + 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_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; + } +#if 0 //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_EXIT( 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 ); + + 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 , FALSE); + + 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 ); +} + +/*++ +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); + //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; + } + //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)); + 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_VERBOSE, 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; + PNET_BUFFER_LIST p_nbl; + PVOID nbl_id; + cl_qlist_t cancel_list; + ULONG send_complete_flags = 0; + IPOIB_ENTER( IPOIB_DBG_SEND ); + + cl_qlist_init( &cancel_list ); + + 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_next( p_item ) ) + { + p_nbl = IPOIB_PACKET_FROM_LIST_ITEM( p_item ); + nbl_id = NDIS_GET_NET_BUFFER_LIST_CANCEL_ID( p_nbl ); + if( nbl_id == cancel_id ) + { + cl_qlist_remove_item( &p_port->send_mgr.pending_list, p_item ); + NET_BUFFER_LIST_STATUS( p_nbl) = NDIS_STATUS_REQUEST_ABORTED ; + cl_qlist_insert_tail( &cancel_list, IPOIB_LIST_ITEM_FROM_PACKET( p_nbl ) ); + } + } + 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 )) + { + p_nbl = IPOIB_PACKET_FROM_LIST_ITEM( p_item ); + NET_BUFFER_LIST_STATUS( p_nbl) = NDIS_STATUS_SEND_ABORTED; + send_complete_flags = 0; + if (NDIS_CURRENT_IRQL() == DISPATCH_LEVEL) + { + NDIS_SET_SEND_COMPLETE_FLAG(send_complete_flags, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); + } + NdisMSendNetBufferListsComplete( p_port->p_adapter->h_adapter, + p_nbl, send_complete_flags ); + } + } + 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; + } + p_desc->p_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-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h new file mode 100644 index 00000000..30090dc0 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h @@ -0,0 +1,829 @@ +/* + * 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 + + +#define IPOIB_PORT_FROM_PACKET( P ) \ + (((ipoib_port_t**)NET_BUFFER_LIST_MINIPORT_RESERVED(P))[0]) +#define IPOIB_ENDPT_FROM_PACKET( P ) \ + (((ipoib_endpt_t**)NET_BUFFER_LIST_MINIPORT_RESERVED(P))[1]) +#define IPOIB_RECV_FROM_PACKET( P ) \ + (((ipoib_recv_desc_t**)NET_BUFFER_LIST_MINIPORT_RESERVED(P))[1]) + +//TODO to be renamed: IPOIB_NBL_FROM_LIST_ITEM +#define IPOIB_PACKET_FROM_LIST_ITEM( I ) \ + (PARENT_STRUCT( I, NET_BUFFER_LIST, MiniportReserved )) +#define IPOIB_LIST_ITEM_FROM_PACKET( P ) \ + ((cl_list_item_t*)NET_BUFFER_LIST_MINIPORT_RESERVED(P)) + +#define IPOIB_NET_BUFFER_LIST_FROM_NETBUFFER( P ) \ + (((NET_BUFFER_LIST**)NET_BUFFER_MINIPORT_RESERVED(P))[0]) +#define IPOIB_FROM_QUEUE( P ) \ + (((void**)NET_BUFFER_MINIPORT_RESERVED(P))[1]) +#define IPOIB_SEND_FROM_NETBUFFER( P ) \ + (((send_buf_t**)NET_BUFFER_MINIPORT_RESERVED(P))[2]) + + +#define IPOIB_GET_NET_BUFFER_LIST_REF_COUNT(_NetBufferList) ((NET_BUFFER_LIST_FIRST_NB(_NetBufferList))->MiniportReserved[3]) +#define IPOIB_DEC_NET_BUFFER_LIST_REF_COUNT(_NetBufferList) (*(PULONG)&(NET_BUFFER_LIST_FIRST_NB(_NetBufferList))->MiniportReserved[3])-- + + +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_UD_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, + 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; + 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_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_desc_t desc; + +} 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; + + KDPC recv_dpc; + + 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; + 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; + +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; + } +} +#endif /* _IPOIB_PORT_H_ */ diff --git a/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.cpp b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.cpp new file mode 100644 index 00000000..ce0650f1 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.cpp @@ -0,0 +1,74 @@ +/* + * 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}, + + {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}, + {0x30, 0x48, 0xE7}, + {0x80, 0x5F, 0xE7}, + + {0x00, 0x00, 0x00}, +}; + diff --git a/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.h b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.h new file mode 100644 index 00000000..9e38b609 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib_NDIS6_CM/kernel/makefile b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/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-1/ulp/ipoib_NDIS6_CM/kernel/makefile.inc b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/makefile.inc new file mode 100644 index 00000000..4f29f500 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/ipoib_NDIS6_CM/kernel/netipoib.inx b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/netipoib.inx new file mode 100644 index 00000000..ca3126b5 --- /dev/null +++ b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/netipoib.inx @@ -0,0 +1,295 @@ +; 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 = %MTL% +DriverVer=06/11/2008,1.0.0000.1207 +CatalogFile=ipoib.cat + +[Manufacturer] +%MTL% = MTL,ntx86,ntamd64,ntia64 + +[ControlFlags] +ExcludeFromSelect = IBA\IPoIB + +[MTL] +; empty since we don't support W9x/Me + +[MTL.ntx86] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[MTL.ntamd64] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[MTL.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 = NdCopyFiles +CopyFiles = WOW64CopyFiles +*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 +ndinstall.exe,,,0x00000002 + +[WOW64CopyFiles] +ibwsd.dll,ibwsd32.dll,,0x00000002 +ibndprov.dll,ibndprov32.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 +ndinstall.exe = 1 + +[SourceDisksFiles.amd64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +ibndprov.dll = 1 +ibndprov32.dll = 1 +ndinstall.exe = 1 + +[SourceDisksFiles.ia64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +ibndprov.dll = 1 +ibndprov32.dll = 1 +ndinstall.exe = 1 + +[DestinationDirs] +IpoibCopyFiles = %DIRID_DRIVERS% +WsdCopyFiles = %DIRID_SYSTEM% +NdCopyFiles = %DIRID_SYSTEM% +WOW64CopyFiles = %DIRID_SYSTEM_X86% +DefaultDestDir = %DIRID_SYSTEM% + +[Strings] +OPENIB = "OpenFabrics Alliance" +MTL = "Mellanox Technologies Ltd." +IpoibDesc = "Mellanox IPoIB Adapter" +IpoibDescP = "Mellanox IPoIB Adapter Partition" +IpoibServiceDispName = "IPoIB" +IcsDisk1 = "Mellanox 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" \ No newline at end of file diff --git a/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/offload.h b/branches/WOF2-1/ulp/ipoib_NDIS6_CM/kernel/offload.h new file mode 100644 index 00000000..de696c6a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibmad/README.txt b/branches/WOF2-1/ulp/libibmad/README.txt new file mode 100644 index 00000000..7c82b7e7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibmad/dirs b/branches/WOF2-1/ulp/libibmad/dirs new file mode 100644 index 00000000..b1cbe453 --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/dirs @@ -0,0 +1,2 @@ +DIRS = \ + src \ No newline at end of file diff --git a/branches/WOF2-1/ulp/libibmad/include/infiniband/mad.h b/branches/WOF2-1/ulp/libibmad/include/infiniband/mad.h new file mode 100644 index 00000000..aa27eb59 --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/include/infiniband/mad.h @@ -0,0 +1,986 @@ +/* + * Copyright (c) 2004-2007 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 _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_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_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_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_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_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, + + 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, + + 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, + + 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, +}; + +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); +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); + +/* 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_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_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(stdout, "ibwarn: [%d] %s: " fmt "\n", getpid(), __func__, ## __VA_ARGS__) + +/** printf style abort MACRO, includes name of function and pid */ +#define IBPANIC(fmt, ...) do { \ + fprintf(stdout, "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-1/ulp/libibmad/include/infiniband/mad_osd.h b/branches/WOF2-1/ulp/libibmad/include/infiniband/mad_osd.h new file mode 100644 index 00000000..dff3a79e --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/include/infiniband/mad_osd.h @@ -0,0 +1,69 @@ +/* + * 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" + +#define MAD_EXPORT __declspec(dllexport) + +#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-1/ulp/libibmad/src/Sources b/branches/WOF2-1/ulp/libibmad/src/Sources new file mode 100644 index 00000000..3eeca40c --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/Sources @@ -0,0 +1,54 @@ +!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;\ + ..\..\libibverbs\include;\ + ..\..\libibumad\include;\ + ..\..\..\inc;\ + ..\..\..\inc\user;\ + ..\..\..\inc\user\linux; + +USER_C_FLAGS = $(USER_C_FLAGS) -DEXPORT_IBMAD_SYMBOLS + +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-1/ulp/libibmad/src/bm.c b/branches/WOF2-1/ulp/libibmad/src/bm.c new file mode 100644 index 00000000..e335d927 --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/bm.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#include + +#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; + char data_with_bkey[IB_BM_BKEY_AND_DATA_SZ] = { 0 }; + + DEBUG("route %s data %p", portid2str(portid), data); + if (portid->lid <= 0) { + IBWARN("only lid routes are supported"); + return 0; + } + + 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 + *((uint64_t *) data_with_bkey) = htonll(call->bkey); + memcpy(data_with_bkey + IB_BM_DATA_OFFS - IB_BM_BKEY_OFFS, 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, data_with_bkey, data_with_bkey)) + goto return_ok; + return NULL; + } + + if (mad_send_via(&rpc, portid, 0, data_with_bkey, srcport) < 0) + return NULL; + +return_ok: + memcpy(data, data_with_bkey + IB_BM_DATA_OFFS - IB_BM_BKEY_OFFS, + IB_BM_DATA_SZ); + return data; +} diff --git a/branches/WOF2-1/ulp/libibmad/src/dump.c b/branches/WOF2-1/ulp/libibmad/src/dump.c new file mode 100644 index 00000000..051c7083 --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/dump.c @@ -0,0 +1,746 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include + +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 (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_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 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-1/ulp/libibmad/src/fields.c b/branches/WOF2-1/ulp/libibmad/src/fields.c new file mode 100644 index 00000000..129f7e5d --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/fields.c @@ -0,0 +1,697 @@ +/* + * Copyright (c) 2004-2007 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 + +/* + * 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(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}, + {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}, + + {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 */ + + {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 */ + + {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 0; /* buf too small */ + + if (!name) + name = f->name; + + l = strlen(name); + if (l < 32) { + memset(dots, '.', 32 - l); + dots[32 - l] = 0; + } + + n = snprintf(buf, bufsz, "%s:%s", name, dots); + _mad_dump_val(f, buf + n, bufsz - n, val); + buf[bufsz - 1] = 0; + + return buf; +} + +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 0; + 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 0; + 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-1/ulp/libibmad/src/gs.c b/branches/WOF2-1/ulp/libibmad/src/gs.c new file mode 100644 index 00000000..f3d245e6 --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/gs.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include + +#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 0; + } + + rpc.mgtclass = IB_PERFORMANCE_CLASS; + rpc.method = IB_MAD_METHOD_GET; + rpc.attr.id = id; + + /* Same for attribute IDs */ + mad_set_field(rcvbuf, 0, IB_PC_PORT_SELECT_F, port); + rpc.attr.mod = 0; + rpc.timeout = timeout; + rpc.datasz = IB_PC_DATA_SZ; + rpc.dataoffs = IB_PC_DATA_OFFS; + + dest->qp = 1; + if (!dest->qkey) + dest->qkey = IB_DEFAULT_QP1_QKEY; + + 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 0; + } + + if (!mask) + mask = ~0; + + rpc.mgtclass = IB_PERFORMANCE_CLASS; + rpc.method = IB_MAD_METHOD_SET; + rpc.attr.id = id; + + memset(rcvbuf, 0, IB_MAD_SIZE); + + /* Same for attribute IDs */ + mad_set_field(rcvbuf, 0, IB_PC_PORT_SELECT_F, port); + mad_set_field(rcvbuf, 0, IB_PC_COUNTER_SELECT_F, mask); + 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; + 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-1/ulp/libibmad/src/ibmad.rc b/branches/WOF2-1/ulp/libibmad/src/ibmad.rc new file mode 100644 index 00000000..d4491108 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibmad/src/ibmad_export.def b/branches/WOF2-1/ulp/libibmad/src/ibmad_export.def new file mode 100644 index 00000000..4a7e62ea --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibmad/src/ibmad_exports.src b/branches/WOF2-1/ulp/libibmad/src/ibmad_exports.src new file mode 100644 index 00000000..00e1b449 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibmad/src/ibmad_main.cpp b/branches/WOF2-1/ulp/libibmad/src/ibmad_main.cpp new file mode 100644 index 00000000..d95ba153 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibmad/src/libibmad.map b/branches/WOF2-1/ulp/libibmad/src/libibmad.map new file mode 100644 index 00000000..7b49a4d8 --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/libibmad.map @@ -0,0 +1,107 @@ +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_perfcounters; + mad_dump_perfcounters_ext; + mad_dump_perfcounters_xmt_sl; + mad_dump_perfcounters_rcv_sl; + mad_dump_physportstate; + mad_dump_portcapmask; + mad_dump_portinfo; + mad_dump_portstates; + mad_dump_portstate; + mad_dump_rhex; + mad_dump_sltovl; + mad_dump_string; + mad_dump_switchinfo; + mad_dump_uint; + mad_dump_vlarbitration; + mad_dump_vlcap; + 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; + 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_portid_str_via; + ib_resolve_self_via; + mad_field_name; + bm_call_via; + local: *; +}; diff --git a/branches/WOF2-1/ulp/libibmad/src/mad.c b/branches/WOF2-1/ulp/libibmad/src/mad.c new file mode 100644 index 00000000..3f04da03 --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/mad.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include +#include + +#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; +} + +void *mad_encode(void *buf, ib_rpc_t * rpc, ib_dr_path_t * drpath, void *data) +{ + int is_resp = rpc->method & IB_MAD_RESPONSE; + + /* first word */ + mad_set_field(buf, 0, IB_MAD_METHOD_F, rpc->method); + mad_set_field(buf, 0, IB_MAD_RESPONSE_F, is_resp ? 1 : 0); + mad_set_field(buf, 0, IB_MAD_CLASSVER_F, + rpc->mgtclass == IB_SA_CLASS ? 2 : 1); + mad_set_field(buf, 0, IB_MAD_MGMTCLASS_F, rpc->mgtclass); + mad_set_field(buf, 0, IB_MAD_BASEVER_F, 1); + + /* second word */ + if (rpc->mgtclass == IB_SMI_DIRECT_CLASS) { + if (!drpath) { + IBWARN("encoding dr mad without drpath (null)"); + return 0; + } + mad_set_field(buf, 0, IB_DRSMP_HOPCNT_F, drpath->cnt); + mad_set_field(buf, 0, IB_DRSMP_HOPPTR_F, + is_resp ? drpath->cnt + 1 : 0x0); + mad_set_field(buf, 0, IB_DRSMP_STATUS_F, rpc->rstatus); + mad_set_field(buf, 0, IB_DRSMP_DIRECTION_F, is_resp ? 1 : 0); /* out */ + } else + mad_set_field(buf, 0, IB_MAD_STATUS_F, rpc->rstatus); + + /* words 3,4,5,6 */ + if (!rpc->trid) + rpc->trid = mad_trid(); + + mad_set_field64(buf, 0, IB_MAD_TRID_F, rpc->trid); + mad_set_field(buf, 0, IB_MAD_ATTRID_F, rpc->attr.id); + mad_set_field(buf, 0, IB_MAD_ATTRMOD_F, rpc->attr.mod); + + /* words 7,8 */ + mad_set_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 (!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-1/ulp/libibmad/src/mad_internal.h b/branches/WOF2-1/ulp/libibmad/src/mad_internal.h new file mode 100644 index 00000000..24418cce --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/mad_internal.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2004-2006 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#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; + +#endif /* _MAD_INTERNAL_H_ */ diff --git a/branches/WOF2-1/ulp/libibmad/src/makefile b/branches/WOF2-1/ulp/libibmad/src/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibmad/src/portid.c b/branches/WOF2-1/ulp/libibmad/src/portid.c new file mode 100644 index 00000000..6f8fea2f --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/portid.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include + +#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-1/ulp/libibmad/src/register.c b/branches/WOF2-1/ulp/libibmad/src/register.c new file mode 100644 index 00000000..adc6c87a --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/register.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2004,2005 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#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-1/ulp/libibmad/src/resolve.c b/branches/WOF2-1/ulp/libibmad/src/resolve.c new file mode 100644 index 00000000..691bdc38 --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/resolve.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2004-2006 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include +#include "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); + + 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_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; + char buf[IB_SA_DATA_SIZE] = { 0 }; + + if (!sm_id) { + sm_id = &sm_portid; + if (ib_resolve_smlid_via(sm_id, timeout, srcport) < 0) + return -1; + } + if (*(uint64_t *) & portid->gid == 0) + mad_set_field64(portid->gid, 0, IB_GID_PREFIX_F, + IB_DEFAULT_SUBN_PREFIX); + if (guid) + mad_set_field64(portid->gid, 0, IB_GID_GUID_F, *guid); + + if ((portid->lid = + ib_path_query_via(srcport, portid->gid, portid->gid, sm_id, + buf)) < 0) + return -1; + + return 0; +} + +int ib_resolve_portid_str_via(ib_portid_t * portid, char *addr_str, + enum MAD_DEST dest_type, ib_portid_t * sm_id, + const struct ibmad_port *srcport) +{ + uint64_t guid; + int lid; + char *routepath; + ib_portid_t selfportid = { 0 }; + int selfport = 0; + + switch (dest_type) { + case IB_DEST_LID: + lid = strtol(addr_str, 0, 0); + if (!IB_LID_VALID(lid)) + return -1; + return ib_portid_set(portid, lid, 0, 0); + + case IB_DEST_DRPATH: + if (str2drpath(&portid->drpath, addr_str, 0, 0) < 0) + return -1; + return 0; + + case IB_DEST_GUID: + if (!(guid = strtoull(addr_str, 0, 0))) + return -1; + + /* keep guid in portid? */ + return ib_resolve_guid_via(portid, &guid, sm_id, 0, srcport); + + case IB_DEST_DRSLID: + lid = strtol(addr_str, &routepath, 0); + routepath++; + if (!IB_LID_VALID(lid)) + return -1; + ib_portid_set(portid, lid, 0, 0); + + /* handle DR parsing and set DrSLID to local lid */ + if (ib_resolve_self_via(&selfportid, &selfport, 0, srcport) < 0) + return -1; + if (str2drpath(&portid->drpath, routepath, selfportid.lid, 0) < + 0) + return -1; + return 0; + + default: + IBWARN("bad dest_type %d", dest_type); + } + + return -1; +} + +int ib_resolve_portid_str(ib_portid_t * portid, char *addr_str, + 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_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-1/ulp/libibmad/src/rpc.c b/branches/WOF2-1/ulp/libibmad/src/rpc.c new file mode 100644 index 00000000..07b623d1 --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/rpc.c @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2004-2006 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; + +static int madrpc_retries = MAD_DEF_RETRIES; +static 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 { + 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; +} + +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 timeout, retries; + + len = 0; + memset(sndbuf, 0, umad_size() + IB_MAD_SIZE); + + if ((len = mad_build_pkt(sndbuf, rpc, dport, 0, payload)) < 0) + return 0; + + timeout = rpc->timeout ? rpc->timeout : + port->timeout ? port->timeout : madrpc_timeout; + retries = port->retries ? port->retries : madrpc_retries; + + if ((len = _do_madrpc(port->port_id, sndbuf, rcvbuf, + port->class_agents[rpc->mgtclass], + len, timeout, retries)) < 0) { + IBWARN("_do_madrpc failed; dport (%s)", portid2str(dport)); + return 0; + } + + mad = umad_get_mad(rcvbuf); + + if ((status = mad_get_field(mad, 0, IB_DRSMP_STATUS_F)) != 0) { + ERRS("MAD completed with error status 0x%x; dport (%s)", + status, portid2str(dport)); + return 0; + } + + if (ibdebug) { + IBWARN("data offs %d sz %d", rpc->dataoffs, rpc->datasz); + xdump(stderr, "mad data\n", mad + rpc->dataoffs, rpc->datasz); + } + + if (rcvdata) + memcpy(rcvdata, mad + rpc->dataoffs, rpc->datasz); + + return rcvdata; +} + +void *mad_rpc_rmpp(const 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; + int timeout, retries; + + memset(sndbuf, 0, umad_size() + IB_MAD_SIZE); + + DEBUG("rmpp %p data %p", rmpp, data); + + if ((len = mad_build_pkt(sndbuf, rpc, dport, rmpp, data)) < 0) + return 0; + + timeout = rpc->timeout ? rpc->timeout : + port->timeout ? port->timeout : madrpc_timeout; + retries = port->retries ? port->retries : madrpc_retries; + + if ((len = _do_madrpc(port->port_id, sndbuf, rcvbuf, + port->class_agents[rpc->mgtclass], + len, timeout, retries)) < 0) { + IBWARN("_do_madrpc failed; dport (%s)", portid2str(dport)); + return 0; + } + + mad = umad_get_mad(rcvbuf); + + if ((status = mad_get_field(mad, 0, IB_MAD_STATUS_F)) != 0) { + ERRS("MAD completed with error status 0x%x; dport (%s)", + status, portid2str(dport)); + return 0; + } + + if (ibdebug) { + IBWARN("data offs %d sz %d", rpc->dataoffs, rpc->datasz); + xdump(stderr, "rmpp mad data\n", mad + rpc->dataoffs, + rpc->datasz); + } + + if (rmpp) { + rmpp->flags = mad_get_field(mad, 0, IB_SA_RMPP_FLAGS_F); + if ((rmpp->flags & 0x3) && + mad_get_field(mad, 0, IB_SA_RMPP_VERS_F) != 1) { + IBWARN("bad rmpp version"); + return 0; + } + rmpp->type = mad_get_field(mad, 0, IB_SA_RMPP_TYPE_F); + rmpp->status = mad_get_field(mad, 0, IB_SA_RMPP_STATUS_F); + DEBUG("rmpp type %d status %d", rmpp->type, rmpp->status); + rmpp->d1.u = mad_get_field(mad, 0, IB_SA_RMPP_D1_F); + rmpp->d2.u = mad_get_field(mad, 0, IB_SA_RMPP_D2_F); + } + + if (data) + memcpy(data, mad + rpc->dataoffs, rpc->datasz); + + rpc->recsz = mad_get_field(mad, 0, IB_SA_ATTROFFS_F); + + return data; +} + +void *madrpc(ib_rpc_t * rpc, ib_portid_t * dport, void *payload, void *rcvdata) +{ + 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-1/ulp/libibmad/src/sa.c b/branches/WOF2-1/ulp/libibmad/src/sa.c new file mode 100644 index 00000000..27e6ee97 --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/sa.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include "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 0; + } + + rpc.mgtclass = IB_SA_CLASS; + rpc.method = sa->method; + rpc.attr.id = sa->attrid; + rpc.attr.mod = sa->mod; + rpc.mask = sa->mask; + rpc.timeout = timeout; + rpc.datasz = IB_SA_DATA_SIZE; + rpc.dataoffs = IB_SA_DATA_OFFS; + rpc.trid = sa->trid; + + portid->qp = 1; + if (!portid->qkey) + portid->qkey = IB_DEFAULT_QP1_QKEY; + + p = mad_rpc_rmpp(ibmad_port, &rpc, portid, 0 /*&sa->rmpp */ , rcvbuf); /* TODO: RMPP */ + + sa->recsz = rpc.recsz; + + return p; +} + +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-1/ulp/libibmad/src/serv.c b/branches/WOF2-1/ulp/libibmad/src/serv.c new file mode 100644 index 00000000..ac3a1778 --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/serv.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2004,2005 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include + +#include "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()); + + DEBUG("rmpp %p data %p", rmpp, data); + + if (mad_build_pkt(umad, rpc, dport, rmpp, data) < 0) + return 0; + + if (ibdebug) { + IBWARN("data offs %d sz %d", rpc->dataoffs, rpc->datasz); + xdump(stderr, "mad send data\n", + (char *)umad_get_mad(umad) + rpc->dataoffs, rpc->datasz); + } + + if (umad_send(srcport->port_id, srcport->class_agents[rpc->mgtclass], + umad, IB_MAD_SIZE, rpc->timeout, 0) < 0) { + IBWARN("send failed; %m"); + return -1; + } + + return 0; +} + +int mad_respond(void *umad, ib_portid_t * portid, uint32_t rstatus) +{ + 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, 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, 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-1/ulp/libibmad/src/smp.c b/branches/WOF2-1/ulp/libibmad/src/smp.c new file mode 100644 index 00000000..5f55ec58 --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/smp.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include "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-1/ulp/libibmad/src/vendor.c b/branches/WOF2-1/ulp/libibmad/src/vendor.c new file mode 100644 index 00000000..4bf95614 --- /dev/null +++ b/branches/WOF2-1/ulp/libibmad/src/vendor.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2004,2005 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include "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 0; /* no direct SMI */ + + if (!(range1 = mad_is_vendor_range1(call->mgmt_class)) && + !(mad_is_vendor_range2(call->mgmt_class))) + return 0; + + resp_expected = response_expected(call->method); + + rpc.mgtclass = call->mgmt_class; + + rpc.method = call->method; + rpc.attr.id = call->attrid; + rpc.attr.mod = call->mod; + rpc.timeout = resp_expected ? call->timeout : 0; + rpc.datasz = + range1 ? IB_VENDOR_RANGE1_DATA_SIZE : IB_VENDOR_RANGE2_DATA_SIZE; + rpc.dataoffs = + range1 ? IB_VENDOR_RANGE1_DATA_OFFS : IB_VENDOR_RANGE2_DATA_OFFS; + + if (!range1) + rpc.oui = call->oui; + + DEBUG + ("class 0x%x method 0x%x attr 0x%x mod 0x%x datasz %d off %d res_ex %d", + rpc.mgtclass, rpc.method, rpc.attr.id, rpc.attr.mod, rpc.datasz, + rpc.dataoffs, resp_expected); + + portid->qp = 1; + if (!portid->qkey) + portid->qkey = IB_DEFAULT_QP1_QKEY; + + if (resp_expected) + return 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-1/ulp/libibnetdisc/README.txt b/branches/WOF2-1/ulp/libibnetdisc/README.txt new file mode 100644 index 00000000..7c82b7e7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibnetdisc/dirs b/branches/WOF2-1/ulp/libibnetdisc/dirs new file mode 100644 index 00000000..b1cbe453 --- /dev/null +++ b/branches/WOF2-1/ulp/libibnetdisc/dirs @@ -0,0 +1,2 @@ +DIRS = \ + src \ No newline at end of file diff --git a/branches/WOF2-1/ulp/libibnetdisc/include/infiniband/ibnetdisc.h b/branches/WOF2-1/ulp/libibnetdisc/include/infiniband/ibnetdisc.h new file mode 100644 index 00000000..c7d293cb --- /dev/null +++ b/branches/WOF2-1/ulp/libibnetdisc/include/infiniband/ibnetdisc.h @@ -0,0 +1,188 @@ +/* + * 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 ib_fabric; /* forward declare */ +struct chassis; /* forward declare */ +struct port; /* forward declare */ + +/** ========================================================================= + * Node + */ +typedef struct node { + struct node *next; /* all node list in fabric */ + struct ib_fabric *fabric; /* the fabric node belongs to */ + + ib_portid_t path_portid; /* path from "from_node" */ + int dist; /* num of hops from "from_node" */ + int smalid; + int 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 port **ports; /* in order array of port pointers */ + /* the size of this array is info.numports + 1 */ + /* items MAY BE NULL! (ie 0 == switches only) */ + + /* chassis info */ + struct node *next_chassis_node; /* next node in ibnd_chassis_t->nodes */ + struct 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; +} ibnd_node_t; + +/** ========================================================================= + * Port + */ +typedef struct 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 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]; +} ibnd_port_t; + + +/** ========================================================================= + * Chassis + */ +typedef struct chassis { + struct 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 12 +#define LINES_MAX_NUM 36 + ibnd_node_t *spinenode[SPINES_MAX_NUM + 1]; + ibnd_node_t *linenode[LINES_MAX_NUM + 1]; +} ibnd_chassis_t; + +/** ========================================================================= + * Fabric + * Main fabric object which is returned and represents the data discovered + */ +typedef struct ib_fabric { + struct ibmad_port *ibmad_port; + /* 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; + int maxhops_discovered; +} ibnd_fabric_t; + +/** ========================================================================= + * Initialization (fabric operations) + */ +MAD_EXPORT void ibnd_debug(int i); +MAD_EXPORT void ibnd_show_progress(int i); + +MAD_EXPORT ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port *ibmad_port, + int timeout_ms, + ib_portid_t *from, int hops); + /** + * open: (required) ibmad_port object from libibmad + * timeout_ms: (required) gives the timeout for a _SINGLE_ query on + * the fabric. So if there are multiple nodes not + * responding this may result in a lengthy delay. + * from: (optional) specify the node to start scanning from. + * If NULL start from the node we are running on. + * hops: (optional) Specify how much of the fabric to traverse. + * negative value == scan entire fabric + */ +MAD_EXPORT void ibnd_destroy_fabric(ibnd_fabric_t *fabric); + +/** ========================================================================= + * Node operations + */ +MAD_EXPORT ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t *fabric, uint64_t guid); +MAD_EXPORT ibnd_node_t *ibnd_find_node_dr(ibnd_fabric_t *fabric, char *dr_str); +MAD_EXPORT ibnd_node_t *ibnd_update_node(ibnd_node_t *node); + +typedef void (*ibnd_iter_node_func_t)(ibnd_node_t *node, void *user_data); +MAD_EXPORT void ibnd_iter_nodes(ibnd_fabric_t *fabric, + ibnd_iter_node_func_t func, + void *user_data); +MAD_EXPORT void ibnd_iter_nodes_type(ibnd_fabric_t *fabric, + ibnd_iter_node_func_t func, + int node_type, + void *user_data); + +/** ========================================================================= + * Chassis queries + */ +MAD_EXPORT uint64_t ibnd_get_chassis_guid(ibnd_fabric_t *fabric, + unsigned char chassisnum); +MAD_EXPORT char *ibnd_get_chassis_type(ibnd_node_t *node); +MAD_EXPORT char *ibnd_get_chassis_slot_str(ibnd_node_t *node, + char *str, size_t size); + +MAD_EXPORT int ibnd_is_xsigo_guid(uint64_t guid); +MAD_EXPORT int ibnd_is_xsigo_tca(uint64_t guid); +MAD_EXPORT int ibnd_is_xsigo_hca(uint64_t guid); + +#endif /* _IBNETDISC_H_ */ diff --git a/branches/WOF2-1/ulp/libibnetdisc/src/Sources b/branches/WOF2-1/ulp/libibnetdisc/src/Sources new file mode 100644 index 00000000..92ce29fa --- /dev/null +++ b/branches/WOF2-1/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 + +INCLUDES = ..\include\infiniband;\ + ..\include;\ + ..\..\libibmad\include;\ + ..\..\..\tools\infiniband-diags\include;\ + ..\..\libibverbs\include;\ + ..\..\libibumad\include;\ + ..\..\..\inc;\ + ..\..\..\inc\user;\ + ..\..\..\inc\user\linux; + +USER_C_FLAGS = $(USER_C_FLAGS) + +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 +!else + $(TARGETPATH)\*\libibumadd.lib \ + $(TARGETPATH)\*\libibmadd.lib +!endif diff --git a/branches/WOF2-1/ulp/libibnetdisc/src/chassis.c b/branches/WOF2-1/ulp/libibnetdisc/src/chassis.c new file mode 100644 index 00000000..dbb0abe5 --- /dev/null +++ b/branches/WOF2-1/ulp/libibnetdisc/src/chassis.c @@ -0,0 +1,832 @@ +/* + * Copyright (c) 2004-2007 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. + * + */ + +/*========================================================*/ +/* 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[5] = { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004" }; +static char *ChassisSlotTypeStr[4] = { "", "Line", "Spine", "SRBD" }; + +char *ibnd_get_chassis_type(ibnd_node_t *node) +{ + /* 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 > ISR2004_CT) + return (NULL); + return ChassisTypeStr[node->ch_type]; +} + +char *ibnd_get_chassis_slot_str(ibnd_node_t *node, char *str, size_t size) +{ + /* 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(struct ibnd_fabric *fabric, unsigned char chassisnum) +{ + ibnd_chassis_t *current; + + for (current = fabric->first_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_node_t *node) +{ + struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(node->fabric); + ibnd_chassis_t *current; + uint64_t chguid; + + chguid = get_chassisguid(node); + for (current = f->first_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) +{ + struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric); + ibnd_chassis_t *chassis; + + chassis = find_chassisnum(f, chassisnum); + if (chassis) + return chassis->chassisguid; + else + return 0; +} + +static int is_router(struct ibnd_node *n) +{ + uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_IB_FC_ROUTER || + devid == VTR_DEVID_IB_IP_ROUTER); +} + +static int is_spine_9096(struct ibnd_node *n) +{ + uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SFB4 || + devid == VTR_DEVID_SFB4_DDR); +} + +static int is_spine_9288(struct ibnd_node *n) +{ + uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SFB12 || + devid == VTR_DEVID_SFB12_DDR); +} + +static int is_spine_2004(struct ibnd_node *n) +{ + uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SFB2004); +} + +static int is_spine_2012(struct ibnd_node *n) +{ + uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SFB2012); +} + +static int is_spine(struct ibnd_node *n) +{ + return (is_spine_9096(n) || is_spine_9288(n) || + is_spine_2004(n) || is_spine_2012(n)); +} + +static int is_line_24(struct ibnd_node *n) +{ + uint32_t devid = mad_get_field(n->node.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(struct ibnd_node *n) +{ + uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SLB8); +} + +static int is_line_2024(struct ibnd_node *n) +{ + uint32_t devid = mad_get_field(n->node.info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SLB2024); +} + +static int is_line(struct ibnd_node *n) +{ + return (is_line_24(n) || is_line_8(n) || is_line_2024(n)); +} + +int is_chassis_switch(struct ibnd_node *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[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(struct ibnd_node *node, ibnd_port_t *lineport) +{ + ibnd_node_t *n = (ibnd_node_t *)node; + + n->ch_slot = SPINE_CS; + if (is_spine_9096(node)) { + 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(node)) { + 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(node)) { + 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(node)) { + 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 { + IBPANIC("Unexpected node found: guid 0x%016" PRIx64, + node->node.guid); + } +} + +static void get_router_slot(struct ibnd_node *node, ibnd_port_t *spineport) +{ + ibnd_node_t *n = (ibnd_node_t *)node; + uint64_t guessnum = 0; + + node->ch_found = 1; + + n->ch_slot = SRBD_CS; + if (is_spine_9096(CONV_NODE_INTERNAL(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(CONV_NODE_INTERNAL(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(CONV_NODE_INTERNAL(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(CONV_NODE_INTERNAL(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 { + IBPANIC("Unexpected node found: guid 0x%016" PRIx64, + spineport->node->guid); + } +} + +static void get_slb_slot(ibnd_node_t *n, ibnd_port_t *spineport) +{ + n->ch_slot = LINE_CS; + if (is_spine_9096(CONV_NODE_INTERNAL(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(CONV_NODE_INTERNAL(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(CONV_NODE_INTERNAL(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(CONV_NODE_INTERNAL(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 { + IBPANIC("Unexpected node found: guid 0x%016" PRIx64, + spineport->node->guid); + } +} + +/* 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 void fill_voltaire_chassis_record(struct ibnd_node *node) +{ + ibnd_node_t *n = (ibnd_node_t *)node; + int p = 0; + ibnd_port_t *port; + struct ibnd_node *remnode = 0; + + if (node->ch_found) /* somehow this node has already been passed */ + return; + 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->node.numports; p++) { + port = node->node.ports[p]; + if (port && is_spine(CONV_NODE_INTERNAL(port->remoteport->node))) + get_router_slot(node, port->remoteport); + } + } else if (is_spine(node)) { + for (p = 1; p <= node->node.numports; p++) { + port = node->node.ports[p]; + if (!port || !port->remoteport) + continue; + remnode = CONV_NODE_INTERNAL(port->remoteport->node); + if (remnode->node.type != IB_NODE_SWITCH) { + if (!remnode->ch_found) + get_router_slot(remnode, port); + continue; + } + if (!n->ch_type) + /* 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 (p = 1; p <= node->node.numports; p++) { + port = node->node.ports[p]; + if (!port || port->portnum > 12 || !port->remoteport) + continue; + /* we assume here that remoteport belongs to spine */ + get_slb_slot(n, port->remoteport); + break; + } + } + + /* for each port of this node, map external ports */ + for (p = 1; p <= node->node.numports; p++) { + port = node->node.ports[p]; + if (!port) + continue; + voltaire_portmap(port); + } + + return; +} + +static int get_line_index(ibnd_node_t *node) +{ + int retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum; + + if (retval > LINES_MAX_NUM || retval < 1) + IBPANIC("Internal error"); + return retval; +} + +static int get_spine_index(ibnd_node_t *node) +{ + int retval; + + if (is_spine_9288(CONV_NODE_INTERNAL(node)) || is_spine_2012(CONV_NODE_INTERNAL(node))) + retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum; + else + retval = node->ch_slotnum; + + if (retval > SPINES_MAX_NUM || retval < 1) + IBPANIC("Internal error"); + return retval; +} + +static void insert_line_router(ibnd_node_t *node, ibnd_chassis_t *chassis) +{ + int i = get_line_index(node); + + if (chassis->linenode[i]) + return; /* already filled slot */ + + chassis->linenode[i] = node; + node->chassis = chassis; +} + +static void insert_spine(ibnd_node_t *node, ibnd_chassis_t *chassis) +{ + int i = get_spine_index(node); + + if (chassis->spinenode[i]) + return; /* already filled slot */ + + chassis->spinenode[i] = node; + node->chassis = chassis; +} + +static void 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++) { + node = chassis->linenode[i]; + + if (!(node && is_line(CONV_NODE_INTERNAL(node)))) + continue; /* empty slot or router */ + + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (!port || port->portnum > 12 || !port->remoteport) + continue; + + remnode = port->remoteport->node; + + if (!CONV_NODE_INTERNAL(remnode)->ch_found) + continue; /* some error - spine not initialized ? FIXME */ + insert_spine(remnode, chassis); + } + } +} + +static void 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++) { + node = chassis->spinenode[i]; + if (!node) + continue; /* empty slot */ + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (!port || !port->remoteport) + continue; + remnode = port->remoteport->node; + + if (!CONV_NODE_INTERNAL(remnode)->ch_found) + continue; /* some error - line/router not initialized ? FIXME */ + insert_line_router(remnode, chassis); + } + } +} + +/* + 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 void build_chassis(struct ibnd_node *node, ibnd_chassis_t *chassis) +{ + int p = 0; + struct ibnd_node *remnode = 0; + ibnd_port_t *port = 0; + + /* we get here with node = chassis_spine */ + insert_spine((ibnd_node_t *)node, chassis); + + /* loop: pass on all ports of node */ + for (p = 1; p <= node->node.numports; p++ ) { + port = node->node.ports[p]; + if (!port || !port->remoteport) + continue; + remnode = CONV_NODE_INTERNAL(port->remoteport->node); + + if (!remnode->ch_found) + continue; /* some error - line or router not initialized ? FIXME */ + + insert_line_router(&(remnode->node), chassis); + } + + pass_on_lines_catch_spines(chassis); + /* 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(chassis); + + /* 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 */ + pass_on_lines_catch_spines(chassis); + pass_on_spines_catch_lines(chassis); + pass_on_spines_interpolate_chguid(chassis); +} + +/*========================================================*/ +/* 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 }; */ + +/* map internal ports to external ports if appropriate */ +static void +voltaire_portmap(ibnd_port_t *port) +{ + struct ibnd_node *n = CONV_NODE_INTERNAL(port->node); + int portnum = port->portnum; + int chipnum = 0; + ibnd_node_t *node = port->node; + + if (!n->ch_found || !is_line(CONV_NODE_INTERNAL(node)) || (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(CONV_NODE_INTERNAL(node))) + port->ext_portnum = int2ext_map_slb24[chipnum][portnum]; + else if (is_line_2024(CONV_NODE_INTERNAL(node))) + port->ext_portnum = int2ext_map_slb2024[chipnum][portnum]; + else + port->ext_portnum = int2ext_map_slb8[chipnum][portnum]; +} + +static void add_chassis(struct ibnd_fabric *fabric) +{ + if (!(fabric->current_chassis = calloc(1, sizeof(ibnd_chassis_t)))) + IBPANIC("out of mem"); + + if (fabric->first_chassis == NULL) { + fabric->first_chassis = fabric->current_chassis; + fabric->last_chassis = fabric->current_chassis; + } else { + fabric->last_chassis->next = fabric->current_chassis; + fabric->last_chassis = fabric->current_chassis; + } +} + +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: + Pointer to the first chassis in a NULL terminated list of chassis in + the fabric specified. +*/ +ibnd_chassis_t *group_nodes(struct ibnd_fabric *fabric) +{ + struct ibnd_node *node; + int dist; + int chassisnum = 0; + ibnd_chassis_t *chassis; + + fabric->first_chassis = NULL; + fabric->current_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 (dist = 0; dist <= fabric->fabric.maxhops_discovered; dist++) { + for (node = fabric->nodesdist[dist]; node; node = node->dnext) { + if (mad_get_field(node->node.info, 0, IB_NODE_VENDORID_F) == VTR_VENDOR_ID) + fill_voltaire_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 <= fabric->fabric.maxhops_discovered; dist++) { + for (node = fabric->nodesdist[dist]; node; node = node->dnext) { + if (mad_get_field(node->node.info, 0, IB_NODE_VENDORID_F) != VTR_VENDOR_ID) + continue; + //if (!node->node.chrecord || node->node.chrecord->chassisnum || !is_spine(node)) + if (!node->ch_found + || (node->node.chassis && node->node.chassis->chassisnum) + || !is_spine(node)) + continue; + add_chassis(fabric); + fabric->current_chassis->chassisnum = ++chassisnum; + build_chassis(node, fabric->current_chassis); + } + } + + /* now make pass on nodes for chassis which are not Voltaire */ + /* grouped by common SystemImageGUID */ + for (dist = 0; dist <= fabric->fabric.maxhops_discovered; dist++) { + for (node = fabric->nodesdist[dist]; node; node = node->dnext) { + if (mad_get_field(node->node.info, 0, IB_NODE_VENDORID_F) == VTR_VENDOR_ID) + continue; + if (mad_get_field64(node->node.info, 0, IB_NODE_SYSTEM_GUID_F)) { + chassis = find_chassisguid((ibnd_node_t *)node); + if (chassis) + chassis->nodecount++; + else { + /* Possible new chassis */ + add_chassis(fabric); + fabric->current_chassis->chassisguid = + get_chassisguid((ibnd_node_t *)node); + fabric->current_chassis->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 = fabric->nodesdist[dist]; node; node = node->dnext) { + if (mad_get_field(node->node.info, 0, IB_NODE_VENDORID_F) == VTR_VENDOR_ID) + continue; + if (mad_get_field64(node->node.info, 0, IB_NODE_SYSTEM_GUID_F)) { + chassis = find_chassisguid((ibnd_node_t *)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, (ibnd_node_t *)node); + } + } + } + } + if (dist == fabric->fabric.maxhops_discovered) + dist = MAXHOPS; /* skip to CAs */ + else + dist++; + } + + return (fabric->first_chassis); +} diff --git a/branches/WOF2-1/ulp/libibnetdisc/src/chassis.h b/branches/WOF2-1/ulp/libibnetdisc/src/chassis.h new file mode 100644 index 00000000..16dad497 --- /dev/null +++ b/branches/WOF2-1/ulp/libibnetdisc/src/chassis.h @@ -0,0 +1,85 @@ +/* + * 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 + +/* 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 }; +enum ibnd_chassis_slot_type { UNRESOLVED_CS, LINE_CS, SPINE_CS, SRBD_CS }; + +ibnd_chassis_t *group_nodes(struct ibnd_fabric *fabric); + +#endif /* _CHASSIS_H_ */ diff --git a/branches/WOF2-1/ulp/libibnetdisc/src/ibnetdisc.c b/branches/WOF2-1/ulp/libibnetdisc/src/ibnetdisc.c new file mode 100644 index 00000000..baea98e9 --- /dev/null +++ b/branches/WOF2-1/ulp/libibnetdisc/src/ibnetdisc.c @@ -0,0 +1,714 @@ +/* + * 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 + +#include +#include + +#include "internal.h" +#include "chassis.h" + +static int timeout_ms = 2000; +static int show_progress = 0; +int ibdebug; + +void +decode_port_info(ibnd_port_t *port) +{ + 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); +} + +static int +get_port_info(struct ibnd_fabric *fabric, struct ibnd_port *port, + int portnum, ib_portid_t *portid) +{ + char width[64], speed[64]; + int iwidth; + int ispeed; + + port->port.portnum = portnum; + iwidth = mad_get_field(port->port.info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F); + ispeed = mad_get_field(port->port.info, 0, IB_PORT_LINK_SPEED_ACTIVE_F); + + if (!smp_query_via(port->port.info, portid, IB_ATTR_PORT_INFO, portnum, timeout_ms, + fabric->fabric.ibmad_port)) + return -1; + + decode_port_info(&(port->port)); + + IBND_DEBUG("portid %s portnum %d: base lid %d state %d physstate %d %s %s\n", + portid2str(portid), portnum, port->port.base_lid, + mad_get_field(port->port.info, 0, IB_PORT_STATE_F), + mad_get_field(port->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)); + return 0; +} + +/* + * Returns -1 if error. + */ +static int +query_node_info(struct ibnd_fabric *fabric, struct ibnd_node *node, ib_portid_t *portid) +{ + if (!smp_query_via(&(node->node.info), portid, IB_ATTR_NODE_INFO, 0, timeout_ms, + fabric->fabric.ibmad_port)) + return -1; + + /* decode just a couple of fields for quicker reference. */ + mad_decode_field(node->node.info, IB_NODE_GUID_F, &(node->node.guid)); + mad_decode_field(node->node.info, IB_NODE_TYPE_F, &(node->node.type)); + mad_decode_field(node->node.info, IB_NODE_NPORTS_F, + &(node->node.numports)); + + return (0); +} + +/* + * Returns 0 if non switch node is found, 1 if switch is found, -1 if error. + */ +static int +query_node(struct ibnd_fabric *fabric, struct ibnd_node *inode, + struct ibnd_port *iport, ib_portid_t *portid) +{ + ibnd_node_t *node = &(inode->node); + ibnd_port_t *port = &(iport->port); + void *nd = inode->node.nodedesc; + + if (query_node_info(fabric, inode, portid)) + return -1; + + port->portnum = mad_get_field(node->info, 0, IB_NODE_LOCAL_PORT_F); + port->guid = mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F); + + if (!smp_query_via(nd, portid, IB_ATTR_NODE_DESC, 0, timeout_ms, + fabric->fabric.ibmad_port)) + return -1; + + if (!smp_query_via(port->info, portid, IB_ATTR_PORT_INFO, 0, timeout_ms, + fabric->fabric.ibmad_port)) + return -1; + decode_port_info(port); + + if (node->type != IB_NODE_SWITCH) + return 0; + + node->smalid = port->base_lid; + node->smalmc = port->lmc; + + /* after we have the sma information find out the real PortInfo for this port */ + if (!smp_query_via(port->info, portid, IB_ATTR_PORT_INFO, port->portnum, timeout_ms, + fabric->fabric.ibmad_port)) + return -1; + decode_port_info(port); + + port->base_lid = (uint16_t) node->smalid; /* LID is still defined by port 0 */ + port->lmc = (uint8_t) node->smalmc; + + if (!smp_query_via(node->switchinfo, portid, IB_ATTR_SWITCH_INFO, 0, timeout_ms, + fabric->fabric.ibmad_port)) + node->smaenhsp0 = 0; /* assume base SP0 */ + else + mad_decode_field(node->switchinfo, IB_SW_ENHANCED_PORT0_F, &node->smaenhsp0); + + IBND_DEBUG("portid %s: got switch node %" PRIx64 " '%s'\n", + portid2str(portid), node->guid, node->nodedesc); + return 0; +} + +static int +add_port_to_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 int +extend_dpath(struct ibnd_fabric *f, ib_portid_t *portid, int nextport) +{ + int rc = 0; + + if (portid->lid) { + /* If we were LID routed we need to set up the drslid */ + if (!f->selfportid.lid) + if (ib_resolve_self_via(&f->selfportid, NULL, NULL, + f->fabric.ibmad_port) < 0) + return -1; + + portid->drpath.drslid = (uint16_t) f->selfportid.lid; + portid->drpath.drdlid = 0xFFFF; + } + + rc = add_port_to_dpath(&portid->drpath, nextport); + + if ((rc != -1) && (portid->drpath.cnt > f->fabric.maxhops_discovered)) + f->fabric.maxhops_discovered = portid->drpath.cnt; + return (rc); +} + +static void +dump_endnode(ib_portid_t *path, char *prompt, + struct ibnd_node *node, struct ibnd_port *port) +{ + char type[64]; + if (!show_progress) + return; + + mad_dump_node_type(type, 64, &(node->node.type), sizeof(int)), + + printf("%s -> %s %s {%016" PRIx64 "} portnum %d base lid %d-%d\"%s\"\n", + portid2str(path), prompt, type, + node->node.guid, + node->node.type == IB_NODE_SWITCH ? 0 : port->port.portnum, + port->port.base_lid, port->port.base_lid + (1 << port->port.lmc) - 1, + node->node.nodedesc); +} + +static struct ibnd_node * +find_existing_node(struct ibnd_fabric *fabric, struct ibnd_node *new) +{ + int hash = HASHGUID(new->node.guid) % HTSZ; + struct ibnd_node *node; + + for (node = fabric->nodestbl[hash]; node; node = node->htnext) + if (node->node.guid == new->node.guid) + return node; + + return NULL; +} + +ibnd_node_t * +ibnd_find_node_guid(ibnd_fabric_t *fabric, uint64_t guid) +{ + struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric); + int hash = HASHGUID(guid) % HTSZ; + struct ibnd_node *node; + + for (node = f->nodestbl[hash]; node; node = node->htnext) + if (node->node.guid == guid) + return (ibnd_node_t *)node; + + return NULL; +} + +ibnd_node_t * +ibnd_update_node(ibnd_node_t *node) +{ + char portinfo_port0[IB_SMP_DATA_SIZE]; + void *nd = node->nodedesc; + int p = 0; + struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(node->fabric); + struct ibnd_node *n = CONV_NODE_INTERNAL(node); + + if (query_node_info(f, n, &(n->node.path_portid))) + return (NULL); + + if (!smp_query_via(nd, &(n->node.path_portid), IB_ATTR_NODE_DESC, 0, timeout_ms, + f->fabric.ibmad_port)) + return (NULL); + + /* update all the port info's */ + for (p = 1; p >= n->node.numports; p++) { + get_port_info(f, CONV_PORT_INTERNAL(n->node.ports[p]), p, &(n->node.path_portid)); + } + + if (n->node.type != IB_NODE_SWITCH) + goto done; + + if (!smp_query_via(portinfo_port0, &(n->node.path_portid), IB_ATTR_PORT_INFO, 0, timeout_ms, + f->fabric.ibmad_port)) + return (NULL); + + n->node.smalid = mad_get_field(portinfo_port0, 0, IB_PORT_LID_F); + n->node.smalmc = mad_get_field(portinfo_port0, 0, IB_PORT_LMC_F); + + if (!smp_query_via(node->switchinfo, &(n->node.path_portid), IB_ATTR_SWITCH_INFO, 0, timeout_ms, + f->fabric.ibmad_port)) + node->smaenhsp0 = 0; /* assume base SP0 */ + else + mad_decode_field(node->switchinfo, IB_SW_ENHANCED_PORT0_F, &n->node.smaenhsp0); + +done: + return (node); +} + +ibnd_node_t * +ibnd_find_node_dr(ibnd_fabric_t *fabric, char *dr_str) +{ + struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric); + int i = 0; + ibnd_node_t *rc = f->fabric.from_node; + ib_dr_path_t path; + + 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); +} + +static void +add_to_nodeguid_hash(struct ibnd_node *node, struct ibnd_node *hash[]) +{ + int hash_idx = HASHGUID(node->node.guid) % HTSZ; + + node->htnext = hash[hash_idx]; + hash[hash_idx] = node; +} + +static void +add_to_portguid_hash(struct ibnd_port *port, struct ibnd_port *hash[]) +{ + int hash_idx = HASHGUID(port->port.guid) % HTSZ; + + port->htnext = hash[hash_idx]; + hash[hash_idx] = port; +} + +static void +add_to_type_list(struct ibnd_node*node, struct ibnd_fabric *fabric) +{ + switch (node->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 void +add_to_nodedist(struct ibnd_node *node, struct ibnd_fabric *fabric) +{ + int dist = node->node.dist; + if (node->node.type != IB_NODE_SWITCH) + dist = MAXHOPS; /* special Ca list */ + + node->dnext = fabric->nodesdist[dist]; + fabric->nodesdist[dist] = node; +} + + +static struct ibnd_node * +create_node(struct ibnd_fabric *fabric, struct ibnd_node *temp, ib_portid_t *path, int dist) +{ + struct ibnd_node *node; + + node = malloc(sizeof(*node)); + if (!node) { + IBPANIC("OOM: node creation failed\n"); + return NULL; + } + + memcpy(node, temp, sizeof(*node)); + node->node.dist = dist; + node->node.path_portid = *path; + node->node.fabric = (ibnd_fabric_t *)fabric; + + add_to_nodeguid_hash(node, fabric->nodestbl); + + /* add this to the all nodes list */ + node->node.next = fabric->fabric.nodes; + fabric->fabric.nodes = (ibnd_node_t *)node; + + add_to_type_list(node, fabric); + add_to_nodedist(node, fabric); + + return node; +} + +static struct ibnd_port * +find_existing_port_node(struct ibnd_node *node, struct ibnd_port *port) +{ + if (port->port.portnum > node->node.numports || node->node.ports == NULL ) + return (NULL); + + return (CONV_PORT_INTERNAL(node->node.ports[port->port.portnum])); +} + +static struct ibnd_port * +add_port_to_node(struct ibnd_fabric *fabric, struct ibnd_node *node, struct ibnd_port *temp) +{ + struct ibnd_port *port; + + port = malloc(sizeof(*port)); + if (!port) + return NULL; + + memcpy(port, temp, sizeof(*port)); + port->port.node = (ibnd_node_t *)node; + port->port.ext_portnum = 0; + + if (node->node.ports == NULL) { + node->node.ports = calloc(sizeof(*node->node.ports), node->node.numports + 1); + if (!node->node.ports) { + IBND_ERROR("Failed to allocate the ports array\n"); + return (NULL); + } + } + + node->node.ports[temp->port.portnum] = (ibnd_port_t *)port; + + add_to_portguid_hash(port, fabric->portstbl); + return port; +} + +static void +link_ports(struct ibnd_node *node, struct ibnd_port *port, + struct ibnd_node *remotenode, struct ibnd_port *remoteport) +{ + IBND_DEBUG("linking: 0x%" PRIx64 " %p->%p:%u and 0x%" PRIx64 " %p->%p:%u\n", + node->node.guid, node, port, port->port.portnum, + remotenode->node.guid, remotenode, + remoteport, remoteport->port.portnum); + if (port->port.remoteport) + port->port.remoteport->remoteport = NULL; + if (remoteport->port.remoteport) + remoteport->port.remoteport->remoteport = NULL; + port->port.remoteport = (ibnd_port_t *)remoteport; + remoteport->port.remoteport = (ibnd_port_t *)port; +} + +static int +get_remote_node(struct ibnd_fabric *fabric, struct ibnd_node *node, struct ibnd_port *port, ib_portid_t *path, + int portnum, int dist) +{ + struct ibnd_node node_buf; + struct ibnd_port port_buf; + struct ibnd_node *remotenode, *oldnode; + struct ibnd_port *remoteport, *oldport; + + memset(&node_buf, 0, sizeof(node_buf)); + memset(&port_buf, 0, sizeof(port_buf)); + + IBND_DEBUG("handle node %p port %p:%d dist %d\n", node, port, portnum, dist); + + if (mad_get_field(port->port.info, 0, IB_PORT_PHYS_STATE_F) + != IB_PORT_PHYS_STATE_LINKUP) + return -1; + + if (extend_dpath(fabric, path, portnum) < 0) + return -1; + + if (query_node(fabric, &node_buf, &port_buf, path)) { + IBWARN("NodeInfo on %s failed, skipping port", + portid2str(path)); + path->drpath.cnt--; /* restore path */ + return -1; + } + + oldnode = find_existing_node(fabric, &node_buf); + if (oldnode) + remotenode = oldnode; + else if (!(remotenode = create_node(fabric, &node_buf, path, dist + 1))) + IBPANIC("no memory"); + + oldport = find_existing_port_node(remotenode, &port_buf); + if (oldport) { + remoteport = oldport; + } else if (!(remoteport = add_port_to_node(fabric, remotenode, &port_buf))) + IBPANIC("no memory"); + + dump_endnode(path, oldnode ? "known remote" : "new remote", + remotenode, remoteport); + + link_ports(node, port, remotenode, remoteport); + + path->drpath.cnt--; /* restore path */ + return 0; +} + +ibnd_fabric_t * +ibnd_discover_fabric(struct ibmad_port *ibmad_port, int timeout_ms, + ib_portid_t *from, int hops) +{ + struct ibnd_fabric *fabric = NULL; + ib_portid_t my_portid = {0}; + struct ibnd_node node_buf; + struct ibnd_port port_buf; + struct ibnd_node *node; + struct ibnd_port *port; + int i; + int dist = 0; + ib_portid_t *path; + int max_hops = MAXHOPS-1; /* default find everything */ + + if (!ibmad_port) { + IBPANIC("ibmad_port must be specified to " + "ibnd_discover_fabric\n"); + return (NULL); + } + if (mad_rpc_class_agent(ibmad_port, IB_SMI_CLASS) == -1 + || + mad_rpc_class_agent(ibmad_port, IB_SMI_DIRECT_CLASS) == -1) { + IBPANIC("ibmad_port must be opened with " + "IB_SMI_CLASS && IB_SMI_DIRECT_CLASS\n"); + return (NULL); + } + + /* if not everything how much? */ + if (hops >= 0) { + max_hops = hops; + } + + /* If not specified start from "my" port */ + if (!from) + from = &my_portid; + + fabric = malloc(sizeof(*fabric)); + + if (!fabric) { + IBPANIC("OOM: failed to malloc ibnd_fabric_t\n"); + return (NULL); + } + + memset(fabric, 0, sizeof(*fabric)); + + fabric->fabric.ibmad_port = ibmad_port; + + IBND_DEBUG("from %s\n", portid2str(from)); + + memset(&node_buf, 0, sizeof(node_buf)); + memset(&port_buf, 0, sizeof(port_buf)); + + if (query_node(fabric, &node_buf, &port_buf, from)) { + IBWARN("can't reach node %s\n", portid2str(from)); + goto error; + } + + node = create_node(fabric, &node_buf, from, 0); + if (!node) + goto error; + + fabric->fabric.from_node = (ibnd_node_t *)node; + + port = add_port_to_node(fabric, node, &port_buf); + if (!port) + IBPANIC("out of memory"); + + if(get_remote_node(fabric, node, port, from, + mad_get_field(node->node.info, 0, IB_NODE_LOCAL_PORT_F), + 0) < 0) + return ((ibnd_fabric_t *)fabric); + + for (dist = 0; dist <= max_hops; dist++) { + + for (node = fabric->nodesdist[dist]; node; node = node->dnext) { + + path = &node->node.path_portid; + + IBND_DEBUG("dist %d node %p\n", dist, node); + dump_endnode(path, "processing", node, port); + + for (i = 1; i <= node->node.numports; i++) { + if (i == mad_get_field(node->node.info, 0, + IB_NODE_LOCAL_PORT_F)) + continue; + + if (get_port_info(fabric, &port_buf, i, path)) { + IBWARN("can't reach node %s port %d", portid2str(path), i); + continue; + } + + port = find_existing_port_node(node, &port_buf); + if (port) + continue; + + port = add_port_to_node(fabric, node, &port_buf); + if (!port) + IBPANIC("out of memory"); + + /* If switch, set port GUID to node port GUID */ + if (node->node.type == IB_NODE_SWITCH) { + port->port.guid = mad_get_field64(node->node.info, + 0, IB_NODE_PORT_GUID_F); + } + + get_remote_node(fabric, node, port, path, i, dist); + } + } + } + + fabric->fabric.chassis = group_nodes(fabric); + + return ((ibnd_fabric_t *)fabric); +error: + free(fabric); + return (NULL); +} + +static void +destroy_node(struct ibnd_node *node) +{ + int p = 0; + + for (p = 0; p <= node->node.numports; p++) { + free(node->node.ports[p]); + } + free(node->node.ports); + free(node); +} + +void +ibnd_destroy_fabric(ibnd_fabric_t *fabric) +{ + struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric); + int dist = 0; + struct ibnd_node *node = NULL; + struct ibnd_node *next = NULL; + ibnd_chassis_t *ch, *ch_next; + + ch = f->first_chassis; + while (ch) { + ch_next = ch->next; + free(ch); + ch = ch_next; + } + for (dist = 0; dist <= MAXHOPS; dist++) { + node = f->nodesdist[dist]; + while (node) { + next = node->dnext; + destroy_node(node); + node = next; + } + } + free(f); +} + +void +ibnd_debug(int i) +{ + if (i) { + ibdebug++; + madrpc_show_errors(1); + umad_debug(i); + } else { + ibdebug = 0; + madrpc_show_errors(0); + umad_debug(0); + } +} + +void +ibnd_show_progress(int i) +{ + show_progress = i; +} + +void +ibnd_iter_nodes(ibnd_fabric_t *fabric, + ibnd_iter_node_func_t func, + void *user_data) +{ + ibnd_node_t *cur = NULL; + + 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) +{ + struct ibnd_fabric *f = CONV_FABRIC_INTERNAL(fabric); + struct ibnd_node *list = NULL; + struct ibnd_node *cur = NULL; + + switch (node_type) { + case IB_NODE_SWITCH: + list = f->switches; + break; + case IB_NODE_CA: + list = f->ch_adapters; + break; + case IB_NODE_ROUTER: + list = f->routers; + break; + default: + IBND_DEBUG("Invalid node_type specified %d\n", node_type); + break; + } + + for (cur = list; cur; cur = cur->type_next) { + func((ibnd_node_t *)cur, user_data); + } +} + diff --git a/branches/WOF2-1/ulp/libibnetdisc/src/ibnetdisc_export.def b/branches/WOF2-1/ulp/libibnetdisc/src/ibnetdisc_export.def new file mode 100644 index 00000000..62e09936 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibnetdisc/src/ibnetdisc_exports.src b/branches/WOF2-1/ulp/libibnetdisc/src/ibnetdisc_exports.src new file mode 100644 index 00000000..64c40851 --- /dev/null +++ b/branches/WOF2-1/ulp/libibnetdisc/src/ibnetdisc_exports.src @@ -0,0 +1,24 @@ +#if DBG +LIBRARY libibnetdiscd.dll +#else +LIBRARY libibnetdisc.dll +#endif + +#ifndef _WIN64 +EXPORTS + ibnd_debug; + ibnd_show_progress; + ibnd_discover_fabric; + ibnd_destroy_fabric; + ibnd_find_node_guid; + ibnd_update_node; + 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-1/ulp/libibnetdisc/src/ibnetdisc_main.cpp b/branches/WOF2-1/ulp/libibnetdisc/src/ibnetdisc_main.cpp new file mode 100644 index 00000000..7a48a480 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibnetdisc/src/internal.h b/branches/WOF2-1/ulp/libibnetdisc/src/internal.h new file mode 100644 index 00000000..5785e339 --- /dev/null +++ b/branches/WOF2-1/ulp/libibnetdisc/src/internal.h @@ -0,0 +1,95 @@ +/* + * 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 + +#define MAXHOPS 63 + +#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__) + +struct ibnd_node { + /* This member MUST BE FIRST */ + ibnd_node_t node; + + /* internal use only */ + unsigned char ch_found; + struct ibnd_node *htnext; /* hash table list */ + struct ibnd_node *dnext; /* nodesdist next */ + struct ibnd_node *type_next; /* next based on type */ +}; +#define CONV_NODE_INTERNAL(node) ((struct ibnd_node *)node) + +struct ibnd_port { + /* This member MUST BE FIRST */ + ibnd_port_t port; + + /* internal use only */ + struct ibnd_port *htnext; +}; +#define CONV_PORT_INTERNAL(port) ((struct ibnd_port *)port) + +/* HASH table defines */ +#define HASHGUID(guid) ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103))) +#define HTSZ 137 + +struct ibnd_fabric { + /* This member MUST BE FIRST */ + ibnd_fabric_t fabric; + + /* internal use only */ + struct ibnd_node *nodestbl[HTSZ]; + struct ibnd_port *portstbl[HTSZ]; + struct ibnd_node *nodesdist[MAXHOPS+1]; + ibnd_chassis_t *first_chassis; + ibnd_chassis_t *current_chassis; + ibnd_chassis_t *last_chassis; + struct ibnd_node *switches; + struct ibnd_node *ch_adapters; + struct ibnd_node *routers; + ib_portid_t selfportid; +}; +#define CONV_FABRIC_INTERNAL(fabric) ((struct ibnd_fabric *)fabric) + +#endif /* _INTERNAL_H_ */ diff --git a/branches/WOF2-1/ulp/libibnetdisc/src/makefile b/branches/WOF2-1/ulp/libibnetdisc/src/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibumad/AUTHORS b/branches/WOF2-1/ulp/libibumad/AUTHORS new file mode 100644 index 00000000..1fd9242b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibumad/COPYING b/branches/WOF2-1/ulp/libibumad/COPYING new file mode 100644 index 00000000..8d741191 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibumad/dirs b/branches/WOF2-1/ulp/libibumad/dirs new file mode 100644 index 00000000..b1cbe453 --- /dev/null +++ b/branches/WOF2-1/ulp/libibumad/dirs @@ -0,0 +1,2 @@ +DIRS = \ + src \ No newline at end of file diff --git a/branches/WOF2-1/ulp/libibumad/include/infiniband/umad.h b/branches/WOF2-1/ulp/libibumad/include/infiniband/umad.h new file mode 100644 index 00000000..8d14fc16 --- /dev/null +++ b/branches/WOF2-1/ulp/libibumad/include/infiniband/umad.h @@ -0,0 +1,219 @@ +/* + * 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 grh_present; + uint8_t reserved_grh; + uint16_t lid; + uint8_t sl; + uint8_t path_bits; + uint8_t reserved_rate; + uint8_t traffic_class; + +} 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; + +} 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-1/ulp/libibumad/src/Sources b/branches/WOF2-1/ulp/libibumad/src/Sources new file mode 100644 index 00000000..1d53cf29 --- /dev/null +++ b/branches/WOF2-1/ulp/libibumad/src/Sources @@ -0,0 +1,38 @@ +!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; + +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-1/ulp/libibumad/src/ibum_export.def b/branches/WOF2-1/ulp/libibumad/src/ibum_export.def new file mode 100644 index 00000000..1d6e3af6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibumad/src/ibum_exports.src b/branches/WOF2-1/ulp/libibumad/src/ibum_exports.src new file mode 100644 index 00000000..d79244ef --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibumad/src/ibum_main.cpp b/branches/WOF2-1/ulp/libibumad/src/ibum_main.cpp new file mode 100644 index 00000000..a308a55b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibumad/src/ibumad.h b/branches/WOF2-1/ulp/libibumad/src/ibumad.h new file mode 100644 index 00000000..2ec59657 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibumad/src/ibumad.rc b/branches/WOF2-1/ulp/libibumad/src/ibumad.rc new file mode 100644 index 00000000..4a78b165 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibumad/src/makefile b/branches/WOF2-1/ulp/libibumad/src/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibumad/src/umad.cpp b/branches/WOF2-1/ulp/libibumad/src/umad.cpp new file mode 100644 index 00000000..bf70c420 --- /dev/null +++ b/branches/WOF2-1/ulp/libibumad/src/umad.cpp @@ -0,0 +1,700 @@ +/* + * 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 "ibumad.h" + +#define IB_OPENIB_OUI (0x001405) + +#define UMAD_MAX_PKEYS 16 + +typedef struct um_port +{ + IWMProvider *prov; + NET64 dev_guid; + OVERLAPPED overlap; + BOOL pending; + 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) +{ + 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 > max) { + umad_release_ca(&ca); + return -ENOMEM; + } + + 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; + } + } + + 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) { + goto close; + } + } + +close: + ibv_close_device(context); +free: + ibv_free_device_list(list); + if (ret != 0) { + delete ca; + } + 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, FALSE, 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 new uint8_t[num * size]; +} + +__declspec(dllexport) +void umad_free(void *umad) +{ + delete umad; +} + +__declspec(dllexport) +size_t umad_size(void) +{ + return sizeof(struct ib_user_mad); +} + +__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; + + hr = ports[portid].prov->Send((WM_MAD *) mad, NULL); + if (FAILED(hr)) { + return GetLastError(); + } + + return 0; +} + +__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]; + hr = port->prov->Receive(mad, sizeof(WM_MAD) + (size_t) *length, &port->overlap); + + if (hr == WV_IO_PENDING) { + if (port->pending && timeout_ms == 0) { + do { + hr = WaitForSingleObject(port->overlap.hEvent, 250); + } while (hr == WAIT_TIMEOUT && port->pending); + } else { + hr = WaitForSingleObject(port->overlap.hEvent, (DWORD) timeout_ms); + if (hr == WAIT_TIMEOUT) { + return -EWOULDBLOCK; + } + } + } + + if (FAILED(hr)) { + return -EIO; + } + + if (mad->Length <= (UINT32) *length) { + port->pending = FALSE; + hr = (HRESULT) mad->Id; + } else { + 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]; + 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) { + return -ETIMEDOUT; + } + } + + if (FAILED(hr) && hr != ERROR_MORE_DATA) { + return -EIO; + } + + port->pending = TRUE; + return 0; +} + +__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)]) +{ + 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 = 1; + 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(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_register_oui(portid, mgmt_class, rmpp_version, oui, method_mask); +} + +__declspec(dllexport) +int umad_unregister(int portid, int agentid) +{ + ports[portid].pending = FALSE; + 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) +{ + UNREFERENCED_PARAMETER(addr); +} + +__declspec(dllexport) +void umad_dump(void *umad) +{ + UNREFERENCED_PARAMETER(umad); +} diff --git a/branches/WOF2-1/ulp/libibverbs/AUTHORS b/branches/WOF2-1/ulp/libibverbs/AUTHORS new file mode 100644 index 00000000..7c71c124 --- /dev/null +++ b/branches/WOF2-1/ulp/libibverbs/AUTHORS @@ -0,0 +1,4 @@ +Roland Dreier +Dotan Barak +Sean Hefty +Michael S. Tsirkin diff --git a/branches/WOF2-1/ulp/libibverbs/COPYING b/branches/WOF2-1/ulp/libibverbs/COPYING new file mode 100644 index 00000000..9589a0bb --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/dirs b/branches/WOF2-1/ulp/libibverbs/dirs new file mode 100644 index 00000000..c0df7b8e --- /dev/null +++ b/branches/WOF2-1/ulp/libibverbs/dirs @@ -0,0 +1,3 @@ +DIRS = \ + src \ + examples diff --git a/branches/WOF2-1/ulp/libibverbs/examples/asyncwatch/SOURCES b/branches/WOF2-1/ulp/libibverbs/examples/asyncwatch/SOURCES new file mode 100644 index 00000000..f8c7c854 --- /dev/null +++ b/branches/WOF2-1/ulp/libibverbs/examples/asyncwatch/SOURCES @@ -0,0 +1,30 @@ +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; + +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-1/ulp/libibverbs/examples/asyncwatch/asyncwatch.c b/branches/WOF2-1/ulp/libibverbs/examples/asyncwatch/asyncwatch.c new file mode 100644 index 00000000..385c8979 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/asyncwatch/asyncwatch.rc b/branches/WOF2-1/ulp/libibverbs/examples/asyncwatch/asyncwatch.rc new file mode 100644 index 00000000..aa7bc92a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/asyncwatch/makefile b/branches/WOF2-1/ulp/libibverbs/examples/asyncwatch/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/device_list.c b/branches/WOF2-1/ulp/libibverbs/examples/device_list.c new file mode 100644 index 00000000..7019279e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/devinfo/SOURCES b/branches/WOF2-1/ulp/libibverbs/examples/devinfo/SOURCES new file mode 100644 index 00000000..ac30a430 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/devinfo/devinfo.c b/branches/WOF2-1/ulp/libibverbs/examples/devinfo/devinfo.c new file mode 100644 index 00000000..c50da422 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/devinfo/devinfo.rc b/branches/WOF2-1/ulp/libibverbs/examples/devinfo/devinfo.rc new file mode 100644 index 00000000..6bbe1451 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/devinfo/makefile b/branches/WOF2-1/ulp/libibverbs/examples/devinfo/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/dirs b/branches/WOF2-1/ulp/libibverbs/examples/dirs new file mode 100644 index 00000000..30a94ebe --- /dev/null +++ b/branches/WOF2-1/ulp/libibverbs/examples/dirs @@ -0,0 +1,6 @@ +DIRS = \ + devinfo \ + rc_pingpong \ + uc_pingpong \ + ud_pingpong \ + asyncwatch diff --git a/branches/WOF2-1/ulp/libibverbs/examples/pingpong.c b/branches/WOF2-1/ulp/libibverbs/examples/pingpong.c new file mode 100644 index 00000000..9fb0658e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/pingpong.h b/branches/WOF2-1/ulp/libibverbs/examples/pingpong.h new file mode 100644 index 00000000..3b59aaeb --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/rc_pingpong/SOURCES b/branches/WOF2-1/ulp/libibverbs/examples/rc_pingpong/SOURCES new file mode 100644 index 00000000..8de70ed4 --- /dev/null +++ b/branches/WOF2-1/ulp/libibverbs/examples/rc_pingpong/SOURCES @@ -0,0 +1,30 @@ +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; + +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-1/ulp/libibverbs/examples/rc_pingpong/makefile b/branches/WOF2-1/ulp/libibverbs/examples/rc_pingpong/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.c b/branches/WOF2-1/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.c new file mode 100644 index 00000000..5f9511aa --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.rc b/branches/WOF2-1/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.rc new file mode 100644 index 00000000..7365c013 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/srq_pingpong/SOURCES b/branches/WOF2-1/ulp/libibverbs/examples/srq_pingpong/SOURCES new file mode 100644 index 00000000..9e55c726 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/srq_pingpong/makefile b/branches/WOF2-1/ulp/libibverbs/examples/srq_pingpong/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.c b/branches/WOF2-1/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.c new file mode 100644 index 00000000..36446aa8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.rc b/branches/WOF2-1/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.rc new file mode 100644 index 00000000..43ea8951 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/uc_pingpong/SOURCES b/branches/WOF2-1/ulp/libibverbs/examples/uc_pingpong/SOURCES new file mode 100644 index 00000000..c84ae84c --- /dev/null +++ b/branches/WOF2-1/ulp/libibverbs/examples/uc_pingpong/SOURCES @@ -0,0 +1,30 @@ +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; + +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-1/ulp/libibverbs/examples/uc_pingpong/makefile b/branches/WOF2-1/ulp/libibverbs/examples/uc_pingpong/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.c b/branches/WOF2-1/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.c new file mode 100644 index 00000000..d17559c1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.rc b/branches/WOF2-1/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.rc new file mode 100644 index 00000000..12dbc6de --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/ud_pingpong/SOURCES b/branches/WOF2-1/ulp/libibverbs/examples/ud_pingpong/SOURCES new file mode 100644 index 00000000..5cdce283 --- /dev/null +++ b/branches/WOF2-1/ulp/libibverbs/examples/ud_pingpong/SOURCES @@ -0,0 +1,30 @@ +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; + +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-1/ulp/libibverbs/examples/ud_pingpong/makefile b/branches/WOF2-1/ulp/libibverbs/examples/ud_pingpong/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.c b/branches/WOF2-1/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.c new file mode 100644 index 00000000..f3e73f7e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.rc b/branches/WOF2-1/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.rc new file mode 100644 index 00000000..c5d0ecc7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/include/infiniband/verbs.h b/branches/WOF2-1/ulp/libibverbs/include/infiniband/verbs.h new file mode 100644 index 00000000..700259e3 --- /dev/null +++ b/branches/WOF2-1/ulp/libibverbs/include/infiniband/verbs.h @@ -0,0 +1,1138 @@ +/* + * 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 +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Interfaces based on libibverbs 1.1.2. + */ + +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +#define EOVERFLOW WV_BUFFER_OVERFLOW +#define EISCONN WV_CONNECTION_ACTIVE +#define ECONNREFUSED WV_CONNECTION_REFUSED +#define ETIMEDOUT WV_TIMEOUT +#define ENETUNREACH WV_HOST_UNREACHABLE +#define EADDRINUSE WV_ADDRESS_ALREADY_EXISTS +#define EALREADY WV_IO_PENDING +#define EAFNOSUPPORT WV_INVALID_ADDRESS +#define EWOULDBLOCK WV_DEVICE_BUSY + +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, + IBV_WC_LOC_LEN_ERR, + IBV_WC_LOC_QP_OP_ERR, + IBV_WC_LOC_PROT_ERR, + IBV_WC_WR_FLUSH_ERR, + IBV_WC_MW_BIND_ERR, + IBV_WC_REM_ACCESS_ERR, + IBV_WC_REM_OP_ERR, + IBV_WC_RNR_RETRY_EXC_ERR, + IBV_WC_RESP_TIMEOUT_ERR, + IBV_WC_REM_INV_REQ_ERR, + IBV_WC_BAD_RESP_ERR, + IBV_WC_LOC_ACCESS_ERR, + IBV_WC_GENERAL_ERR, + IBV_WC_FATAL_ERR, + IBV_WC_RETRY_EXC_ERR, + IBV_WC_REM_ABORT_ERR, + IBV_WC_LOC_EEC_OP_ERR, + IBV_WC_LOC_RDD_VIOL_ERR, + IBV_WC_REM_INV_RD_REQ_ERR, + IBV_WC_INV_EECN_ERR, + IBV_WC_INV_EEC_STATE_ERR +}; + +__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; + + enum ibv_wc_flags 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; + 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; + 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; + enum ibv_send_flags send_flags; + enum ibv_access_flags 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; +}; + +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, enum ibv_access_flags 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, + enum ibv_srq_attr_mask 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, + enum ibv_qp_attr_mask 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, + enum ibv_qp_attr_mask 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); + +#ifdef __cplusplus +} +#endif + +#endif /* INFINIBAND_VERBS_H */ diff --git a/branches/WOF2-1/ulp/libibverbs/src/Sources b/branches/WOF2-1/ulp/libibverbs/src/Sources new file mode 100644 index 00000000..20c50ae1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/src/device.cpp b/branches/WOF2-1/ulp/libibverbs/src/device.cpp new file mode 100644 index 00000000..a515a16f --- /dev/null +++ b/branches/WOF2-1/ulp/libibverbs/src/device.cpp @@ -0,0 +1,370 @@ +/* + * 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) +{ + 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(); + 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-1/ulp/libibverbs/src/enum_strs.cpp b/branches/WOF2-1/ulp/libibverbs/src/enum_strs.cpp new file mode 100644 index 00000000..945583f9 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/src/ibv_export.def b/branches/WOF2-1/ulp/libibverbs/src/ibv_export.def new file mode 100644 index 00000000..6c76ba5d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/src/ibv_exports.src b/branches/WOF2-1/ulp/libibverbs/src/ibv_exports.src new file mode 100644 index 00000000..67707a55 --- /dev/null +++ b/branches/WOF2-1/ulp/libibverbs/src/ibv_exports.src @@ -0,0 +1,56 @@ +#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 +#endif diff --git a/branches/WOF2-1/ulp/libibverbs/src/ibv_main.cpp b/branches/WOF2-1/ulp/libibverbs/src/ibv_main.cpp new file mode 100644 index 00000000..04f4de58 --- /dev/null +++ b/branches/WOF2-1/ulp/libibverbs/src/ibv_main.cpp @@ -0,0 +1,42 @@ +/* + * 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 + +extern CRITICAL_SECTION lock; + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(hInstance); + UNREFERENCED_PARAMETER(dwReason); + UNREFERENCED_PARAMETER(lpReserved); + + InitializeCriticalSection(&lock); + return TRUE; +} diff --git a/branches/WOF2-1/ulp/libibverbs/src/ibverbs.h b/branches/WOF2-1/ulp/libibverbs/src/ibverbs.h new file mode 100644 index 00000000..baf012c6 --- /dev/null +++ b/branches/WOF2-1/ulp/libibverbs/src/ibverbs.h @@ -0,0 +1,45 @@ +/* + * 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 + +extern COMP_MANAGER comp_mgr; + +__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_VERBS_H */ diff --git a/branches/WOF2-1/ulp/libibverbs/src/ibverbs.rc b/branches/WOF2-1/ulp/libibverbs/src/ibverbs.rc new file mode 100644 index 00000000..1e2b9c1f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/src/makefile b/branches/WOF2-1/ulp/libibverbs/src/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/libibverbs/src/verbs.cpp b/branches/WOF2-1/ulp/libibverbs/src/verbs.cpp new file mode 100644 index 00000000..e5dffc60 --- /dev/null +++ b/branches/WOF2-1/ulp/libibverbs/src/verbs.cpp @@ -0,0 +1,882 @@ +/* + * 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 ? ret : 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 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 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 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 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, enum ibv_access_flags 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) +{ + return mr->pd->handle->DeregisterMemory(mr->lkey, NULL); +} + +__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; + + 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 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) { + hr = cq->handle->Notify(solicited_only ? WvCqSolicited : WvCqNextCompletion, + &cq->comp_entry.Overlap); + if (SUCCEEDED(hr) || hr == WV_IO_PENDING) { + hr = 0; + } + } else { + hr = 0; + } + return 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) { + CompEntryCancel(&cq->comp_entry); + } + 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) +{ +} + +__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, + enum ibv_srq_attr_mask 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 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 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 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, (enum ibv_qp_attr_mask) 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, + enum ibv_qp_attr_mask 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 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, + enum ibv_qp_attr_mask 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 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 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 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 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 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 qp->ud_handle->DetachMulticast((WV_GID *) gid, lid, NULL); +} diff --git a/branches/WOF2-1/ulp/librdmacm/AUTHORS b/branches/WOF2-1/ulp/librdmacm/AUTHORS new file mode 100644 index 00000000..589c93d1 --- /dev/null +++ b/branches/WOF2-1/ulp/librdmacm/AUTHORS @@ -0,0 +1 @@ +Sean Hefty diff --git a/branches/WOF2-1/ulp/librdmacm/COPYING b/branches/WOF2-1/ulp/librdmacm/COPYING new file mode 100644 index 00000000..41367600 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/librdmacm/dirs b/branches/WOF2-1/ulp/librdmacm/dirs new file mode 100644 index 00000000..b1051907 --- /dev/null +++ b/branches/WOF2-1/ulp/librdmacm/dirs @@ -0,0 +1,3 @@ +DIRS = \ + src \ + examples diff --git a/branches/WOF2-1/ulp/librdmacm/examples/cmatose/SOURCES b/branches/WOF2-1/ulp/librdmacm/examples/cmatose/SOURCES new file mode 100644 index 00000000..cfe59ff2 --- /dev/null +++ b/branches/WOF2-1/ulp/librdmacm/examples/cmatose/SOURCES @@ -0,0 +1,30 @@ +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; + +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-1/ulp/librdmacm/examples/cmatose/cmatose.c b/branches/WOF2-1/ulp/librdmacm/examples/cmatose/cmatose.c new file mode 100644 index 00000000..e3ce6e6f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/librdmacm/examples/cmatose/makefile b/branches/WOF2-1/ulp/librdmacm/examples/cmatose/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/librdmacm/examples/dirs b/branches/WOF2-1/ulp/librdmacm/examples/dirs new file mode 100644 index 00000000..2bdf906e --- /dev/null +++ b/branches/WOF2-1/ulp/librdmacm/examples/dirs @@ -0,0 +1,2 @@ +DIRS = \ + cmatose diff --git a/branches/WOF2-1/ulp/librdmacm/examples/mckey/mckey.c b/branches/WOF2-1/ulp/librdmacm/examples/mckey/mckey.c new file mode 100644 index 00000000..a858ad6b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/librdmacm/examples/rping/rping.c b/branches/WOF2-1/ulp/librdmacm/examples/rping/rping.c new file mode 100644 index 00000000..1e264feb --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/librdmacm/examples/udaddy/udaddy.c b/branches/WOF2-1/ulp/librdmacm/examples/udaddy/udaddy.c new file mode 100644 index 00000000..9e74a228 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/librdmacm/include/rdma/rdma_cma.h b/branches/WOF2-1/ulp/librdmacm/include/rdma/rdma_cma.h new file mode 100644 index 00000000..c665dcd2 --- /dev/null +++ b/branches/WOF2-1/ulp/librdmacm/include/rdma/rdma_cma.h @@ -0,0 +1,636 @@ +/* + * 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 + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Interfaces based on librdmacm 1.0.8. + */ + +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +/* + * Upon receiving a device removal event, users must destroy the associated + * RDMA identifier and release all resources allocated with the device. + */ +enum rdma_cm_event_type +{ + RDMA_CM_EVENT_ADDR_RESOLVED, + RDMA_CM_EVENT_ADDR_ERROR, + RDMA_CM_EVENT_ROUTE_RESOLVED, + RDMA_CM_EVENT_ROUTE_ERROR, + RDMA_CM_EVENT_CONNECT_REQUEST, + RDMA_CM_EVENT_CONNECT_RESPONSE, + RDMA_CM_EVENT_CONNECT_ERROR, + RDMA_CM_EVENT_UNREACHABLE, + RDMA_CM_EVENT_REJECTED, + RDMA_CM_EVENT_ESTABLISHED, + RDMA_CM_EVENT_DISCONNECTED, + RDMA_CM_EVENT_DEVICE_REMOVAL, + RDMA_CM_EVENT_MULTICAST_JOIN, + RDMA_CM_EVENT_MULTICAST_ERROR, + RDMA_CM_EVENT_ADDR_CHANGE, + RDMA_CM_EVENT_TIMEWAIT_EXIT +}; + +enum rdma_port_space +{ + RDMA_PS_IPOIB = 0x0002, + RDMA_PS_TCP = 0x0106, + RDMA_PS_UDP = 0x0111, +}; + +/* + * Global qkey value for UDP QPs and multicast groups created via the + * RDMA CM. + */ +#define RDMA_UDP_QKEY 0x01234567 + +struct ib_addr +{ + union ibv_gid sgid; + union ibv_gid dgid; + uint16_t pkey; +}; + +struct rdma_addr +{ + struct sockaddr src_addr; + uint8_t src_pad[sizeof(SOCKADDR_IN6) - + sizeof(struct sockaddr)]; + struct sockaddr dst_addr; + uint8_t dst_pad[sizeof(SOCKADDR_IN6) - + sizeof(struct sockaddr)]; + union + { + struct ib_addr ibaddr; + } addr; +}; + +struct ibv_sa_path_rec +{ + uint8_t data[64]; +}; + +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_conn_param +{ + const void *private_data; + uint8_t private_data_len; + uint8_t responder_resources; + uint8_t initiator_depth; + uint8_t flow_control; + uint8_t retry_count; /* ignored when accepting */ + uint8_t rnr_retry_count; + /* Fields below ignored if a QP is created on the rdma_cm_id. */ + uint8_t srq; + uint32_t qp_num; +}; + +struct rdma_ud_param +{ + const void *private_data; + uint8_t private_data_len; + struct ibv_ah_attr ah_attr; + uint32_t qp_num; + uint32_t qkey; +}; + +struct rdma_cm_event +{ + struct rdma_cm_id *id; + struct rdma_cm_id *listen_id; + enum rdma_cm_event_type event; + int status; + union + { + struct rdma_conn_param conn; + struct rdma_ud_param ud; + + } param; +}; + +/** + * rdma_create_event_channel - Open a channel used to report communication events. + * Description: + * Asynchronous events are reported to users through event channels. Each + * event channel maps to a file descriptor. + * Notes: + * All created event channels must be destroyed by calling + * rdma_destroy_event_channel. Users should call rdma_get_cm_event to + * retrieve events on an event channel. + * See also: + * rdma_get_cm_event, rdma_destroy_event_channel + */ +__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_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); + +/** + * 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); + +#ifdef __cplusplus +} +#endif + +#endif /* RDMA_CMA_H */ diff --git a/branches/WOF2-1/ulp/librdmacm/src/Sources b/branches/WOF2-1/ulp/librdmacm/src/Sources new file mode 100644 index 00000000..3a771696 --- /dev/null +++ b/branches/WOF2-1/ulp/librdmacm/src/Sources @@ -0,0 +1,40 @@ +!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 + +INCLUDES = ..\include;..\..\..\inc;..\..\..\inc\user;..\..\libibverbs\include + +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-1/ulp/librdmacm/src/cma.cpp b/branches/WOF2-1/ulp/librdmacm/src/cma.cpp new file mode 100644 index 00000000..757e4cda --- /dev/null +++ b/branches/WOF2-1/ulp/librdmacm/src/cma.cpp @@ -0,0 +1,1073 @@ +/* + * 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 +#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 backlog; + int index; + volatile LONG refcnt; + struct rdma_cm_id **req_list; +}; + +struct cma_device +{ + struct ibv_context *verbs; + uint64_t guid; + int port_cnt; + uint8_t max_initiator_depth; + uint8_t max_responder_resources; +}; + +struct cma_event { + struct rdma_cm_event event; + uint8_t private_data[56]; + struct cma_id_private *id_priv; +}; + +static struct cma_device *cma_dev_array; +static int cma_dev_cnt; + +static void ucma_cleanup(void) +{ + if (cma_dev_cnt > 0) { + while (cma_dev_cnt > 0) { + ibv_close_device(cma_dev_array[--cma_dev_cnt].verbs); + } + delete cma_dev_array; + cma_dev_cnt = 0; + } + if (windata.prov != NULL) { + ibvw_release_windata(&windata, IBVW_WINDATA_VERSION); + windata.prov = NULL; + } +} + +static int ucma_init(void) +{ + struct ibv_device **dev_list = NULL; + struct cma_device *cma_dev; + struct ibv_device_attr attr; + int i, ret; + + EnterCriticalSection(&lock); + if (cma_dev_cnt > 0) { + goto out; + } + + ret = ibvw_get_windata(&windata, IBVW_WINDATA_VERSION); + if (ret) { + goto err; + } + + dev_list = ibv_get_device_list(&cma_dev_cnt); + if (dev_list == NULL) { + ret = -1; + goto err; + } + + cma_dev_array = new struct cma_device[cma_dev_cnt]; + if (cma_dev_array == NULL) { + ret = -1; + goto err; + } + + for (i = 0; dev_list[i]; ++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 err; + } + + ret = ibv_query_device(cma_dev->verbs, &attr); + if (ret) { + goto err; + } + + 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); +out: + LeaveCriticalSection(&lock); + return 0; + +err: + ucma_cleanup(); + LeaveCriticalSection(&lock); + if (dev_list) { + ibv_free_device_list(dev_list); + } + return ret; +} + +__declspec(dllexport) +struct ibv_context **rdma_get_devices(int *num_devices) +{ + struct ibv_context **devs = NULL; + int i; + + if (!cma_dev_cnt && ucma_init()) { + goto out; + } + + devs = 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; +} + +__declspec(dllexport) +struct rdma_event_channel *rdma_create_event_channel(void) +{ + struct rdma_event_channel *channel; + + if (!cma_dev_cnt && ucma_init()) { + 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; +} + +__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; + + hr = cma_dev_cnt ? 0 : ucma_init(); + if (hr) { + return hr; + } + + id_priv = new struct cma_id_private; + if (id_priv == NULL) { + return NULL; + } + + RtlZeroMemory(id_priv, sizeof(struct cma_id_private)); + id_priv->refcnt = 1; + id_priv->id.context = context; + id_priv->id.channel = channel; + id_priv->id.ps = ps; + CompEntryInit(&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)) { + goto err; + } + + *id = &id_priv->id; + return 0; + +err: + delete id_priv; + 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(); + } + + InterlockedDecrement(&id_priv->refcnt); + while (id_priv->refcnt) { + Sleep(0); + } + delete id_priv; + 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; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + hr = id->ep.connect->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; + 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) { + hr = ucma_get_device(id_priv, attr.Device.DeviceGuid); + if (FAILED(hr)) { + return hr; + } + + 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; + + 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) { + hr = ucma_get_device(id_priv, attr.Device.DeviceGuid); + if (FAILED(hr)) + return hr; + 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; + + if (id->ps == RDMA_PS_TCP) { + hr = id->ep.connect->BindAddress(addr); + if (SUCCEEDED(hr)) { + hr = ucma_query_connect(id, NULL); + } + } else { + hr = id->ep.datagram->BindAddress(addr); + if (SUCCEEDED(hr)) { + hr = ucma_query_datagram(id, NULL); + } + } + + if (SUCCEEDED(hr)) { + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + id_priv->state = cma_addr_bind; + } + return hr; +} + +__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; + + 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 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 WSAGetLastError(); + } + src_addr = &addr.Sa; + } + + hr = rdma_bind_addr(id, src_addr); + if (FAILED(hr)) { + return hr; + } + } + + 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 0; +} + +__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::Resolve(&id->route.addr.src_addr, &id->route.addr.dst_addr, &path); + if (FAILED(hr)) { + return 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 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 0; +} + +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 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)); +} + +__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 (id->verbs != pd->context) { + return -1; + } + + qp = ibv_create_qp(pd, qp_init_attr); + if (!qp) { + return -1; + } + + 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 err; + } + + id->qp = qp; + return 0; +err: + ibv_destroy_qp(qp); + return ret; +} + +__declspec(dllexport) +void rdma_destroy_qp(struct rdma_cm_id *id) +{ + ibv_destroy_qp(id->qp); +} + +static int ucma_valid_param(struct cma_id_private *id_priv, + struct rdma_conn_param *conn_param) +{ + if (id_priv->id.ps != RDMA_PS_TCP) { + return 0; + } + + if ((conn_param->responder_resources > id_priv->cma_dev->max_responder_resources) || + (conn_param->initiator_depth > id_priv->cma_dev->max_initiator_depth)) { + return -1; + } + + return 0; +} + +__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; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + hr = ucma_valid_param(id_priv, conn_param); + if (FAILED(hr)) { + return hr; + } + + RtlZeroMemory(&attr, sizeof attr); + attr.ResponderResources = conn_param->responder_resources; + attr.InitiatorDepth = conn_param->initiator_depth; + attr.RetryCount = conn_param->retry_count; + attr.RnrRetryCount = conn_param->rnr_retry_count; + if ((attr.DataLength = conn_param->private_data_len)) { + RtlCopyMemory(attr.Data, conn_param->private_data, attr.DataLength); + } + + 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 hr; + } + + return 0; +} + +static int ucma_get_request(struct cma_id_private *listen, int index) +{ + struct cma_id_private *id_priv = NULL; + HRESULT hr; + + EnterCriticalSection(&lock); + if (listen->state != cma_listening) { + hr = WV_INVALID_PARAMETER; + goto err1; + } + + InterlockedIncrement(&listen->refcnt); + hr = rdma_create_id(listen->id.channel, &listen->req_list[index], + listen, listen->id.ps); + if (FAILED(hr)) { + 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) { + 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 hr; +} + +__declspec(dllexport) +int rdma_listen(struct rdma_cm_id *id, int backlog) +{ + struct cma_id_private *id_priv, *req_id; + HRESULT hr; + int i; + + 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 hr; + } + + for (i = 0; i < backlog; i++) { + hr = ucma_get_request(id_priv, i); + if (FAILED(hr)) { + return hr; + } + } + + return 0; +} + +__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; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + hr = ucma_valid_param(id_priv, conn_param); + if (FAILED(hr)) { + return hr; + } + + RtlZeroMemory(&attr, sizeof attr); + attr.ResponderResources = conn_param->responder_resources; + attr.InitiatorDepth = conn_param->initiator_depth; + attr.RetryCount = conn_param->retry_count; + attr.RnrRetryCount = conn_param->rnr_retry_count; + if ((attr.DataLength = conn_param->private_data_len)) { + RtlCopyMemory(attr.Data, conn_param->private_data, attr.DataLength); + } + + 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 hr; + } + + return 0; +} + +__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 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 hr; + } + + return 0; +} + +__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 (SUCCEEDED(event->event.status)) { + event->event.status = ucma_query_connect(&id_priv->id, + &event->event.param.conn); + } + + if (SUCCEEDED(event->event.status)) { + event->event.event = RDMA_CM_EVENT_CONNECT_REQUEST; + id_priv->state = cma_passive_connect; + event->event.listen_id = &listen->id; + } else { + 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 (FAILED(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 WV_IO_PENDING; + +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 (SUCCEEDED(event->event.status)) { + event->event.status = ucma_query_connect(&id_priv->id, + &event->event.param.conn); + } + + if (SUCCEEDED(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; + HRESULT hr = 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); + hr = WV_CANCELLED; + 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: + hr = 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); + hr = WV_CANCELLED; + } + LeaveCriticalSection(&lock); + + return hr; +} + +__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) { + 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.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 WV_NOT_SUPPORTED; +} + +__declspec(dllexport) +int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) +{ + return WV_NOT_SUPPORTED; +} + +__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 WV_NOT_SUPPORTED; +} + +__declspec(dllexport) +int rdma_migrate_id(struct rdma_cm_id *id, struct rdma_event_channel *channel) +{ + id->channel = channel; + return 0; +} diff --git a/branches/WOF2-1/ulp/librdmacm/src/cma.h b/branches/WOF2-1/ulp/librdmacm/src/cma.h new file mode 100644 index 00000000..fb65026b --- /dev/null +++ b/branches/WOF2-1/ulp/librdmacm/src/cma.h @@ -0,0 +1,46 @@ +/* + * 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; + +__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 /* CMA_H */ diff --git a/branches/WOF2-1/ulp/librdmacm/src/cma.rc b/branches/WOF2-1/ulp/librdmacm/src/cma.rc new file mode 100644 index 00000000..fd205458 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/librdmacm/src/cma_export.def b/branches/WOF2-1/ulp/librdmacm/src/cma_export.def new file mode 100644 index 00000000..7a2b1ec4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/librdmacm/src/cma_exports.src b/branches/WOF2-1/ulp/librdmacm/src/cma_exports.src new file mode 100644 index 00000000..853173b3 --- /dev/null +++ b/branches/WOF2-1/ulp/librdmacm/src/cma_exports.src @@ -0,0 +1,33 @@ +#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 +#endif diff --git a/branches/WOF2-1/ulp/librdmacm/src/cma_main.cpp b/branches/WOF2-1/ulp/librdmacm/src/cma_main.cpp new file mode 100644 index 00000000..44519eb4 --- /dev/null +++ b/branches/WOF2-1/ulp/librdmacm/src/cma_main.cpp @@ -0,0 +1,44 @@ +/* + * 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; + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(hInstance); + UNREFERENCED_PARAMETER(dwReason); + UNREFERENCED_PARAMETER(lpReserved); + + InitializeCriticalSection(&lock); + + return TRUE; +} diff --git a/branches/WOF2-1/ulp/librdmacm/src/makefile b/branches/WOF2-1/ulp/librdmacm/src/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/dirs b/branches/WOF2-1/ulp/nd/dirs new file mode 100644 index 00000000..db5a8974 --- /dev/null +++ b/branches/WOF2-1/ulp/nd/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/ulp/nd/user/NdAdapter.cpp b/branches/WOF2-1/ulp/nd/user/NdAdapter.cpp new file mode 100644 index 00000000..a174d94c --- /dev/null +++ b/branches/WOF2-1/ulp/nd/user/NdAdapter.cpp @@ -0,0 +1,950 @@ +/* + * 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->MaxInboundSge = pAttr->max_sges; + pInfo->MaxInboundRequests = pAttr->max_wrs; + pInfo->MaxInboundLength = INT_MAX; + pInfo->MaxOutboundSge = pAttr->max_sges; + pInfo->MaxOutboundRequests = pAttr->max_wrs; + pInfo->MaxOutboundLength = INT_MAX; + 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); + 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-1/ulp/nd/user/NdAdapter.h b/branches/WOF2-1/ulp/nd/user/NdAdapter.h new file mode 100644 index 00000000..79b79e04 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/NdConnector.cpp b/branches/WOF2-1/ulp/nd/user/NdConnector.cpp new file mode 100644 index 00000000..3cb4aa2d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/NdConnector.h b/branches/WOF2-1/ulp/nd/user/NdConnector.h new file mode 100644 index 00000000..6f701a9e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/NdCq.cpp b/branches/WOF2-1/ulp/nd/user/NdCq.cpp new file mode 100644 index 00000000..94c71c3b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/NdCq.h b/branches/WOF2-1/ulp/nd/user/NdCq.h new file mode 100644 index 00000000..f4bdb79a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/NdEndpoint.cpp b/branches/WOF2-1/ulp/nd/user/NdEndpoint.cpp new file mode 100644 index 00000000..3325477a --- /dev/null +++ b/branches/WOF2-1/ulp/nd/user/NdEndpoint.cpp @@ -0,0 +1,944 @@ +/* + * 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" + +#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_send != NULL || + m_pParent->m_Ifc.user_verbs.post_recv != NULL /*|| + m_pParent->m_Ifc.user_verbs.bind_mw != NULL*/ ); + + HRESULT hr = CreateQp( + pInboundCq, + pOutboundCq, + nInboundEntries, + nOutboundEntries, + nInboundSge, + nOutboundSge, + InboundReadLimit, + OutboundReadLimit ); + + if( FAILED( hr ) ) + return hr; + + 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 ) + { + // Worst case. + *pMaxInlineData = nOutboundSge * 12; + } + + 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; + 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; + // 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; + 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 + ) +{ + ND_ENTER( ND_DBG_NDI ); + + 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.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; +} + +} // namespace diff --git a/branches/WOF2-1/ulp/nd/user/NdEndpoint.h b/branches/WOF2-1/ulp/nd/user/NdEndpoint.h new file mode 100644 index 00000000..f47a6c34 --- /dev/null +++ b/branches/WOF2-1/ulp/nd/user/NdEndpoint.h @@ -0,0 +1,202 @@ +/* + * 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 + ); + + void DestroyQp(); + + 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; +}; + +} // namespace diff --git a/branches/WOF2-1/ulp/nd/user/NdListen.cpp b/branches/WOF2-1/ulp/nd/user/NdListen.cpp new file mode 100644 index 00000000..82f01110 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/NdListen.h b/branches/WOF2-1/ulp/nd/user/NdListen.h new file mode 100644 index 00000000..3372fbf8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/NdMr.cpp b/branches/WOF2-1/ulp/nd/user/NdMr.cpp new file mode 100644 index 00000000..2216e63f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/NdMr.h b/branches/WOF2-1/ulp/nd/user/NdMr.h new file mode 100644 index 00000000..1b320e63 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/NdMw.cpp b/branches/WOF2-1/ulp/nd/user/NdMw.cpp new file mode 100644 index 00000000..cc10eb04 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/NdMw.h b/branches/WOF2-1/ulp/nd/user/NdMw.h new file mode 100644 index 00000000..be1f0d44 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/NdProv.cpp b/branches/WOF2-1/ulp/nd/user/NdProv.cpp new file mode 100644 index 00000000..720ef076 --- /dev/null +++ b/branches/WOF2-1/ulp/nd/user/NdProv.cpp @@ -0,0 +1,570 @@ +/* + * 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; */ + +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: + + +#if defined(EVENT_TRACING) +#if DBG + WPP_INIT_TRACING(L"ibndprov.dll"); +#else + WPP_INIT_TRACING(L"ibndprov.dll"); +#endif +#elif DBG + TCHAR env_var[16]; + DWORD i; + + 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 + + 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-1/ulp/nd/user/NdProv.def b/branches/WOF2-1/ulp/nd/user/NdProv.def new file mode 100644 index 00000000..f2fb99c5 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/NdProv.h b/branches/WOF2-1/ulp/nd/user/NdProv.h new file mode 100644 index 00000000..21de4a70 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/NdProv.rc b/branches/WOF2-1/ulp/nd/user/NdProv.rc new file mode 100644 index 00000000..d40c4240 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/README.txt b/branches/WOF2-1/ulp/nd/user/README.txt new file mode 100644 index 00000000..35420c10 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/SOURCES b/branches/WOF2-1/ulp/nd/user/SOURCES new file mode 100644 index 00000000..7e2593b8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/fake.c b/branches/WOF2-1/ulp/nd/user/fake.c new file mode 100644 index 00000000..34ad6498 --- /dev/null +++ b/branches/WOF2-1/ulp/nd/user/fake.c @@ -0,0 +1,2 @@ + +int __cdecl main() { return 0; } diff --git a/branches/WOF2-1/ulp/nd/user/fre_svr-03_amd64/amd64/ibndprov.dll b/branches/WOF2-1/ulp/nd/user/fre_svr-03_amd64/amd64/ibndprov.dll new file mode 100644 index 0000000000000000000000000000000000000000..15e993726730efbbcc378fa93c2b67690c5ec950 GIT binary patch literal 43520 zcmeIbdw5jU)jz%`nS>!1X23+lO$Hn^a?wao1Cct1OyG=6AV5H>U=orEiG*ZKCKwcT zaDrxXoHkzCVqadRTw1`sO0Crpu}%O@fQS)oja6$<+jlT(k zuRm^Oqndtz!(|mE<<$0YBgxNYtn|J(Hp&~4wK{!lia9aHz}PnAq=?*ARe&anTj@u{ zV;GA^ltLUsg8uptK+I9iI?&ZB68II*Mnrg9lomyO4>2|weI@;Xv3knvVr&OZOn|X` znjGz~hq29|d(mjdCTMy83`Bpc@Z4~JSGb+^ZWNCG34RDS8hd2FNSe{@6{W@QV#E*8 zpbsF>u(u;b{8@qZ6)sVc;~qdE)qe~j;?D|VUQtt9Q-VA`R*aeVxjUi~qE=qdSy_#W zeKdw11nPG$Ld2hyvH20n|BL<;6o?1k(cc6Wu2ta;Dx9stvk!`T+VARS5xZ4|8&!C( z3LjD7eia^4;bIm3QH39?@M{%bsP>bgLaPc_s_-!tpZnDGPgVG&3XiL>Q*EzOO>21H zr#`QxpH$Po9gu&a`us;f6g4x{bdQ>jQPaOypX(X$yw*NJO}7xs-i(kw9>GW@kf~o; zISi;!6VU+AWeWu0YJj2(q?`gIcK>4;MH!dbfe~YWl z%iYCpr#Yv*xN4o#oW6KT{^iJDUbnW&={DyTR~4^wZg5tS>@TaXb31ELc6)`pq@12+ zj2^3UR+^>KViy&zSiER4HJ>rY%FE3vOi^Ky3eSxe!Nu)qmJ=#|OXoHtA~n{KEXj`Gq-Bp=9H_Bb;8Ao416tiuhCO zM;D zwA-Q!)cTHL@|Ulezc{y`u)v;|yJST{#G~qS_9ZI>!6MR;WYETIUy?JRUQXd~_41_x zS)GM2-t;`r*B(;)Tb8@9FlR|#z9Y9l5MV{s`l{;Nt614bpZ)BjJbm6llka-xy;9f7 zXG&7a?%2KXiML07ddFLT-nM%66{{=O7FQCDuPCkLkm7Y4U4`qM?!t;HX!o+>5+`Lw z{H?me%2Vm{1?*7MhV>%7`bq&mRAHYAJy(hR2UNIsmPi-O7O>%J0j<{vXt-9u#VZ^R zhQGy5_wCg+>unV^&Jy?Bxj8wv&7Hf@>0YwYSyNf;ayd(vIcw`G-9y$}Tek=FXjC>H5MDzvQ?={HoE`SaW{v!=~m=uPTbGwHtnjQQ(n%6X?}j(hF%JR=o?>)mR3y?`_BP}6q`Xt_&3^F0EVZxK-A-|hE`^s?o)<)z-a zd7TY&Zg}qgBR|-3V)84ojIolrtBFtXQ#Na6#%edVy6ac3t*BaESL>`BGkdl8tyo)Cif!^n?2^`^ksyZR6OVL?Khzx;n9?Tulb<~w3K^db$cnyAEi^vc<~gr#jYDz{%&64g=UVHlbFO2s{hA$*zwV})> zO>44QGRkZ|dwQdE71hZ?u{{kXvy9K$EY`BN4yraA)#N6JC4b8CKu>%^2a>C##v86d zRuM9$9Oqf($hsC;uKuigsd4_C%m50qB;WiQNM+c4F=dF)MYt}EdS{s;&8E&G2i_!I z6*4+d^n>?x^`gswbA8S1Ix1_%N1#cv7;?$macTcEz%!*Ss1LW%B&9?St5a4m7mZ7GnWto* zWFV?%ysXoK%qA3M*&3x7TcbU;%(qmJ5bu*x0LG}TVUA^A49%|Wn{NO#0h&B_#KvG2 z=j-eAFVBzFd2WdHsP&tcLNq<^dpuu9v0SIENg9_KuuVB^n|nBd^*RIZ#~PN73!~nN zv5adA#)dPD&q?~SsrQ7mjHadfA=?-7OMC*cZCo1Lm@@){%f~ojBl{OwTHk@7p>T@Bmt(*<7nwq-?R}w;tQ1(v zWxoPJU{Z?}zg+sx{2CiYRS(I2$*SR6)^-fkZfoo5A5Q1lwh`{cwllGQNk{B=1W~FM zA+epEXd_E&qe-%8(N0COOofB8pB9oiYMwpC=03wxbGSZeIW>|mke(iy_7qPy2Hw{j zmQD{p0@*kBy(~>;S`MBuM?JIFYz&;%8*b?DhURQ?be+kf&Sb5X&dw%j@&H^X1K0iv zXycN|HjK|My+q;~zU?EuG`-6`pMEAweyc9Kt8TgRS^FeudI#lpxDDR(@pV}T5{?`g zaYQRHg$v>j7>*o>KXM>$$TIzr1F=V1$Scv0YYQ!Exw8UuJKPt0&L`Gg)^yx^`g-q~ z7vOTzc)pIY8EpZnDG+X?NxD30ycnM)a(td*i=ch~ z^nyl~sAo_IH0rP5DbDnG-k)Sxni=i}^OZR%@cxLXye28r+cT-Z4*Je)3yuh9c#5a> z@OGw!v(WdnsAo_I?Zz3FM$|z&)7pY@;fI=}Dc+v`W`WC;bB3i;BFZlrFrG^=o=d{z zXm3iSe#GPWgZNmoa;3I3HlJw_>^t8wYoYRgSa6G=ztJzwi1RSob< z{6_1%X{m|o7(8DaqUtnBao(PLv|63i|H#4XM8ZHlpAb2YCMj`Xd17>V(!lbh$a3Se zhiy&AAC(B<@FDvez3oOz&)}l$>2S0 zY-$7F>kW}KL~D^r=wN;0Xm!Z))>Ag+HOY9~ZIG11ZNUkRF?m}9?h#VkM=80Dro64k z+#|P~W=0rEzLDxPXwUfUaV%Suja4fVDlY}=SYp38bfR5%d{djn*cj7xMo C~a5> zLrn59YBj#?Op4T~HQ8xAj#jt4PYWR$OY8y(0&VXb61$AYmBVVkO>O5a8Nv?AP&1(8 z6`ipIsDRM@d0S6Wt~<`#q3ezH_IzvX@P$jMv6z<6$hj!+8JCFd`WYRmpO!>6!c0J}dCaIXrteJs-DDs&OtawZ1NyQfiW6R9t|zEx?s9?#=3Yh6#N0ALGjnGVv@&-(K@W4M zp-;vc!|Z*6GB~GfVcCTFlI5eC~Mb zbaWTI?iOxbhKcV`-pTbXGNbA$ySF6B?Cm){WVP7+Iq7y^PB);Lo<@EbZBKbCDCh`& zzJ|B7DxyE%YD?P68>JO!Egw5NldQnPe@j-5+m+Ak%DGTJ4E^M@TN!isXZ{7ip8bm3 zd{&wegYEdHv2ispsO=_)KkkW-LZPzOR2G~I!KD#oF#M#m+{|OSekm3^Z65~Q3UmVP zHjA0es!-~;A5z_OA=u*S#)cnY6HiZOfjJzOdWRpzx$JXTGI&FRDzefc9pr;bV%ZEW zxe|Fx6aEwmdC%#LTkUEi8O-Ll#-Q6V=oUz5J*T6(wI74c{TO5z8E^;TdNIDicb02?bgzWP+Vs2$+Au4*CMHKrk?>0o0 zg=s$T4n%sFVV^w$+h?_Ma&Ci|skwZnW@D!GHCGs)^ERQfO;H};?buBu;F!C=1hIr0 zkCnA1V5fu03I6o&p-^U^H;#<%fUIn{cnBNs(R^u5;Voh2k-UQ|&9R#Pib7XIk2~EoBU;sG-KRe3t2y%9~ zR9LSP3d$wX2M|EZ81_Kf%N<`I-%kvp}PqoBY znMdml`$n1@J{yo`@2jCcW7{T!w>?z1jz$5h928{s$4xtf(fV}mxZoSm+0m4_V^lO{ zR-TTg%mR_tC^I^=j8o>TY*411NCFxjHETo|$S=ez5^0%kS@~L4&Op)lx1d9R+!^8$n|C@^&xmnlo6tH%tsc@hcyxnTI<4ATo|V` z;$btVm|Zyo&8Pf9Rz3qtUwb%8Ul14urKg~L%370H@OwbX`;87V44Ds{NdceATkgWj z!B}lV3*3F4Gv^TJI*!y^7Thq($>4L)VK$|kSFmMw)1rRl%$ukP3TA~;TizqC!RR_N zPlZx{ijR@Vf1wH40A`VsfoQt%*_B6x%oPGw_RIV$^BLBo_o!MK27 zy_v65X0BCKj=A|BwCj&6ATZ4In4p`>T9aAu@pGZjL0SNUm(Sq~+Nac4!=z0b8v3cOxb&9 z8d{q!bj=JXE9e$YVl-Xy5{RX=lP zFofzO!NFN~a}r%eU>Fj80u@(=n`^<%Ux7p!M51`0l$&|hp8c|{oCB+omOYa|9PLY2 zNzlD9p{0+qzrX{&La5jKNUO-cYD`w4xqV?eEzS=AI+NX}x5!F^We24pXj!rkgIk3Obnz(on!9&*5KfDY7d!gCW87;tbUH?#`K(6TE*uJTB~{B$#)orehwGdoM5X3JWQ zEci#b{)ue4nI976Ttpd=5*CTI1B_SC~Hq>zu3LxRxw~2&D>*CvE zr=tiIbm`qA_*i-?ZF4ShkMU-YZoz8gIY=}%=C<{&pb=ks4W>=G7-Wz_%fahJ>r$e1 zDbX4@fYv13L}?-|6=XR2Nlt?|gWjE>cd&Rl@x*EisBkl=wjNab04wG2b_J~y!jO=a z^PpJyot$FD1css5L@WYjttJ-yB~C{;X9cgh8r8WC;!cyjB``kxao3Rb=ZkI68Oox# zQ1;!4v0^ECm8@XjdNB16(ix$=V8w^m6HGYSM1*@-5TCk(BfgiwFo>5zLzlIVX2CDM z0OB$xDR|dx#$f7XV*xnlhQ!1fIM#*ep%5sIXe>0B`3k4BFXV&p630N%8PbD)q#=!AK{E}>OhekANi1;nMPyisDM{t(*IP6J>LFu*;!Svw>z-yjNjiie zU+-Tc&IbpP#aHIr3@QF}s;YHwa`V0G+auXh7o+z(0jMkG6ASL=ET;$MGj*{DBO{l;vjoy4ZoWrI8>Mc1%?R>z7;eN4U_~C#J!*AbFHw-E2hM@vz z4P^vpMB09|&n%F)d>jAaNYnzgi_izzkvA7Bq zyhUoXhwLf2HAB^-7HXb$MxoSS|6bkbor11|0<~I3sgA{MBpN zKj^SwYa&p4^+I%aJMxkpY`0MbUKLt3wlb)$)XXBmlX$A3cr`ObF#m{k{{~Arg-bac$m)O zB4-2?F6Yxi)X!JfHNN5IZmew%R-(Ew)SwIfm197( z!Rw7XNb4LoSAok#%4?C>I0)fTm(uaoTjK*$e@c2Xu7!ZCJRn#yvorYo4fOnWOCPnf z)0+7SXL8>$9NA}JSZ~P8GILDy;#*7_q?Dj$C7rH6M;@X zp_AfJz_|q$t3!F2WZJB}4y@jGkKuafAd%SnO$=EVF|fa23V?1mr@?^2GXH_5F@)aa zD=3Bqk5sa&7MS_tDhLci(5cYeWvyu}_zb*0vZ8RN18Pu&Ipu`fC?XF=mv7wKL<5ad z2Ouri11JW=64iyzr_~x^PpPzd;*?;$WaxlZ`nq_~DZh6lceP=}`4N35qHh=V9RnFr z6cRL|790)ja0kfVUDOeH47Mb8Le}WX=SJpZf$((5k7{$|zIP~8P2y+x2*+C%ily(qXVJcSd0N3)7A9F81c z&hyyxcYXDqD#0YGd{o|}E{&4Zb0i<7-$o;in@nIBI=&0VQr0?-1uNmK0?{~eFljKL zyxUYH5;Rt-yW_jqh(@Ebkz+6$m3EP%$~`<6X+4iZ&pXtfiIKd!sNtd5rqfD1Q-lKn z+_`a^#KHt$9AA^55#ffQQ#PrEb_cXz@d5ec9t7{$A(S+je3)URn_*R1DV9b4WU5Ou zfTbu8`ib*8)yNg|B8RD zWo(3hEkKEX>|Z1O%HUL!3|MeAe+Bq#NT1s*l6N=)Ho>>xkJ|(bLO9$eji3n(+nJjC ztOYVNg!@d~OH*}WX%)>~+!_MI@bEs!JGpd&d;gnwc##QCAil10^S40VI6_%rNrjGv z#hli9lv}|Dj4hOU>=ka)K_x}pDI3ZsLtEMm?#MeQlh=$Kc}F+UR8D;Xz@FVXq$6)6 z#}AG?1L5br45Y}z9tAFubZ*|mf!HBqeEyoYS%MuPE;%U;yc&N7=_0w^!#jdB3^P*pL8YQ8*Pwa(jxF`G`}5uwur38M?vlyV+oe3(fAU1$e~*!jj~tbh zH>6Or0Xi2<@#kAho~*((@mlr00$Fd^*&NIXDSzaKDpsWZ!9(6pb)ja4k(1s2V?4YCI^V+^ zf!>#WN$=Gezz(xz+!%oIZS|gyyJx<8HW>LbIsm?qj%+Wbz0d+#(ZAQu%sAibwTZZn zWd(ZS3e>;nHM8C;MJ86LK<_2E$+bDfdw#^-OTFhu-i=lh+*f+fC%Qqvr1#o&e?leM zdqgL1J!{-LllCp-$Os=*6&2pH25IUK&3Ss^B%pWnH^tXI0 z#zxZr_i{ebX9*0WX6Hjqa*vHf-VAQTXMr}M)Sq<_P79&Z8Z|R?nnP(WS4HSzhkpr_ zE<}?Aod`~H#0C9DPFsjKH@QR|Ws7En718;DTNq%9I#pPO%OUD86ye$!LiP!x)~nJr`X+i177W6r4kC^8fVO8_0z03#D-^y+yC-E*Z_#m zVb$h9w|jPQis4p(j4a^V{R=paC2B4Z1cT2Sc#b&L+b zJ_d8pm$Ntc0v+CZkJg7fddcbb7+tc;^gjW9`gf7tV+w zoaZ(r(CJPYEY;qzGTIMNJ!rZla14$W+InJO+9~ate;XTG?PTBsIup>?8fTD$&$h^p zDx$-4643s`^SdslE&@0_#}1o2uDvDPkaUp=G01zZp42q(0SMQcI2xxB=F_-|pyV}0 zTBbD7N~M66(mN=PLa1d;y^s}wgrFvo57aaVzxX>pWk0tGPEqjr2^|085Q}?A1H6qi zvAr+CN`7$`b zgq?nS5)o*Soo<>qw4L6{AnRuygV`t6mcv?v&Ig8?cWEUqP6)rK^deTW5TE>DUiPc7 zr@;_l`Rj<~ZD?2eEy-(M_DSRY9}tcG&saPJy(I>^Ya?$Bxh2`Z0_Q*raEdkmoZV;r z(lKYQsIA1E%7vfX)G{{)MI&3rks-icPTRTQMjKG#=&q2Q z_hHuj&iV2HA-nPxKg|1F9EZG81f=|NF9S#~!tRLFe73AjW5d^_wjU+Uhs{soAE4K< zZN;Q#|52OhtBCkf!~Q@Ub~OgUhaEnX)$^GuQ>XuJZThVd(?832KiL%DIsFUN=|91z zzk_g(o_=(L>Bl7rOn>{p=|9_sgG6=uNmB%7y+h35=;kTgkG9jbRFoOL?@BkQR_Qq)q`&T;j9k1ehI5jdV$XbU0mwU z%YMb7ypQdyHY>D+vwP3$jrTv!M~78KmAJWF+WgDG(VE0fGv5CT)Dk2o!BVBJPe>h! z9EsXVTpWOH(r=6ld7%T;bfORuJS)^3tmV<{ z6PB6`Jg7;{^;DZn%~aVN(hIT4MuqwC^CKv4<8U1HB_@t`fS8rEVp z?00rklkgpBdk=U~X!~*ZYEG})2@FH8Zf+c=Ll;^Fgt?A=yC%N4Pl;#-|CLFd z=Z8g;x-}0Rs~8!)l7mJzNR!friyH;eR{P*HPn;j)a!PoaBU{e|`fAJF8GCjpSLxx) zU0B}Ar~+T^pwx}`$00e?a_3N&J5Bh`@#T(cD=~PXAiUDadL?FSU{l;z-8`2sg#%Z< zLxN~$8!YK~UMzWhwG$aI?m#bE;>gQzU3l>$MoZ)93Gs!0BD~_s#tu2Q!D6OjJPF4J zcPk*8Z-?v;S`b@PhFlQOg!SNX3*rhqsEPJFLoA5JDE|)04hYW7fSs0wqZlmWAK(Tf zzsVA|S~0KQk4e3IP#GhDg^1g+G%T2hwEaXZ-2okM&ci+3mKf9uehwosdav?7Y6E0r z!6yf`VOW@n&FpN0qu>kOkBjmr~ zK0HTu4|EF2@0s}+5OFS|a{w6HRh<5RLqmvj2{x z*y7A-u$)5z1$;yEA=N`3d0LQnjw*Lio*&1Qtp>zGsd+$&TT}I*G{`ONbATNnlU-S8 zCcfP4`=!N$G!-}U`~_y;GZwxhKo*x*+LZdSLsc5-fPq{L`J@nCp=M%y$bJI%+?`oM z2$1OuwUMRPQ?}62gLgOA%jjjh*g*iJa-fhV9W0OTJgwD*O*CO6x+WI|L`bj=^-Mc! z8Xx7rDUtu2*jbz4XX1B#`RQ7D|LIye-%}G=;I!7p5Nggq6E-+7%5z~yTrGKfW8CTZ zy}*5;giD#mt<$jH$=RQd55&<#^xkgI{u|;ng}v*=I#^1JNj{pvq7%R%9KJB)5-A|`X;`Fez_0i0DO-Ew?*bq z^D62RG+Whbz{oLR?@8HD`gnRB=>r0Zf6P z5Jb1p-GKbC0}I;NO1wvE8MiMWWYR%GskMWb~m6*(t`$8IuN1jCm9v z#iGTXWC{#Q6bi2b@HMILp9p^yIgH4wq@Cqqa`GU;nvWN}#j352^@CwV7qAl$e7Meo{p151N5_8E1pv28yPUGO0i~2BZ z@*l|by=y6TrA?Bm^I#i@nZmqilS4w;iWi!>hn5nmGR%Qn1b+91 zGw6)28ySpS|0tp|-lTdRQOvNzw{U_(NnNsxJOjUXXGmw~;{~0|CC?quPgCs54N&%R z2O)blrGsBop9A}Vp2I`q@DN4;W+{Rjzq_s1RF>GSyo8So7}|PFa!H5rxg&C72c7Xk z?}FKIGDEnzj4y6!#0cpQS{m-4)z#pB(3WQ8@H;_`7(#C$nbcwtQnkObg|3nz@d(NZ z*XsnXR|{P6j>;Bs<;+L*2=g-Wj>s*{vU=t0EF7YmDk2dO-4JH=e0h0USSer* zSSLtqL5C?^J~XNqNe2nbR#~Mw+4(BfUpc^!15?c8M7VHCa z5BC;BL3HN}4w}U^*9@+?E_HBHL6k{#RCsQVz1b`#{= zKr;e2b8zxzTp{q5bmO(HCHhvnjTuT^_!MdLL4LPwBf<1I9VYz zx$&W0>IGrU8e!z2e2zdWKacOY#42}zz$ocEFslC*5e#>eZv;k7bPj#QB755>H0J!x zj?;CV)#@$c2KbUMX-5w6{nC2&C7o={?GuQ@5zP-@JH*`+<#&)xnaD+J6_{hQC4+3i zX3Rc$K+M6br-DFy;YJ4#B{v;$ZH9z<@h+O?rV~6rfBV0}^Bs{q-$jXkeD{OT?@<2Z zONrwrgYEtZRSQ-p9;Yl^u+{E%yc4hSZbsx3Y4^st--Ou3Yi4-K6>F6{6(^_gEZhis z_SR&EGEZ4&o$bBEt{e-c-uMK`2e{x|D0MlHziMsj3#DF*xYBhtXPnMG1+Smrg;w0c zgc$kekZpvQc~1Idcn5P#zI;RP1k{Uh(FA(Q+Pvc~*4s!ATah|A&_0>jASVu%<&r&j{(C(*_GtxBJ<;WTu+f8hj_T7e-J0le0uE{;lfDD~7nq9sW+z2)@` zQgSwwT(_}dFCOe)-*Aj2PK0S)Q^cw#9W^E_&|FzDY z?4KWki6FO~j+0|Qlf5sS?Afy|8>fU)V@12_i)WwgrNhM87VdvI^A1|bQ}h-pd?o0g zj76>FW<8bX#lDSq6Xx8hU+lNNYrs81;}0GpTKSicluPi2Rcrva(Oxom?g;7K)A1W$ zx28;LXBWZdz*Tn1c#qY<>)}!s>bBcn;va?XHB+S+rp!-*7gj%@29ZuK$ph8e@Qhqy zd&%U84dA0ZzFa2ZxCGAI(YEYGdgB9|Knh$;1T6!h)F~Je=1U!55>oU67vD#c%s@|7 zYI-WXI(Om@7x!C)9er_%jNZvmh1~*oh2|}#J5(Mj!hJCU!!YJ=Fu&YDJqov}?ES`M zy!U+!2k#Su&5DT4$UK`0^US!FznSd)W`glvItu{778+i*SxVz!uGuWk-XvwAp3-_? zavK>|a2WcNXF%tJ&xdF6MZXBMxb`Y;xoVbS`Ls$0iCwr2M$4&egBh7l{9Dv&(l{03 z0zRa6l#?V0eLsisMHh--d@*+_)t2)V9L2mz>~h}`ngss71DR#@v|G6lCvob<0lJ(W zv4IwP>e3(oD|)IKFG7X&)HX`|=~MLo_DPCU=O&y86q3Y^}sQahg z5q105QM_);w`IxxT;PxQe+dl3@`u4Fd=K;5Z;4|PQTk%!SC`qz!1b5wY+VE8nOG?=!(L41SJ28rP>UM%< z-l990&e+UY?rxP7ahetWW3*88Zia9_j<8 z0#_gSO-Clw0N8QdSJ(m2YlTp>ufuFK(7j?S-wK6N_v|Ee$J6`#zXIC#p;bBiU1I|s zq48mE#xV6Y8_A5pFn@~)=U&=Z4)I~GM16c$G5cNjrZ7?TVWKqi+OS(67q!zx>+U>y zKMD*3J0dZZI*w2f=O-MG4`t=-}{Y=AhS_gkmauapvkMr_=JKVW^Q+Yk#RL&tk zSMMdLJgqn=c*6D z!`_>cc`E2dL|xWi4gMLYgTereV12r4r22ofyGAi+7Mr>7T_ee#A45(Y7O;92OvV4PZ(urH91z1aY6$x)@gn^o zSHXt!WR?*NufoLjy9%Q2(x+X|C2llH0tS71TfWFZl{K z(Pck>Tn&L?(EA=o54TBPfUESodb44QcOOfgk zsmDYrC{oQlbtDaMyuw3zFQpXq6;lijx4>VeMMtL011RM0sL@J<^j=>1cVZ1gdIzOZ zIfDwfsR^w6>PZ$#%)wdR;u2gv78C5EvC%is2~PmE9m;rzZ!F&y&`Y5F+O|0S*RH~a zF96W`!2Q@}^;nb6CCnHQ&LzsP0}#G!^20k69Pe?s+tLikuOPvG!XYQ^8g8K4{ba8zmA1T+F)^^)p^2)y&X9+UJPhNR#s!K83&WtRd~+$ zC|}7-le0g=QQ==Ox-%P*Wqhu|Qje;+nV~W%yWQ3(u5{MLDN;Jl!SRAenJ;$=xpd_% zZR9;J^IjiQhF$Q}AQ#=AfF0VKOcpvJQ5^>#Yp$S6JlIg>&Bg~}#c3!U z&c8yZMX;g{&gHu;kLntKz;YA?+(-TlB4>mMVCS~Ao|+~Sc@Gk4VvJkMkb`z%hpO#a zK`MF*phbW~qOsf=KqU7Ho3e&JsVq2I_}U4hE>SlCfYaj!jsXBk7(gcg4gy94PoSFs z;K+X6y+kM4zCi4NQ#9UEEXu0fkQAlNzP^>W{t0`{>B2BsG#s&*%3aLq&iRcp|Is?)Dh(cB_o&%75 z!hJP2vaaMt*5$Y`g7&%n^k?|DNdD6$@Gm*>`KuTt_3T_I^m1-GI1aD=_B%fFfYslu zXJ3ZvPbd4=Sip@Ta3gq7<~#@jafYPHQyFp2P#|ucF+QhMgPqX@K+%X$IN~CyoMz{M-3`6X+UT*AcaQ z+;q|cQbvELBzy-2s+v|esOlH40q9rNvZ|_~qPedfyEwWA_Y2g*=k#^}4EH&`%56kp zY%O|e7r*5jIxf?6?^x<9`|dPN@s8wuF8~$9K{3C{u}V~n0Tnr4Q z?4wHeU3e{aF{Yl}>keO88u?HAWg&zW18yOj8-Dpd!ZAer&zD-v9Ty!XPIq;9?iiln zyELq+Bob$5(}Yd^3&3!1Gd>R&6K&6ebIG|7JzY;dGiO2fBG9_jokA1i z#H4^3gLfvO4vkhxZdALuj1zt`Cp23CPzz;mON9Mbzx()TB1L5>XLkqfwIz=@?1r?fk%8J^PPT9hwi5U*=2W zychRUCOyiJ+j%Q^nv4kU(CiCqmZwk)9{}77V9$PaNX_E@5s?w!_4wkKp^)dEbOtKX zE05T(!nm?R;e$rK@#J7ABAU{GF&dc$OAJke4-cA4H#F#Xk>Qar8IFNl=yQ#q;Q{K| zxYdIgpA+x7)oz@fB!4QUUd}eOqGlS!G>=OR)M||lnj0umnQQ!Voaj{h2#k@F58pTu)>7h1YWy7@y0TQs!G2 zgAQ+2dx}~^Y|0XxorS+|If?g}#>gh&Qqv0mmN?q7M!Xm7J({7p_xL!?^!{X6J-nZR zA@#F3AGCUtx z4m{%cfGNCw-@`WxBbmsHmIo*idLvVF6mx%A^cgw$s5|^kq=qYrq%-d#Fbp5rA0(3E z8x0*edm(|XyFlnt@@HKK%US(;1-B)T|LBSlx_f-w9hELa)rQmHdhc=aMhh|d~P8O^CcM(9O-XXE#&d4g`AEt zd^bmmJJlxj+ACRX;_U>;z>UfoxpH#=`fbuJJ9T6TlW_*yhLC3+YEDoHV?vF*uc$& z@b^OSaa(?P)X$?)_a?-*LGd9rzR{k%3T73)aKnxE6Tv;`!F%owd?@i6C~S8M&OaXr z`%&@X%}*3aJ#7C_YA<4(P5CkJD@fstxA)gr-$u}rg}wI7Q!iqfVRJ6n_&wRbD9t;E z-Y%FE;~u5t>gPy*tBdz;>Wjx0L+HCvZE4vT)Lzv4w(L(@mWdl(Cz5>e5atuuW-ri( zQtuX>sb`esytBw_BC_$hc9>ElJUAm*+zt;}|M>>lM?(MY05ULb-=7X3^dC*X>f)!* zw+2c3`;&E8y1(pN$4wlQJ$lKOS_VB@sTs5vFs=d^whq%a9of5 zoR4~hiX3#FsGcI8Ad4mql>qCZd9cdCvcYlYW>A5lBf3IIYjI`(HTc0O)hMSQ7u}J} z=SlQCXQ3W%nA25gQX}W#4aYkJS1Bv?SW@VF2R6QyK_fQk0~Vw^?wC81@wszbUgeYw z7#E+z+wB~Ejxs$Uj976P+L~gfBYKXqm7|K?Mkw{BChDrr5K2u)toKP=Gob$(>I0wf zV5+aO!aTd2o`HeYO>oQ69RQJ?@oS*TsBsL~c7~ zI`bAD)YLKE>rbZ>2poiLL61Qb3R^G}nCI{T73pm4i-vKp0}c7bSv%jG`6w|4XfPW0 z74RPHS6w(HdI6=q6=dILgi;&PAU{P2rRE}vIk#uN9ZJ0_B0iC-pmvs4s7Hna5|ibC z#9`H^KUhbXbYo-pjqICOK;3`!CSuDdMzR&jzOYgGw-2mjmH4mzGp~a?4Aj4@%sUB^ z&>RLJRNgWj{+oi|R(cfMTYN|TepK+nzkQ2#4NYB)axFeC zBLBjO`22|Y_rh^;_M59fY2r=PW0LoSbJAI+r!Na#ASqTuUP-?Gt8Pc^YjR14=v}czF&Vl<9ZQ68b9flg7|)EQBbaeE;H*TK zZc;LvRBC3E3MR2hvoB_obZIQD@4}vxt}y|V3-!k*u<@lAvhf9}Z2asLHvV%_qBAEm zvwIRVmtM@w1rwQh_5^&pB8`phyQn8Mp!WB^3hxC>if2i)O)TkYgKI=le7??r|5V^1 zy-OD#!{VQgap~};rhYBzr5IRB=}4ARFoLB3$COznm(FBhrrD#J>7k^qgn)Q{>|`3l z<;$y4~+^Wxe|*wUh}mw{kG(X3rRc6?$$g1E1Mx2+{E3D{>tsFJ8pD!52QQ3?XJbk)0N!KRn9nia<|NG9 zMVPk>F>k4uw-jdnT+Es-ErF$#npj$ak)>grX%DG$JzCF3qu%Jx6I`Os7}Ob!I;i`! zTF0oze3+Q=6#C$_NCYiFlY)_;g@KJ-23l}>@v*o>d^Afq1spj~j=}Sz#q*p8FjhR9 zf@f2ffd}~9n4;%qViKF^zJN_E9m6I9pNZ&y;?rY$F6u&G90&AWioU^1W5G*fXQg)a z^B3CH_>1?4bOg@{{u&SdN{QmHW}2%h#6y>`k$urT#CdNz#$7NI{Y__Mbrv?J&(tM2 zNz5tdGa4^=#0VZSJ_LFt=^-15EUCtz(rz^HHlZEx6Xs#;)2RW$(-))Pv?!i#0X{>_ zTMtREE;$~2U}DJ+fm7!@IPK;-xK93$> zJ@rNMIx8k)#}AQE|7;*i+GzM%f1u@H@qZ9!A|}QfBl7AWLOJs4Bc6Q-d3{tbBCmt$ zp}pb${_p>x7nJ$``~RW8KCaeXQ&qCT#ah{7x6Qe+qQq&h&Z(|)*Hl+7sHk+Z$77ed zD_2(3xa*25S5)0zQB}&=Co#x#R9COBb1kT=Dsfj-SLNb~O^p3chmsupU+{G`PHM$j z?`BnQ{D;E)KNVida%!CT-{z@diG9Ns)Ht1vinTSxcyvsR>@0Rkm6g>cERDyhl(9WJ z{J*~WHPt1~+FGi?*pDe^(Es$iQ>!PHme!yy{*T}oM|E+j+P;L#rfk6Y*flJtvbxqO z7gv>Hq~DLg?nd?lW~-S}77Rc_Ic9rRlek*f|3*`1WTd{eF4xuKw9gHx&{GEt0` z#uhkhHdIuBbZT{M`v$kc+_5XF%K2bQbL&f-E}9rLLWr^a*yT?5u*HjVmo3h9WX=-* z_w%Nhf*Sl^&v_tY@jA@Gczp+z8JQ_&nR8tQhEc;G zSy)$5S}U=8V^&nv49aJ0Lbw&tw!^v6S;-{ZN-5v2;d2KosVv;!+)z?k!%C_*xGF2w zaztzCSx0fLJGZ8$8e^QzkhZ(nz&9}sM~shNe)hdLI(q^XQq5%O{MtqZ}0unj>=7a`t*;6d1n zpruREpAEr{P=L^fG6vXlF(^CqtTryDC zijaihLhvBuBNQP_K-i8k?nOvLKZo%A41{KccMvGOT20SDc_-plgdGTd2$Zf=)21nm zl>TI> zP=Gq62tnZbOQfwRZ$Z2fd0hzIh^Hg}5aN9ZZj_fJJp)h%Y(#J){~YQaLOdV&9f)s3 zUJ~Ma0aK9w0O(tauo z;-io_gqa9g2zG>95NZ+bL-+~8&k>$S=tAg4(7};+5yDJ_g$OqzxDY%Dk0SgRLIB|p z2wx(M{13(^BV-~hK`2AmjPM}BK7{8H-bDBmLBE}`OA#c55`?=EevI&62rnRkw{2a3M4yJcjUFgtrhrL5O)A zJb{pbkc+Syp&DT;!lMXJA{<3{2jMdW!w%37;VJ|PVI@K(f*0XogkK;WLiioRpAo)6 zNc$OMmmy>!EJ3J1xF2B;!f}L85JvArn+OXKDiH2Q_zA*q5MDv}6v4QQvFQl&5pG7P zMR*wDR|u~ne2I{@8~q^UA*@C4AZ$ZuLwFzITZGg-j9r7U1fd#XE5f4)PazybcpKpp z1pUv^9>SFf62el1H3%+*hY+4dcpc$mgt%WY{OMQ>i)DHi$Ku%tW?&;(0)rjOlG!L` zgsFzT5W9e-uvB&--Xp;74sX7V$7=%<8Fq@y%qFub>=I@HvtG(BgNnJFO=Hv93^o)0 z&-;}ugI&dDu}o;<)G(+sy7_ce8t#hizf^GB0ajTiJbB z9~zmDH8F)f0PElf?1!wGJ;)wn53@(ukJyiyeeL2>EVvu_s$r{yVNk3lF3(@?E{3J#Viju(OQ@uM1-#T`y9V?%Li;o7<~Em>7v>MV3`aybiO z)M=TnDpw(v)GG85ky%|sY1k8mWi{16VaTG0+}p_BDdZj0I7_s)MXsyZU0ygi7hP0T zl~oTefpu0_86K2qqjqCSxMD>qAMHBW4ZI^YU0b)d3UqPRILj*PwE~cL0~)I+ff1nP z5j{(tWyM-2HRZg$jm{c%PRc4VeMD1~Q02iTgm{gZu2Sd5LV-v`rmLp9lvA3TiO9dr zRW%?7gLM_UVZ;?~EUp|-=B_Dr6;{=47?6$0Dvj<^jA#HJlsOb0lpl=;oN>9Fg=>Rt3n?-95!ZUCw~8_`^r#-RlA&9y(a06`4CM}8zm{XgRT9@T zGMHr>6?%cA zM9j$xtxRBAxGPty|qH29%Y4z<@v<~)b z5H1(}vO<+=T~23dVKH1d8;5I0RB`f+znIS`Jb7QDPOUI}26VH5OUr;vA*bb=3Y|4I zh3@hp+TGwRtvjIutpRzG-cIwg59GEHdYQjHsqrRFi}|Y`^QdYvE;t&CZ{$si>~0aBt!j`?JH8 zsofy(9N3GRP4()y%u&Tin~bMx3%Sgz@kmpw_Vx;QNx7;bE1ktPLiQqP8(D)e9V?I^(Mkr+Zl{H-Uzac`t>mvwyoavG8GS@8P9$e!1PlVM?jO_;eZ-i%j z@M8j6W-@lb4<9PvQry9N1Mv>Pl~=;Qso)vFcM-ZDKz+bFu0q?0KLGgnEcize-wWuN z4Ie7v1%R7z8GSS24S?6;B0fE91%!)<#|?msvfxKUUj=~6=D?4OI;#LLzYfnLKLfB~ z9`ca?0AR!S&<4c;PhOAy5Pt*kd8^1j3YaIMJ&dsc@F@fb;@8b*>_-SRmhFHS<>2H2 zaWmkT2X-p;&UTEKXD`U4KP#q7TZoP=70A8!c zt$-zJoX&NoREoanoTm=qOSIVtxTFenLYu1qCsvC(7Qp)vXpWize~&=peFyMToL5qO z2H?F2hY)WBd|l0V+=lr?AUXsA%jpzL0nY$_jX-pOJCoJ8;lD>69H+9=IFz?geS&x3 zdGtF2@bsOa3F1M(33p*m5w`%Q-2YD*|9w8S7z@jbSebgxjeE43Gza3EDfPRpl z1Q@dwbBMSBu=PIB6Zo71yzqWOlL>%r2-`8P4#2~W=ofJlLM;N(obI(eia<2{zrX*N zDWIdP95@qTp6F5NaH;^A9wHxC^5EkKuXRBVW22v>%#Elw(^Zx?W=Ks_i8{4GJ+iTDD3mO{^=fdU zVa6Fr1!7K=x{=C9yc%a375wZ2ssU#zqaylSiJEls(cjN3oXBMGkO4@st8gZhg)uUm z$t2@hqJx`1R|Q-uBSu((QLQWT2vk z$lHf8%;I=tAvTbHW}NuYNXyY{HQKC3OBKi=x;W5cDcYRRabBYKLo-UfYja8|F+1Od zyNr`9ol476oDmUiBjG7?C!Le$IsM22aECKq+xqEyh|5Z2RYTr2YU^`1k&qz}Gqm_RkuBmbKHmQ{I`s zbJfnGo#i`SJL`9Pb~f&8-nnh(j-7jV9@yEkGqAH`XV=c|ojp5)JNtGTcA0ji?K1C5 z-<7c|YnOGGyeog#s$E69>UVi|HSTKOwQbjqU3+&O*wwNtu&ZNN*RJkeJ-dRt`gWb$ z#daHZn|7z|Ht$Z~ov}M>w{^F?JAe18-9@|0ce{4i@Am9&+}*r;@9qP;TXqL_ckJ%k z-MzbKcW`&#?sL1@p0qvYJ?VQg_GIm`?veN8?^(5{Xixbb*Pg~b&3m@(*|BHuo&$SY z_5}8H?CILmy{Bi7d2jmOjJ;WVt$XFY`FmIGE!tbY*R{8PuV-)L-k!a|y?uMn?PdE6 z`%L@N_L=vk@5|Viwa>aw-j}~`)xM&A<@;Rw>i2o}HSTNPw{72!eS7yE*q6RPV}I8E zRr`zfm+yD&uix+4-?+bd|F-=*_8-{avOloDV}IBF?)^RcgZumTpWDx#Fg#&;BJBzD V6PU^aSa$(TKl}Gi>p$E2{|671WMBXQ literal 0 HcmV?d00001 diff --git a/branches/WOF2-1/ulp/nd/user/fre_svr-03_amd64/amd64/ndinstall.exe b/branches/WOF2-1/ulp/nd/user/fre_svr-03_amd64/amd64/ndinstall.exe new file mode 100644 index 0000000000000000000000000000000000000000..75c8ef338920c654c3d11a8a75206450cd995668 GIT binary patch literal 11776 zcmeHNeSA~Z`9DdM5=zq+Bv26L0;v{xD{X~BTbt0N+(HVmEiYnO8tuhQE-M89f}(jhWGb9_uiE7;A|!3(8)@XV{`*I5RoV8B zs%~%x8GpdHG~j4toDQ$o$1_VfCJ^#6ZZBh*Tg5c`T--#xKEkmdi+Mf3>inaWn4{2GEkbe1O=M>$Z+Ou zj}Z9P)Itd4(8Nf;_)&x?fKn4sQji6EDA7*HW;!q?LQc|hJk=307>iGg6i30&$c`Yh?p224mMiI4O6z}P_Pb;#7+j}2Nn2{0@+*S7WoPsu0V|fKN~C8A5&n50$*0( zBMQ7%fi4Bw6Xsbz>#{<|`#PAV{{)XRX7`xW|=3f!!~R~2}p0`FF! zSAq2ktWjXK0?QOQQGr7gn5sav0(%udbt~n#J#iSjo{(!T+f?jFl%By{T_4}e=n|DPe=LzN-2v}kvov9iIr54 zN-`IJ)g%jc1<49zo^Yg*BYnl|yYgmN-M^0O!ea za0SRRlr3l*0L=+1gRN6;??!tLcw(wr5#+hXn$l1pz<%1a9M1)UHPxkd#^+_K%yY<5*0Q`#=E6#>u25EvDKjq#a@9=mSzJX(cvMzd3Ho09~AVuN|;J1=%^fhr3lcMRH zc#FKS?zYRD1pS=TUGL^x-=M(*cAGoMUsWCKGk8H&snr{5vRA z5XuDtz5tV*x6MRlE)H~cB&LxYuvi+5<>meb)IXnypEnL9CyWv<_q%=%f zIg@i-%mgN@N|sm2Eyd`}cX&dawOP@`EO+w_OqQgv)EDx&7<$iG%JGbYX>fR59*&Nd zGLF!;6kQIiNYp||HHIPXeg>BohX+=C8N@V+mZq`xuYU;fnh~vF@6D z^=_{VzQbIm4Vy6K>8SYX<82v>&4%Hqtg=*Pe>rvBp+_dq{LQD6H)qbDH6{stbxyBY z?h7o#Pkru$oEje2y=65^+}@fHCU1>z$#?4mT1dQAHTo_Z_3*Z+ z&B)rK7Ndz3x}oTFs;uZbstCLzB;MO7Z~mG#K8KBd&&WoDybu$HD*A209?>uY9Bg=6yyQDR}HosD!bwclC1yGu@NYmHGipADZrLnR2> z>R|wR@X2c9aZvJ(var$4Mh)XGKmeFcY^%jsK(QQaUZ*v$josT0#+JPnWA;egmQcZn z20hdj?q;L64#xd1#Ib_SXtzXXCqd9?2tqT;Pw#(hD^D9}qy{0q#3>p+K8KEv5)B5) zZ2e8tkx|2fzXL?t>nuW>Xc$guRIX^)sc?S+$O`&i+9+x$Pvkxg+SzoUb~Vnq$T}na z{15@VC^T=QCmal_djJp}aGg!R&tl|(H6VLXswb3K8VWD zNjeA%>1?S(zXnPje~XR-6WfgSLMLc8=FP(J`3tvzozAt@@Um$5nmR_0;!maGUnKvm zlSY=!>xwPM;mZn78VObx8}6V};5*91FjZkaVAj#W7v6=|anNesMo0M4m`f&zhU~wI z;+nS5Y-u#m6VY&^Oo@-?P!#EC&IH8xETm>c4Q4u{;-hJkOp`|Q^S{z+c^SNe=@{GE zU+&{TWo=|jof$1jk=b6PY_DIzHdbQ0Ky^ksa_)@J_^vK#&eM69xd0Qt8-tIDe$d`J=4;KxqB=huVvG9a$(eM*goH~M0O5cLwOg zJ*J~Lofwg?)%T2Gh3ha3Q!oofLjyG_sxL?3)Z<`ag(@8z=@hY+g!5m#$eugEMoy{N z$X9AUrDggAUfVK#QfNo|j#(<%j!3VYpBd@(@P(1y06$U|eH8A%x|2nJCKU(@J!7CA z%AN;>*RaCujM%8JK~9aS;hr9C?1JQ_ThXb!ww@uPVVvB(B6LqQ>_8#14`a5@C^-dl zrWA9<7Jbr4-BvE#nNcnTnR4Mot>RwHngT()BooU+&@TY6MYTBqt=il0i#a}30tTZ5 z^m+>DL>3Kd=xWstri4gGL4366FzMLVmBtKPtIL>ao=2x8_7hE3j^w#!oi*=dUfUTq z{gvXD8?ZZ%U<>z#Qg+f6Z4o}{8MG}1gGIyJXVKfk5?RpB1tYjpF`Y4QwrB|HSuAL$ zfr@Ed(ONtSm@PUXLvqEfpMQzrf*IM=&ho;)25$h@Fjh!o*L3p9;sHu#BYR*aczTXu zx6as#2nUg7MQib#p*SD3f5birl{aACKSAY1^{W74lc0OA_BW`c+lO_{$xwgHg70fz z2ZfCkQ$R4n7(ZaK@1rXapNyCTIuh_l}-u{Wd0 z3Oqf!R^kv7T+*qMW2T3Si4G9M3V&t=6)PMNbg?4zj2=3DM@|(1E2J3ox{*V!wpSNbw>XoWa=?)jxr|(r1Z6t_F={h9B$8AabYV&r}Gj4^OLD6dKApZ!ZcLrAV_Sr9QkeC3Ao}eSO=m1Rv5? zHmA7=_Z6FP(3aG0PTyi0Y)#*?Fxk51=&Y!XWbz}0+f!|Y2LmaBS(miSR@fcLFh|<4 z3Ablk3x6N@Fs}{wy7s=|?vlsFCbVNxFdtwgFGEN2ju!3?(fK^aHmY8$7}kv72o_#pliJxuL)mobO1J9B^b!GtHqp znsY?MNU9i@S)e0;T7)Czc}GP1uaHri0W0A1%#~fj|<|*oI zg&)|`El02!%z?J@bBBQ0s99)cqU$Ao$YDOQtu~xX;nVaYh$(Obb_m=dAql}0<^%`7gK1!xZe7F_yKC0)2o6wAg|xDOiy#TgsD z=Gp{EWN`(m!{@>~)VZTsVYPGLl>@scGP3;@I1hi0<2!~-q0%Ntk}(72eo3U?j3m1{2R)bN<;2^*3mF-s z5KBR(us_v1nvi&X7_`@rRp_4tQ#2$cUq@1Mll`hxHAz(sl=W4rbB2x75`BIh(W|~g zlIsZh1+E&$u_RP!$s{d5g{0-C`1{xC?8A)x$RO8kWKez)8Kjy{2KZ&(HmU?^LzWEb z?~iE=594$sf%a$63P9VO5cBTHMsN({>rbFr5TEP@-#4XioT|kI-^LRLD$DP)eC66l?$s`Mo5;;|o#&#B7;wwwLGS zPIP%Z_&1cgFXBcrCA=)aafCdhn#u79AR%%Yq#T3UwILj*Xf%ENJfGTT}? z$7+kqJFMY-9^Y~a@NUc*s2&0jq2Xeh`9!!m713@?_xKw5( zs~|auKqDeXjSj>}1CZK*_P$2?A45ViRkigp)*^G(I{f}xeuW=(jlm{ofS3K0LrSQ0 z*voS!(;eo83l||~e61)NA@e9*35dmGa8vSY^KubiM$Kh$P(o&1Qwo?t&qX6y|1otX z@0sro@F9n1o_9F{YlIx8G@H-2EaWc>d7U)mX+_+51y(+-DRuY}VC85mn*I;Yo`its zJg@9qm$li+`DqKqx2x&sR`^^Y564QO&IN=#t-d|P1y3z8I%RzCxyXK}=lHr)EuAyp_~B;r_BG4q z-8?ON&VPL6jP36~aO|s}Ug){^x!X%O{;BCi*B4_atq$L0$<7%1Tj;G(cdIFhxv^{b;xpL?|T?9DrWwr}zKEnZva zPab1_psuXz$O@sqWPjIw`O?~Tq2#XOl*2#w)1TgwMXtgR=0+d$4vPG>WcQ)*+^~-p z4&8F#^OElLF{@`@KlAxFpZ%=FwCUGw&r90hPF>qml2^Qa#@!#kvwr9Qep0gQ;>EWd zs|POc`k#{}lWcc>SkbX#{iA>CEP14(sxV~PKX}KFUn)7a^o{k?tS{X7${*I37{~1S zX!{$5lO4j{C60M_wBP$m)yhG?sVzDD*`#Rljz`uQE?7#8CC{9i_RP(HzHjp_CHFkP z@#J>b%CheF=iTP~UUJu%>g5sf;c)T8=cf<5+nH55x$XI)QLP6GR?U2DE4g^M@Q?Q| z)Ls8d?8MqlNrih>TW9q9^%J3~M<-6tyKBV3F-LPhD}QLwv`ydN(YD~dXI5?c+3UF< zHM~0T*~+IacWlWRpH+Tx!j$~ERWH7^EbGBLG{0y&w(Fh?u{}3F^~wE<7CcAR^f6ubc6T0cQ<2AzI)wIfrWeSj&9jAsC5D|k0x<|sne zgNJ_ml_K8{+z+@5`8C=WFcsf|ROVp7y~u9^?*{yQ4D8Ko?S~C+@OdS^fBZUy+7%#-Vk5QN4V$PQ7pSyMU&S~i?egoDB9fM%cRut6z;j7o zE?&yyNI3_PVw1@fQh>fv3^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-1/ulp/nd/user/fre_svr-03_ia64/ia64/ndinstall.exe b/branches/WOF2-1/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-1/ulp/nd/user/fre_svr-03_x86/i386/ibndprov.dll b/branches/WOF2-1/ulp/nd/user/fre_svr-03_x86/i386/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-1/ulp/nd/user/fre_svr-03_x86/i386/ndinstall.exe b/branches/WOF2-1/ulp/nd/user/fre_svr-03_x86/i386/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-1/ulp/nd/user/fre_svr-08_amd64/amd64/ibndprov.dll b/branches/WOF2-1/ulp/nd/user/fre_svr-08_amd64/amd64/ibndprov.dll new file mode 100644 index 0000000000000000000000000000000000000000..80a6c14ec406b1928013527c98b06800d37ffcf5 GIT binary patch literal 43520 zcmeIbeSB2K)dxPCY{C)}cELo$n=H6!M8HU*27+}j*}z@dK!6~qU=orIiR5KXZXhV? z#toXyW!uzZOZ(VLA+&(jQfoD&RyTkWFltb%vAzZMX&0ky)E0xb?(chM?rt`3K5c)$ z{_%T04}2!)&ik1&=bSlnX71gbo10lQV@!__3^LXVNdK(-?>GPHL-zRTZR6P!V_%%n zs&l+JBd@fq#_X!D+EiUwVJ<4HtgKSZ8=dCr+Dda-rP;P(wYj3I*f}pDAk4mFZ(M&EujBjO|8BqDWm|3235cEBz7AQH;gnF%)<@5dp+=ZPtN~R-K@v zR-PB&jc9H01m5i7?=dz5eYwBQSREyIF}8;$!q1qECL{E(hq3Kw)ir^!siCxg2BOaEz+PvgSTq1T!V=k z{JsVcYtXO3*ERUD2BS1MS;K3d25->dxn|MtM;d%vgD+|DVhztbw02^Lj4yV`I1X#| zzOTW1HF%o_3pBV}tG9PZ{SZ9}hI9|H^vwtvQxJ@l1DX4kl|#PA^qaIQC)FoK;#_xyflxS-v9o za-^@W-B{^V%sGXXg`1oe&Pvh^tEy@hXEpM+mMKN0RGTrXR_QD^OT~pQ%3QO2*>Y;$ zI?>AWQ#EMO;8YD7G}t#ml>1PFZ)@;14R&hKufb5eA^4wafAZp|?|t5qmOjb(*n5c+ zXWj9i?r-cb4^RE{+45I^rzuLYyKX-XAdWc$x zOb_X)VdIV$s%rJ@E7k~tMZ_b?5E`$2Mb?mVS^1-t%a!tEZ5G0KQ+=Kus-*R|Dtl>u z){2~5M|Pedz?#a2OQrAmQ6eX72(X#ZBx5obYjyM0f zd;R)(>&rG4mJ^NV6_;~J&$U}z`J0?depw~7dr4uDlM*BTmCm#B*qlNEyR~@vl_FlJ zL6$1w@fvKoSHvH>O2F3n0v4wWxa(>GbFUFF`C0*&uW>jS{w;SZTdS%!+sdk)Masg3 zSy{I)T)5P!tk~kLE-!SsoW-l0HMQl+h~<`7DP<+ws1?RKBrAs@{4*Ad_-+kO%@Xl` z4VGt%`0*tIx^e^z)$h^b*5x8ScL-ds#p82De$Pq)7p)dh$rEtuS^*0*_;i7Yhx)N< z^zPJP-bRuCp$5}_mOXL)?1f7`@jV-+-}mFFznw9T`AuA5R^wYgSoU-MYeya#-}TnE zClA_w=L}qV-I=+QPk(l5it>K%4UevUaYNRYo~IgTHUIYdHp%wznaoWOe)z}IJ`FmG@3D1 zv~WG~DgKnqpPRZ~!Pa;4`i*6k>uYPA)$6M^-d0lW%->pGnqOE^d`6cY~yOwEuvfX`N-xh=7#-&G5f8SjZ~s zJ`>7~?#)DQ8qcL2B+uOw%GLKyL+)6fYY64u%X5tn`t>og=eYTn5EVK*OX|@>t3}oAr zku%@;q|IV2Y44z7=_n>QIV`y|Px*Ud<2n#sCpF%14U!6wF!K~oDn-(@NOBD%)k%$u z7o_=-ks)~(&p|BJ?u{zJ^FoA0VbnWIR4JW0iyU~9bd9Iy`hhaWC#7rJ1F_+RCh6Lt z`PUB4&lsAY5t*+_bBrDB0mCdXC^L3Mw0mXvSu%D=^*vNTYVR>*?>K4mN^_L4lCdo? zogR4`fQ>5$>HyEg_JBUzMw65nIjl}u#auM5)TO;5dnE%=J@t8=4rDeVBg57xMcEqd z(IwuMdW2Z7ln5|UYYlTOd!uM}W$$7Gpb60Az9Tvcv$$AatABoRw9b7)v|B6Rv=XA} ze&6l>auCaP+M1-vX@1+xqqc=dBUrD~|9-S#<>WBxofymH_CRzv!T6MFes~emQvZLLJ*kLYQTEO{{b%%s8wR?eIh!%K%nVUxMyQp}&L(Nb5L{;f*MS0P+ekR$XRS?P}wb_UY0U9hBOk7(C}=YcmeV9XmYcSSZ63&WJs1ICePp*x{HF z^Yq6KM;~h?ufzbZt+c3R&-X9vP%d_#A6I)>(<#rH>pf?qlsM0MU2U>-II8yo>F~JT z@$UDp&&FEg{xZsDwE3kbf4Gq*>GDD2#rQ0d<8v2U1nmc=7c{aAs)I71(Le!rVVc|h z{&d62v~V|=ue9m@_s0xMYm(ADJ<|uupzpNyz?g7?yKr_7Z)bKm34PBVR0n0yZj51N zL>aU*yFCySuGA#W^z;lg3tVRQ8&=MY$iHOBcrL+sE(zzOy_u2v5%sV4zaJaf1o76@ zk#uX4t{&7T_*ZiG7^S$b#+6rVEjO(kM><09{!$;QYJlIkuR@(Stu#>?gZoRvpfXKT zjHl8SC^lW4B}jDB3Z)}OmDRoFqPS^{*usxx)~H4u6rZO1E=s>FCY zbiL7@p0AA^-f%AEoW{I_SjwjAnlPUoNC5$LAV{>|HqMU}TeuR{fte8QK-GZ~D1d%# zY*GFVoE4(ql71k0PQ_fxRn$f6QZ3Iu7x?0%!3F>)H~%JSQwk6Xo%au6hg+4Frdg9 zUa5^fY&_O<)O|E)(V<5rUOpXweQMAX|KYjGVbBZN(#VWHF+&lPW;}&nBaCHLf`kmu zPaYWCX|=sQV3I%u7G$<@U5K7Bfle?r+CSnlWA^i>*Ow)RB-yLuNxw zLU*-8j6f{ZhQJEg5zdBPD24lX;8`+0Wt~G4XMC!o{Yqu3q_Z{3%~)oK z@&2D-wu}vQde*8lQ_|Ko%Ch>iIup)DGCgN?$~;;uXL!!)mBjk<4BHmtj%QF>_Qe?f z4EqJJ`x5~VXmIz(B3`ON7s2|oQD|P7O|4C%)=Z+cS_Lh+GJQ0JERS>LIJe?#oKCd$YO$%~TudU9>&rtstW#uu8PFE}}p0dQ0++Yo#@4 zEf+gFldQtRe^XXZ+0{?&YJV^nhJL~ycQEGg&3zBRp829;J||6$!ghSyq?l?L)OM4@ z7xTzR!C*;S5(_MZ;L-?E8UCcO?6i~FJ}DYIZ7&Ag26X%)C^c-c{IVkHPj?E1Yn3 zgP5s>e5TSdQ~K(8#-}_@C~Q;JoxB~pi3A*T_m=>cbmPgAwm9r`FgbxA{UaDm^Y_M( z(e0Pjhb(Tw#&bMZ+K_*1n0aLI4zMb>03XGYyjIGS){^JMp`JN%06o~%^LDjQRzC_n zb{(qkKug^Y-*rd8DN2^?DKMc)IR)gGQ}Jg{DXJi4k4uAf8gy%L9YKdTT5*$Ss1_$zuLELqwM)DZ_we*gxDhM&l9MZ-}2r> z$}XHe$~51e^Fbvxm{b7M1M$>QJXgd`GMOsa1P5~=B`*YGFevr;-Wb_CJq<%!4_;Br zEwZdCmR#Bk;wWK#eu!8Ob)v&J?c1k=L5F%WC-ZxIfJN;Dhq}su$N`FAFWVb4#qa4R zFH)@CYk*rzR^#lMYVu?%E2}pc5HV9^P}!Iquc7yq)+j4;hkC=lk>-Za2Bg{Zai}CR=*Q0Y^%xwfRJ4RGG*Zh%`&Nvo$ z?n@HmOE8T&sWxH+knW9O($C;MQO5{GFgF=AH`Yj$Xx$52bYXr@CVn<^>e^^sbwu^ag=ZP}&ETR?-&F0`q~A=PMoL8S?Kxn+Tqj>+ixU!dOjQD_no>v;BDH z`i@jx23#`gOMyqA&unTpFJQ~;rUm}k**8!S)XWGb=`kWcx{kD0f=L%6CgiF%j?3!V zU!Wv!O;)?8x%Fs{3qo=*spCCfm-^`lCj9|1uKG@~*(}mzt0a zU=}H6WIt67ws3kZ_-2e*uoJuB7)d-X_!;|1Zw(o$x{s81|)WdJRt z7eG)>EUnu`u@l*x7U9W(^eB*?2!4^(D?|2TaLZF@b?z5J+fX*w;Vrh9gGudgW0lH$zIM!SfrP(zy=S{6H@UVldqKLTw$!e!Nv6UwwQi-S zjB`hI6iNMEG|K0wFJjS8>Ct5}ySD;Uusk)#nEg_An%{v1%p91r2Da;SYPT{0UBJdy zUk=Oy0n}r?lVuf3|0T>U6m$Y*#3O@Co5Q!>Qeana0Yh$1v8y$ycJdyQ zCKh-Urz4!R0<*71ac+Ys$+D*i#)mKF8nXVp(I>J-vM4T;y?0`)SUz4RE7-dkOg(~h zMkp+-Zs9cq6HYb};T{&mhwtEs?FO)C2bQ};PcOcxQs~(+@8)DOr1EHqyZW% zyMaO)I47C&v3g>#4j}m-u>6M85_AO5LqC5e__?u;XgIf?z$m+`oOg(Z7qGzFp8_@C z4;rCnjZa0qY!hTglS)~P_vu^_r8#^H_by@*VJALasWSbUkLn(^|9XcG!> z>!LT84(G6GfO<>NYn>0-Fx)RT4Br{DVR(jAF>M$UwGBfV&>G1IP7T?9Bp0;L%#-Us z_5%Z1jj7)XkcK6`!P3f8-juz0WIrctr5s<3i@+#MwFnrLv|Y#oFW@XjdYTq>*|(GP z1{flkwCD|@)3S`VR8T6IG?$_{v4MTT_m^btb5`(vuYj*uT!jkWA~o7WHk90!s_9V+ zH4kQk3e9|7+i1Q5T?YkfwHSAtAhqW?NfhusZ6WLCv&ZBwPGkR|!@|kUzk?`p#LThW z#Y@O)yL%y1;$#n0rzfDR{S=a*z%)B89YHZBU(qFBaZ2_zBvO0IHQ1)*feB>at_e^P z_c*Tblly0~)U=3M8-mINYa{#yAE7Bf!dYGI8QA%?Xg#2lj@-etyYE}k~Xo{>luu}Luw4IZEd6wK@7dFK^zK6lvSn$6n);Q9H@D04q`LL~785{z@?*+TiuZ9HDiNo2bC$BK346 zHV#5K*rj%S@#Yl&tRIn{jAr+u{j6X)nwPsUFj@T$(afPfOhdtRsuwuW+d5iUN+Br) zuy)j?GAFV_JxZgo%IfPxUTiwRZ~n7;&{&A$SAgTiRD}s^B|5{eL4CGmXuNKwI)c0_ zUd0w6&$1qlmD-7(r!8(|nQIN+3$R|S>y7!Xpe@Iec9qkBPA;L7=upAAc^0cfeV%06 ztiB4Y-clxVy>o;}?D;B+tcxhvUoZtgw_B27Kw+8xAfz#b-sCGNh6RsQLO~5M^Tpgm zU=)JRg61x1OJ;#5;PsJJl`|bsgCfi-CDg_fc`&+M|); zQAgl0*pk@&SO<^aL>7cg8-F#5Vf+L}8$a}1N!uihA6~_0X52BKNw+ewt;3>YRA9tt>%tQ&=+Z0gHxvPLqlnTef9Qc8nKUv&w( znKgb&sl5>Un{_*awHJ`|7C>@o578U*tl+Nj6ix*m%^JRNIC6YB&ts$C^~HOd1e2)p zQF)HLLX_ld57ANMqvYFZq%ji+j6%nEputMoCbK{}oK+wiCk`eJ29#&FhD2P5m1^(! zCN`qcXl&#d&PE@#7s&3cX(gvj3se>Gv03v_UO>1K43=C{wt3J_-GyXJVPUrI;dZKB5e zpmsicjJ(-cM7cxTyR6IZUELx1R!&1V0af&n8}6YKeUN``-ZTG>f30IugnzAzBL6S^ zYx7CAvFYCiKY}mD2Wvq%*QSr5$qL()Ay=6n@-c#|Ox!`!__ef><|(F-z$pCsJIFS< zZv#*NiTHJy2~HlqhH_IkPunCyF=6?HK8AIi+;*H>yav!5cEF3=euMgnxIZ?M|An@% zsoYW5FOye{9CaNPG;Oom0qmKbBRcA)as1$@n@ae3E(0lYupfc@BZZsta29sRSS6DF z+DZ5))M{;|asTyPe$sFmZN=!UA>l9JJ}_m98Vzna3ZE)D+(^d+bnyGC*!zV2u+XZY zA`}cbGIhwF+(5JlDOlQA2Fp32`w4*1DZKNUymM$De$0`_dxI}&HMx$|U0m5{?vO6H zLlQ`9{+$aJt>&ctf=R#RgIZxG)|ib&(&SJZ8?ivsncZZ*2E(l5ElI)C@YZ!3cl>~w zfPX)vSysTvz=bBYffwU-5HH|c87%8uF(Lte0KTGAzio}fSMPOI1ZxippAQWB*ICnBk$R$1^#&@VM@WmVs2P}T%`tgI^xnDP6&0_32a#g6^ zwYN%{A1gQIsM#jFnq&6-BT6#vIxeZNNx^0VEr@EuN4Ej^Vm=@Mrl{gfQO22~NaM%* z!QJ4*4Cr!lqH%}Pn6HAt-o>bYNYvk_)xVP0zZ~_WsxQ&%FBSFsU!wX(s-J?z(i}*G z3z_?v)MG<;nD8%!wI8i-hBY^Gt)KQ5j()@bQDeiaoF+MD;v+N0!53nUUodC~ct@!J zU4n-^f7S(?8AeVv`u9<}9{SzQ8-b3Oz47nW8o&;?vg-M?>J}NF_-oz>(i%f1=WK`CT&juC#SY&JC|!sq2|5v+Y^f>y+xP?*A0BhqoRM38RD^Z$dfFFJ<>n+4tO-oq(|8yFH9YJ=8P=)fFtb}#d@ zd+Epppa7lNlO<%pGZe`^r{L4@txP6O82HJzFcQykIqXg*J*u@)C)#MGdT1jf$D7qd zl>oaCPYvH8Kw<|v@Y9&cutK~Qg$`54=x{tbMACu4Rid-HaA#b%3_j!KR|Rs^GdbkM z#t{Q;&7O1e>3W91DART5Buy7glu7T=bUkf33|v}+_(NwYajoZQ<)k!OeM0QMGy9PI z1ttHGk_Vl#$dHCTyzrxz1Aq=}*_(MOI^lzeWDwG@OfivEmSiqRJ#JTj4`(4~+`#^E zq~+?YZNiRz!P#nmegIMcj~VAQNJk zr&>FeX&}Tf$W}mc3{E4=r6eLKc}NkLDNeM~C}5@d9*QFqYB{7{$cjKjP?N|9YMKL| zixc(!ZE%2s&tJe%FAl7@H`LGDNETc90<2V6OE+uV`8%;MfOkL4Pr^>W@9}@fP7g%d z>3#p7+Uc{PON5=iHJ%7G%uY|9HnN@G#vtowe*&{ltSv`F4|EnV(!5JI;*x~$flAL} zB@6P&59DON40{?30hV7xEN?@*(laElIhijR@Be^k?0drECg>?L(7hUYM^KSu-x{3x zEWwG@;(oi=`d7z-g`%_?W%sn}B(L@F$TFyMqU1H;a*y5PH_5sz1N@H3j?9;z4wrPJv*(rQAmA#I2s*cx9F6tFgw0aiD@QAy>&K+KDEu zChGo+KgmXGJ1n|DB`R{U=riv4`fKE01QPXH(6ngy4&)1;wyAYt6tc#)P9{TuyO$o~ zf;-rN632A;3@J;#}*Znp80NQqOT(24;uCdpuAo#Gu=dXG`QzhE;zZIH(YsB==H{MS+ z#Wzm>5^efl;M3nhxDTFwbc5-~B?wIaiJ{Yft{sPl+VqpA@Ka%J@>Lnk0FD6bWWXz6 z6Py8-(6|AIX=-=i6oeOya4j(cOow=w4#Wt(G_~m3-#eX79a~W98)nswZvV$w9dZ2< zR-g1cJ`;3FsXHh0MTh!6wzHvGp)H)|m#3Qd-I415|O6SqHpz{KVH#w7I3Sbk~lGvMU# ziQS1<4QsF(4mh@{N!-l}?LFW{q3y@L>p8vdBrpoSHu;HOxTWzr9k9?UAk1~_+e6}u zyOVfK<$q;T=ec3gq;Aba$0|k!59F|s4b!Bw;o?TYV5@!j`6kYaaSWMhXM z-C!|OHfqAL!QBdY%(X-Ihb@Rl6GvPS&xZBjXba*7R1Ass+aoN9Wyt>q$@YWG!I`PB z(=u@Ef<^oT+*ahbR>D>*=GF5tsdqODV+61eaTAt?1@n-$pLj}fK*yVNa3{Al3Z(*{ z!AKmuSNWIP0NGgJv0-gkSHrmx!BllbUNuI#2|%157a)c2NctUgs7^bQG|KhG%pov} zI3;5N;Fm84w#TI8lgQXu4Wbh5mhg1$}+Z%3QSw7a$n7Itww=9Y0hM!t2w2K{m$ z$Z_}{1#ZjC!RB?;C1|#;&47^wljecS4s}^Fi7Ol*2^S7)QXjTfqj;0JYO?Y#B+SGL zoGCclMEXqD5htzFj<&WBKiZn`8!@$Ga6+1^R}7f>b>d7f;rnZdv@a@FPTGZ>wCQ}J zfg~rdpe&~{$XkgUs+_!PRtjA@A>Il6jn2$59XNT#m}uCX(tN`V&L|+yOZdhlwS=?e z`j1US8Z|~w7zpLTkU~cpvMRctFMu#n0sf^O5G%zLC*qKg1^PA(P3E+nv}u~K_&;rK>ow9pAeT-g3TFV zFHIa(T=r7oCj`-LbPpgm?7)IHwi54=TEnb#d5Ik{@@{r~?s!)`%6Mz)RXk#b9p0r=9ct3*Rpc3XT}hSBEyl|@mrL$D zpr2;i)f=GfV_t;p+0+hx5q$yd1FDBg7o!qJ0cI(H8^61~*HkjDTYU~66fm^+nB<}k z<5S1vaUFD?3%v_w!^sTc<}yB2--r>?eY0fTH><72U7-4Ar11McjTl02KAF^F5z@53 zT2I%;5ZQ%%!gZ0r^=g4D-bbky*UP+Ajxa9~@1q!jJ-=R-pj|JEBlnD^ibw=RH-uRo zUtXRURtlH{)(Il@=rEDXM~LbL(hk5_ zp^aZw!9FniXm24D#M`-ogXVM1HHT}iOC6k45M@$bIjSAk0%Mjz8<4HeI|=;l?-;<2 zb4qlH_hM^f6?|pA7qntN{k`$x)GVg;Q%x#43qvaRUP>(c5O>bNR)Zf++?2gFd{b8V z(iT4a@A%RTa4m%2DKSyxe?Idjgc)8Wkqo$GrnyZZ-#F9bhp1MpT9I#>tS4XTT8B@X zN_H5urnCUtDxESHPU}8MsoeybH_$9WaRg>;#}xukQ8!-OTA}B+F@s4jKSmmUm@jVU zSO@}6j7eug$A@)Qfq`61vn2jLadz$Rqh7fmCh|--U^lFIr&q z_ngr&s)KqGwhb_9qO<8^7TI%RYGc;l?KpAA`K{g}Zh)`&EA7%D(tov{drl`Cv-Ekuo13tfW+G-xc@s|?E&j8!K3k3#NCmyFHT(Aw@_vnfZ z@osA56ou}Mb6*Ovi^t6Hk}K9PB?+gg@HVUkJ$tLuf@!Z<=b!7n#IByiJ>^G8KEMV2 z!K5_){Ia#FFPL;Kp4F~%S(A0jOuT-A7g})(6Jq3DK=u+|;Caa_!(*6b^5zaKP50h$5HiWTdMa74oUh=S8icQ)`7=NIcW9mxse4lYIo%_^>Ed~TUSzw; z;5inool2Cw2*my=G%bkT=ZX0vlyfjp5d#t*BWwpmGDKg*BtQu=6kGP8q$E@d{f8E{u=| zmF`u!D9aa9Mqm`i{0-QI8?DFTN|ildnT+?okKy2bVz5~Ou^E|cvtY6rcknlpJzq^V z-b?2LAlOpF^EOLyEKE3?#n~ILF4a?94@_<+V+&41U&0*deDL|`ES~xEFpGy?#VyrL zH7uW2=?Jk4x65cbm2EIBQ;2^H+Dsu%g}4NhKKL1DGm?ZJJn~CMFvysaM5W~%6~{Ag z5WC!Wj3$A`X|F#D+&_3Z~9W<-LXz;&o}L#}m+SI(|RP8!gjL@QbclR|t%P@5LNn+!CA%eA7;*`TLB&O0c6t*Sriqg-|_3!A+e?mO}21-_y6)_$Jsi}?esIKF9jB5G~CZl?hE0m$AM z4t&?$!(-FBaevMMixWCR#>~NnhsuC?z*PqRrXUfb4;H-i3t0X1Dj}5Xt1uM}beGu5 zw?x6DpYA1er_ek6zXIC#qE$Kb9b*F>rSV~I$1wHPTgY_5Fi&B^xwrPsr};2fp*+5& znE8&fEld=Bm?#hN(s+;V5mDMAT32%DohUF2Y=?2dq)Q0}agM_A_)u2gk-gKtSjO)npNULUzBj_eM&3yt;B^w`ZrIuQ#s$&*Bb`!4e`aF| zt%ctw;XdjR_kMW49ZELeTwc#NmkY?>)q4pF6^cSPYlQ~xr@?ne?}m}J2|Dd<2?hhd z`K>q{WWDKaME<~bs9{I~wyMW?0-dk!gr~hXG3}Lr2M@@grR?RvDwGsPUj*yZog>W; z6uNU1g=VpV3*R}Ce7RBN%t2aewoi`7rmh25jQoi6>qf}q*Nw=#12olr+LfbcV043U z16PhB`qF$xdeIe{8RRpXfTqo8%8I7Y>V?!}ph`3s@)-^FKZX2O8dih8m100QXzo)m z#lR<1rjOQMDZhIa@@L`Gk{WIO@C1NgPZpus(8kZ?m0qJ|l`PDQ*maEwUpIbJ%j zm)7oeiE$6bb!)8u2@H)S~M6MJan_R{(a})S^xTJJ2XN2?gabi?DTK& z2W%#xD}g`20#>)dApDp80nh$~Bp)7Pv8NI*&ku7CRGcSMj97Rbh&$jO7<8vT@p>+C z2?Rz_;%E1e!oh{LQur?5AAq^~ulon$f%3oMAE>2!c<_4@7zMo>IC{8MauP1nZ}JcP z^v9sbH~I&L`zs2Z6o%&h*?FfL&WI(0(rEnLcIbJdsM`FMC>Ob77(#!9y^wdw_M>Vy_aID_F5?h zhuh#U)1o6&;$dX+_tI!3Li_+P{Cly6A-;#=D4a@}yR`_`eeFaGIp)CZZgLr_{dHJO zuye-d-asckew22oQykt&d@DdNe)8+v;u1jUN?iCN0Id()pKT5uZ(>_u#(;1>QM?F1 z__WC%?@)2f$6<@58IWH^g8hWUPTDCfq0+vX>j{i9JyXDl{I121$TxwV0zN{*KQ#24 zXqcf578hE*PWZBaf)p7q2s9!oqcPiz1IifOraG%qx|)+LXMTz!!@pp3XX}t;e5%1x zhobmcLHxPWh3H!0Dk9#&ntf)fIbBwoJ^?~;0oVkz()HF(v_=tF%gU3U7gtR0t0LXknxtg0=bYuzU?sJ?#uyJf481{9u7a9?Au@gH+~In1P{ub2SFgtkTiK3L$2d0 z26~D6LtjVHl+G|iJ`9&cNB|~riQ^xg!XXa6g;JZ0{Tei?pEM5X2HF7ELS*Q$fV2m+ z4K8(Tmg!Q5xY9B3X$|fN8_+rA1m<_R>FiUNfwp|pzPwgYXTZK3_{iJqKh$jSHQX)m zp)F%m3Qoi53e?$?d~hq0=@qa~#95{t))`%0@a?j=k*ghNstG^Px=7^{Fq=;R-Za36 zhr|R_p_>8PPY}nw^Usl-)FuynXN1nD?m-=p{T*yBl4%CC7lY{aAGHGnbAi5?O0M|{ z2fQFnl;_hy7F5{h{2HiFdoOcfhLLEARYN;<0Wk-EpCo)A1?rksIH>F2Tmvwmu4PSK zLrrrZJ9ct(CGKIA!e{h$1B~_=J!Lmh7~6}_Y4=|L6&;<0^zS6cw;L( zF}dN15n4YyD||f$+Z1pKA;IVhPtAP^BpAol?z`|h>~c&!xz!!sl4N=vXh0e^jl)3d zkJH@ni}(=^AzE|!a*Mg+!lTBVPY=%>Lk+%D!@5c$@n>Y=&Bi|gjP_>ZF}Rj!ixyZ+ z4u-)K_An+-U25@cvcM^G4s*g{}_!*q=*yMAa zv>x5q@R<{QVG-?^1KpqDJfH8s@z;uJBVn+U%E@?$*g8x=dIGJlfpnHdi@c5Rv1`TsC>|OCFh(QO zV2Pn=@Zmvo>4pydCNk^_li@0G3w@>$2e6EKHtulaiO-3rf4zb;lY~Fc7nondXJ#5^ zCaM~yAD@|xd}eUej-A3w@8SzL5^2M|)H^&I`m~e1b!3%33+>AAK@M*wy@2iREs_^x zI|}Q0VwosOy{iI|8G8!{&$IqbbJ6E|U3C72n3e@y74ZmhY?Wgf?IajhNzPn5iTO1N)a7C!eu_nX=+*^Z5%X|)o)Ant+ zz)-LrPGe%g-px(WG4AtLWvu&rfo#nF2M#W{F_QVMEe7egoCjgv*(@bw$)O;A;{adQ zMd8}nFg_ttB`2aUV&2VqeE14>YnGvRB4k2AY83Nk;gl2~E`{gsTlhX4F3e$W=Y6M3<*sR&eQ#2bn6=V2jj_mB@Ul7tL$oGueby%|A#9IrH zhb+RtH*FC|aE zG`%GmmmfQOJ9b1Rp6lsQxfH0w5hu>)%JmDD=%LKE_09qRErs7^P;#AtWBbz9MtHw4G%`@1-(_7^= zNQ5P6qYOFl22ZVhvt)+Yzd-Dp$UAMAYyCr&OnSOTaRi_eJSmk`{r5>TN7DIwv)djdzJep^SIHJU_v zW#3K3XbQE7OElA=Kc6@&vN*>FlbXFWal~WeoA6@_PxaToOdN(GEbs3f`z*`{dP5GH z0KY(0jhlr;0uEN3PhxtzO++uKbgU*HtFHtO?Z za{Ecs**DQZNbS?R1SxddfkPKBx(b+(*@~tiK;gqM(ruwHCdL$@Rr%TZd*7S;!z=Iv zJ8%N-L*U)pFS>9bm4n>gG8uMsYA`9#Na_sNRDwyr$0LNvp7s{L7aH;W3o3%r8KKNw zNFb)laNyI5urBBy2zN<0HjrP*-s?V0L8o85fv5NB2_>z-G<*~YTbO@u!AjPT@9Hgt zEZvcy{$=<W2E<_AUV5LsbQno}+Y(Ayb=3mGXd3DgVAXJ-HmX$U}$YY4~i<30fQ> zdf(?*PBWspUR?Slk2Y8UZf!qK(x&xOuilvN^3G%C15YI0Lg;#@6(jLP%tA!Q>hZ<( zm~=dGa)WE?V7SL4o(8KCv0&1P`-wUUZuAyRdK{5pQVagJQB`cCgGujF0S|oXw}!6N z1ZPE|w3y!DtY_{Uc>Xft`HvCLry`!8k9akpmCne7Z{n9z6r>_`Y zAgNYEPEoG@i*85sX}PGwami_W(XkuUL@Zah0*(Xm=w*g;QnZl_UJ1Xv(I@YAM0YsS zPT{5$&DX;kfDI^eisjz~bh|x^xCTGgRwc z(FIYdx^X%-4tk2iqkzU(W-K1VjOl>$$GLRV6WH`(Gn<|_olQ@_m`&Fuv*f-DdlI`Q z`b{pBpAyHW6ko`u4|L0XCg;uPGDwbIx`nv%*=Vym^pnazN3-MCiPv^ljPU> zdtZb10>;O(_;eGCf85|2QxKc0GvLPz9?-jVu~97c@hF!LZ;k3Vq8!ENN2N|Ok746= zm$EVb7?-{vIyWknv3@V3Z*?%8$-qqM6PW3N_^vp=Xm8RC8q?*>sGG?|iYQMEHEHG; zl)s#rkT=#p#uZx-nTNJ?v)I_Kfu5)z6ZJFEz$WHRU=!1gY~lms{qe4G1(U8A$0p^? zWs}mcV3TwfHnGRlC2~ZYydI5Zai~7(rjHNT*G-CJlN2MHR6HK-B%qymHtB&R|D?;t zvZTCASyK8emZUSY@jcX=XtR%D4AWy+Li(jF0b_{8ybz8wHZkwchaSCEKzqQ zOXwTdGju!!RF?3fxk%8Xt%)q*Gw{m9ST?cv0^m52P5cb}V2;PUUW9qQ5c8UZc}-;I z&%~_ilH*u%v56(;8Cf#Ml>C6k3p8id;I#>QHUZ@)d=}>tWhbKS1e8Uc$F;IXJ?6>8 zjIW?CP7Bbp7&OTn3tAZ1q*Y1&h%vdu^8^<63UKATI}!CKi28{JmRO9CH-;sGpA+Ys zFdmvS)1W!iO^avKlndCj;)!e;@R^4Gr#(KY=b|q3#c@F2XlD}InS^#G%}?sm@wUgJ zZL}Y1o2P-sz%?-)>8nhxNi&ImE@5N)2J;V}8^RZJY{VQJAHaCy^^k#aEWX;HjeP?8 zHKAYd1L!&Faqt1>)r-+)@*rMqrRg3{{~nT3T|zA8)5H=Uz^sG21@0!`X#}3*S>od; z!}UX~&=0&F%q7N=jBzB-Pwb<1CQXZF<3Afbjym*fZpI(&-*G&rOkix?cS0$Ql|H~& zfeAeM?SZs@q%owKBI-{39%IRFPyhG3_ktAv>EFHoB(_GWt}Lo> zF}-fNVsmaOD{|VavZ^YT>Z9pdEJuG5UbQ^ikv3oa)^uM~UNwGOItOGd+=Mw;Lw)h2>`EfZlJde$ zHEeA-)ls!+le1bQBlAS9a&9WaFsgZ#rL|?nH4^(OYE5PJuyn?547VcMb~v{<%b8@m zQOdQ4@VSE(mFHJDD~igiSy5GmtGsL@NAyor*HKubWLH;LVT|8mh%a{5DE83LV`oE& zjb-3O{1Ej(s=czJ89N-n1Nb_~ zF4(&PgzaYNR0PB2jJ<~R48TNe9Q*K`NY6t8%r7P*Fobl3_*slu5ejf^uLr@6Z~!3` zcj37Yp&6kSArx28cOF6mLNNkEFd_6^3|yz<{1TxR?Y@RkjL?CQf;WKv3YZAE3s4Ve z0uE*btA(*#gsBK_gl2>S1Q)^_ghw&PR)iGb@HXl#LfC`wF#^TQwfG|Bcj7r0;V=Tz z;@h=2HkPaoI5r~`pxv-OUP>Sa{ zfHL5t2#pBED5D_s1J|b!&qaO*o_8ay2O)sx45WABnE^H+zYcH_;5xwFl!iP5;+=Rd z0PIGc14x^S=T<-q(jNkSVN$c52z!v<1sd%^=mO3?2_<3)@G8P52)dszHW^_af{d^cVGBYd!jBMsiO_-YKEmG-CO-^(5pF=Z72$4# zA0qq$;V42kLLWlR9?%`(N`!2Ln-D4y8W0{r_!UA2!dnQRBItg~*o6pl5V838XhQe}!fAw05n}ftAK_aFYY}P@dV?KuAMajc_}{cMzUH=tk&ANZ8NVOav>!I)r+Jy$H`B{2t*Pg7IeetAn1P1*aU=W2&o9G5ULTrhwv!Ea|kHKqF6N3vltf3#xMi4YaD}J z%M#dlW`x;?JrlctC9))TA>Mnyt`Il#rr?U?Iy9K{^zk%J#@>u~ZWE)u#D`rks!Zxu| zR>p2)n^`%lV3n+jx!CQjn$<9c)v_&YE30GM*d6Rnww>L@?q>HeH>`wvnTIv79qc}K zKWk)O*2Gk{llj=U*>_ko`!0KceUI&853=tw`^M$PSg^P7#mZI=!>DpiWjTzJMB%9^M|LRi?Yg+ zs^K}X?rO`!gA#4jY$*yCEGy=t-9)Q9ja-Y@)NZT$FdM1<0a zp2g0R!cZsGrMx{@5ZauSlwnOwV1AA=azhdNJOHmx~iB{nwp77zui?i zBn5+YhM!h?`hKW$6rB`t)IUih1 zWF(0wt1MIUE1i6b!*LpaRb>qq9i9lej7)M?Yy^LB`7Ek(iDE<2guw7#B67;}iJkIG ztGJBAmJGK;;uTSv26kIjS>>>1I8BCh8crLz^oX7EI^j;kViRteQo`+W#7J^N(wkqQ z)Q*^lI-GI2oP|q+ZSyHIyozfx)LU7J82X?dLOCP1SREqQpgNQ~a`_sL6<0}I&(Pdq z^I2G)?;`D{$<^R|;>xOOO}Hwnpf?0R7t!{Qh7yrBz-tkSo1B%->N2hXBT@&6VMMxu zeHAvQgWHXiw#c&3+e1o5$dFc$rf(>&lr{`kN*sSxNK0x zP~x!CA+8Hok7T%TB8`v`&LQw(Uca~szm8w-V&aZv)+r;^%ozWIe-;3yGu za)zaya4onyj6yhvh*wlzMvHc}6PxbA^(eQr>UJ(sv!EY2^43uwz|?T8{y?l=(hIS5bQmnc&s44)z0RB&k-k|^Y~bX&f&x;kGe z9iiO{*T&%k!~EwL!G}aVF$jxFXW6FGjS%e+hYZTa%x!_&XIQN&to+rrm7^oUJ8_j_ zspH1d@D_N1QSxeFR|(b_gbYntRjpw6K^a@hM;;r}(F2$$EcpXtC&nC|Qv}_k&Ppw9zXl>TOO9`8u*RC$BsxDKu@qz=%Van80 z2t0@Oq9s$gS}t=`Fw!RD@tS-t^V)NyDOR(!OereWRAjlcuv*Ao1Z^Wr5T+cZQSw1E zC;3#1pyo(yQfWA#Lt*vCd}q0{f^;mkv4uory2Dm|j&lck<27DIbH9Ti5X6(BNG?v|f z7i7U#in>z)`w+VE+z(ik4WBEX%K?A41a!jlalk(>1w=c41*A8}4GC(|=0XH}>E|f0@EX@Hv7)uY}g5?6A^?=d27#qsR1HQQu{iA#j;MJ?) zH$?g(z=}N37wHP%qBWo;o^5~^tVKG?Oa)wvAS1m1@V~U@7C_I<@Npx3C*YY|P!`Vt zz)2h63&yh<@MZ+UzX0%O2#fIiDBzO?ps|X%D1<)`p#%7L0y;K|vF8E4i$HVwA>cDb z$Vd6~V)z#kh~|xeS2aKTamtu2@QmWw}dkzX<9YX8@29{EwpKh<`spf(|V!@Tix;yS@pnmBG{Q zM9Y=%zC%3O9lT5`{Qar$^b=f6lfSk%oznF{#i3sHU>uqi|gN(TRO0L$^8a;o5^ zr++S-D(J#}*ifPdo_^}v1suvy4oU<6Rv_-g^AgnF$n%R((v0?KM2fhqW_w2CmWQe+?h?Rh<4A{FyimYXO1|TwjP0 zg+?*Jnb5D`X`G59m$1M@ppf0zpVXaAYN*E+15Ki&OPd2jCCb$bi;mhN@! zt=sF~+qk!R@9w>O_8!=KcyH@o|K5(hU3OGb;eMQ+J$S=Um~QrhBbscUh!G`2Li>~7i9(%Ry0>1gR{>2B$13AFUJ;7oGA zVZUjA%Kp^-8T+mK<^8$)*X=LZU%KD5ziz*K|L*;J_8-`Pcz^4D|Nf5sUHiND_v{bs z@7texAmf1bfP5hLz`6qk2TBjP4%8iRA80(#d|>y1z61RS*g?ZV)4}9}=7T8*Qx9ew zv>ucX<{n&ku;5_nLD#{$gYJWk2b&M>KDg)LfrEz+wjT5!%s6B{Bp)h0O0hbh&^I>#Pmq=Bj!g^9!Y%!Q+XJ68-VGj M|JiB%XIuY&0Ct{(y8r+H literal 0 HcmV?d00001 diff --git a/branches/WOF2-1/ulp/nd/user/fre_svr-08_amd64/amd64/ndinstall.exe b/branches/WOF2-1/ulp/nd/user/fre_svr-08_amd64/amd64/ndinstall.exe new file mode 100644 index 0000000000000000000000000000000000000000..76b5015b1b2a09cd0865b039dd6a447f82e51dc9 GIT binary patch literal 10752 zcmeHN4{#J!ntwBy2}vNCfQ$wfq=AXXKVZm2DiESGW&#~)BoG9IU^2|~kdevE>`V^? zk2{G29AlF^ch9YIS69Tl;?_Of^=`LTpgc(+C!lBr)>~1oZaL&?hYc#LuAuJP_xoPI z34@@wRaaZJwP&YZf8YDw_r8Dcd)+Tz&w>??vI54K4b3nZ+XG0Khu^>Yb_&B~llGOd zpBBG1d5=YTZSs=Na8imVVrvrqE-B!TMq`?^T9p#1s1%M$zJ;w)S1hPbFD)%`3DK`l z-rx9$=U92JJ-2m#xsLvGTXzfi!}2sAA1vR?=`WT)!Qs<1Kh4`XMjpSwC38w-4Jv}s;4cJxNx&ZoxJ$q% z1^l*v+XTEz$j{l6gWJBr*wwc6?ujN{nsnuO?pa4$XeHWFCt9&7F+RiOFRw9SC2M8( zp)FxeYyn%$7UFLSt7L5~$u^*AOl4in&1ygiv(+q$r&pXMSd6V>(}73uN7q77Rg5-c z2TSZ8;2K*Gt^`|)z7KN~panpc@aQw=hcRCTo`1D&NNQ?VTVpDbP@`I7EUG19kyce} zYgH5L!T~kewk#Y?#sX{GTKss)sG6Ecwk>IFkz!G))q4+H7+0gscS+tzBzeGa>>`FMPT``;-Hh5WUV^cKM)sl#5u|O=6 zthz}`s9Gu!g-|t-h$W<|%HT~UOjiAI1R)jxL&zVFs6kW27w3O*b_fy@sy`yB(4r>% zS{Q*fMe>+cR?nyoO4FpuR#V<$bq!W$sXvlZo4SQ2X?Mzl1}DKLV?Q8*q%^%an76iGF*IceVr%#abdr zeEEb~$N~`rcmlh9Y6R)SO~2A`Nb#vc_*cof8lSu7N{zy#)|T1Qy;1*agg}c)k(fW2 zi-WN4s(hhvG>F(CmuccUq&%%kER>ro`4k1qvAEUO`u=_T+5Ro-=036Gk=mWaI`Ij^3`IXE>xcIhfoM2)fFN(_ll2oR2PReXNv~ki zkf!u1E?MdIxjeEy2t{o|(KVz9yc0O@Q^Z@lrBADtd;h{E_a-$xt6wMdEBecZb0aw9 zo|iQ|Bjuh$9Hig1q~121HKsN0z!W!K~o?I(}B&*WZiayRF5E1-Soh}l1?z=Cdf(Z2@< z;8B9!z4T^+K^=bs2nT{6Iv(=5G+>=*5sbv?ESq`KwHd&d+3wmV;12)~ZFcPjKoAIh z9)SD;`cr{o-its1`b;ojg2N^l1d#Qg%f0r8V5H*(n^jI9u!ianhBBMS9>-wn3@yTP z%9aj9VKjIAby^20TY>#T30j4`S>E&MXE%eLa&0rBY&h?yz?7obw?Wf&jAg6v&Lp+cufe35SOCL$m^)b7jLzA|!656cMRNLxfxV=E`oWLn3&-U2S&N+h#Hy8SnmtXk zZ<>8u>LtfZcUw$5(ig+py!6G0R-e9@&?cFpPr^^^J5%&~ywics&{U|0W{R(7llA%K z*~y=SJSuBNc!uoR&v=x+1E<`5L)RKk-E?mb+%uflLqhs67G}GP2L(CPh+I*6pL9{! zn)Q|C&3aO5*57Ft;YHTe>GoG}QuFDh`vH_*`{Mu^`!3v(<2yKTZs(vhMSv37aDESp zGxm){NDtKIR*ROYNX~3@l`EN`tHOIPr6ryxw#sTAx$dGS_ZfHJdD-#L4d?Mcp*BIT zKa?ujPdnPD|7vK=-Yg78+&+T0Z*sD3-w#G`jY2vjZ*H_PHnd8&KMN|-ctNIN2QZ~~ zTAYXC_C*9>MitrFT>snTL~xCh^)h+O5v|ZTMr1ktGOPs8(0}4-UA_ku2*$G_)9^Dq zI&`~Ys+@?O^a)JCikt?>?tpQJ?6+W$9v@9x&ZLTw1%GX?1Vv6a5MWqgybpk7FMtW+ z9oT{1-WIF-h~cz>uITpLp+wf5Gf7vegnRZnyg)LXo^BWe0!tOqdtel_rW+=6!YIRO zM_0Ey&>fnVv5x>uH=MbKxQmJVy$=oJXu9D8P67Kb(AVv!(3N$KUR@jU64QhHty1l! zmx_lLNRstm%eqC@kLg9(-L#w11Jdv-=O{R;LOl)hP8-I86`Bosw@?n0u0t33;U-XU zxMvnsJW}sCUhq~ljD!ene8Wh%pE~C5OYfz}aM`+XvwAK987c#5gI2b#cvepqeaCnD z_yav-{{{@r?!zqdWi@Qa!)NFNa$yEWn$xcuN@n6S6^LMF;@<;gU~=gJ&M*oL8B2B? zCZ`*AjiHFpbF>(J!}(*dV42bbRk<|fK4qW4C{fSOMexN7_A(F(g&yVYQMtbKK1fZC zmizn5Ll^oDBW3;Ypxl3?{OoAt#PBSN6++ol7f5!UO5K|7uCS$U&^=OvWdFNynzLat zfwG1v1V%J4&vz}U5r*^Q-$4Im7IHbgrO#nk8_tI?eA%c`ITkLNN{vc3j1QXuVWFN` z3s$7AlLL$9^vo&Yt5Xu{*;rCB(&~7u??9f-G)oD1=iq#x=*N|Uey`&N&)6o%3(E_e zww%1XS78;}Bz@5+rT%!LME4dI98l^96Xo7?KOTDhRZaD;CjQIahjUc_aCndM_mQON z{aA$ZQ`k9c;fVWW{lOIF&s61>{$_nJyA?!P&>XtQ)t{YoVK9BlGGyiMN|#;&o>od! zgq9N3eX^$xufjgZV+VEo(Gsp2W;H4Y&tHnoi^KR)#N?8F5LSVsR{bm5op^8?+AK3% zH_uu$XJcj0hB-)}^5g^=QIQM!<&4eMQ%50`9Zd&t03^atA?9bsx@7$T45$#IO~3WG zXs`FZ5AU%5Z^Vf%tCOqfj1Q%|+pMV(dysqB3e+puLr*`=%00>RncjPN~U{+EiwcLJO59%yU6@N-}anT2T{#6Zfu zRFF?{M!|ca=NuipkOC8N#4?@<4tfQ%#WMpp~d zyfO}Qb(jwUJ{+ zAoq%Hx(^S3`(z^N_6G@M>_cVL+w6Lj^kwYlAp4O00Eopl)_2JMA~0GdOjtymP}>Q7 zfxzRm-Y4Frn3j%4Bn@X89mBZ=_kARRAL<_>hMob6NiGwO%F`g4`_`y@JrCcPhd-5v zPszi}hH*3Rn)C`;e_PRyc+>A(^nT22ihfMH#;bdZ76e*s7fvVz$K=3aW$Ll!z`?uq zvE{PfSgy-Oa>4wfkG%yBZIt6@-h%Y0^YY_L!C}SyO0#~1)^+9C-{W{;8cA!5jkrMf z*2y{;j%9n`D9>Qphvb*VW?{C~h*zPN71mf=ik(HwIZ(o!S}}75fiE6Cc!#JTy^A_i zBWg<9&MEgFTs2f*D@WNrkM2NT4xG zdpL%j{7u&0jyhVGKOFTZ)+AB4ZEtUE7iGmjyIEX=?8U5oc_6OM4M$KPWd>_kyTcm$ z32P5|sbwqOgbxQI{Vz(FCLpV1BHNzTh!dVQCMU z*d~*+-5-y)Ya8Mi>q@Q*Bs4QV)$C4^4tq7#wTTCgakCN{LF3DiWpsF;jeW|ZRj0Iltka9}MbF!p1bEh^SaI;l?C9As>F z9#td)$gMQjEOIXicd6baEKmt!^|mFsKnZrn{^?2?OtF2b8*E3xVlA>XoX}GK$i30^ zC>!FdAkmaqY;7t&Hx&(#*G;IZZ(!_OG}7pgqkIhC;2Qrzc(te9*R((D2+)iA|LKJ@ z6TfmH$Q|ilTO}P2y@8|m4_{k6c+*RB|Munoo)}LZPjM9d z^t+003;YD&c$^)HPTwu-1bzyzN@C0fI-Mz7(JE*z;Bhn`@DqR&CgZmgz+HfEqD6q8 z0<=J9H}Dp~pP&&Bogd#qBVAu#e`o|OyabPm&Zf&}Som4K`YLq%PsL;~ceDT&Tt16> zazQQbOX;M7dlOD3t@uW~5MPMf0q;Rn8F7h`TC zc)IZA+7JE>u*Q!b4luYD0MfT@8i}!PPV2@GQY^zdeBempi#F+w!-g>UqMYxmzkZWl z2_^{}$?h<0B0WJ+sZU?s{am~Gb$kvh%hS6QdK2Keq^|~F;;VV91|)0-o5||nD`Vzd ziU)nkPXLnSOP-R}%XLl%UpE@|6uTLE72s?5EQ(efaUze`uue$C|B6@8o`n}R+>Sb6 zUyP%KUl-8t06Jkw43@+oDGW*yyb2@+A=AhGT`2UBb!2mHZK-Fj(pT9o<5yG`@k@gs zOYvVGT=M$T?-k}k+G?&Tz-?H@qY;E%>(Qql967F#^TidIDdInqdp(24zmDUSY2**( z=~8G)40}NV+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-1/ulp/nd/user/fre_svr-08_ia64/ia64/ndinstall.exe b/branches/WOF2-1/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-1/ulp/nd/user/fre_svr-08_x86/i386/ibndprov.dll b/branches/WOF2-1/ulp/nd/user/fre_svr-08_x86/i386/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-1/ulp/nd/user/fre_svr-08_x86/i386/ndinstall.exe b/branches/WOF2-1/ulp/nd/user/fre_svr-08_x86/i386/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-1/ulp/nd/user/fre_xp_x86/i386/ibndprov.dll b/branches/WOF2-1/ulp/nd/user/fre_xp_x86/i386/ibndprov.dll new file mode 100644 index 0000000000000000000000000000000000000000..dbbf559610b27fa3c73d0fadd9e79c64d5b2d2e0 GIT binary patch literal 37376 zcmeIb4SZD9wKu$zOu_&IGhmPaK?e83c_&oudfTBgEEf%XlY42ci6%`@9rOfkR`^-sZk^%L7 z?)!Ux_x;_#nzPUTTzjpx*Is+=eaDU%Wc zReyNh+xI-S;2E@lo8r()n@XPkHh9)v5HrW?^i3go@R4`>jgcaTYmma)g?(d#NLG>@#*;b%5P;ZdnTQ1TvBO#~nN=VdG#wd_IJ z__1l1yGQ`Bh+9jz?FOLFY$qV-&&-(j zCTFX2BjR`;&=+1;cTgq-&G>(l)6v+BjBlV%%nKmm-46)*Gc$He(Cz;O|39F>quUre z4rl|s1$Yjy6F`5z+6vYI-UWOF_!JNcA)X4D4M+q$jJRT4*8=VYJP7DO+$*>q27C&L zL4C6UHvw)1T!k@_i})u1^cRDB`pd=jra-t6b*u#33NQnL|CBLIB3cQknF*N8*y8+^ z1(rffDdk0YX@v#X(jrR%?w1xXT}kl;D=LfWTHLHJ6RHJ=KEJNIX_G_0pm>Gt2E>=S zHZ(Z|eNlB&^(Mz=M-z>m(q@<7a3XDMy|A&4F)GsJXw)yRscxZ!^5SL1RBgdDGcy4a z0SN#dU|45nX8=CHallc)ApqsQW$TmkCvNC!{?qO||MK&Tnv~j4zxdhAB304LIx)|2 z@8ZMnKEE-x_Rc4kJbi59XLo-1w}+SBVz(9B>`Rsw*z>K6i|!P=qckO#|3B| zz=g*tbXMY)SyqqKsKily3SWZbN-aezhk>;i+z(ru-7+1qH3!*I#Ab5HI2N^?rt)I$B+gLfCx8%|d-G#_pPIxqt86VrIJ$z6f|A$IKqh#Whcs>+doK-hLqRmHks= zezB)?tN845zxwm{^5yzlO3ZAZ4K%_%!7;#f7BlN9M7vASp4H5ryVcA-0en~bc+Oul z*HTwnuw~1J#M}KhS4CFHZ7#v}F2KittV%O8{;Oqr@{O5G+?wN6SMPi*^6L}Y2`@~l z&hI|4~gO51sm3-R|FBySsJGYxy3%@s|@$muRp2pi1+J{clU2JA7l)pFA0V{;vJ_ zuK9PZlKc64T)%7CiO=qd|KiQY4}R=;-Qu*}{m(~llj~YnZDuDB{`FcjTZ?};0qWTX zR?P$wId-~A&i4c4>j&Jl&dk%BSPg4oPS(uYP^N}8;vfBeSG;E5^4h)q2}aW_$FDw# zoj(80RU75@oLeA22wzuYW^RDZVP=1*Gqc`$gl{*q!bae+*~~UIn^|>>nKc2-yD>Ha z-xY@lj=5~+AXpfIaU1@HPgOmQA?_> z<(Q1dWl^Dba`E>Wba^IgQ|`uzR}1% z5rbujq?s@%GIB7tA-ayH#-PZk!5bQ4>S(SEic}58HmK`p@>C+V4|!G5_I07COBQwQ z{CoVNkswe)M`FjhqjSa*Ln=}my&V~T?StOXBB)3EqB+8STstnl#~P7br0F=JHCQ96 z_Ns$Oi$YS7#=Ty}L@PqN0d}#2A*`v|s|n6lq?RJ264jWR5xZC|l^}C4yHIC^?w-xwkF|DkGter?TbYTJzw+`C3c+1v#;y< zeXVFS^^`C0o{X9FR!_O1+nU-_WI|dXBE8$1)>D+NM08uzdy356)(qo8(VEz8HHd1_ zszSw?qBXl}Z+38RKyk@z>hbj)a-Y!l^o>IwbWC+0&kGyh=Zgs!pLU7-X_v^Keu@0) z;qpu7MD2k-pL)LEuVvZ;CzY$U2Y7+L<7#(%Ec4u&C`JeqreGX)h!IkR z_JA1CW6^Zqg0i|$>Y)FzeZH~W=JFLAR=$cfQh8jrHKM0T*KLjLDT?j3Mu87DwNxGt z77!a^M4P5oDkoM?mx>blSp@j26RojTd-Wl$Yal%8%7&QL((qSLcH9va2?5dBsg`vv zRlhkZqQe^1F-ANs>K^m#Yb=@@EtN=G$~PaiA0dPr$|qI>n?qwq`lYNhdG z$L&oYN6Q{_!nioeoG>3AoH2S22!J8_utH|lcbqsgsYugp)raHa{7Xpe!f^3DwuO)i z?+I1MN$sS!x~&Vx)!4CKf2Q9&Z_GRsz%NXdnjV|JrwCG}R2de@dEraW3n@8o95SHE zyzn%cr_dy9p=-xCR|Entrg*E6VHM_Bt*)hrxY{b@T7`*jUyLht&!oZhJrf2^a{4{J33BYP2yr4SFMucYVXMj;d20Gqx<;Pp%jw4XzcS%7#H7Ty^&AaR~xK1j%yB; z-59Pi6yk^ijc7t6e91mv^tk3w<2CN%;n29IDq)XTXlfqF7wN1W6{>hifuen5i&A9wD zAVIjpzRnXc`a8BoFLfWhxES=)zUUP+QGGpX&RX4|wx?Vt-)g-lRggAyD0week@iKE zS^%lEG?&282p*(p9Ib(C-4US)h$X|a>zvf5Js?bw4)=W;-+iT2uIqY#oeJPs20} z9J>w*lcd9)CoyF)5pl7I;B5lQkVY&TbbQ42IuSd$5BEA4VFjdUKYCew6jBq8Gx;!1j83ThD7Mz5ZIqqn^?}Uoz z5}Zl}tp;TsVHlSv!7_!2xQ_#&;N^h3UBkdRGC0BU0}+E!?&BB9_zYXad%kevNBd&A zMpA1Jx=-E%sRRq6-k8M42pyWEagxXfVu=zRHHrEc>;SztnZ{cT=A;Y@1p9_ zbtj6E6&TjifvKdS1j+-`bQ~Ti$W1BtiHNaAQh*?}SUdHc={cf(X|GI|==m3c97WZN zCF6Uh)ClA3J>R(g)k;=17Eiy2phO+4b)Sr=o%~+Ur#W$MBH|)R^?SY@2hoW3#R9d8hP{fU7z^#O(q{$| zVZ@IRM8a{kxOhA_Br~+oN^po zeYQyBDTu&QAecf`r{5ksz+R5TA|AjpE5m5p*<9Ol0uJC=zmeDn?eszNTASt2)!JMtx90LSV+%_#D=SIBQB9l zh{r|6gsHfwnJce%Jqir2?p;oo(%y8sEbC36OF^%WE;-1lXF?J#W+q&VO9vBXS061Dr>*Ry@2Dz8!+rgB1bR=K84$u3Mo?nz*??{TmXl7Bt3hcdQ- z`CU4{E4E>w-=*=p)V`~&wC04M1WQ)~Yl!q%;%yBok0s7Fro?|Np%M$K_QnM*Qn??g zLACnLl{4Yq_I~wq7p>$mA&U|46kZ8qfD#*L$ce&VdLzxOgB)yQW<$qc9v~zmhb`Z8;UO1YoC~U5h%lAPW=)^S8x| z?HBwr;?XNONGA;BtIs=3bN=VtFBUduj6Dy<+(pqR@NPl$YQnu7KQ5Oynp`vYY&%J zmiXKBzPBul+1IT(7{W!Of$hdo8Z0%0qtxX|FfBj=>p$UlINh1gf<*1|C8q~UPUR(6 z-Vj`}tfEr-@bbm42o(R_1;5|(oAv0h_RScmG`-t51N2-R0eUvWqG*U;ouPKdl8bu6 z>aU(0TupI0#I;To)xFUm?4T8iD{yuMbFHlTiP3rIE8(!tUaS&AXT zT#B24h0zNNhYn)*P^?&VA*kLk17Sv>iWpQu{m#)tK#b=qDjK5jzYZeeeYM~UY$N*r z=pObqrGvVjit7s3yJe zVuffK@>tH=P>b4Q8M4(aAYt7SFS^diby&~CWj-I>rv4oa(roS_6Y%}w^4*&m=-&1J z@cSDK9?KzU4f3Z+JFTcvYS&2LTZMqzG0eISik4H-&gHljEj|o%(Q;Or0Q7{br3wR7 zXk3}6>QEWfoVvvSewTNRGHy0EFpuSetwB%KHyCVn>GF6Rp@CH7b4|fW)4L{!TB-fi zU{u3GyR?%U#@glzsm;`NPSAMD50#dn@=BZk57L0!$Asw+s0qD4rm;CumX%22^1+ZP zxTFLF>GDK~3lQO&|HRPc{e|H$O)4~_^+_fE!(Cp{a=}$wN&Oh+${f8>d)^=tRbtDE zYmbrMxMJMx!%!LnmJ6goMk<^l6&9ev7{BWR>Xcqgr|zAD4)o7R0L3xKxHqYw2FCL6 zo3Ni1z`o}1V_6s=;I&e*4IPU2{L5N2SxR)Y`QM|yaoU~UMObovyB$NE)ny}`ZXjNB z?k!NbXO;Uay3USvc^T816F=94P~ls!aCU$Q_F-ZnRVlM@RR{}Lj$Zchxx!|CBpFMv93ox#UFO#OifIxNCfypC4i9*f3!%vL5= zX?&kySm)4G;yMmvP0C3Jc2Kgw(?ocl$@)rB*j~Ayt-|*Tse+?j$J%ujF!d;}f%5Jf zd`v1%z{F0QhsAnq8@^2J6RkR_B0;ppN)>w17Kg>4_Qm4$qBQ}R4cPyaiVfJJbKhOS zw#K;cHv8LR+*X5sFh(jii&le#tvjn}z?=>fm<^b-)6tOuv-v?>jNa3FG%#weUY=l6 z0t8$AwclUSp!W@5Pa1T!Fj+d_dqD&FIWrh(JlAy&{l$qa@8AuUM38sMeqBV#U|IVV z&Mq5BE)5J$pspH7sfJpZ-(Y!74dC(KS;Aw1uO$eN=6OMQOyYQ)K7p>1l}Qt*Mx5F< zsrL-fJN*`-VYsO)v2`T!HBnT+5B`XUudJLcCzOmEw=v zZs-0a8*Xos-6p07EVl+$;&0XawAom?4G3yz4V5%J__P#N=C{$V{#0K5O{l(?8nZ*C z?T!7`=9ex&!S8=X6x8`{x^9${U+IG=IG&R!lswAGJ#q&x#Yy+j+Mj8#2r&K@bKJKu z?5+$TcJ52eHkcER1PlgG{(?F^IvTho^T2J!J=t?ibklJPkL9qfA%TjJDWkU48D!3k zOe5N^8OY{tKb)ZLn#>Cv_1GeM)aD%rU4LJ=*ENX`|I=TC!*!2B)saPU)aG+ztU|?} zq#OT?J1|Z$VY_L172d7uMn1%5^H|{x&$0z2?jfCY;f?#T%ptSVf4E`6I;iTW6wLD% zfR{5p63w0^o}#BZaq))E+4A)^y ziA4t_i&vDmRaJCIl*o*tS#g!LED=*xtf%~`($0OyX*tdzV*x|1+Q#rX-!e4YB@IUkoM(ivJD~EpQlVPR*GYvMtoFqGSnW%&+be}xL5BNn4HG=Cl1)z*`!YF5q?A%< zIoWxUFDi}a3bCkM)N!|Lqr16{PX0qTx6u!j*kl`hlD{q1-=_1ujkQ$3MpxFdeQs;K z-)+_VjRyx9&20l_6F978Bm;vh##lu$2CsiX={U@J)1>}j$;Ae8L-Z=R z@!xetzkG@$mtjp%t}mtE_);50EX0}cej0|segl+le2~WYPIZT=bvv(h0c!p39*6kL zdmJu39~`0HP6{ZEzR!rqHd=t&$dLd&fSJ>*E~(p(m9f7iULH0^??J_Zz>h;gE%ABp z4HB%Z{xSXv-h$$$>vwspKh#rC+4*dG@|EtT|yW zN`-OIIaf(I^B^8Z2C`i}~ACgy9#c`;d#<#Q&fEU42mvU!0YtrpGzL%N>jD|yi}Ol}aH&Qo=!O!`yDUn0&OtMiV!LD1zn z$IgFn?NKQLmNC|Mwpg3*RTEUx(awL+eCx8&?tySCFoxfyT@wk%3w$PV{#`nx2Jv7G zXJ$EP<_e76y4YBSmx?*^B23^xV^En<0f=)|Dp*Z_-Q>E6Li3c-l=4jL$=CkM)Pfw&G> z#E8qGxaky%L~Da;3jGx&3f=8GIFQ$3WZ22Hi)8S8HC8UEE%H#^U;~LuN&-$Hkt<>QKG03OpsfdHL?+2(M z1c#-gS)XXTB%&0R;JUu(BS}{GMaN;LSBgbvxg*cuDcWDskX};v8l*~WKP9&NMAwkm zenxB`9ybyUu4t+1BY8DyIVBeAB#V!ZA}MGAsaaCTeia2{IL~gvJ#?OKyW;JYn580RJIooZw9nQWlq9DE@&uAF@#Fqv@Zp37Y<` zSb@cg*0`YA9djy1-8eVMG zx5SCA!(#g({{yu91Pnz>T-$_7-!Es8Q@|3paGy|P6>f9;G(xf4H&M7n9w(*7gAKad zr2g|KwY&Pxe>nL-iSIU)kcPAVv0B?ji(GjG-G~~gx;0dt?9`jdX)>tm&5Xo=o7g*> zyuvgQja^c?hs>8$OC6A(kzI|9zwsS`Soc3hC{8Pnib@&DeL+aR5JyNF&t+X)jrGS& zVvY~}&ia^`;Z%t(O(-+K2yx3W=LKz^h2w=rs#4fdrE$KE)89LAAkxLz;o2{{j))eS z9Z>gR2dwA-JK{&!5hs~-6<~*G`AFss=S$TnUn-@ezBodC-@^XYLYh@rL=2fn44EM_ zWPYXZJi7BuG^SmN;F04VT0cfszW|mavbqa5p7z~YUy+oiLP{Z`5LC%_K`c2du9gYI zmmWF@rC4%7vZNwKVUfmim|{5r}67LB)X1^u2Z7RClBO>{lZ);W;RI4$jrva zn@%2Y6XDW`?)?%7k%K+>0P{EYT`|A*;V2Q%gx&OiiRrqrsE$(&q1@>lqSY;|miAaT zQ20W0T~HLQg(S(ZD%0LaquTS>cAD+V)$R={IKpFDm%nXkK-Df&OD#~f7nm}-b*^1?{$oTLBAh`=w>{RmPjX#=Z_DUCXGw?X=h*0><5tKP=T;|T9STJqWX+`P+PC}R= zV%HhuzWfxRIMz~+V_kN@pJCBK6iBR3UlGYzh9y=Rb}D`whugE1`Ze0ju*BmQ?kDf* zzu~r*PF7`D^oTo8aqsgi3Ai1m+kLpLd{a%op02Y%OtFEBVnt6p$r*O_Jv8%4Me#@e}@DC{B1NlSqcuXh;&RH5-$na49k4O9jiYN#uz zYk{39zOWqW;$t@cyAr=4#7_2+n_iTZ;L7?WTXZb?H9u93xcrBrlQDj$|!uR+D+9w1|tJbH|}%$M*{iWLKUB8bSd;E z_e~7EN>vE6c|);$EjqQVVS2#*vG>nFtc@1m{$0K3G1;qU6{#r376P`T&x+;49A&JE z;(0Y!a(s2AC1nlDuDS-O(GmbYZk#MR3)7X`|J%dZ|8#s|z;c!tpi~>OdyWNoh5y%_ z48JBa;2ebPkSl9YcF*5B3$$Hl32j<;zlN&ZwK_m7?Y9JPS9T70shtsj@?{r_oY>0t z`p-Y|``_Gy!Wb(gSPE6>+?Q2I!jb$%7m+GlKe!Nh^qAw^Pp(BaR_lIpJzcxIR^c+x zMXcvL03H%aWc7Gx1eJI^R=V&GEI>EOnZg^Ay%k*~#-1)Ser^62sDzA${{<>m$*FrF z*hK}Y;2ZCD<2&&COe+#mX;+FK#pdHgcwoDXPaJ#;Y^y|CuYL04RQmwy|{pL6KSP~i{ zrFXjv_1){{`HZ9pXyd0>My^lIa4hTtnaYqyyySNKl+0ho#B2=nuWeuRQu}<4ubT5&dwhPeNG1Cq@ zOIut&q@Ix{cT(Vd4tL`k6gO^S=nC&LOVk)@KV*qYk9f*!%5f{m7{~=*e+F;<$ZOS0 ztT~U&qY^k67NTt0HERV^kc`aZ%3%(aL!@&CdRTWBL>%$7HUP!m#k5|UOy)Xm`5C?7 z8}>$Hy1bPQ>2|DUXirqkwGaM#)_^lo8X%9X+nYe=)O?8?2TevU&X!QN!9R|=fWlRX zlOka%q-_&a_KBW4r0L9k5JNajg>*v0Q>b&Nvw;}Z3=Ed5pxo$?7Wb3$!B-G6_(I$f zp$dp*l2HXjj>$M2RuW$z#lWc-P}F0b$eehJ6M6Pg@E4v8Wj6&6uVJ=vP0c!kKEfg3 zJ-rCVL1(*;#-aAUIk>TjU8ILRT`l+}S3(yZ0pJ1BQ#KqOt22{>>M^<r==J%vVP-*MgKy^n}p+o`eg z4pNVn9o*O4t$lOndgQ>Q9E&|5*P71$I^25NAEhmy!R1CTf=@sFw6v4Tmx+p3@!`E%z&AR0YTgw>Dbj-Qbk8f|C7~ z2X+0HhcHP6b`6M@_adK6OO9K@}b$w$9%LH4r_ChDJlsa5C`WbR(Z@ zp+7pLWorKmL=71|nas*cCjA1DnM4YDaRQ!B#Dj`zoFMMbhlP)msvv|HCsnz}Jh~SP zTv24g8VIfPHQoG=+x*X4u+zV%c!*`^k=+U3!+iz zw8V#u;wAt0BPa{6_hKEk&~?Jxic*hDT~Ue+E*nn$*M$tWZMfopC2pFJHN0>|IZl)AJs5e1{0#4STFeCvAh*Oy};8#Th=^ zKm=__NVZ{VAR*%1(Yjrb!jd`O^M|kPvq_N+ups&F#XslJIh4`!5`FIVYUWH}yv%wpr32w&)<|$V5X^{?;HbmGe>XxoHGxq?Tu*3ct8p0_R zbNvUj8XxKQNJV@CIWOEecohs|saPW&p8TGmD}k-8LP>Wm#IzQVE>R61i~MM~J#Y-H zE*m%uM5JE{3h>iiK@#)rG}HFW%Yu6-zN}(&s5V5e5$1A@JTraOEF4N-fR;y$n>!C< zWp=Kjt^?X0=Vti<+Q_=)9JvDO$*>>$kBYmNmcC*YJYD2I#GyU~gm+Q9qX!vqq626ATo*i+QSK}frIv?D66%ia=>y5Mk$^b zfkC3}dH_LWjMv^vkEZlnd@-I@wWs|ww@)TX`FKl;4+G?D9Q_Z7436R>XRydfXR!OC z9E-D7(ov#@IFIEu{(H(+rvv|SP?w$#0LPE`XApBU+K&h`Gun>|)BUdFlo<=Hk9-gO z8Ed9!jB=^%nJ8uCahTM5-Q(}gC45%O~T5xPC(&-Xi|=kPQ%dS`pV}; z3NMw_Zx=T3nsd2LmtNMO7!p~idGK1C{}^@CsGM-qD7L^Hr2Bq5T2WBGXv(L!bH2i} zU6>ioc&cDT*J6r+Kaw1;tyZA|k8oLC%YtZ`$1%#_7#U@y7CU%#P=-+xOQmQ%#p$zy zH)kHai5#i$jjDayr}ItRxeXD%pTMZa+jp4nAp|G`w3XVo1{p>T5i+&N*t{8CQ;f~C zFdD|J)sbZ&hJ;g=(?WjaN`96Irw4+>hw3t*yi(Uws$*P)V^fYOH2QWIK^6p-qGG4J)+Y)6{n&Hrz#IeMfXOUSw~QJc}Hl<`sR*Y&Me+f zZi5g*L?-0r%6t^I3_r;-p;s57>KH6UZ*_bVS(zEp+eGxX080U-x9Nf2Vu2w>@Y8@_ z`iJj{=KWT>8@vsLv54o*MmDrB{p{J6X;7K_v8^5KVnAtl6XU}_t(M12jCop3E^!Gr z#uTMQ@EJCgfYWmX!*Cn+zsF>Q!*5l46M__n>>|LaZ@35!lh*hq7eOH&_=9;%ClS=4 zUbkR>!HCFR_Hn!Am$zML98`i+$~f4K@ik^lU2YtB(VY>~=BMy&@pV+}f8{!gH=)d{ z*}RGWx^)zBTMlZQ#1RYmy-L4WF6I9Yr=g?6!9b~iQ>nfzy1(niW>cHMg zzFvHt2Bf_8BEDciIIQNThbTEwlxgy<-@=l)D|W<^`D-MssrjKZlrFX<2-2*TH_v!^}0AKU`ibE}1@vcTKIBUMnq` zP7k;TeAsm6>;)4Lj3(EOtyV1hv9D?>o+mh%)hF*PwJ*(?gr>AztEjC)T?suB`A{~B zluCFDL`2}wd&NKuU-aIi=EvUuP+DS>CRFlu?hJTjPtT^(ye0YhzUAB^n}KT3;dmV5 zMo8)+vbhK18z%Hy9$Ak=!%_?0Ghn?+_9OwhT>)>BrzOGD{tVe|rym73h-Pq!kuF`K zu64gmeTmd|y@UwV#_iS@sA}y?6<5`Y<-1V3dBh#n8E{8Y#53fdx?3-{_l6u%&f-Uu zQ}_|(n|n@bf7jD*tCc!sPgNycRlE-Fs^a{d8aS%F3j^HWij(ZG`Cmvx(B}Im_8cUR z3oWY()v&<*Td-F`Vh+a{4o}B`lem#jkMw52{luToreoIFyvJh=MI91OG!^ZTR_Mf{ zZfOO=_xBX*x{Dr!muqd0bzXPT4|}Zo?xG*auDyVpZ4vhdUeDcZ^ZZ+5{aaz?#LF8_ zvJ`3q4z}&UT6&$N7M!k#Ev=)m*IyVHffhXv(bmVv;|_=5*{B?tz&T$ibN-K|c;JDn zQykEojqc)%J>Q~i$8&8sU`u+IuO4}1;HUr{SU0}2&iCd-kms*e(qGnuD)o}U!QSvb zSx$4sXxq6L*t^sncgHa-?C4~|>F)!7v<*G~Id-u;zaF`A~_#YrOBb$K(!j0VK zO5ipZj@W`R@d2M6Z$Pp77UJHyp=(gf59&%4Si`H`dv&GKALVgz1k|y~ zPk~4gAPWx8(y7&Gj3-)m2ixDBL!{V(vC^gLuE&UzkNP8TkeL>yV} zM0uACa_3ovWC_pEc-A67(&iz5c8^)#-BnFV795`D8)MyFw9@l*ZN#t5rvhgo>@uzQ z387xp7pN}(3sklLg_Zb`d!iV$FXPbz{|kg3B+$?IlRXddY)=9A5n(+14Z`Swzf^XE zg$m*TNgv<3HBT7pbL||WCPw+f4={rxa!0~F70+cw*%AHwo4~nB*ZGfN`nx&7V`*Eo z3p^$Abw5TvVqsdDr^|srrOkH)s3`Q3o0-p9eKi-)S^gKOSeZ;GWpC7uXR&Z<-d0CC z(Zl&tQg;+o@o=u;C_QbFVAT8WMeQTKz7;OT&_m0eL(hlwT0S{JhmkPH5#b@5bVx?z zo2i$d+mz>kK6?Ym9ZWBd6Xt;YS$#q*4tt9a5$Exm519;u8dybay86Q}nD&uf;IW{t>D^E;+{W^L`r{1A} zuomHGr8YqMKw0=7AieJ%R=a$-gRe;k$*S~uy@ciVZ1@bPW6q9L2F(pz0SA+8gtH46Q>thiKP)RFaj`FqP8ZzYQCehlj7H-YmHcV~poKe3RS; z)1soHLgb7PxwsOW)SzTmzbr-Dr@CJ!{;w6T!ec5!ZbOsUckAw z!3hnz!AKmcmALR_soS*N7Lpz!^&w6gd^u36R^kdserr%!q>vD(#AR@AjALS}%5#_6 z!?*ijAk+>-&16pw&XD-NoS3gdL?m`dkOvk4m-)fRM!i;-7kT9wJ%xTL?SRrk%l0tz;@DzRQ$EV(;Cn1rAp<62wZ&XG5$tgh@g>Q zh)_mxp)W+Z1=2*uPY||?xCmX(MQ9%E#H+X%Ez^&R(VV~;lo}u(Dn{Hu4w((nsg% zvWB?<mh;Qp1^g17z%TRl z{IVz>mq))JZNo*f;O!bJcb`g}vJ$tCTk$gxy$i@j;2)Btr57Gwj$2tr`o$>)Jck)k z6IIN+M9e8b5N`aRQFn1Ak7*0KQm28N)jy+=f|OHy{rClRZbls;dW=^3UIm zTTT^(9}NmW928b7Vg6VfjWQ#S*x|i1a5!JEmHGH;3ZCdYT??{45ww`^6xS^|XCe8c z5q!tu=wN@=d0}RlyjkZ5S2iRYy%|~S+A=)L;-qQr|BMi>bpK~0o=wE5>vlCf_;^#r zwli3mnB9GGSy9eogLwId=5}wKM~KrrS^K2%93IIE!JzBh-I`9EoyXyacNv^-^f=L& zaTD@9F(#v0cX}i|blk?U91x2jsl5^K(+y^#@0a$+^DUhHILR|ZK+m%V?w*7x1bfBOAo;7G-)GHGr+^5LPNKhptOxbBOd;J=4Txa%ITT{(mq3Y!CmRsIj4 zox@fvo$AL~y zA2!HU9?Jn6#o&3{0m}hcFU-GH;|?F5KULr*G0kMz;#irj46h*q5r!j?Eie(ElH>Vxhp% zR=?4)v^l@INpLnd7S=a9*jdWa>JS)f67Xpc{&|nNkxS`|ANW?%?T(tIO>okIqOD z;l9k#&BoNrRr zsbq1%E#^0GZmD)UEO%_=AKYQ=fyfeh6InrhYxM@) z@hSpH=T|p2wz9&gl@90T`X&%EP!;UW@%6LHsPZPD4|3L^BaRlKzPSkv5Yj9;s>~r= zGI^P$wAixTn9P~ZS|V3E@r{=v5V3j_=sug;;!&0+Lb0&1dQ&T#GbVPqqs`IC;zwea zH*ebHa0b}RVj@c&o9fYVC$DIUtG=dnG20ed-sBt?56%@-EVeCG@Y%sOHrh#i8=Y(; z7}Z$6fg@T+Z7r{E6)a9?Gx}&`xL?|W56P?~G?|N)Ihtw~m)cl;OI>42bxXb6ztB;w ze6OjggJI5u90i~oI^fiHyq)SEcw^Tw_Ud{7u6;9+fnEXw5au$r3UDXFpCkSNt|@Vh zO$YQMtibmI;rsAl*A~D9q~D6``D+5~PPhG&+_i=q2pxnQW zxPJkh0z3=25nus$aQx;N;Ldp9f_lFMQ~~}BaLtE41XKbZ#eFueGl0V)z&qD4_E*5a z02To!3*es!&%pIpxc(dZ*a!IXI>t5uet@!Zxb6|P^NYBId9nk3{APeQ*(qlFOe0CLM*W!NX zJoFRc5?sFqybAbt#QOo)BYq0-eje990q+cydk&z*eFpOFLii*g26=yi`yU{_9@h^5 zGZCMM`}rt;2-h!Bz65dA2shz66M2?`zB<6ofJc!2ub@*E0q}MK3J_O~G&=D1BLMNE z2K6lgYy%K)KBoNO*Gz1Na4CAK)WE#16);1{44`0NMdR z0z3`a5BL+{3xKu@@&YITtOslbJP3FWa1ih@;48r7o!|+e08kCM7x2FTy@1~Vz69v* zLmogLU=^ShAOW5Pyb3r17z9LhLyiGyfE9pxz&(J60Z#+=0X_np2TT$nOMnbOIiMcU z3HaZD=K%)*Cjowdz6W{-P!IS%;6=cPfG+?uCGZ-s4A2O;5AZbLcYx0T>iZc>0OSES z0Nj8l0EYly0j~5gb`ziwunBN4;90;2fG+`>?_sKe0CkXo-KglyOAwqiEI(Ri*z$H zU=~k?-ZillmdestI?G_0cn~8SFW1avdCbff<0FdstbkcqAzQ+%Y$>~yEn~}B5i5pu zU}GhimCM*lR?aH$wY*hqHM@sd9v*0hn;FbAt;n^+yb&eXte$JdxP zvnG6?qMCQlikbQYzOPY=OXW8-I!;4 z@Opv!nTLH31l`3RfIaj>_8@zR{R>;Vp|}PUY#W~?3K|>ptDDN38eu{dH*aOQ$Lx~d zSl!yXVnYKyQO59E4Sb}}DY#mgy?%pzBPH4ETkX!xEiGmfkE_|tKbzLt*euu^o9%V= z=A=|50j8EcI3bxQY(i|cAUN&KwYA6*sAnX$wf;^=P~7I~8v6!UZBR@TzF=w>wzW9y zu>6AJTbf$zn4p``W@vn~lcHc+*lV55n=hRjT5Jm$M|R#AKG$YWAHiKtXsH(J>|qno zTzyk*bJ#>!ZTP_3xXN1FHU?*}ui-S^1PemxUm&WLe;v`@;&jy3-w~7so@_?N^&4R- z1Vs}AY8t+0p_8-t-5i1vf!+4u{XIkk52)kYsO(9_m^WP^DEFi#gAe( zE{QN37a5A#xa1Mc#-%8j1rnM!Qq#4tg5`nY+R(bK6$B1Je@v!Jr&3QK1i@8|Z%5{! z+<=nm!j}yplr{C$n;;Uw%xexLHFIm)jv*4DHVwV{rh38N5I}RZyWuJBg>guDL}K(crQ)s1;=8Le%w! z=K7{UjdJe;ML6v^7U82WStb~X02xMGBv2PY!N;k&F zqogt}_y`{?arlUBP~e-T?~p2k>H^CO^zmqvwq|F0;8i}7R;bB z0#GZ3MQZNO@t2GKz8E0+y`0af}#U`7#FYfVO+v!AI2pG`Y=9T>BIOG z>chBLr4Mofmo?&HeM?Os?}+&EVcEDr;rU2BMk*w4bG^c}kp!+uxGjOuVci>bBV(PN!X{3*W%zmJMNh3*oVE#1}-v^{~lNzo~8mR7;SAg^&QO zZfk4}TecZC5IzWcS)6!3TIw*L%dl7YMEsf@vD{8H_li5c~sik@wEhFtMBTKK=Ml>#v zmy$9BcoY;#^#=&r3ePWWQ(lj=zS&tXYztr%loC9IS~trb2-9jHg>t);flb**3|UhE zcZzGZE4qef8E3w>@(<1j6nCSe+9@+JlpDdBs0%XBLKqgD1&un$hrJPMm&Cvj=qjjH z?c88@H1Z7yPK-81F^owgULcJ+f`vmhn#AfGxBv6^-;e^k&G27wzkEkAHs^mm>&=4y zhQ0V7l>bX85J6kF@KM687xG7E9pFC=6OWS%@HxU)x(E9>Q6Yu+jXBDMYXv-zcKlkn zFLEjTlEt`Rir+$n>F;&b=NGvYLK+{8p_mwEE8H?O4(fts7(&1^>IJ9!=hGXeVyfC=7G^aDQCi71QTP~`L-gT z6CPGQe75xnIgl#g&W3O^e601{7mLj{_;{xVwO4_hokR6~Xl_Dy&fIid{@(^PK zJ51a!(1&D>M>;}d>8FPWntED?R+~|0Gis_w4AEsdYOFz>w{V!(7Qgx}Zsd1_CsruA})b!NsRC8)Usx@_eYE5cg zYGZ0k>aNrWQy)%!Ga1?Ck8-+3T{mWIvKUH|Lt1l$_=qeeV3+^xWHW?YYj}M{<9X`|I3EdD^_R zybXDq^6t#rmG^kw(L9JJdme4Y8x|W14XX`K!$*d~q-9C#l75+VDoK?*F*!atCHb-B ziN>kMdB)AgL{mAq^0DbJrgNs!l(i|{DOynN`qUqRF3+YGrG1$8aoQJY8_}Pw={@O> zr$3i|Dt%^#AtNuNFk@8)9>vP|x6I#U9?Mi`y_dBpyFPno_Rq7Q$$m5Y^Xv&Znw)t# zD{@xmY|e4!{5a>QInU+%IVUams=RCSGV*fsO7kl7n(|unzM@So)&ZQ$fp3+e+TbwM z8#WuZ7+i*JhIT`z;bFsLhCPOZhQ&$mCVi0fw zmDZQ`Wcn}DUr&$AO3q5lx;5*atY2j>&MC}k%y~TLshnqX{*rSx$CSG)_cytHx&65x z=KekR2YGw*KF#|)59)-SLi>@1Q-+SDsmWI)-;n%yvesxaE;p7KYmFZoCz85c4lGp`2cEt$(Q9huuQcY^Of$oysIK;}^97nw0xH)P$MwI<7v_5G};vR=s= z%$kw?v+P&0k7R$CJ(RsRXG4xB=SMjo-jHX^+n%>C??B$Myi<9n^Dg9JBal6eKDHU|GISgI4E=@= z4PP1Zk_wValA4nKchZTZ>BeOA)onazeAjrwc%>=Pl!Wo!Y7$M~GyTlel=735$5UQR zv87d{?M#bJpPinaejGjg&-BcUH5vOePG@|U5taF`neSw-&1%jPvhK_JL)NjZud_fFtF&b+QXOgz{_#Cx3#dc!T?_uYmr!%4%v zNzWwBO-@a|CHdCm(&Tl?Lh|-xG5P7_calFy{xJEI>-#v2zJ z4aQWX#dxc+6#8tV@pfaI@h)Sh@dw67pv9ht_Bw>ak})QoX{KqRDcRI%>IOfDOkZN- bbwSGN6eo0t2HJw{#$Gb;p>g#8hrj;=1UHo< literal 0 HcmV?d00001 diff --git a/branches/WOF2-1/ulp/nd/user/fre_xp_x86/i386/ndinstall.exe b/branches/WOF2-1/ulp/nd/user/fre_xp_x86/i386/ndinstall.exe new file mode 100644 index 0000000000000000000000000000000000000000..55a3211b35161404ebf973db2a0f5a728df76d64 GIT binary patch literal 11264 zcmeHN3v^Re);?)d2oT!HGztP5wAC^^4847%O-fVRKp9&|NuSVCLUY@sq)A9_N>R|( zv<&eYUsGQ*>R3@=lo?S+VHku873fSs9x9BeQ%7)uWoB?hC{nrqcW#nWK>gSH*P8XO zHOrH=&)#RBefHUBpXWU%g$o}h(S#5wKoAJo3QU7ujDI)^B0KixZL#F{Blb_)Dk<1M zsn}}ss9bJmo!i`?sxdnpPENIyRk^(mmCd2bn{QGzI4$h-(W6HugjKJZ} zaI)9Du?y*wz3z=YBCgxm2`rhMv+*5KZsNvgME>%Pts-8!akq$N6-yP58cWCjP3vfqc*R34=eK zW1BeO!{ZQ9yJ%Z!XAcP~LY7Rom^m|ePtr!J0aWHDz>uIPq;tC4z8;3mLG!09AHdI7rt+W;>BXuue3ZU$WsC6T{0=NLRfJ#6lB;6R9poAP4PbB}k`EoiU6IlZ= ztw}jRqXdiy=x!+I*qYz~jJW?7}tjK!AaShuILIM=9hI#i~dd1StebJ?1(#QgnbHQL^p<&q6JWlPz+Z` zfkc>%1A2+S-{p| zM3kECUe?eQu2i+c##zG^!?HX!T*>#@1|4~<9m7XdbFGqa(@e%pRf)sA6ee*_Rjtio zfsN=V%4o#UquzDa4%(VmP=GdlXIZ<`Y>CK)J+y=&lFb0>t6|N}Ynoe{u~$W}XYm33Qq;57gHxn62x?N)|YbL`{{Cu0=6bQuA75VIy0z#A>z5WW$?W zt`#nqOok-|zu~}Q$PeTH3sR_wr1?Ne>O8r0=x6G+-Do1`Peo zIb&(5-`gL&6ibM&U+~`4vU*?+)=N$)cn7SqpFo3>>a3_ZMg3?h6TJO=RsuNnGU2FE zP^v)k$F!e#W36XtwIS)g%5VinQ)%$|u2d0wza6}LHN`E%mbkO&pa%~?TGib zJ&72nII@G<7I^DvBws}E1$sdVzQ9?E>Z2CdE6SPf9Dmy}r2TCl(fFB7G!ASQMPi@Z}?-l9Sme~M*!wAC^=Ui!ueZ_o^@dXQC7!50oN`-8{XiqCJ9vtNQctWk7KDw{-OxUu13VXZ{X;lY1uGkUN2Eh-%q*Y>EG zXb2_RknpXRMXi<#=|RJQAe^Ece!i4{yENdE+^^8L9`;_Cvd7mSwU`@uzeG2Ulj`p9 z9**0QLkHVdRO;)uRd6$W{dO+V*YD;=K+(WOLFl`c>h%s6M{-}ZutFAm7IpT?gECap z7ZW@LBq*)Wz;yO0LzGo@*=pZDLF}LE;Ol7M&<-l)y)u-ELtiNP*tTviN;u@(Bh`B4 z?$e8_LKCs0n8D!4LnNdc5wD}9HHAhR8mSQp%HLD_yW-dBkqVW=6dap~5w&#~A>aRMn^MN!XF_o4H%5oIc?&ij6_rR2Mv;E!^eF|$Zns!7bvid#*vtuo! zAuzK3=3o`nRrF~^7R;XNPo*Q|OYZ!o^gsu3vC8rJ|@~0NS zyok2(*7sjD;|-^I89%~b*lR2bHet$CRP5&2 zAaCdurJ3Vl`Qeb?BvwzY_6`%2n~@4Ps)H&HcEFa9w`*InV78=iAtyzL7Ix^62sBex zi-vvydr!q}$sgNtVH5^GHy#+R^uF)g+6s}_#vZ0SV{JdkzF1!q7u&dYJ*Mfu);Tb6>Ya~bTdU26@v0%+OpA=kn_s~TugPWr3tdGm3r@I z(BaEUQe)5e%B@|KP+HlF{EFaMacUcUDDDN?(R2s!Mt!yW)J$~0$Qz6> ziumFL1)rA?&le<&Em>eJDzaiTl~{ySv>-gyyZm_xGK)Wvav-Ya%Vm(B%8cV(a^Iy( zoEAD#eBWH+q}qQsP7kCs1}a}y@T2_sa^Kxj;_b0Y;5a^47W~<8LjC|+OjIJ#x7qR# ztVOfB##S$0v>R%r=X0d6lWe7O9E18~e7=m?7i2ITOL*&8!6g@53c(d0oCyxbNtGyr zX85DFV(gRMB~T;dCkx9b2+PL`%ael2upkz*lF~90{{_>@9A^$Q=b-b@qH4@m{tNy~ z+F8L3bjH!#ZsZHX=Qu*ZN%aJ4umHal1>;~gOszsK_5|62B7sYY5B?r=g<7&pcEy2W zEN_sR_^S9)-XmkwW&AK-|D`8xS^Q6)5GIEVjBIoDH`BE88Wzv*E zaZWF-jcXeN*+5~?f9C+dNbb9M$#1}TAL}=q=9csg3;YU-NFaU@U+{Q*TX!JuafRP- zh9`bQKNrs*4a(8!xCz&6bJ8voxUz9rgt1)sHm3|VPJ#r>yq(>@xj;OBHj?6Q7-4M z<4a@<%J?JvzTlP+moMzcX!+l*IfJ3VA3Ze>rM3Zt43j*rwG0GbC@U)C{~W9X_tb4* zTs{Y(4|ozbd5W(|5$#Rn_3>G%m|u+Jlv$G~ip{!(qTyLY|CG2`Jc(JwbPk>mtsC$? zEGUg4H#EzH#EnQrCX#r7gblSV8KG4KBPvH1{dRc$_!rY%+tM_4lq9YlOG0>Wh?J!` zR33)r>!SC?ZOMr@mBwvZK8!iscCIXtCmY*15j!oPFV|jhkHGAU{)_gaTkhM16IYV< z1NY}RtI!cCYOI%8HFWD(jo$LH17sVpWI=Etd_q^=EVyIJF5`lrpE4+C3a?LiJ9zW? zgTCI#0@n!03)18Is*(sV$*V*s_%5(;6pf=)(=LS6?BsLGyRvgG9>j-A3!f#Jd z1OQWdF`>jW#0t(&%T238S0EaN0 z=tOMgIlc=5r<-IL5IfX6g)h>z9bT2t@(m18cqRm-BmIUGq0Z%E`-U@}dg>jf6Wnks zg0rCRio;Vq>Mub3aCw3;xCYsvZj9TaudL0ABHoz#sPd}awOP?1p$`MdAPcu3{CT1f zo#tcv#eOZ@Iq!4*AGLcq#c${xG&kb>!FBOyeV++mG5y$TG^mUB4lv$+L8$}HoDr1z zFwPS(+zh#VDrY#$7|t+fwCBAsJLW^LKb3m&{0IJ2s&jGm(1TCQ=_D+(>z1ToyBb|d zV`VvwCl=E<)kx#40>rfsD4Rqy+AgAr`67zR6H%gGMALLYPd^mn0^$v1okhgbbynbj zLAH*g>9$^U>E0Onxhp|OcF@dqcBJ;k(9hrzQqs9M#v%u&{FnSOy3qii;dh_6fWMF5 zLvi$>zB!;P!6{CVQ<+1j4jn)A#i3)Py1i%5f5o4HR6Haw3C@2WeaIcFh1?36J5CGP z#u4+TAY*)SLOgRElnj*o{D&h1Ropmm;!tn~MIZR->Osg$bA__unb= z=Suy{0k+)`MY8(<^bG7ywXyB>&iu{7+Rx@-<*+{(D36 z<8C36p8$@D=MO4{`wo1I69pk>hw$csHvzoz+e8sDN=m{f2YC7+yeGlKdH*}Zf78A0 zpCq`Y%C$Q^?49gN@)1qVwtGERn)-&OF5iOX;MP}^#tj=s#SKk4av22Wi`oV*8( z9$bgw#;L)KdtNsz`B4dZ<<~kc(W;d=w!$PDhY5`|2 zajd|NB}tCPKq+yAu2!ic)F{lRv6bHM&b1Jt8^R3_9I)S_+|UJov8{p4@xTI>Qe<{? zam2AL6v&-`kAuTn&DJ`O^Lc2Pf~C{m`D16J6fj8oCv~I&NoPqy&~PF^G#A znDnq2$rCZYTqW3)=ttHlfF2-VQ*8!rK}q_tF9WCm_W}mPb5Z(1dSA?C`Wx9Gt$$iR zNE>&@4bll`$3*Dn$Dh1DLaVm#7#E_YJG;j}m_q4}fAky}zw5|6z3R-fZ@8vx{Ovo> z*z^ahzD+!N1K%wO~nCq8IHY`+N3>wz!^)*~_y=9$n|6QGfPA zi}tVc15Y@{_`c5GePk*-?r-HcY&rC0_QAMYTjz|Qv+11;|IF5}f751vCFZU4HGSDk z*7jL}6AMD`s8i#{#v+R^^l=iS+lcA2!^y#4Vze)&rF zCw1G}GYr4I>D71JvlDLJ^SABWv@^{7UD@W6ins51)wF8NAFH#E{_~E&upN)KDKF+_ zCuF~PD&xi5zqohfPqSBV>Nv68vTF9hk4t9O+&!%4*5VaD;gOcCN507%cUMhf?u^b& zx=H>+n)~KFv6Xy#RQu7|a@qJ-gP*NgAFbWfYM3?r&8NKS$ERm9%O@PZ^?33>=RUkJ zWBt!}be4Vi;(hC%ex}uGJTV zdv1F6?`s#9J)+xb^xZOc-kt2yZ+#EFGOT^|btk5M^6LYK_enoqe+(}g|Lr04cL&Vb z<||uDkE-I|0K)-ec9^CzBBN<> zl7upmI`Sal!3!>}+XWkJkaLJ~Km6KD?Q&y14B1HSw!tP^j|E(srmxIqvG&kwu#UtI zskapMx*>D9zGS>St3^-)Q)&iDBO0_7JCInG)H>bXlx;^z$sxr?mIedeeewXVawV^7Jw3H>OWYSEp;zXQt0iFHB#RekxtA zxlS`(lcLGd%+V~@tkOK7c}mlv*`Rqv^QLB(=FggsHJ@oNX~t#TnlU-!j*JI0UduR` z@nObaGfrkq&YYf^l9`b?Gcz|cKXYDYX=Y94J()kxd_Hqi=FZIS%mbN6GQZCJCNo+q z(<-&MX{Tx#?Hp~P)}*b_)@toqueM$LwDv{q%i7nqJGFi0&+!fw_g5%&3`kW+r1` z3K$c!h^b+gF)Ns6rj6m5$CziC-!NO4?aVG_Kl2`QFZ_Kvr9VZQsz{}NFGw|}+EZQP XjrD(~yMNUBqX&NUz>gk?c;J5kX-*qt literal 0 HcmV?d00001 diff --git a/branches/WOF2-1/ulp/nd/user/makefile b/branches/WOF2-1/ulp/nd/user/makefile new file mode 100644 index 00000000..af891baf --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/nd/user/makefile.inc b/branches/WOF2-1/ulp/nd/user/makefile.inc new file mode 100644 index 00000000..6588a1d6 --- /dev/null +++ b/branches/WOF2-1/ulp/nd/user/makefile.inc @@ -0,0 +1,41 @@ +# 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_amd64 objfre_win7_amd64 /E/I/K/Y + xcopy fre_w7_amd64 objchk_win7_amd64 /E/I/K/Y + xcopy fre_w7_x86 objfre_win7_x86 /E/I/K/Y + xcopy fre_w7_x86 objchk_win7_x86 /E/I/K/Y + 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-03_amd64 objfre_wnet_amd64 /E/I/K/Y + xcopy fre_svr-03_amd64 objchk_wnet_amd64 /E/I/K/Y + xcopy fre_svr-03_x86 objfre_wnet_x86 /E/I/K/Y + xcopy fre_svr-03_x86 objchk_wnet_x86 /E/I/K/Y + xcopy fre_svr-08_amd64 objfre_wlh_amd64 /E/I/K/Y + xcopy fre_svr-08_amd64 objchk_wlh_amd64 /E/I/K/Y + xcopy fre_svr-08_x86 objfre_wlh_x86 /E/I/K/Y + xcopy fre_svr-08_x86 objchk_wlh_x86 /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 + xcopy fre_xp_x86 objfre_wxp_x86 /E/I/K/Y + xcopy fre_xp_x86 objchk_wxp_x86 /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-1/ulp/nd/user/nddebug.h b/branches/WOF2-1/ulp/nd/user/nddebug.h new file mode 100644 index 00000000..ab5607b4 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/netdirect/dirs b/branches/WOF2-1/ulp/netdirect/dirs new file mode 100644 index 00000000..0e61a797 --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/dirs @@ -0,0 +1 @@ +DIRS = user diff --git a/branches/WOF2-1/ulp/netdirect/user/SOURCES b/branches/WOF2-1/ulp/netdirect/user/SOURCES new file mode 100644 index 00000000..e58168a5 --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/user/SOURCES @@ -0,0 +1,42 @@ +!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_exports.def +!else +DLLDEF = $(OBJ_PATH)\$O\nd_exports.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 \ +!if $(FREEBUILD) + $(TARGETPATH)\*\winverbs.lib +!else + $(TARGETPATH)\*\winverbsd.lib +!endif diff --git a/branches/WOF2-1/ulp/netdirect/user/makefile b/branches/WOF2-1/ulp/netdirect/user/makefile new file mode 100644 index 00000000..c43884f1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/netdirect/user/nd_adapter.cpp b/branches/WOF2-1/ulp/netdirect/user/nd_adapter.cpp new file mode 100644 index 00000000..fc9f45d1 --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/user/nd_adapter.cpp @@ -0,0 +1,301 @@ +/* + * 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 hr; + } + + hr = m_pWvProvider->TranslateAddress(pAddress, &m_DevAddress); + if (FAILED(hr)) { + return hr; + } + + hr = m_pWvProvider->OpenDevice(m_DevAddress.DeviceGuid, &m_pWvDevice); + if (FAILED(hr)) { + return hr; + } + + hr = m_pWvDevice->AllocateProtectionDomain(&m_pWvPd); + if (FAILED(hr)) { + return 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(); +} + +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 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 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 (FAILED(hr)) { + CleanupMr(mr); + } else { + *phMr = (ND_MR_HANDLE) mr; + } + + return 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 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-1/ulp/netdirect/user/nd_adapter.h b/branches/WOF2-1/ulp/netdirect/user/nd_adapter.h new file mode 100644 index 00000000..01919584 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/netdirect/user/nd_base.cpp b/branches/WOF2-1/ulp/netdirect/user/nd_base.cpp new file mode 100644 index 00000000..6390f60c --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/user/nd_base.cpp @@ -0,0 +1,53 @@ +/* + * 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" + +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; +} diff --git a/branches/WOF2-1/ulp/netdirect/user/nd_base.h b/branches/WOF2-1/ulp/netdirect/user/nd_base.h new file mode 100644 index 00000000..da84e6a3 --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/user/nd_base.h @@ -0,0 +1,63 @@ +/* + * 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 + +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); +} + +#endif // _ND_BASE_H_ diff --git a/branches/WOF2-1/ulp/netdirect/user/nd_connect.cpp b/branches/WOF2-1/ulp/netdirect/user/nd_connect.cpp new file mode 100644 index 00000000..22d12e46 --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/user/nd_connect.cpp @@ -0,0 +1,259 @@ +/* + * 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" + + +CNDConnector::CNDConnector(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; + m_pWvConnEp = NULL; +} + +STDMETHODIMP CNDConnector:: +Init(void) +{ + return m_pAdapter->m_pWvProvider->CreateConnectEndpoint(&m_pWvConnEp); +} + +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) +{ + return m_pWvConnEp->CancelOverlappedRequests(); +} + +STDMETHODIMP CNDConnector:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + SIZE_T *pNumberOfBytesTransferred, BOOL bWait) +{ + return m_pWvConnEp->GetOverlappedResult(pOverlapped, + (DWORD *) pNumberOfBytesTransferred, + bWait); +} + +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; + + RtlCopyMemory(&addr, pAddress, AddressLength); + if (addr.Sa.sa_family == AF_INET) { + addr.Sin.sin_port = LocalPort; + } else { + addr.Sin6.sin6_port = LocalPort; + } + + 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; + + return m_pWvConnEp->Connect(ep->m_pWvQp, &addr.Sa, &attr, pOverlapped); +} + +STDMETHODIMP CNDConnector:: +CompleteConnect(OVERLAPPED* pOverlapped) +{ + WV_CONNECT_PARAM attr; + + RtlZeroMemory(&attr, sizeof attr); + return m_pWvConnEp->Accept(NULL, &attr, pOverlapped); +} + +STDMETHODIMP CNDConnector:: +Accept(INDEndpoint* pEndpoint, + const void* pPrivateData, SIZE_T PrivateDataLength, + OVERLAPPED* pOverlapped) +{ + CNDEndpoint *ep = (CNDEndpoint *) pEndpoint; + WV_CONNECT_PARAM attr; + + RtlZeroMemory(&attr, sizeof attr); + if ((attr.DataLength = PrivateDataLength)) { + RtlCopyMemory(attr.Data, pPrivateData, PrivateDataLength); + } + attr.ResponderResources = ep->m_ResponderResources; + attr.InitiatorDepth = ep->m_InitiatorDepth; + + return m_pWvConnEp->Accept(ep->m_pWvQp, &attr, pOverlapped); +} + +STDMETHODIMP CNDConnector:: +Reject(const void* pPrivateData, SIZE_T PrivateDataLength) +{ + return m_pWvConnEp->Reject(pPrivateData, PrivateDataLength); +} + +STDMETHODIMP CNDConnector:: +GetConnectionData(SIZE_T* pInboundReadLimit, SIZE_T* pOutboundReadLimit, + void* pPrivateData, SIZE_T* pPrivateDataLength) +{ + WV_CONNECT_ATTRIBUTES attr; + HRESULT hr; + + if (pPrivateDataLength && *pPrivateDataLength < ND_PRIVATE_DATA_SIZE) { + *pPrivateDataLength = ND_PRIVATE_DATA_SIZE; + return ND_BUFFER_OVERFLOW; + } + + hr = m_pWvConnEp->Query(&attr); + if (FAILED(hr)) { + return hr; + } + + *pInboundReadLimit = attr.Param.ResponderResources; + *pOutboundReadLimit = attr.Param.InitiatorDepth; + if (pPrivateDataLength) { + RtlCopyMemory(pPrivateData, attr.Param.Data, ND_PRIVATE_DATA_SIZE); + *pPrivateDataLength = ND_PRIVATE_DATA_SIZE; + } + return ND_SUCCESS; +} + +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 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 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 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 hr; +} + +STDMETHODIMP CNDConnector:: +NotifyDisconnect(OVERLAPPED* pOverlapped) +{ + return m_pWvConnEp->NotifyDisconnect(pOverlapped); +} + +STDMETHODIMP CNDConnector:: +Disconnect(OVERLAPPED* pOverlapped) +{ + return m_pWvConnEp->Disconnect(pOverlapped); +} diff --git a/branches/WOF2-1/ulp/netdirect/user/nd_connect.h b/branches/WOF2-1/ulp/netdirect/user/nd_connect.h new file mode 100644 index 00000000..2da2f222 --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/user/nd_connect.h @@ -0,0 +1,119 @@ +/* + * 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(); +}; + +#endif // _ND_CONNECTOR_H_ diff --git a/branches/WOF2-1/ulp/netdirect/user/nd_cq.cpp b/branches/WOF2-1/ulp/netdirect/user/nd_cq.cpp new file mode 100644 index 00000000..0324ed1d --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/user/nd_cq.cpp @@ -0,0 +1,124 @@ +/* + * 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) +{ + return m_pAdapter->m_pWvDevice->CreateCompletionQueue(&nEntries, &m_pWvCq); +} + +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) +{ + return m_pWvCq->CancelOverlappedRequests(); +} + +STDMETHODIMP CNDCompletionQueue:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + SIZE_T *pNumberOfBytesTransferred, BOOL bWait) +{ + return m_pWvCq->GetOverlappedResult(pOverlapped, + (DWORD *) pNumberOfBytesTransferred, bWait); +} + +STDMETHODIMP CNDCompletionQueue:: +Resize(SIZE_T nEntries) +{ + return m_pWvCq->Resize(&nEntries); +} + +STDMETHODIMP CNDCompletionQueue:: +Notify(DWORD Type, OVERLAPPED* pOverlapped) +{ + return m_pWvCq->Notify((WV_CQ_NOTIFY_TYPE) Type, pOverlapped); +} + +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; + pResults[total]->Status = comp[i].Status; + pResults[total++]->BytesTransferred = comp[i].Length; + } + } + return total; +} diff --git a/branches/WOF2-1/ulp/netdirect/user/nd_cq.h b/branches/WOF2-1/ulp/netdirect/user/nd_cq.h new file mode 100644 index 00000000..ba1c91a4 --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/user/nd_cq.h @@ -0,0 +1,95 @@ +/* + * 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); +}; + +#endif // _ND_CQ_H_ diff --git a/branches/WOF2-1/ulp/netdirect/user/nd_ep.cpp b/branches/WOF2-1/ulp/netdirect/user/nd_ep.cpp new file mode 100644 index 00000000..07383f23 --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/user/nd_ep.cpp @@ -0,0 +1,282 @@ +/* + * 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 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->AddRef(); + m_pOutboundCq->AddRef(); + m_InitiatorDepth = OutboundReadLimit; + m_ResponderResources = InboundReadLimit; + + 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.QpType = WvQpTypeRc; + + hr = m_pConnector->m_pAdapter->m_pWvPd->CreateConnectQueuePair(&create, &m_pWvQp); + if (FAILED(hr)) { + return 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 hr; + } + + hr = m_pWvQp->Modify(&attr, opts, NULL); + if (FAILED(hr)) { + return hr; + } + + *pMaxInlineData = 0; + 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_(void) CNDEndpoint:: +ConvertSgl(const ND_SGE* pSgl, SIZE_T nSge, WV_SGE* pWvSgl) +{ + SIZE_T i; + + for (i = 0; i < nSge; i++) { + pWvSgl[i].pAddress = pSgl[i].pAddr; + pWvSgl[i].Length = (UINT32) pSgl[i].Length; + pWvSgl[i].Lkey = pSgl[i].hMr ? ((ND_MR *) pSgl[i].hMr)->Keys.Lkey : 0; + } +} + +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; + + ConvertSgl(pSgl, nSge, sgl); + opts = ConvertSendFlags(Flags) | (pSgl[0].hMr ? 0 : WV_SEND_INLINE); + return m_pWvQp->Send((UINT64) pResult, sgl, nSge, opts, 0); +} + +STDMETHODIMP CNDEndpoint:: +SendAndInvalidate(ND_RESULT* pResult, const ND_SGE* pSgl, SIZE_T nSge, + const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, DWORD Flags) +{ + return Send(pResult, pSgl, nSge, Flags); +} + +STDMETHODIMP CNDEndpoint:: +Receive(ND_RESULT* pResult, const ND_SGE* pSgl, SIZE_T nSge) +{ + WV_SGE sgl[ND_MAX_SGE]; + + ConvertSgl(pSgl, nSge, sgl); + return m_pWvQp->PostReceive((UINT64) pResult, sgl, nSge); +} + +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; + WV_SGE sge; + + pMwDescriptor->Base = htonll((UINT64) (ULONG_PTR) pBuffer); + pMwDescriptor->Length = htonll(BufferSize); + pMwDescriptor->Token = mr->Keys.Rkey; + + RtlZeroMemory(&sge, sizeof sge); + return m_pWvQp->Write((UINT64) pResult, &sge, 1, ConvertSendFlags(Flags), + 0, NULL, 0); +} + +STDMETHODIMP CNDEndpoint:: +Invalidate(ND_RESULT* pResult, INDMemoryWindow* pMw, DWORD Flags) +{ + WV_SGE sge; + + RtlZeroMemory(&sge, sizeof sge); + return m_pWvQp->Write((UINT64) pResult, &sge, 1, ConvertSendFlags(Flags), + 0, NULL, 0); +} + +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]; + DWORD opts; + + ConvertSgl(pSgl, nSge, sgl); + opts = ConvertSendFlags(Flags) | (pSgl[0].hMr ? 0 : WV_SEND_INLINE); + return m_pWvQp->Read((UINT64) pResult, sgl, nSge, opts, + pRemoteMwDescriptor->Base + htonll(Offset), + pRemoteMwDescriptor->Token); +} + +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]; + DWORD opts; + + ConvertSgl(pSgl, nSge, sgl); + opts = ConvertSendFlags(Flags) | (pSgl[0].hMr ? 0 : WV_SEND_INLINE); + return m_pWvQp->Write((UINT64) pResult, sgl, nSge, opts, 0, + pRemoteMwDescriptor->Base + htonll(Offset), + pRemoteMwDescriptor->Token); +} diff --git a/branches/WOF2-1/ulp/netdirect/user/nd_ep.h b/branches/WOF2-1/ulp/netdirect/user/nd_ep.h new file mode 100644 index 00000000..8e60d00d --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/user/nd_ep.h @@ -0,0 +1,130 @@ +/* + * 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; + +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) 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-1/ulp/netdirect/user/nd_export.def b/branches/WOF2-1/ulp/netdirect/user/nd_export.def new file mode 100644 index 00000000..920a72ba --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/user/nd_export.def @@ -0,0 +1,35 @@ +/* + * 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. + */ + +LIBRARY WVNDPROV.DLL + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + WSPStartup diff --git a/branches/WOF2-1/ulp/netdirect/user/nd_exports.src b/branches/WOF2-1/ulp/netdirect/user/nd_exports.src new file mode 100644 index 00000000..042f3cdb --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/netdirect/user/nd_listen.cpp b/branches/WOF2-1/ulp/netdirect/user/nd_listen.cpp new file mode 100644 index 00000000..ab505897 --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/user/nd_listen.cpp @@ -0,0 +1,145 @@ +/* + * 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; + + if (Protocol != 6) { + return ND_NOT_SUPPORTED; + } + + hr = m_pAdapter->m_pWvProvider->CreateConnectEndpoint(&m_pWvConnEp); + if (FAILED(hr)) { + return 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 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) +{ + return m_pWvConnEp->CancelOverlappedRequests(); +} + +STDMETHODIMP CNDListen:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + SIZE_T *pNumberOfBytesTransferred, BOOL bWait) +{ + return m_pWvConnEp->GetOverlappedResult(pOverlapped, + (DWORD *) pNumberOfBytesTransferred, + bWait); +} + +STDMETHODIMP CNDListen:: +GetConnectionRequest(INDConnector* pConnector, OVERLAPPED* pOverlapped) +{ + CNDConnector *conn = (CNDConnector *) pConnector; + + return m_pWvConnEp->GetRequest(conn->m_pWvConnEp, pOverlapped); +} diff --git a/branches/WOF2-1/ulp/netdirect/user/nd_listen.h b/branches/WOF2-1/ulp/netdirect/user/nd_listen.h new file mode 100644 index 00000000..15526fbe --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/netdirect/user/nd_main.cpp b/branches/WOF2-1/ulp/netdirect/user/nd_main.cpp new file mode 100644 index 00000000..6ffe16aa --- /dev/null +++ b/branches/WOF2-1/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 /*WSPAPI*/ 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-1/ulp/netdirect/user/nd_main.h b/branches/WOF2-1/ulp/netdirect/user/nd_main.h new file mode 100644 index 00000000..9a892722 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/netdirect/user/nd_mw.cpp b/branches/WOF2-1/ulp/netdirect/user/nd_mw.cpp new file mode 100644 index 00000000..64a8feb6 --- /dev/null +++ b/branches/WOF2-1/ulp/netdirect/user/nd_mw.cpp @@ -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. + */ + +#include "nd_mw.h" + +CNDMemoryWindow::CNDMemoryWindow(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; + m_pWvMw = NULL; +} + +STDMETHODIMP CNDMemoryWindow:: +Init(void) +{ + return m_pAdapter->m_pWvPd->AllocateMemoryWindow(&m_pWvMw); +} + +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-1/ulp/netdirect/user/nd_mw.h b/branches/WOF2-1/ulp/netdirect/user/nd_mw.h new file mode 100644 index 00000000..b7e42bc1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/netdirect/user/nd_provider.cpp b/branches/WOF2-1/ulp/netdirect/user/nd_provider.cpp new file mode 100644 index 00000000..8f6f1388 --- /dev/null +++ b/branches/WOF2-1/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 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 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-1/ulp/netdirect/user/nd_provider.h b/branches/WOF2-1/ulp/netdirect/user/nd_provider.h new file mode 100644 index 00000000..63278c85 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/netdirect/user/netdirect.rc b/branches/WOF2-1/ulp/netdirect/user/netdirect.rc new file mode 100644 index 00000000..7ed0d78b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/opensm/dirs b/branches/WOF2-1/ulp/opensm/dirs new file mode 100644 index 00000000..db5a8974 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/ulp/opensm/user/README.opensm-build b/branches/WOF2-1/ulp/opensm/user/README.opensm-build new file mode 100644 index 00000000..cccd07a1 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/README.opensm-build @@ -0,0 +1,24 @@ +##### Begin svn/gen1/trunk/src/userspace/osm/README.opensm-build + +# How to Build the OpenSM Subnet Manager +# ---------------------------------------- + +# This file is arranged as a shell script so you can paste or execute +# it. This is for building from the SVN source at openib.org. + +# 1. Complete steps outlined in README.kernel-build. +# 2. Complete steps outlined in README.user-build. + +# set TOP to wherever you've checked out the openib repository. +TOP=/usr/src/openib + +export TSHOME=$TOP/src/linux-kernel/infiniband/include/ +export MTHOME=$TOP/src/userspace/hw/mellanox-hca/mthome/ + +# Add util dir to path for makedepend +export PATH=$TOP/src/userspace/osm/util:$PATH + +cd $TOP/src/userspace/osm +make VENDOR=ts + +##### end \ No newline at end of file diff --git a/branches/WOF2-1/ulp/opensm/user/TODO b/branches/WOF2-1/ulp/opensm/user/TODO new file mode 100644 index 00000000..684ef454 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/TODO @@ -0,0 +1,16 @@ +Support new HOQ value for the ports feeding HCA ports + +Support Static Lid assignment with a flag for specifying a file with guid to lid. + +Support PKey comp in Path Record +Support SL comp in Path Record + +Support VL traversal in Path Record - compute the SL accordingly + Make it a runtime option, So we do not pay the price if no SL are used. + +Support a fast Path Record mode - if the fabric is totally uniform in rate and + MTU. No need to traverse the path at all... + +Improve the MinHop routing algorithm such that it only calc the min hops +for switches, then + diff --git a/branches/WOF2-1/ulp/opensm/user/config.h b/branches/WOF2-1/ulp/opensm/user/config.h new file mode 100644 index 00000000..5d7c42de --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/config.h @@ -0,0 +1,71 @@ +/* + * 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 +#include + +#define chmod(a,b) _chmod(a,b) +#define S_IRUSR _S_IREAD +#define S_IWUSR _S_IWRITE + +#define snprintf _snprintf +#define fileno _fileno + +#define stat _stat +#define fstat(a,b) fstat_alias((a),(b)) + +inline int +fstat_alias(int filedes, struct _stat *buf) +{ + return _fstat(filedes, buf); +} + +#endif /*_CONFIG_h_ */ + + + + diff --git a/branches/WOF2-1/ulp/opensm/user/dirs b/branches/WOF2-1/ulp/opensm/user/dirs new file mode 100644 index 00000000..d7822e5e --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/dirs @@ -0,0 +1,7 @@ +DIRS=\ + libvendor \ + libopensm \ + opensm \ + osmtest \ + ibtrapgen + diff --git a/branches/WOF2-1/ulp/opensm/user/doc/OpenSM_PKey_Mgr.txt b/branches/WOF2-1/ulp/opensm/user/doc/OpenSM_PKey_Mgr.txt new file mode 100644 index 00000000..df4031cd --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/doc/OpenSM_PKey_Mgr.txt @@ -0,0 +1,79 @@ +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-1/ulp/opensm/user/doc/OpenSM_RN_0_3_1.pdf b/branches/WOF2-1/ulp/opensm/user/doc/OpenSM_RN_0_3_1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4eaacf87aabeba3261a395dfc2be991e5a4355f5 GIT binary patch literal 83938 zcmce8bzD?i*YKbs0uqXJjnd69w4{`DcgN7(NQn|k3JOYhcQ;5&cS$z_(k1!Lpm?v> zd!OgN@9+D)=MR|Kv(JjXYOl4|IbUrX4T|rtI5%#IkI>f@v_#0jp=HJ)(%7Xra7sLko(^}cv>YA8CY@xP@!XOW|LLf6M7==O9($EUX z4AU#19Mr<(tgP&zU!h{W`YK}!afI0%R5sA5g6dp`x{MHZeFF|dRtN`^fq@~Ig#~2D z%w`DUU}R@zG34O+?=v)^){A0iuWM_6WrB<-WMo3p!r$!}YLGD0KV61`i!}tuAfRin zYi?x(B|%2l2x14N56adRebNs0=1{K!9fC>XYDmG@7NTnan*?3As}U((i>nz>Ie)*& z8e++>Z*O8{3H3ZM9|Rj_P*GI_S~{4U|LG6R8No10S{Xp8P_%>mME7S0^c@k5WOX2v zeyH?eSTwKw)Ax~|9Ek#T1pmBI5MpN! z;|i)Zf1St*W8ud{26-R|YQa$N$^=~is0U?&f@TmlF}H`-&8dpbJk zV=gcGOEPp{)K`9JT{w?=Z$wlPfro{MBp+vW@NH$<^rg{+wp;K;k)2iPPVv`#|Kxh5 zymN<@&+$%o8}AYF^?fw%{|M~=*w>H%mrBBSOXQ~SI3LC^F3yN8oCyao0%2mV>tj=y zm)Fuu)IoSOLth#4o07|jBX4Uiom5!fZe^C4vreIY5l_D0Pq^^l2PzhpdVrZhT zdu7AI=2lLBB8!P08YP+8SpJr-D}TleihcO?<)i#4pxr8 zWBdmK*uDqmPJgV!-z_+7%3tw;fr^%P4%XIIw)W6XlIRnlfR%-{xrwf&z6($uCV2~( zQvD%<@1(FXG5-fru3h;LQvQzhUtR8Z*Te)Ax3qGy1d7_(IsDE&bXWEtP+p7u2g)Cd z@r!GNP5CSLAfU7(#MaRS;`A2|S=cz({{y;ft@?rPn&E5Z|KX5-C_nRc6!@-m%zsfj z*yP{nq6Yz`AWlGGh_1bZ?eB{L27&)f-LKp;|Awx=x*{|32 z7e0USOFx_nG(P~!TN&CrLAe78LZB|j0Ai_c@^{Pni_m|?4!)M^5A1)(`QN!TIp}_d zkseGB^A3OZV{ELyDD)4N`h}Ta{Sh<(T$3R4a}xpGKS6ytbYl#L1``%$4j>D3^9yt7 zN>B%X9SEeLpZ~@ru73Y1C>h|jlez{8g$jen21WY=B5b4n-OKz8AFveZCt<%(|BJhk zfhJ(zZ~Z~<@4&A&B+%3g>P>&l{wLtSI1m}&HK+d!{0IM6z^?`SPrzZn|7l%7Kb+}5 zuggzzVWeLR>7StgV(`#)xu)iyX}_KUg$_#{t|age(64^~6YWgbHuKNWujz$BzZTLz zL5KbRXXw|f`j60m(hGxrP0K$)|HXJ^fIrp!pP^sV3xj^GoBss;7vqF#`!zNH4E=fr z6#7qF`X}hW*s6@JmA*X09%`8k&;kW?^9|daFo;?}_j6CKY)KfpTf5qp3o}6}|GtV0 z!eHpY^SA?q{g`Dk0u7dRyND+DH&n(}i z3j6ubMtQY2{2@SwAG>i@Mz+7-uETEpV|#9|&}k_TLZ3RNsj1P@Xajp#$x_`wMBm?} z#!`Hj#_s~)@9SMTws}iU)zN6jZPXKJ)YH5wVM~X#wP{TN-yZZJl(~(R`?1BWL%*@D zZAt9PA3vyV!|SF%g8S7k94~oUx7uB1 zv4rr@v_xsp+Bm+~bdm3)Bz5u!+&c5N!3zK{CyV)GkEwb#B&xx?yjfO*2s@7V(;SHM zOWvix4^@5kc|iZnT{vZcg8E~ClAl{r#islxPTdD138B7Px*y=^nppTv@LwcJGZh>< z#Aq;84v8128m+?7u@$v;xk$sF!daq!*6GTo(#X2e7pKlRs z=iozWW*j(xpuuRWz1ci}9=zDi?`HC-P?B`StS5BIE%-h5E&50Jq~KdU!CA)J)(Xb{ zdI{lQ9$SX_yvPdcYyTpwQ*|(1DL470N`-v*V-hvrQ+(pDoqeXV4U=enGS3y_vW4%+ zqim9?lSMsCn_ajxR_b8WeWB-^_3pH(EUXCiVGGTG0EG|#D1AMU0g}yyrX2hSsl&9GePLyc-Xz0SoJ5WCRnATm;H3 zvaDNgsW$~sPI42O(@PUeBOrsa zi6y_KoypGuXsQFvBd+d)X28&-obHL0xq&D&xi``Oi)H*0QU3qo`&(SU1epJSxa6!X zbS?kF)-TcKJE}k21#~U>frh%~&{PZhQ4+dOVPt}SQh*jGM4@{mdlP$?U%_2@oooN` z9on^L`a>*NehwxJ18A-ff<^#_rw|h(V`zrR$O2?|Vq$M61F?nW8CI6CycSmI5wJ41 zvX!^i)rVF+1R;(l`VbLYT^HcBivqJlD-%CU3W5R(KMD$e_E48&mzw}oerSaj0x)DkjQZ6il4^sHpdG2(YlQv9Jj6F|nZ+CO$s!A<07^J`D{$ zJq-;HH#avA-_PsvBLMjhzyuHh2lohYIR&@{K)P%OBmn?$@Nicb3={Oa34ptC3;s63 z9YiE#bO78fxSKa_-GE29eFy<`(Nr#=V=j9^MDR^ULaDJhJg(y8R$DvG55ADW+V5 z9+=toMZW+7S(yCx+>X8-3szFmOLD=t3I;-r$@Z++1B&yI-D2;iL5GDsVTyMtJ|*GJ zLyP;Vr7got2TF#Hz7c6s^O}X-Z|27sMJyoFYxOe4kCWzS9O_Cp&3y6)oLHLCb5{xMv$35O^vI z@Ir~BIFHGb&KRRxee%(ucFXnkvL-6V?nA|s#P^59MI-a@xL@HK?JahhMj}O8{3;JwOrv^CjS0xn?i=S^D@Jk>>@c2<-($JB8);n;%5!@(!!shkiOh zj#c-IrZw=Hv?oeBn*^=%btIgq0zFPW*rvFV(8ArQdRFPfQ89O*!R@Wts| zZsMeV2xb475=z8~xJK`kodkD1NyhF&iRf}UtBoe+IZ zEo9I%>xzSNf!gB&)eVT}K~=filGaIUYjG+|5cMmzzA&kS>TD6LpTkdFV!vq%QKe%b=R`^#dxyOl220E4tGBnFn;Z)LbkjpNrY_$Z``+ox{r7NZ5v5))JLi24B9awr2~+r^MUUSMC|{1O za^}((Co^?4Pxy~4D(_@Yy!ux5B!|exvUSZqG96f!T?7AIh=E7iWXwZ6Cuw9tU27(3 z?ja^=nCK%N(LVTYwXM(R8sHd-M-#M!F`Fj&TSxI5`In=sxE%2+PIg+DmPMWsmw>*} zV+2fw+#8(M#F%K=4$o$kcFYK(f@faYy*iVrvV6>RVyGUX;#+1|+naX$qlOM?~-w39i*&_Dz1l zIT#Om-(Te3ol)n9daC9gOgv`yRGAZ1v$U!w{+$sCVM{P?4d0ucC4Ki9TulHIRM16L zhtAE-w8jiYpUhM^Y-~P{psiQ5P5bx+K68?OxX5#EQP(?Nc^2=z$`x*v?Xa12)|A;* z+2VJBl;5v>)If9D|AnXY)koqR@oRo(K0fCHmjHz&q_(lTBF;RTp4@KY(fs|KOF+^J zT3CpZ*@>ZprrsM#i-^S%4+p7{h8=S&;+ylORq=|3*peKILS^cuAA%6XX^X$rzqeb= z+?Tlb`W2ymxw`qdMf!Wo$CG>K`uUUD?pg?>iw@W*wi^yX7ug}jmw=mQioAI*m`+3v za?b+Q$2_|hE&=k#IcJH73^|hJ{(D)dyrbFsR+oT;Sr75cfiG24^sPmC`O4+}{=1(p z0YXd@yz7>ub2MfcKy7hzJZX}T!A}ap#28%7^yBtWj7j5xm0g-s(plrtI_I}B0?e%R zUG7~1yqMb#UJIYJxUPOl4fo`BDl0roM{o5UuvTNo$!%#%$BlpD%UXCIicGU^wND(X zeL48WBmENa$ys}d_drT~U0hSZ=H%_I>U&>H+FstRa2wMo%}cAPF=9kl+eRkrjTT$1 zQj~7*u_PNo(A!^8>*7q;Oz<+fkkRFdmiErwtai=#g1rH52lFLgI0a?~i!Ht=-xso3WxsHc8c26b*01@fiNl1EQs_}& zIMxbA#v**{8r3l|;aV5?jTL!nk!v_E-bag^Tcy;r!`qUpvQ3%mTg6&YRlxY$(H&#E z=jm8h1z~`5bYF=}KqK$AnrGQFN#Y(uMIN|`kaJv>dKJz%Y?-!w8`=ZHyy~aKF5+t! z?(V#43wjy@>!v2CbU{TLQr>6Em&0p&cA32`?&L{u7?}vcB3;zy#MGxJ#N#yOgY7B2 z=rj9eRmFw*!7B!s)E>D-#r|jN=QN-@WAoz?=h%$vO;HYe!y>uy+F7&v%aITK3{-gE zZ9#1tJ3NaiQgk@QtC`+)9jrN&-%w6qfs?xYaSveDW@dE?mv=_yQxtD+dqve2umnfU5k^9V5 zXB;+WF76cHM$p*tqnEKSM>bC^^_g}e%`^ys;(oUU{m|A?6oefYPccVF01@0vwIUvpSxPwL=Zxx8i+frc95mldPk(<4J|(GzZGJ5oR!uHXY3Nz z8i(2z%NyqQ9=ctym>$oe ze!BK%;=U=TBbmLdihjbg-m{e|7J8=^i((wOEXvH}qBmwD1_>12-}e(@H!PAH1V;wP z`G=UdE2VR16hmYaw0-0~rbhvq54|?HwkSSqRLpz}Kkz1A{%~hDK>d8Zf8tdA!h*As zxKxN(upu&Y2)6q$%27?gM^@9o{r+-r^Q1?! zf|~}+^aiEkfTtC~lq^XwX;$kj=B{}FkY_Esu)n!7v6bgQ*XUqlqRLaGt2^PQB{yUP z_5L^!iI5dmn`VGyUeE|A&)$X}@J>-IX06E1)>=rZ^f=LHgxg!`>%4pLW}wXniN+6^ zi9WUdi*+@i(Z&4})%`DqQtBi}8Twi?pXx7%D8zal+?9EA6*GIAyFR74Q5LY)H)P6( z4x6u@3r=rT+b})T&v&o1AvQkS5=QH@c6?R7to`C_Bge_SD(|(w%GM33@o!?TTWgv; zb@>9%e1)d{q|#2b^_RL_dn;Z%__{_Yom!s55?OA5rK`WFwEoHlQcf6bXAeMeR?5id zj&RTlIThQbY0jn&tk!18YD9FZm)50QXwW=~jSn9#+~rJ@oQO4>khf_{Ek%lg1I_O` zQLN7#C!bVb0`NmG0dXU;YutJl_3jmI)C~b~lk)QV8!vGH6Kw4#&pJXmRBI{Lu@ydb zl+L>6iRvho0)Q=1dfN8Y#YB9h5ICIGM{Yw%!?i zl5=2LIAkNOwVz*PYKcq<=uKaLK3e(wh$%sPbYjqU&1%Azo<~x8diSmDtu(i7z#(N_3rJn@zsN=zrhJX-D?Bb5`YS)cJ$f>O)x*lr@TdDlud^qpR{>qhp_;l88Tl;e4%g#mmoV>6keS6)OHo@G;DFI^I3!}mO ziEoO2?y3zg)kCh+6Fays4#NQB+NgN$WLou^$3f}z)l9n#juv-Y%Q^`LW?P9ZXG}|t zhHLP1I^6SICn5v8#8rVP;pf>Dk4YGCd-QFi)uA<+!Kl`enmds}4~jVzaU;i6%ecFX;d&h`%=sBC2P@^u*Xl59 zC03#>?mFbO7o)R3qpvGODR>q6EyW{8|5>bnq2%zw0qYoj3o6kE_rki77d#RE(kG?9 zmjF47;{6JebRynps}-C5_m`s^BEwx6`ZN0R`sPiRH`ht|Gi&#WMU~Rmf(e}~oevFW zT=%FgL3M364&{22T3z*pXt%PQRU^vUv>hZJ6#K(9E#b;Xm2$95zG3qoWW$XZ8OnwP zMRXRew?Q6-R^tN;8&TfO7^QKIiaQP0(1ymZSFRksrMCEp&Wa}p>Kcq37S7Lp5~H4# z%}Z9P%8G2&gKCwvJFAoiWfB7a+@z1MVkQwg%8fh3|*tjIin~4BU^y`d@3t ze^=FoG5SBL<}wJg0Dl}MU6K7qF$UJ9@t(^17BJ9%lx}mB z#%(b~9=ONnueNQH4(``2q6h$GKr+U1nGd!TK0Uz-B@<%;xyfBHtvDV9LLN)WiTXDV zc1~?^lsholqs6hOjc?Z>Go2DdHrAKjm0cqM2lRY04%BZFN*~K|-L_8~UweK~kie@< z$fkGP=gy{c^x!hSsTCoOR3Yz!(#E@5m-I2!^zkSMS@C>~Kw;dMy4bN!Z@4(eB_6SM zCOln?=tNix_0On=}5?c%RsIy7Ru|uX)hT(kkS> zbY|m9KY1ui`te05&$=2vnWo+;`yu{WU*7F?ug$y^nh%FJByFPUm|tuxLDX z{MCxs7-#VFZNtC_<68P!5p!ctlgIuqgJ~jj+H(}TZxDw(UX<^N-HXs99u!MWdg|l- zDxyQgHAhXUDuRdwl_{}V0s8?M!O1)q2QMmpcEQ~+;>I@_=?vnPmPN;MD&e5J4_h7! zJ9QiPI0Z(T+LdY{`8kfpN$$5(3ZcSlTd1DgBdJru^HF0x`H1BeWPXl%$Aym2(_6^P zKk+%Q$9TT7gNw&&{FQrkvK_-su-Y}?oi}Mv9PU~C} zQXI07Pe!XFqxPWqwWQoa+%>#0 zGt_$~bH{{I2x)K+JE?8sbp{-~WH>n|LtD?uXVvYe zu97u>o5#2l+{F-aqla4({&N^OyTDo2TO?82yYRu>#e}DSp3XhHR}XHIV&+~f!@J9zEtf-<5FmufOCk5bhcK}^CLGo09sm_!Ei=O!lqvE7mGe~io&}zW1Xe4* zXyzJQGTY*zTtZ`I7uQCaQOo-|*RV$R1>V;mWPDv}FXdwHY7>GD$?xX_>SHimjCpt; zWyd|&)+x!Cv8YCD2+~8#&i`1fjA=DZ_)Ru5D43Wm$fU`rsOARWvrbi0A^8HI)ac{k z;qX^{H$fyyrct~0fUKxjaEus|uTWnF_Pxe6${>r6?nvqw0Q1WjW2U(v%l9mY-s!Jg zv*RNyPIV+vL?BS^n`|-b@Wx!;nH^_O8ZOtWU3zD{EJdbk5>tbzpweiWhah{P*v!dU zFr;K_&r8W22f>$3UkkumTtnncU!6*^-$G{9mpXo9HF2!GGh!WEn-sm zSHe@U-|z9^l#O>zKLpj>KAm1HIz(WW9fC z?A~@|uZ0ncMJ%zW!UYH*BkN85do+Zd3;*R1;lD>i(Dk|B&u|E9D7`v${TK1@d;I%; zjQ9Nj@B2|4w4E3R1J-v7{r5+_{66!46E9(yelqu?wcx5h=STO-zlwe*6(d+{}wB(=Nkm=jb?^Q_`fdjm7)E_`nQMX zFc|+Q+p8-R|3S<3{tCnW zx~F&Qb)V`r{T&@j{{fyQ;;`<^<$cJ<0JrR1Oi=k|+~#1qs}_S{y!-HjGL^|Ly@p z>LT4MpU36zT;i)7i_0qKQNOAPjATBDY19vr%f18T&`D+v=U5oB{wukOX5syYlm8^yE> ze(<0+vZ0%6hPeT|&EzDD<6YX;`x1B_#P)ciB?fU<59TJ7)-0A@0vz=gde-y-mA)q| zEpI%;yYO}#mhm#+Xg5_B84qcP6hUQQeEMX49H)>Ir3|JmM<6!~5RE+$rW!^VYmnjj z)?P->cIy@P4AddeTIi$RTEd#m!5xgvLX}Fj&UI z9ero3151Tsm4uMe|CJYH&$egyd*yvS8KA%fwoS6*zkQ&d-wr&Lj(^<{hYa z^rH3(lJy7oF}A(%LzheQKQG_%i--xdUqE?oAGBSvt$!a;aS*HeV8eI&T+VbNbVxpN zxwa!ZLV;-0@=_))*93oTMevc|Q;_|0{jhOD*7bA=jAsUN?-EAS?1V5FITv5~O7IqI zCpm>X6?XF5W!dn1FL^0{(CuD^^V*rtX#d^1(gPsA0?+~qu8e-u>DNjK zu^1k@cpK_xrz)`zR(MaiEV9JBJH3+ZnL~~Xi^$?v51bTtdOn08$FsTuqlPFR77$r(7a4(EZ^36is?o*mTY{FG<_6giY+Q&J*^illriP|aPEdfQFV@=158 zaQfV&D`IAU&9|vS{?bjVNxFABrsBUyWu=ShsSAV1$T1`b<)yNV% zHvgnM*dpa_Kdl(@A}^wyJp-nNNa$xPg~7I(B1-j+Ofy+wFKeYLEm~}2gR+e=4{vlsop+e;;MM;1eRIq7m(b^(tnqXIfy)C zvPn6u^A>+Smh>&c zh2@NgCs`67xfP|NKTNGk0zx>8-iY>!!rczmb_J0kx~IBH_{%R#r4vLS zO}}Q&9n&&p>ItrOlSs8BId#a1S?@wUqk61tRw#{2zl71`a*1e&$`e=7NbOs?YWs~J zAHpM3i!y!o@z%s05R=@!?bb5{%qP#D_R-A?E>$MavvSc3@m*5ebw%%}q4I_yCsp=F z9b(LXo*l%UujoEQF7;t}y!>vP;3knkK-Jf(&WLf@bma9_gmU(qjh$LOBcyaEV3VBM zM_=s>G)v$$#*a5|@JudqnCwaEQMwa3xWsO&>iNz~epYL~8|GDh7(&w;TBi4~Y1T5# zWbVd!9n>wZ<6)HVVtIW7jRvs>Nr_b^ z+ti`0irUcA0$nQN;&*7N2o?5<{)RD9>(*o09Pue(6qAnGB9@&eD)VnexwrxZf}FH` zJzZ@ld_j6t@!Gu8{@ihQ!l?)M)Ra=5m8*i2y|zl<9ZWcAt$L6grxzY6+!Up7m<-(3 zXR3JW_5NabX>mcTxD(Mjxtis%cNJT*K?~^%u_vCbi_#qWJWDyvbQP4@nB~|8mS(kG zM%wU+!~|RBql}k}TW254W$d1qGQ|!{X=9cpWx#ug!9OE%5136Tb-rJ;s*{=PW1N$M ziQuj+$FQw(Kf{qS?_Cs{r=ag!I&W5DxilsBQIE%B6kcri!*5FMe#m$qfz%Z%N)sr+ z_>A-|LH$M28+;c>0rdAeg|t&{6kD7fzOhIKs=(@!UiBo|ThAp@?>tFp8s_xW>}>SSHHtw; zJpYn#eCr`qDF-Dz0Zn;$IdQGnYCm2ELG{>9bQ8-wkKT&Ox__+XR*G!3@pfx$nl6n+ z8Tg5gRwUVny3vqYOLiin%)*^mcJgJZDO{5*Yj0|y2L`*1nwbo={l~#!5+|ARLQTgp zEKlVq_Jl+gb_uojER?D~XVwW|iL-9(GJUY@a{8PdtcX?fu3IfSxAKJDW${QtlaW5@ z+v%y3wpilp@w2&v4#x$){7~}{L1RyYib2!~Y67&Aj!6rTh01oTf%pz(y$~$qXu?U+ z+K_?w#}XnaV(h9V!`PeKN@h|b!3jat-Tb#QZ-0IHvQLAAXmNB^3z9<$AEVlVc%UPP z#yYuumPNPtxKoFWWBjF;&})~s8%{1;U-H~uH~Ci9vMjDhiG4_E)Zog!O=u9q-FXx_ z>AI=1=_HHaNqzeMlM1yWkY2)qtjw;lur6=pAz9(oNF~iL?sY*M#-1ltFPAfM7zM9^n zaeLB}IO6flDa7XyJmM`%%p(~xOw;HDxvUGf>FDv&!4w3kGB%7YXUApt)weHB@v#zg zA2A!1K^|qHM=|%t+zLx{OW5WuvHRdPft-BX(6xVPR4rjCVGdA|aEFh-o&LuDx zfFtFix=^H{^|`VHg7dahEr&H~EFZV18cTr$x+Y@paT}A1B1zHod?tUhe9!>M+|+#m zF@7&wL;(3UXh+}J*oxXUKSI`^o~&3SEI&*_R$)qbF7w61`&3CXm9qOfcw1xs1jHqI zUD0p2)zB4t&V3#G3q|TXk?Tb*(HlTPPk7r?BV;lV-N$vfkgMGhMXTLao)O|XtB}z* zlK2+96r`V1QPKo&()C)+@jJ-N|`2HLkm$88ub*ep;Qp@9mD7; z{-h#YYkaURjj!n>SIg<>A;Vlu{qR*7j{@u4ws=~4_ES~$%SKV7W^@X|zOKblh(i*W z(W|F(mD05N*!4I8MAg_RbV5^;lZAAWb4r%8ftAxk*%rl)-h7#^#vzNG3vN!H-gjLJ zaPL_(!0!tge&R}JNuld{*w5z?JV<|FGY#nuk~ep`weS7}QcIb*D1OgH|3w|=dnpFiUHIeK zIMDZE3v}ckAC3EYt^s?H^_N1;_hJq#A^o2|E_Vg$C;5M_B(SkE{_CO%m>v2MAM~+U zW=7~U8PLb5|9g73BJskS$k;Ra*xD`R$y}GUZ z5AuwJI<12tU)n;;a5;hv5Y=wq0iN=Siu7I@q}H#Cd+I%;TruUh#SWzYDuytPMvgU#?mYh^w2p2|u0mt45+ zF8TNKtEcgSgz}z}s7}w8M$T+^7uJq%*=o&Riewy{u?5lF$3K4TkYD9gFEP~?{*}H8 z)83KF>0vOKxn8ZiE)e2r-Hx2PNbhs^U@95^>ta7<4dY%1Tz6_8splslsbwZ9FQ<`g zE9tmG(?u(4U<;UJ8mQ!R?^H+1!-u!#q^UQVrrqJI6FXNyUxym;>O*n!MoTE z%d;#&GeS-GemCKu|h`L_W=+TpXiA$KIKq{tZ1z z{pEVW@?+-I9-l&$6?N;k*%n>Xk0>qptS@?Gdit#N-aSeav6ADBY7qHUq^NX2u$g*a zNJ+Dbga3nb&qR(#R8G8N2hH1i+ku{ox7^1)q{>Ipq8_6zmpBfH69?+Ey1&5IXq?jZ z)f+Wj>#eNsI~QhP0e5BLG3Ack7c4Kc^nHq@itC>AOmBiJ%fpem^5{)qpJSJ)OzXwP za#~)VlM^F{5NZMBGL)^-`Q;YI{gd5&R2qcr*!J4>Da9#b_DrBw_S{<07c68w4!_FC z9>u}hx^bN7*@WE0l+w8ikmBG7ejZqIlNJNNb*jOY@L$Rk+}&cFV(3wX%Nq5 zKO&GX^^W^k(vZ#IE}l=6Rb}7*l7@?S#3qcA@MNieg z);%7oRUT=hkg#7Xq_fI>Q zbo0I()iG7nT$sxViuEN+gLP~SNV$3vIc(|IK4H97rIy+`1|U?vAQmipfZ=Z|xqK`4 zwxs_pPlTF9t^AoujrALIs~Mk{^+}xVGAYszI#sJhPoGA7GLs9hAI?YqW=5Lvk^#3U znlQKC$U&ANp6zXJQ2E%U%|r=$L_mU4`-5~d-PfOT=A*)^;G{mtJaUX4#trxsR`(h= zn^Nh0K@>x~UzbY_w*(f7_wg9KWc*_nElx8g zUoNRpu>js7&OB$U`nGiLIS;Zfv^h|xL)*Y3hS)3po@Oarg?iq% z@ZHYf5KtdltD&KPx;yvYmtBb29sqwMTwFptMO(*^E2Rp@#)}M@ELq~d#OACx``AQP zZ}<|B`rDG*F7MHSF$&%Nyc#Bn^1w&Qr}06!VQ8w>FEmu*VvPu?!_9IgiEQ56sc%Wo z?|BjVS-c8vPyMU~{2X0+`!RB}YZ)$Py8Gozs^(jyQEe}^@YI_XA}Wh(J&i|$B|_`i z`{tz*Z(0bph6v3`ft7<%Y!fd&-o#no$y>E#jQF&g=y9%d@X{w2RXlxdgy!4+6d>jk|`+Vsea5h4VM9tdrz*(H{ECzpBlDq#6F9 znUunFxXk)BbN0bY5Ovs#X4O0_z?nZhfxS=y zO$$x&#^i?Tu?xmF#Tj)=X z=ah)SDZY*tqRSAa?MpkFryw*-G(N4_XKz^Fus&>VB7aFYkn;rrj)dl8F4@_OcEm|v zUDAidc#up4lJEd#6mrfUQYi`oml*m3#pEuQUs1&JjA*6U85_q zC@K@-=j7(}6|q`fae{H?3!gnvub%p0h65Y* z6u$z0WQ)=UKWSQIs)eu`5;~+2?MwE8^osnPuDyoVs4tG@GzO0l9#ynjkfk-eQoYIPxPlD z&z|9Pmr$pmdRLp(>eBMX4QZx6l#qn&^flsIxN~T#HH`CNRryaMx8Zx5 z2b9$)PV~nFqumoOHn0vT#Th0bCZwj!{B+%Vd!-J_pe>3oJZW`t zleQarWN~DK6mLWYPHxHLJo^oC5=N&ko?vq9R0NXe@zE_R*3Q-j zx4r;1JrduHhP^EotOpNZlSCYh?z(19ddMYtDiM9|(0P$EeLq<&S<1=xTm3ES8fM-d z`*Ggak;WEwg_zi`L4w#gMz0<+w3~gCP||pe`6wZqP2e0ezV~wu9I@sU;wcTun|A@d zSp{Ed!rA0wkx7eE(Sf|h=Z|V1gfDYbQ`xHImWCqcX1s$BFBwRpdW!NkOixZuu;WDt zSFZY#`zq9wKDWh+hfLHTihov3tzx5XL6h8<#q2hSc=UC>HZ<3wOO+sIDK^I~=leqr6hhuq#y)Pc8Ufm*t@G#`htd|q2MXVp$<4Wc)vqFtbcz?n)0F^2f@jI`9ON?75^!}7|wX(#Kbu5ZVC z4$+w)tWl7hrxvV8O!(of_;3^i#fHeu)eA+MGgP$q5!ZL;c>|R@Ef*N?)~wLDNuVK` z*U}OO0R7<0_?{nP7o~5Mt!Bp0;EI(Pv(X(6IdYY*K4c+XUodbTDq9uRg-gYFM8-yq(RQXCNf$z5Vhe%nE#B=Gb6$#mwn6walkj?w zMy*1wLY27UfRJ*hRo97>V<&JT`Rt~~dn(u5#54JkW$ulnX$YSGjDNTrl6s+Oi88AS z$w)&`5e^(Cw%vfR9X)2ua7xG*CHi_-CEKFV5ThjpNu&TOhb(V8)sxnQ}`Tq1b2%FuzPJt(A z(%T>Ekt!Y~w^&a+)BxH%RUu0g^naA6V~*24cZU&Ez=Y4}mR2CaU7>qTqMsOhHX0}g zl3fg++il!yq7H#m$H_n4_Lw?Xy<-e-60?Plb4joxWL$;2K-1eU;+K~CDc4Sz9dOZa zjW@snBJoPZ34Y|;swGl7vSM-GLW3dF2vh^!zaU0f@lT1*9q^a3Y&LBZpTc!$rz4O)eiQ<+X^DO_%zR z8wagFpuAF{**f7_;mp)?4|Gy(4C(@Ol|8aC3F=0q%Lh6DZNo=6f0GvfaxDID(_*IU zN63Gs#Z1?aQU9B?_Df8f{}l9=*+|h00<9um*gxh<;BxUrY#nx0Oy2J|>2h9A>( z&U)K4EM$A{RDC7J8=qz&=F!YNw48bRF!i;C=S|bgNsZ!8I&Df4T72O=%<6gMuZ7hg zM>!M6u=8TJ&1aFR2qvs4I9X|r2$+I1IGuIJh&5h+BpC&Q(*%n<%2aMCB7jQH}_t(Gv8uMMaOK)M6Gi9%-&m-BiK@Zet_7 zqAZ)-DIwHSN*73us0oKSbUUfxEG8OCIgA&_$=r+t(t@Zs`mDxpZf#dD1^}L_%F}b> zQ-xw(5Encz7SGG@{z!Ni`7}LFN_Cj-D`Gr-tsG5I7o4ORIj4z8o{n=Zs1Y^M3@NgdcF<$_#rsQ)SigNO zfD+r`cj%Kr{^~1#LRodZq5-dx(5#6&*!Af%N)7#lx<%WVSoTTm(EG=EX~mQu9INMq zF3JZhvUH~v>B`p$@$lw{c!IgH!PVo1=}894B{}J!qiS%VZBFh7@^xHS^Gw2{$m|QWZQoABHpKF*7b?55+Wrb`(1K!q_gdoVc5+Me2sPQ;JaQ5%h6aIVamQ%kceB+^Yj zy{mOZ9T0zD(G2l+V~}y1)v3mhQhz4W#Yl9ga*tanLhOFj!i~dLWGnX!Y+N`F%Wn$t zAxm-qYI~}?RcFQk4gcj-aU>zu3Zg9Oj>a2@`LWO1uoE0s?45hDG4&3YVi=njg!uy0 zX&F0*{Hph>(_NmrkUPgSLd;Ww`v}?Vd6T-lIiuZb$R!o<6=$bY`VkQ^wKW)TS@jG1 z;dmG4@!-8=lm+r-6v7u$H z;gMqvZ%JI*)_Sa)`Hn=qAYT<}=~I{{?;LyU?hHVtwY}%}Sbg;(mY-4QU&rd}SI_(r ztFK>m^Dkock2m-IjMYD0#`3?3)mNZ?lKf#BvIx@6$$L!EGilO6;sti!k zoW+moh#(HM$WlQy)KZqLWRV;W7x2`#PEXW?_J(z`wJK#2yl%>UGx>oRtG?%=?s?4U z@ez%}ncPq~a*KfO`h3#yzKEtqk9i@LVc&Ra*_}eugl`8qJDS6UY-NId4i=$LkPoI1 zg{Cy@%*-CD;faiw2tUxc@wLWFFFCUlGncK1$eXe{@!oKZ9}!`88gDVa+}CW@n1ue& z>`*)0Q6O&k7v7w^m_?u~-eZh?YMtr*859y_CrbMwslnXRrcu(72z zwNHT-D1@mAMF&r;={=Ba{lE@27hNMlThv>6?={hki^;c51Ge)}zWK-C>$zB<@0M-U zzhM*M;dtXqI7)lS*caJuU?YCYok2}g4^g+=3KZ1a1jH(_b82U*l8oqEJPB}R{6a5QmW$OIUEhG##>|NEALAL%kL>fi zyeT=O*N-yr?XO5*)czeyK3T&i*TumB%)tom5LD>pS|O50W~X2v0^ZOz={#=;u`$jI zu(T&Meg&TKkGxd3jZO}<7$~{{Gx^f|p`MlU-M1%=?|A z)=`Z*{Sj1|ba0-x0EeAB#!a!x2vuxP&h-YNSiPE-!Nu>3e6FS5Wpoy>mQ!Z8+UsWI zih-AYY@j{gIy!{b4`lSQGEkDjnMa_x?z3I5#&`oeJfx^#u|XhR3KQ?ts3*kF;w*z* z$v3!z>*hU(y5uQTfk@yCd^j>hJw(}1ov!#s;#3`yVauKlz=8pM8LIV!1n<49P?i76 zS1u$#T~Zcc&;qZAke26d+O2n40y`?r>AEB7uo6ntE`dvovZ2sdh#b1rN3W3$+l$f> z+9VpjKycyNKp27)gi1glq7hB>|89BTUaUOk$Cpg46#8sTgd;HQLM+IkfH&K8xJXWw1e}Y(66i*wF z5fbtO=bczOKl{0Kk~kAM#W7LVMxM&`CtlHv@jw9#(hfcqqJczDo{Yh4OdIef-jmB% z&_yx}i25gT5IsRIpyQ1cpJ!x<40h@klPlfWKI686q6faX%!IRE>fG}7IzU0tax4=W zQdd5*Lmk|v=!YX$pq8V2Ht#-)+kP}*Pa<|aOpK@E8-`6d^(W31gzYEq@S0;XR89p; zvdq>4prwPGsaB{Juk^`vO-gDLSDY}_F#bDtK4VtF0dj{#nz6}`DZ_C*1DdN)L4dd+ zS&Rm^huzLs0ES%>zhr;inm)$0!-S)UDOhsOMKz*MP>O0JZw zuz!MdQvJK>{8m~@|A>&#%Vot6Rpu75BZH`KD`Qh)eA2>9j*Ob(n{S*A zYFNEI5M~BB%_lx3!cr9cPIvYmQ#;Y|@@3zz8|$%6-_(Yr4Q_pot8dYqLHrn0$ny5tP4_f5I9?a|H;Jxm;t?h+OPOaX5l!NyNoxXZOP}3DMJ30)Oa>0<5YCm|PkybJ zo~<;V$OuAb-SI8rQDHXmPS(iO=VXPu!o45q`0gvp6$szz%j8zdh{bV4CrM<9KF#b^BRRQ$cZA@u8wT_@1)ZpeHJ91DC&WjErhNMgPs zNTM~V1iag5b(ja%T$Ll=wpe#7NBYZ5iz=7D`lm_VqU2+Agi+l-CXQ^z`(YK9oTit( zPEub2M^q&mUe8AI^hiB~lAo~{Xs+-0xu@P%+6Y~g5wuUrSXFm2J*NT;)E3tWM+dHV zzbwB~fGN=^5fve<=K>)%MRetoxSIH?)uUT*CWj#k3@=0Xr;hZZAyMC5l#=;!O))wC z4cd0;z$j(GlT*RzpvO2MZt@VF2J4XI>X-_WR7Yt!E4g>a$$QFkr7qLrf+q*VH&Es% zZ$OMfe@;XdobHz#Ri+%`YsR;=jiog*vCT!X+bjH*Xg0)61g+in_Kk|-%eXgS_MQ!7 zKKW>>12I?5ta}nPG3crEUnu=LT^^$lmBDVz5f?FbSn%eXj^aYFY)UeR*e7VAySfzfxG`r!Esvl)GE(pG?FHnRl$qh~F9HVf%A zvB%-eJab^p=%*q_{FiA+`56g}AHiG1c($*-Z173E4~ofxV>C(OPa;C8prd)mHt-%% zJisBzd(U*NAX=)F2o9N0`Ch$3Cd97blHyV;h+P%wP7&RGNY)&Me(>2$1 z*cg~r37eCAW(hP#1|al%G-mM5b+jHN8kcA$tNS0=cTp{;om5iwi3ap3nKWoo4-a}} zW_T-ITnuv=)bll^GY=9aLpasC;d3LbuJ*#OkzjQ#Eu#CGsmAU~KG2%wN6#I%Zth|? z=d_*2d|m=7ZMSDuVph8Aj@+u=rLPS}oPCY-TMJ(suq-`WC!Y4tuQvml=Zib%QR;g4 z43!@@Dd5GAI`m5)+h?m;`{xw|X@<-8T+T3~Z#uO@9UzOMO4i6*v`NX0i`&oe7Kr(( zBflF^UFCt+&u_%SuNK(FW(Yc)9!L>**J&R)o!srq@qAEf`|-P{y8N9FPd~)xQdNS< zmAW-tq*)=C!hNf}z2M&DYHD=~NjV;lK~V6c*lWGoI9H1`zoLX!0goyr)UAEk8W4s( zP$Kl{kIM3VL|S+FM903jZ#aiIOL#QbpKoAk&eur=MP*;6L2G%xJ;p8nm=*e{br%(TMiSNV0*)CfCue=uI2f4YA#8xq0%m?Zx$0V+{wa75>2MePez>h<%zE_mj=*<{tK&UYo3&)wnD3 zC)!n;KAlB?-d9zsUEzvLum@FNvvldY>Z zh+WO9@6fKj^{1hpa>&nD~u0GNn4mS1qTanKz~N@CVV?vcD;>& zTP&&sz9a$q^0QYRZ&_g9-M_X{6R~EK9x!i&5dIw;nadd}a@8 za9cDh^;O06**V4PA}kOvSVQheX4-8l!tn`;v@&TF`klNNHTyc^&lkvsyijj*XJ!;= z?Kg^B-d0v%=dOBv!B1WN)t=+3RE&RLp&r%5`M5}KE3T+yv1ITbe2E)NQ{)%4ak|ZK zjX~o>;#SAaJ$PFT$MS~IpZ)D!B3Xk~`ZOG4#JK_M*Wz-yXdP-$QU!b?MHFwtFUv;-}hc-vN~`7z?F0T=**%~qzvR*mW8xS zQ?3fn$D6vQM&XSUP$0-y#$frRbKh)U3vM6vLQr>fcDl!%>cBe40Dl)^gByauOq&wR09K85a-6d(^G>*j0P>-mxiirtwu)rGqU(Zrlv_ z+OR424*77%c-N@VquQh9N3$;nzqHB2oAcGLGHzQ1w+iqw{@% z`qFAeGK!0q-(Y*vzcd`9R=HnWB&#B;6^{jg%HVCm_yn*Q)1b$#w>02287?~#=nS9H zd^B#QummK~oFz?X$yM^exPR1o2>^axMSOF;RS+lJH^`qV0wsB6Dk%3#4aDL^=#fd9e(Q0T4myPq8sLK#{y~~2cqbYm&xdcU{Q=)YaW<4o3F7_fJ8Ueuyz8= zA6@$%qEgY6Yg3JJVjYU6LRBC+rBEzBV>LKKEc(5;T#xydJqF_VPgh=^o?pEADQ&d6 zhoj<$9%PfFTyd(xI`ln`oD%%9x^DUG#{0!~NUzCjx29@@M3|I zzE8SsXsNqIYiKczO{D*?djggdi9R)WBIkUsgaUD*W+jn?4yKmjr{^)jU&3T~Q7dDD zB3tx>4m3v8q9kUl)%@RYl7l2Fh5*J$+MIu=->F!96IfA#Z{Oox&QbL_!!-nAMWn)O zwm$5Ej_b2w|BII9f8tC3aZB@G4DP>Ex&Mky`QNuR{|>D9A9m{htM=u8T3h~anECyO zN$tOHm$Lqqar6&nem~W9o!5upeU@u>h&@V7TJ=eu>Lk}>*4idlPLbmMJS#dYKTJpZ^qll&c(t!_SeOpn`2-m4QGaoi~kQxH5 zn)oEDsZO|!njh)W{hRt&rl;ICa}3apQfzgHgcU>Nr2fwM<@orKb>30(#h(!7XXoPH z*$bmv*HA91mhcU?{sNY^1JOv;OG0OIYoZ%*VaIkcWNJpysVQIDL4z{VLwn+@z?)+< z3^qBsYI3f@yVYRi7i0BkCF%MS_L9i*FC4`gNp)S z<@75z*l-0Ip|h#jTYAuR`4*+oDuCu6ad(f)K(T|ujsmC&2LmFHN^WNI*0;9#gK z{C-UGTDfK0WAdD0^3bzX8EQ8Bde=1=8}Ow146cl9%y1l%gl;WzhbHaCAL2N$=;j49 zZv%!s!e~Fr{FtgZO|hDy{)}UxpJmc(3to z-<%R#I)J4ZE#K5oQ35-XUvnGPG%qe%G<$o;hx)1$st5?oagytnxZe6TaYxwj7gLSy z;tMkl7g+jOG&s~8Yf(udM{_~`t*+a#x%JLl(-NJ~S*sGf#mxOX+Xkwsa7!Egm_+P{ zUJkK$%L}kZt;%yz-TgVhRn#3J?v=oNn}7xPgd5mf$*a zqamOiN`)|yF`4_ZWx5JM(%@8h9+#9M2TS98<8DM|BuXVX68a+@WSc{qbA2EfrXnx1 zkXVc=TH*E!Q#l{!YlC9FM0Cd%NO3oj{0l~@6 znm%U$*``Oy*ar@vZqV2MeKECWX`~gB&2BWh?I$CL-&EHbYiK)&m8+=cacH6v$fR7v&&QiP*==c!NkVv0U!TEO2?Ly0*?BG9pO_ zsw3f4HLdcM>s<6Am*XO=PlGl@rA@Jtwt2$2$>>Sv;(O)@#%!saGPu>z%UCYUL}#mT zb_kgEcf*^{6R)W#y|uv@lGQThe-(W&BQ!h7bz=YaYga+clVFo-54sj|iyigwmG*pa zRgjm(F|j9u_-T7WGF%M<;Y`5+6Mh7d-p4q=NOJT@&vttZRm2p(%`#Dfr zj6jjHTANPpg33cHf@v*oA40*N^I&*1!wopg%z4k3iR_H*%tG&T=F~_y0`;O+3zHa2TayB^#G19~ zOe>(HDVh1qH-N*eo_Ot_tRiUNbC|u!R$&F$znhzY24QGa{A|1P3gB?vC?35tWL<4X z4>%KSdLXB+ypk&319$r{F`=D~e{k|0GZEOYmBT*8bA|1K)=F}e`9WeADHs*24ab_A zHU6cY7yKHu=Bc`QG_t@rI;GtkmuLkTf=SF#4r$x1Pu{BuNThZ|QZ>15@=#Z>q(8Wp zo8G~k-L?b!9-6oZo(gB&OMaKQHwX(mr)RO!VQ%tB)QqMV_U@>O=)9eU94AOo059k`8mL0r#yF zTYOH7wr7^?F0~DDJgxJ-pbdsWJJOm?_`blLJi>OhcAjdF0?c zzz()VqPRWU>G!)|VpZ}}d+1ZZ5wHY-vi5>3gkEBY+$psTtn6~d}BF#iOYrFhmQM;2X{N zm?fHxI?LuD%1kxt){ilQmcbtEOi+jC=z;<+;PIJdNHj{jg+thT1^sqLo7y=5o9Fzh zZr>%tXp~%2pv+a~?su4hr7`+?kXX7oaw=3qnk&Fmrjoo5&zb-IQ-9p^%N}2VXDBFf z!FZ@ZO&T3z?1vYSxImx!YvBcQXtj~=D)LIES&Hk)CzSJ*_M1iR zTWQ#GiAyOJCUqgGOxEM1ztaXc{H6J&`6LEwM#;NPAr#g|xl^WwNG>VAl?aL}2QwO^ zDo-DUy*k%^ZhVnbTRk}V4dU-;RWJsT5|sy2U~^OlCoHx%$Dp`EETXly7@|*q>`fqu ztYlzfqKw;(gtuJC%t59jS{E?o?RK*z$s;_K<~j!o@hmMFINqt1!T|Yh=Ft0m1yl}M zNXE}MHv+-E>o&=1@oLV>nV8mR$M?I`;A@Y~x;mR65)B3JPIP!grwhR6KDG}I2mRn} z*mwvBd)q27a-Kw~n*kB|kc+Rqxou(+Xd3vr`_YxvvFrU5mZP4izSkKt3$ermh1phy?(j{9lDc`4K0E1osd0}F8hTGv`_ z$H+Wo(((^*GMQEM6LT*((qh}O-)zouL4q2N8I$rnbF6x~S|si${(XwpD5*cUq` zkrArBzg01$rRb1Wsu+xw!d+zs`Kn(E_u7*c4Uwq9u{5mqgk+!fVxo=w&0&>EIZT-x zKl>U@*dRpa@!OIQlDt!Jf7a4f?-Kg$pz??=A>euXhZ3hKPp`gAVol zJ^B5JX7LM=0c4MFNBsF*DC30`Sj9b=C_bTFlc@WgXE2={)=AzlOcaaMygb}oTV+V> zf$`u#WSUIL`RDKU?$)W90$?>5pqx0+;{&+#>ZZ6I2jg%9r&YI-pu2@!hbYq?Iv)R@P=A!-~-~z*_So z@u`Cop6^WkV8&*20}~-=#cYWyHWph1DP1k!joBmRil+2*F|Vwd{CTB%X>s3hWpTqV z1RO0H-hRs4o;UJiw$|-fr*7~)Nt28b_3MrI!=0E@=h%AQd;i%;(=dWWaxE_wj);o_ z6}h_Dl}A1h&l4iIf7uZ@JaS{ZJuLZIGE5aDWx1e+vg+s5yg8+%G6|#VHmu8)(>f>b z`pIi?ZsB6KbH^9isiS`hvN7yPIn6%O`9`4Wcp_|JTdG0uNQdT5sFoVxR2~wrV~Y?( ztsU0qmUPfQIIonuEWN!Z#Vi^=4K?M{8h}BzkY!%|IOUyJrzn-pp%Fm@_of#0lMP5i zQMtxY*FuAI;h-pnle+rn!8#4nF7sYj=@JBx@j`W|WYIgU?5fr^lcS%a)rIGQc~Kjy z*2ic5Acf55U~I&Tl|5_L9e4c>$~8!6BLaEbA`rVa!`_EuLqP{@cY$k>aZ$NqOxtMs ztOoe4?Y;^A{F_lN{*HnrG2!-;795pu*Iv+LfDjhJpilG&>4_;TTp1$v(+Y|p9?MVC z%MgAmpsPw7kC#cjv{iKIK<;a$Z+nH718Myi7TaaFu?tF%C{98_L50Q z5uGRN&_oF1;8^`Ofq2uJB)*abS>%2Dqu3uWWL0EQL_CTH)f$Lvbu-AoI(7HjHU+FK z&R&Qbk#;jc>-JY`@cKCC5q0R(yh5-Q<{PMkfe1-_-)w@rE$lLWl4h9c=4}AjrVU#2 z`_$bm9rYhg%2Vlkt{~@kSt?vWo}c^k1tr`NL9~hiRs8jA!xD-IOG*}5fs;Dh;3?b? z8PqIOG?$73vzf~q-3LcmtbnPqr6E^Ix{>gdAedwN6pNB3cM|J!5HS0515+IM{%4I} zRw_(FaQSNIS;;41yGy$oXC&KZ5m5Ni)D@yw0`z4lR`E_Xs_CWSl7^s8%semHzkt)! zqx}7;2MPCCHCNl|9yz=Bw|{?l6$|&(V1^Fo`qLJU|H#jh?)g#TfC{bvDwF=2h5_3= zt%cK;FJlKPyfItd%V*7L!(~Lb%+fu0)0gr9nA1UJtAy;9~-{!61}=U>)@~S zqQD}8VR(6$G@2C(l6xj(!qjd*TRIz88frA(0{JT6LuQwa9Pl5cl5{AXT&HQ9c_&a( zP_SUt_pPQ$ovAK-+3nfAw?pw@x4zqe`fTc@^ zZ1HqN9-gG+R8P!DM;-6w-bu@+rqluF*zH)J)GIwTIXy~b8nh3k!0um2X^Jg^wc(UI z%zJCM+8#QiTlczKwgyDOnl}tx9*@Tlt3S!4cc=p`S>O`w=0GmQJD!bv_5M^u9zfsD zWR&RXt6=)_n_H2?Ds2Zed)2#Z307eqG!?n`Z(&xRvdNjWYP@-pz>bTW8QEqhdT7+y zyG=C3blyZHD|+IotsS%A+BeXRnqFB;Xbo4$VB7vmNovygC7jdL(@9}T%P61h!lZU( zN^--5K0DJqGLcZ1(J{`Y&W0PhzZTo?Jafwi;@@)njriyO3k=DtU1eF(pwI)SSTAgaR zQAJ1u`}G5Cg6~8IT6n$z1cchbCRm=299z4oT{p#4m0477JB88GmLtfU)L=4e=KGtE z=sj&_^WCRowX?DGJAEwusOp(W_1@>t;o(j^OWZrqx3GvaTgFWj;+fxLiz4_e)!IT} z(b;}xX0=s&?m8X)qZ~jCkrZ5Z!K0df7YU!b9&Qur(25@S^8*SjVQX};9k8yywuqUlwC#RMS9vTxA~i*0b*Qc=2AdG= z?~cNi!KGj}G-!;21?BUVqiI#EryK<~hN{PWfxyK!g(S#f&10^4Z8>MR>r4G%^ zb;V=A{XH4s)kfJCK*3EZ!-xkk$}BwlT=gI-&D<~Mbf`Wdv%iaGLa;Okkklcgj(<7n zigQBsGkgoJ0h3*8dg{i2A7~mptFc!?am5WrLW@t|Zr_wZkM|Tc<~(tdJdZZVBc>rj zZjrMg*A=M`<(6v;U&v*`FX{*1-#OIlLPd)YnH_SN6D48Ldfn3yIdxb6>*bn}lQY|; z^&oouTdvff>p39(enm+vIdu7=#h31Sf6x%sXcg7u0ur_<(Pqj%|HNZQG7g6P7ej^r zv=sDDhYEj~;=g1a|3UTfcb@j&@BD97AOAK~_<#N7|EF4yzd!U}O!WW%LxsP8;{OCB zGco^(`2Gh&g${LT=XJ5~U3cm`;j1u)6JCeMC1ayh&7_xl=Sfio6cLm#DkMrVUp`%z zIlz=_j;8e5beLIU^88)CdxJK&=h4W{G&bimLhxai zXey!e3V}@!R$L{pwx&DfH1hPe%U9VBC(-B>Kcp-~&uZu@v7(S7iyO3pvy95VrL~i56-Y zY|4z(BhZ{u$%S*4b}$9QxdnxM>y3#j`Vz`jbPNeDx3*6StJBJSwQDtv>X9cf@jlt>+qWuZTKZxVsE2`Y&N#kqJx?jBZG zkA!%`7QaT;l7?YKx>)Gl}tJD^CUSqmbUx9A2KHNw$V$CDLGxrIao=UZF zg#m`Nj^Fc2Q4z^%Z9L@fsGIcTpTrV}Qc?Jpt@xAKJDD&A1zIG2SDu(WlIKYxxFir@ zMA~#Y5v+5JmyMgth$J|+U!W+_$rVjqB=6#LmnokjMsC6Q|?h%cagB zy0|n#RI`H2h;NX?LShe5HiEsdqg{?lQuUC&j&I#|NRA;Iek!nehDd+#m_dKNDSt8Qw{;7dV5i@Sd(3Og zBj;~C$xmb4h=vuXq00h(rs(8H3SKX;D(l=Qb@W+cwRF4W#6FQgp)>eQB7Jd1F+{CX)h9T!gEKDr*C!d8R zo-j$y%t-geq?cK+;J8ecW?A%{0#bsj zCXGa|rnl7$c`z!mBK7!F-^~lU_d}jp7Yv%*8ZJF&iYIxC)%JOQX{odEbsPVkm)oz@WjJT*9B!z>RO0By0)>$avW%O&{3%^^anv+ zZU>ogop%tnZjoyNKM}UVby=~okAqT)3<^aIiodfOX0XllbAwmSJisEUU6;@tMjUFM zSX_213%cRF3>6e`@+ZsoH*xO_CmOn||6qH<7}0VPbJnH;(WjyZSUqRTIz7(>CT~zL z!NIOFcP+gg)r;GQc+lCmEdJOZZ!tLBogU8DAadx;0ggJ(JcI5}%2;`;9)_sCY2;(M z*IXLj*q|p@PegARZD8*b+|-lx51fh*pyOvP7xK!@jB`c*K>=zRe)w`(-}7N6>nfs8 z82J=IFYab>?uIrlz)E5;7;) zUD2F>ig|!bEGPN6Aan1_Q6bI@m$F>>z+XGRhur%}=rcXFm74QxMd>x%FSPXK#pNV? z?9rZcd)Phr8b_tr47CZrILBCEaH{L94Gpg=qrG04Yhe4mP9<`@G)IOfECxot=-dOR z3+OcuK}B^;Z<(_!*4I9EQllXN$3`AR-4F_Te()Ke;fI7oera7N9_3m5AOzwbp>+Pa z=8UDXR2WT2z4^(Taf%S8CJ)4Sz++C4(j!gUPAC5XVqXq$NMb$b0Yy@Lkx{4lYM~$B zi#5>5F%s+lTFm~PG5)U#@gEnn|4JM9cS7cmp#OiAxBnl-?7v<4e?!PH|8?oVzUqHN zG5a4j{r;VhVPgNI>;DJEthc(Z{rb@NzX=&=ow^NqCw%P26Wf4B0h%2?Fws1TqysH7 zTTmV7$RVFx<8Sclw86LV`1ySpzoT&Gg z(LBA8Mi7wYyOwCbq!Omf0~plmF2~H}ewGWv8#C-1GNFkz|Z4OgNP|n0QyC@0=-poOuBQUF0LI9CQi#l>&0i$d@MUMssY4 zC~k;_sIi;|bq@X}?7@c>0cur)6_B!31L#E0$MGkq)`aB$-d@ZPj310-y7jy5j-2Bj z#Uu$E7HAG`Zk{lv%A(XqedDPCZud>eI#uGV>@PM3xtm+%kArY$_|59_#{Y^I zZ`vi;LFqP;>meW5HTcKnK+*wNhxPM=IiImhvm0A+77+GeHh8=||if zzetoWz}LGiMIY4TBBBa@9A-BhkowUmSya<&4lxFg@C;OuucPKHSw_qt=(u@1IHia(VS9pG;F!e$c*x|K!WX2i&V-?{DNxt8NyPUh zmPp=Q+Q)5No`?wvV8U9O=czdYXX9bXJXh3b@mM%LKplW=mrhWoMZ;NzN^x&%j_#w9 z`s^~{M6y)dV6t2~ov!-@_7u+^cig7Us6yHV>K#)A&S$UM8F0g?+1mtZyymkV;bP4o z-@dVLx1f=s8T^myTY4^Rnv_@_5sUl5AW?!#y9CLRCIhgVp7ZXj$AWQr_mBId%(C`-}`Pg zr-bFWDbHt}V|&&M&(Gx9A}iW*aHo0~u4Q{o%B~<2ms2XRR|(H&5nU9XZ9`)ek2ON! zIj{Bay+t4-87A^r_~uq1e?)3q_@g|xB9Ax9s6d4}0BpP0PNsHc_VTU9wRe$C)JRgq zwZM0G4T6bEJ1$dV+bmIZk3kp6tTOPN z-mApEHlj9OFaTl!hv0yKms2(&$X|>^4+yXl>@gZv_AX`&KZX z0w~8E83|ZFo>D_-22^$G_fmXE9VJ3K8pyhqE%U>SiQO|bl?^qOQJ|300w$pT@=_cb z5fUD6PT&T^T8LrDH!fK@=&9tdLWRPYN8zazR0_RIR!ga+^5rBRtAxhqN(p{drDYnS zFv$6%^GjcJ+GomM9E)-nW4kzg_15=(Bwad_n|&`Bj0TS7^wG};`n5w zA@Id0=1q1#v;>EHrX9O2&h0amf!v%$2Pk0?;dWhXp*v!p5a@!e4r`{s8GI zi2@WZqTZ57c!|kgu>zvksQf<|{xgg_1ID;Eq|f&88$~8w`G92NU=Dkxq-2eJypIa1 z#^Ck$v4;qsVu~9e7K--J4&I7s`8IlkV1qc3VgXP2Bq+8xK>d~=pv8+VF14jCE7o&| zGqhgH&Q@ zn+d1j!MH_(Vx}m?@CkXEk_0-B9)Td7-@F*_X|c6F^TH#ZPfTPYuiajrX}75(zMB#- z_dP>>ZLT-XV$@7LGb2ubOMfJvjWI!l+s3%>fV>KJPFT0YFR;JZ9;_Dbd&Nl#J>M&s z)omzSydkd>nC(ijwE^h~AnMRLbP=-7WdlB3T29g8m{#YObZgLSf_rWdPg^f*mmHfS z3x@@#>OSRKu3a)!4=64JiAqFYoHZrfc{U0_4ub{73m63*07x!KEm zxTs$}&jC@szsFxMY?o)A5zHWHZD_cKgRXGJtX!)UeXb{#>Kvllw+Q=O}FiS zwWD98bAB4xj$Gkb4ZjaGli?3VH!dQF+0J?J>gUt_E_1}n z$cZ1pE!>skWe*O2Yx?A%=aV*$@X#GeTd&-rqqLuH&G7IS`mntNLEx*3G2sa@5PE2x zGhG0{3$LrB2~sF0^-N3rwD?kI6<}5`xn>0nkU3-i^igYyuh5kKK_13``$zjqmlvsl zPA2}~F_U<5c1tkr>m;HgGxxp%h;`4kADH&NJ>Nb*`>}hb1<&k*5llMVFG(bCZjK9o zDM8~1IDVKM-<%lVq&XPWPB$`gqb}1$62u`f{-%C?& z{Bck$mKpe(itI)~mQ?`;QFos4+#h&a_qt3EOHUGX9Uqvy_fB&R8ik#9mj=*p@i{(UVL$z|BG|PU(%0%73cr>9Pz)9_RRn0u>ME>YvzBm zXa9AU_`6a5CmihGec1oUjq?ArDDWTUA*`%yoc~nx^(VWN?XM)QKe<+H|0GF^`M;U@ z|NCbDPwjaY&OgCp|KLRPOI_Rkk1xdcFXq1_9AhfmdxA~27WQ}VP+yk`dI*u?cXp<- zv3i`R<);lZ7w0vQ5W{es9M0vd4c`peEnkNaI3@B7e)2x*|u;!b+$C4 zM~1Sfhl7h@FWpLfa#z*mW=bXVffNXKSx&0R7bKlMe0 zf}7PJ#lZ%Zev>J?pNhlqepy6*JzzVz+K7`V3^b9aoZqZl=93MS6My#$UEyZBp!z3u z4y-P^`(P^nsS)R_sJ@JVIdW!S$XL)J0TSPj-O zmUt+Q->;6^2$KgRMsLY8)vB)RW0_DsWIkVL4Tkgc8yc376;^H7Fv00Xd>zsW(^!!nK- z^Yh4QVLr+d5SImK_b-VBGy9kzNoOL+9C7g-;`q=<0YPE~--8NgE<}4yNzZy9u~R5= zpb$y!ACV29HtTlQd$v+mVe0HNC&p=pQTYsMpra&6AU3JJTl>Wj$Jr^)CXOq;V~wB? zIPA~G80p%fx_nJLo1e2>yV$gBR<_e5awNF$(iahMgV|=tZ@^{vxav_g>V)S20J4<+ zS67D9(0ri+r*WyGOcgwr?)$!wdw+RZiiE-e{w)r^@K8+OV z5u#gqy_JV`XNKNTJ{lMY#lJHjAlli9*fVGETES*gq=7mdBVIBGRIB0C55toSW=HH1 z6b6_Ei|WT+^v}1lM!!dQJ1WPH?y8J21h+G0l{=d!PITc9MDK)D!Q zq(7uG#n=SY?vKxi=(h;UteZ$9Gac}}`O?3GQS3EV&5#~Ue)j!H#OuaJD$4`A88mAB zKHw1}w!|2xAf)EpX2d%sB?c3dgn8ApB-^CaVCYX_# zLF~IA_9bJ9*q0CzK@h|idq_kQu_h7YLn4Hb#QMKgz09q9Zr%3$dA=`?9QEEhb?U8C zr%s*QcWTu9rM5v$7S%7M?H?Q0@$jtVKPQ}8^wo2X^V@R$QE}w)b?+5g)Ohiio3_kp z_QwYYCVun3hN;~bG~4{^*@CVdMQ1;p5i?_xyB)dz=WBL3vhZ$FREhVi=ZHD7;Pdx~ zZY#IuMo)G2(Q1eC58SZ#bg4IMRCLt(yL{O{a^z_F^e>pbZ$Y0+e>tzu znfrE!=iWay^6{3#ajv%>jJxFMvGnUw>c>;hlv~!M?(r@Cp3JEtlonm^NZdc^O*$>_uGX2Sf=T>FJAAKV&e$(cfe{^5ApyHb0%X8d&VcYRs zNmZ4M&RyO6=FRq%Y!_2)MV3;xP7f`&=hJL^6E7uAET1th=2~*bza8rxot=B!{OUg@ zw*T9fdqU|=AMHDr`|RqsU#xk)SiTuR= zzW*&gd@lFvYfh}6w>x)*J6opIx4FJ+*{g1?iX&V6H7VxmwcMMc`VOnmu1Uj$Z}T$L&8hZYP~_(m2Uj+&@xrt(4!%*M+)LwguS{t&u1MpB`R+Z6j&5GG-QrTUKddox za>eE8FPz_+es#nrHGj)FvBT`~FXjDuDV*tq4_fC)s`F#-s3YHB|9x$ztQWr@dMJH; z({+V6jd}OI&V833ifMoPYSujCuK8N;+di?=)+0^IKYg>ITD0M&1Kk%7Jd{zR%BL}l zv)-Tm&9yS!zG#`A&p@rirfA(wHmyQ;!_hr$oSF6@h23E83l7Cjjw&YOyP_@9sZoxa>b|V&mZ}|%R?oq z`^1q~^4GlGCdXeBeZy`H_e~yM>`1-??|o6H^xs=LHEnn~W>(qKz6tAMmi}4mV4;|V zma)Z#AHK2oz_~mHd;d49S1Y`0xO@4?rZZF9wCNs`)bxCn-N|?M{XRa>XDe05cqrXA1y zRm5{*)mK*w)c>e(y{$VdO)b%@V%eBVAJ>2RLZR_n>QuU1=iR&I=jEXSLO_v{;5<+s{3H?58P`rBhSN0r{tY;?QB1@f-h-mc4|Kk_UpoUB~QesS5m z?tc=;Pj4E#@q?S+WFJ>$)u*Gf)F@H^_MRsN?#1@}scpS#7vApj!rKcUUAfe3<_?v@r$O0Rso?A;-8RbOgl`@GVW-3v!wy3r_V zSKrz7YdhCvTz&7Ub8JSI-}X(rd~WW@@;j&8KlJ_38wZvgc`p8oE~BCuD`A zKh<)*TA;%S;*F;P*!9)$SGk zZ2pWx*DrpvbNSeg%ch)La3l8h{{Ot%q|Ln7x9r%S^~{B0)v|q*Q2b!Azgk^Be_;26 ziYN9Idu>4K2M=~M_`OB(qji>TZeIWOyF;%3@6t*CsRypOdu?WP?L4!1baJ&==fj4> zn){u(mJ}^rYGbwBefq|aFY)~Oi6yUWJJ_h;)A;YNw46V!WW$r?R=rg*BYTN^U5n#) zmIhAH2Jc*TJNNH>N-p2nqVS$7Up;Pca^!cHS{Ha{Lf-Fx&)>Y!ieFAQD%q&aheswX zjxMx%)K|{4{%tizt|&Nc(xGl+hP_{-!Q#e+wkr2`e{o__t`q&X9)CE0VvcP^H!m&z zLB}EAy|VJt^$Fjd8d5Y{s+M&-$|D%Js|MulK#3y<+|ucOJF8_4>n;N1SVqfh;u?^L$CJND0ce{;)!lfJUW zr+N6?h@`b6cxj70t%RO0k%~l}GhAF2~U;VZAi|6CN zjsHF0rB{xwZ`jp#cKyh^Uv>DU`1HQT;@&KIt5vlEefRFX-L}T=V_%K*e_VLWzF9fr zN-tJRPe@hmqA$d}{j0Ceq|^I7oAyUt?pWfTPonzPn!T`8 z!{}4rxn|!PHGf05EpOb-TcURkchx7!N&Eim`(@oK=?5IszdV{@TOW7)d|H9Ni^s*} zd;i{!ZuwkO9zMvH*sI6g{Lh^^@xPDnq)y*|zGf`mF#b$kQ+?~r3AXf(zjRu2rS7(u z2cH|XWL1&e6T3xgRh}Af_?t_ zQJvRzDl%vDa{TU5kMwum9aX1bVSBbg|NgNm-1oVRxO zbd-26%k~@9^?0;L19?v#H`Jz{W*W1=Q{&UWQ zmo6yIJU3RaYojavl>-uHhTHOy|H&z&f0qC=jGYkPgzxbYK@r2 zt2R{5$acQgu6KXS_w&XNzpK0V?$hFv-+8U=goKYvJbA9g^xmVlE^5%I?Ug<`PnKSM zHt*wMy(VYR^>pEbbN)&z_q6J>=3q1Xf*cv!e;bEsfwH^fujMXe{mEB- z;dgc8zj(6cZ0XHSro9k1*M7dolN~2MPtLa``<0DdU5Qt0YtHx&j{2wn;g8FgKelR; zdsY0ErtSXP)_3I9dzCh>-?8F@bM}XyTzKl(oN?&2@^z0d8NFi3n>TM>JN&SwvT(?+ z3zOHzXRL@HzWSr+%2TSXOD?wagZ{^kEvcAu=ZF;-JDk7T_twcD5AC`h6MgSY-h}+z)qViyqo_rE5ixlYRQ0`Kf5d(sx(P9a6A;tEAmU+G^hrO5ctJMLbhZU{U0jFXKa0Y^7tEZ2eZ|9H1mtimFy3Ba@ALdwIYwwuHZQGaG`lc_c#iB6@HKV#+v2{IH{gw(?Vh73rE;$J9mAwya}sYi0p#H8L))!Qc~MJJ^uh6Tu;#-}E5T=h1I{S#8F z#U%IZ8D(RiyGuyw$?}6LD_#y~ck8jQDg>*St9R(wDJp4Tzka%ZAt9^BvQIbsf3d9e zS&nsU?kJBI=-JSzP%A`OHY&kG%v&sY9|c`u(P=3Vbtk2$l;lHILLt)mv zs;Q11LK$6WZjUz#KWW4HDiX#+2&03^>4GUW5L5?a7QwHQoApM>BEmGE*A!+&74)WI zJ(%@o#S;d@@0^>#B9TNhpMVG?@t}^&q&JPY7||rE*Br)L2`mX*0!3auu+{$;Nw}ix z)8$m66mx@Wge=d9BW%&(@G^y}nVW{N<=J3_Ee04qb!#?%ge}hoBW%&Z@F`iZYC1Ns zRz7(aFe|pORrGHfCu_MKZPsEKwBG zJsh9bvhK}gIyS!*OI%o1iUemx6SoiBfCLwTCk$#b1%4}@Fg4wN^Wj+$h4m%FSuut8 zhyBbhB zD*FEyNob=VB$lpZ^J3aqbjjAdL{&l@eTN9@CHt4lNtmMt%6BjqzEoqaDJp(U80T_Y zQiqwwEg7OEaTpM#Jf=NbG6z5n8>AV~Wyu@{H22#soH{LR<5E#_Btu#fhaHKeNK59Z zI6+I1mfT^(G4x|)WypvWlAI`A$iqg`RuZ?FB!&%+T9qLqQ%Hu4Od*tTn^DLlMQqeo zhKx)h88RY;aG)?%HZp~9h%rS*rjQI7nL;w8C55n36v>8dk~P-N30o;rq$PvcN|7Qh z8N?id6lv*%*f7mAxh|SH*85sMOvz5KSrUj3Q--u;5Fe%tX~`h2tz@UyEE&YLl_4z| z#I=(g4D8{2Qq#})*674oCh*m z)<6$lz%m^qC6L&orkN*8kSen7QIo7`ns*k=irZr;l4&NM#tgbjQb{!VOuCdHY5rM{ z#7t_)i<#LKRJPF7#YQPZMk0>~cW9BE(kAuZ{{lr_JLchh{dU>{~#8Pd}GaAjpkOW(tkHNUrZ z^L<0uyojg0ialwVfMVcLdH# zk(Ta<(Ljo{BoI>;+pXCGL&ZiUWo1Z92gH??AuS2Slr=9uann?^oIm6afA9-7PvPP%3WLJ5|Yf!Hu*eMTaXTe4B3n$4n1*vGAzuW1}~A^;@|lm94& z<(?qbH6nl9lHHbOp@k`dVWoXi{xB_`C1iKgJTzj-FjgM2yJ;HwS%H*5x*jo`lHxfx zEmGF^2%s#qq&a9K5W%Mz*OB!%@<&wFBiZ?IMPUJCbwE-i>p*0lu1h!8trSW9j}8g* zc+5+P+$i6)=#ncdLsI{v>yj%gLDCeoVM;vsZ?h@UEZM`Al_9D7F)AxVQvahv!m_IQ z!QV|Y(E3p_Wu-_<0x`=;KF~~A{FTKh zxw0~(C4soIGGs&osphqdZd%l==K;o|Nc;%RKkI>Pm{Md!0!fjP2&70hOybUv?LHy7AIpXS~?(Z zSs9WNh}rsCj>QU!fsMx1VKGq2dr69mx*!p#;lkW>Iw^y6KxQE+lC={fejSooNQN{? zL+g+jrH1#3&6G7sL+gNCSs9WtNQdOg%8-;oIwVup{CyRcj1S5}6!WDr+YhK$4? z4R<7_mbK&$S5}6!BoJ3thGce>5(t*{;9}QIS(7xhZc3Q4QY3XjIwVt8inJsUQ`YyytpY1m}*k~aLY=N zm}d(lS5}531mYiMc_!zM8)!qXdaOL>snA69vjPc&^gx(alJit(BH93yKkN8nuFFO-8kb*k(Tsf%9>~C*%gk( zD7msSB-y`+vNB{O_IS+Sz*lG*THhsCR)!?|mmbM2D?<|hqen8!n%{{lG!3l>a%E*m z;(zo=uB-$})6jY(Q`Y=WT%l=bJ&-FaLs}AuD=R}<5(vtw=Jk>aj!6+XD@Bt1OFvAe ztQ2WUAf~K&!a+e*VoTn z`?TJ{KwHI}L+safBK2v`1eN|a2eFVj6I5CbO_1hHP-!k&kHk_@ki9cCP(&{zMOubI zjJA@?LY3yC^~!Rjd6HJ8ztEvaVwi68TM%~D9$_}6NJ|E>F3sQeRr$MLmaasKv~)tO zOY@CErFm$*d6;3PNMRdmlGr~nEfuAgm1AA@$_?BOms@q=2Y&4AJ5bHy@%yF0zvJb7 zt^A6>3G=%>iXE?o>LebI$IcI? zA(-Ezx$LM6(6{lab{kLAWH$1<;0f{%817>RWfe20pk@-jtUmz@^| z>Lk#SIfqP%&u8b!p0LF0R4_EgoJ^7CwFkeR6|ktHu+g#)Sp`}#D>Io2SpaFvZ0LtD z)Mv1v=7cP;t%ck9+;;xPBQ0YESF*?EzPUgWp)m^~!Iit#}dcz#e3$ov{Q z4H-Yc3&o|_dBm0pRa`zh52^Gbn3lgYrjxlfJ3M~o@KqNKVCUhDu9c$NdEC+}Dy)a1 zXm%cv=$rZMJk-#MRHvQC5PFf@Zu9Fci9S_4Om9dg!ov*1RM{K^xEa<1KeTCg83vD^ zC9=DPiNU%ALj&)uWU8WpH8%DWx%%;Iey82d{iCiSjPB;1PcQR9CeQ>c)XBi&;PC58 zkcmU_I-w1}ddhsD7Yo+r=0BOE7orz_?W2>q&`Ge?G(a+R>_R8_8CEuuux-39^um89 zMi0hNg7?pvVAhFf2Cv%*ZSZ|Jy=}a1^b-6{dSqG{)Kxu@g`8fno$AH-!|p01 z^rNA{CK`qi_E^Do8Xm|~PWst^`(eN3EEv@1f-K~vf?)WIKqaDX)_hDGR85OuXv5Pl zx`uuRHfZRFHrTTmHar_XIO9N_TPE1&goXwm zu>ZLY4%6qwPz)Z^=VhIU6!F0mLL0+SysQ_)tS}<-BZ{NtZ6ss3|mlE7X!)EZi?6yFKiLMtgRxvnh9~i3`e2UM{Ith#<(>8wAi#Qa&(*>D0 zD}F=+fdY)oj{R5xHpSr8{a6C*7cKQ%@?!~Lixp)qbP{y*VQu`_hXVx#x?Wru3ioAt z8SBKLp$jZ#fxghQ8@=$mdmR}5Rxx;gL~W26yg&1bfxC3-TUp=Xz?k?}zuO=3tsX^l zoBCGP2BDIuuENw68R&*8UHD}3DG!$3m} zO|*fEj}Jg5EI7#ESCw$o9|W_-C2sI&$T|`12N~-`^c|{)EiQ3`hYUjzH+aawFkG^kb+)JeBh!vvzeEz62l<_wNi-R#1#P<$SSg5^|M%6TuvSr-vGt62(xXysbX!G(We6G3;9$W2sAUF%GPC^Gp+`(RK5Zd7ktpr_LrZ%9YBA#e*i_Ur$)&gW2WP&q-jAw7*Ho@>KQyUhvi18O1LPIhBf(#mp;TL3>sX*dbX9pJDi18O1 zBB{ZXz4~^3$O7yQYop=R8OYFPHq_v#RWbhZXgG-mva0%a@T-A@sa~j}p-4ph$_iwn zu{9^tP~82{3sX^?0S!miK+;jy378#7C+cM^k7QWd8mNtgfWQ%afgCcCHyVztYS0B_ z+6G6~KvquI3y!CX!5w*FZ1F^c>p12QVeN^o*5kv>yM?Te3K^pDVAdzB4D+ij z!>(t$pOIKR8)&dIk{ZH@@%a*H;}Um#2z_WMOcd@|k(Lry1!Qi>#EF6si7s)eK!)^^ zxKbcPCq@kwqz7E$^3m|K`e0qASQHLn=V5UNyQ_Wcr+8 z*Q#P~HAw~VHmp`&XL-n=hM4Jr3}Y3~1jyB}v5KUG5Mvcd2^q#Jk`gl3iE*sh)LdeW z=XGLJbBQS-$k+n~zCZ@|;Sx^|5aNO2;Q{F+Xee%Ukl}&B!$YR!HK-UoJp@AquM@j7 zQqH2iyzGI(7K?U_m14{fA=5^16<(*0J1BbQ2&>$2Rm>1eXCJqG;v%AFT6xlb%8!% zWdWA}nYdK2sv!%|AyXUdSuS3F7>1V+@+Qzm95WIS=vf>xQUj2QL&hBtOa)Qg;#t?rjTg54BY_te=p_&Q(=og>XD>zu!dPr(o zLjTk*Hc&7$75t$Xze}MHb>X4Oz0wB9rzAM)B@Dp#A`_B&BqpTVgHGF4Ie^wsYfaIb zgLR$Mx~ZdS{9DN>4j#Zjk>sRQOm1LR2A_cJh~{^^kr2;5VhMJsy1~RIru1(Q4Pdn( z|9Gc34M61}#N|*NZIe>N251=LsGHn>K)=NJq#i>Yt<&N$?1ZGWR7UpT{0APQY95nu zd!c!1|27G!X^wUYDZLVVaIGD&{gMac5lZL=Gw=v6@*0_Xcre(+BnC?~;FOTN<1pkn zoN6Y_>xdcHJJk`J_ztG8`w&N)K8dN0RtfzQ@bOOc7+Rqm3Tr#PnNXLb`JjZ9L5T^2 z?V;^3)Xb;1smswUVXz}MAwF$j3Z~E&a-h61HY=yTv7(!RFq`b5usM|K<9)PA?xAVy#KMF6;6f7q#)EU2E940>{|1Lg9~L<7MuR(33kN$*26is| z8K>lsiCZ{uz6!eb77oQ8%89jb;LbSEr41VhHm}futAzt@HFQpH;b2ZX$mbRgIF(Qi zhiy9S6N4-?u^BflwrIkeR^!B;tQrEBpuBP5=CBq1JHT+9hXV3oEX;nQf<4suOcvdQ zpV=ZMx#z$h2`N#PqkE(zcaKkts+X9Wme{W!M5+VV6>uw2_{MBcz7ncO4@~O=LFGR2 zNr`qFJ}?W16jeE}>f>59i*v>)aZX3~tP{ARjyY98v)MVFf-1YZdVnj zyOPsc2~FyzfSzy=v>g(Rh~okcSdXzOCMkVB8&w!PtqbZt}pSG`vqLd=~eel!RV3R0#rY zbB6!HYl=v@MfI}f4T${gO9=drQAuGL`?io#=3^%k_K&WepZQ=xhNBvzmqCWSFp+62 zur##uvgp+y!@V4lAs=d#p=^LW4;S_1dC2h*8L|yTKMki*V;^`Ak+$Qvnxf8rFFV;9 zWVjkL$Us20JcM?jBU_Q83}+GJ*pOLezSGbSIS!)?xmqGar3Arxd5|bR&&%%%1sN`S z$h_fFhdd8=I_xkZV)4;m<6I(-&ms%4oyKoSMVX%;SPU|Lon(;VD!}+WKl`Q*YnI7f z6`wRUatPrw^Ld7L*kY)Rd0Im|KU=d#84Jcmna9c2uTjP_K?WH=-5F%Ou*N83M;qBHx=Ya>=8bFO;4?6hv^1H}$h#sYgoJ3rf6j56Y{ zRIFcOdz>H0yx|oN+n%AFYNE4;asx30;VG_{sD2vT z@eO@Ye~QX)mPai_a8L&KwX^`<_q(R0D9E>tL zA6UM$U!1~-&K|Nas9q0?>!m)-=QGj8$5QnMte>tKKbjcZp)!To+0XOE;`6XPh|Ydw;K=iMJ(2;-Z}AN>e&=J9 zQUB*R;jY>KhR}?TLnE=7>NoMleji;&ejnMVaRp5|iRx#gzw#i^Hrfhjed1#wBYPR% zDJA?i${3dl%ZdKS8b4~)b>aR z6Wb$6PjzN5`x(cElQWSaJ3wV5uJa)MPUaF>buyQ@10$S7@J)0^-7?_|VrtR{3&@T7 zp{#-SLH9CNp+W4zUO6Do!!AW+G|ooR47&&v=LmPHbR4)XBJI4?_Ne-#&+}2+;~IcI z&(AI(MO{#GNVtXyL1I&sViB97{Ep~?ayI%rUKwWSmzM|_WJr(`{ZIr&Wh|3xz-sJd zZj@0TAX!WM@R7a8gWC*ZKU`)|`<5hY6wKz7Fo+~^m z&rciLsq7BXC}UUP1{wRFk5Pueoyw?h!gU3Go|o6J@ls;ZE=bT28=%ODK99Y}X|SJ%{TMKjk=P6sM&zu^s*Z>s!dZLKXp(vSiFAA(kI~Nhz)$a_RE09O%l-sPKU}U z4}A2zfXoApoA9OswSkZBmp+=eMO_v-t3gK2u&4y2Jn-|&LUFu)nvaFcp*%ph#0IF1 zCpPu-`Y=Nu$P^mw=f}x{%IF@20(G*sP-9M?=cRj;-%EJ_Q_<()tqG!wpYQ;yi0o02 zkv$5xPsBGtMtl>>8Oa`noty9gGO|a(-IF~EGQtDAvr1wW)CG`O1v26faH?Q6Ucy{L zM$YW0q9pzRGLqv#>X7UU*rJF(fQ zvM=BYgZKl;h(EwqOZElGh(AF3p7;aQhmvy?WF&Wk)j|9LWMp4JI+nx-*l9_802w() zX(%@*JV0r=as6s2)h0GY@sx3GAp<};iOL1z9)NT)iB)h~AZI$r$e9k|3yD=ABlmO~ zUa~XpgSa|jwZkIsaV1B_i({y9AJp)Qm(jmyNC}eX;r%J&9-yHNhu8onrO%`Jab#K9 zZKLT!&CdD^d!+8$-;qz@E~lW`!eN1lhuYho81 z_lceHW)PV-mF5#s(`%v&y^}*|OL>6nGQxXY&=B4OO2?*A--Hwe;gw47b~OCz4ebN( z(iwSxcVCDNJh-?wwnLJP%!h}U6^gvVn@5DZcprw$5z;EO4;mjJb4}s{+_2Mq0f#Hv z2Rs`YheqxpG!|5ob_h_3%tvjHV2W@JZ$S{-vkl$&JZywSXKX4&XE<&8JpS^xXnQyl z`aF8SfC!21TX>7qIKL=fB7PUw*u=Mc@v^9KY&d?9`S2nKV6-#Xtk21$rNk$q48>Nn zrmcGG#GwhSy24hyVZF{Zd&N5wd_8*ldua)Nch8=^@M@f^m+I|>f_|Us>E*8-xy73( YAhD&U#iyk4(hU@i+A372-#pg#f8MppG5`Po literal 0 HcmV?d00001 diff --git a/branches/WOF2-1/ulp/opensm/user/doc/OpenSM_UM_0_3.pdf b/branches/WOF2-1/ulp/opensm/user/doc/OpenSM_UM_0_3.pdf new file mode 100644 index 0000000000000000000000000000000000000000..99511713d56b7e92b2381f2868b675daa12d6645 GIT binary patch literal 223001 zcmb@u1z42b8ZHbgNTNT)O^NQg+Qq?D9` zz+zhI0|Et~p9h1T!{FiMJjaEH z3vy0>JYb&l^SIC3gNFz3urspp@baBs55{>;HXc6ib9(0GRzH@%h$IW+62Yit8zQM->J0}Mp?|B~w+~AxXd@$%a zKj7m#7t??g(6e%IadPpV)hQQ{BF?S{BxyvlNBsJoOSm{8yl3^y#mRFnX1F+^JZJp{ z7(16YxVRwa^vngM;&b2S;yvdZTo9n5oaG1MhMgVbJgP*e<=_MZhWpQVU7U<8ZQxEo zO~c{P0IC@XkdqsSL(b039t2nksCeo?p;EWEcL53MCsxItPRYS)E5Ml z&C3VlF*O34LU`atd{9mYAda((k(0|&G2_IcqmxpRJ}QSmWkW#!uDzNb4sZ~MgprGpjlDU* zK-I_`?hNn)eD8>#65ItqaxnrV07N|+QgL;$0V*~y3*i+WKP|n8u-_s|T`kwXyl*e~3blAfaS$3J}wBhX029HLhr6 z47UN0cz{fdK>DNH|3XKIrVj$-Jf3j#q#O7(@>_B_5YT*ZXj;11z(I^+Oo(+jqyd{D zQvA7v5n}xQrX<|i1;OChhJP>sERImz@k|a45D%~#(9rP0ARwS;fdZ}ubTLq%o8XYP zv~htu0l(WAxxgjiCP(5b!tKmmED(+Z#0NkEv9z-bpj%rUEZGoaLqkI|!>K!6O}M5{ z!5Ew%AEb*csxc3Ivma{tQTvwqBI9h1a!nEnv^MoTZ*2m7?sXOAOz{X0@LfZ1_~Q4? zKwOahr;8=7sH(or16<~Y$g>S z79Prw6qhKeC~Gjp(r&`V)W%{UFJs&i%`>hpd`$|=`fi)(AU{S$!wp5LELr$PNxSQ^ zeN!QqgU#1oRq1!PWiw7|<|SZ8@^gJjQqIem=`wrGcA3OCM%|&UosNCkO0Wkt`exFP zdvRCk@49^ZA-l`Q&#NVC7C2$@K18(JBF(xuDl}It-}YrpSddyMe7zXt-!$I5ltBH*aXDx@>{pjr5KJgEa>k?*EF-C*ktb6txTOeLkF|u|5=m z7*EyB@X?>f^m_Nj zc9MdtFcJ(%Cuah;DVKrKSW`-qo6k$Jq~Tf+fmFp!R-*4=_IDr;m-E1 zP9{JU134T>rHGi|kg&IN0j3>|oun`cCwm8R`#V5fBfiSZ#RYWE;G>3J92ol@P>8@* zf}2_z{W%x>d#<{@3lIpv0;eMSD8u|FEMe~oPz35W5UG|<&H!6P-*!Yy(dg*oudq42 z#2*m}>=S;)J0cxvD1m_V;$#2@b2@{RjO<*EY?yF35Wx*%l;L9Mh4#4852R)l8pa=rL`5uFD12~p;<{*0j)Y+C5WbbV2YymQ|Ge!L50^t1z7Q)U2 z=H`R)!v2PPR4b0k^O49WDgesspDOrmmLp{WTckho)2}a|OdZg*y6-g$F?~6cuWcCj80KHRg6z!j2+Al z0|DvD%+lP|2@!2T*t%FAaRV7JYAcEaVF>}w6aLiW3Cm+W9ydIvun}W_QwQ`E zwi=L2EL}Vhp`-zKah`WKM+&gF zu{7}ju>sNT0ylR8f*a6^(H}YQWTKRvInd9Y(G3@{_xrbQfK!=M4F964qbYx5$OBT8 zlLQ$#J6oFD*&=F=>Jibi_}tJ_A#_GVCoXdAP{#^8r6I(Wzu`kbl8A;D(O~|O@DZ68 z!UY5K{uiN7QpPdpi4Kmv80hhS>ExFeBerFKW|T9T7;&ocS9;t>_Hr@;nq@aQNZQ8U z{j6qS;J?P!FR%R_TgN1i6?IB8e^0Amc0dOpF%zKVAC)T?3-}+JI<8@IrhvsP%`D+g zXG0#?!Tsqlh#lx3J`6jy-zgq{PpSwWKw>qvf|~%1#&O31D8z|VMU%3ez-h!S?T*<0DhV$3Kyw3<69+liJDurmAly*CKb`lCw<3-_5R6Z0?O!Pu@Dq?2 z;2*XQHgKSG{H3?Q#0!*@=dX~z?8f(()NwTSH#Y$Tj;Uec>T;AyP3_%*W(iRQ&o~Mv zjO))V@>|AZz>~Cb>?nUpokwc;J3bhsf!NpoausKHINaeZIPZUx_Q;BecI+4UUxoiy z-sA!dtpWcfyN10j9Ox4NR{FVt!;3$C^4JOgG%4TTa~}dg5^iSXYU2X3cS2a!7HCH$ zjGW;>^7%_23On6ooesd0hVB&Z-xD7f5d6yac5Elue+T0}RgO-;j%|7zTBpGNmfg5O zDsG5|0DdN^b3?dJneF#p<7j=LojmO{h$FhA$o>_|z@MLF+oM;I@^>A#4lP2M$uRNXM_|9awvs(FEh65O$)eGR0F7^&by`2lN zi8FFC1t|eJ+Q<&r0|QA9h))x1kfbHBBeygLI>M`rT~EbTfRl4LIt=7qWdv{ zI{+$AWDFep0`MnP z{*z~bcn7v;r?dT8v!3Lc6WsG{3!wVH^_uFyX+I}BLX&@-GXdv4r)tY7wErA&oq+w- ziB4x%;27^X1#_tWK5Yl?9)R;WUTzRKaDv7I;R7LVND!xT+K9uf-vNU7aK0xwp7Gmj zR6)QE%W+H{FAJ=USQQG~iJYv8xZ3;Gf&S+l5OG)ko8DmN<{LxTU!|3neL)<5C%&-G6w5LFQ3()LLDe=F!W=OY15wDnJbQ>g*~IPt^( z0&qh52;hX!KLJi<22~K^Ny7h<;AF}Xz)4&5Pk>V?0RZ^lHb7kC{q~{XKKD-m#Dag= z`1eKDe^Jp1=_3hFRQgYVQ(>(NI(o{2=&1h-z=@DY04IU@Pk>XQ3;>*b;lBW!kUj!9 ziR6C*oa%E_fm^BnZR8UUM*t^n)IR~v#PRPg?Y~HHLK*=8J|XlkfTIb27#VSk{lDDw zg!B=>Nl^R~;7lYVuFn4lz;Dt=04G85Pk=L#{QI=z-zq{}UH^^)#5;6Uo0% zqy7uP3F#vVPJ-f}0B0ik_s;Ua0GyCM0yqhZe*&C|h!iiu16X8rK zBi`Ko&qz3-jX>Z&Ve~JAqX~b+GS^Yx^xqRI;?>1(J0qS7{nt=9ns5r?;o!*AM0 zGMog)KV>)*&0L6QL`R(d3&II)1j6s`>z@dx!`aE+1UQKSx;YNuWhL;40dXP8A!iGm zkw_f%Uedrd?a}iFX)c5femNC~G#K&Wm;Diq7l)3@(IM;6OgUS`RK&YPfcVj$O5Jgh z0XDP1(Hi2Rgp9_~QomGp^yd=xHug>$4n`)wCP+B*B9{LZf`|!-|9;;`AB`i706fj$ zkdu)3weJJwA3MwMR~o?3AA!$t{33z}4Ey_&2?WT0UP#>2=&~CW#joGFG1xEdRQ-HB zxftJ1l$<*FGI~sFr&FNVHN02GKX4lo^6gZj$g(@NZ#=)vR$RF|^ffbG%w*H|Z5$1L z?|#lA6pB)-iz-goOvciJ#+F6%=uPW>#!A{$Gee40TLkfluK2!T`UDHs(`Dn=zRe54 zvm%vby=gb%I0UqA6Gktu#E__N#Is8?`r0ODnSIZ2X`y8b*Xz+wx9b<%(f4BFg{}U2MD0GOIX0txt^1932 z=r>ngPEu#OCQ5eQnf!YDJ5nVNgR1v}@?cUl3C`EK0~A$n(+X{Wc9*G?!lxnx)VLMj zpjGvS%2|t;$}}f9hhnCp78EPpB8-0i+K*<{Dhy0vzNePT5j;j)wlf*DV0LlM^4dyI zK4!}FiA^+PU;3y219Os#SkYpQuuJjTlugy;wwbPIhaTnu|O9tBY`~%+1UiB(Wj!? z6-xBRFn>NwyM-QUSx=+b-NdIoombo@OYz8!r4Lji zTv|tQtb~+WrPa^fo8=pQg%z&tTgGIbDxS@`Zkcl9Jy|U5`ZJjO(6iVr*zL9tx!q6I zKK&dcdal-Og)F*2Un|DM(eVM#yhfNo!EfUNQm4z1fWa>A)fgPKfn3_58tHmHExV?% zFV_+nA(~-yOiRyW(EK?i=!;_(t|a8>Wk*|HMNVkkNP*>z8sB;BFO}KcEbdL!FYsWu zIJr?ZZ{p2BbZ>Q<*iUSGTamdNLRda`h>KtEzN~!5h7?we()4XsKe=ZQiF3Vyvf=w1 zukU#tOi)r6qlSj9tu0}z+_4VLKIm>bZlmaG-P;bAvE*-tj@{tI(r%x`Mf&2ReBQ-U zy;Q}bR{XX=UZ%q4!*+4@AWP-}X5n0XM*wSri~`cQ+=8$O}}5qV!# zWm1e>Jc3@r{tfBdOKhYs?~v5XaVC8yHrZmM(7|gwlhYGF$KGP@?r2O44`gc>COwQc z{bJ~p-C%eB?WXR93mF&ar;u3;@lt#R@Gp4dUuY471fzF>C_npLC?V<;l``g;qlW(u=jt_Z{%V{2w)AuE{uDyN6lit8Yl4=pST=CWu-L!k`hm6pXDa zh8xN98TE&RF(W}}ka{NTQzT|z%}8RfI9ngqQ}o54z)Z?MyZN0ywRsd5+!_=wR3$OI zjMa>I&Inf~(@S=7iMd)tRPhM}#Dq$>&;gsi>60^+NRBLDKU?gE0h`FK3 zt0fwqF{{e*ba{|^@%|#&qU|CfdHAd(b}szgVELDF>d{q;^npAJj(Lh2hMVFXSyva9 z=BeI28feTCG2$e(3$u`>Zf(-(7~p(K*?Kcvz;JkR0B3i zP)Jnj6`Q4=m72Xy{NPJ_REcSU_Atg0;}V*6+-vy5kp&x^+W7h)uL!SniJ2h0KM# zI^p``rP75$h1`Wpg)eo}OYfVumSMhp{L$qjMR~O)_D9cAvk$x(!QQWI z{<3W)X8iiy2Cs6j2m3zzPqy(Ws&F6US_L5oy`?w^O*G-sxxyQe+HOW+OBqcO9w9)% zKyjN7GsP*DKLr;y?wH5_FtsNIJw=88Z56C4r@FlAt84XwyyKPHxLP|mp{3nkrKz~p z%5K}S<%TA8&=m;gHkMs2_gMCr^_a|fu_wOJt81~>^o1HW1BCnqdxT^JIXs(hHQ%x- zF1!_AhdGfsp|`5GdR4rJQ(A{%j3wpU^j^-c%lEK7!EM)dw$1UWyTdybwc&qGMrsIeIosx^J`$s5qreh>BX2yCz#D<9n2n91C8E`a zHqGN0PcU>}MFe-rvc91Gw%^$W_@M5f#UQl*O@HWoYX6S0pfR)YcAH?t*2AHW`$T(+ z1oXP}eAj|r(Y3pFD7|u?asCwasZrTMUX|{vQi9wic^hTHG)Y-`xzR`$2`h$J1$PDW zD2b?ex^(5tC#Fv>J-HXXn3%636o>YN?uo5pZGE3>rrY!#e%bgud&S0R>dvQK-zDg| zxUW0YZgA*k6~q;keHi;X^Hu1BinFovu9MxDnmKZ3m07Nh&~I*YLOqXqR^O%@e6F?l zkhOt2jJoJ|{XtGkT}$eNvWK5Y?DYh15@`-S`6VqwyrGj7%!YZ$m%FIFPRIv<*`a)EoB`vd{9+n zGcI}CVX|`T)z;|Nd#I%C$k5vr`^CmuF56Gj$Tk^wr}mWElHcH<;o40qj@yh0^2O|` zAmt$IA0$*I(k4bG{!Fq+8cG&VE>59H2}#*WHBEh&CYn~1PMQ8NeK*50VT-u@H2CsR+=pT2qqefBJ$BLC6z3(sAjFBBLQ^c6}L zRu!=oWfl_`KP*8iaV=RaH7p%|q41)m3|3ZDPFJ2%L0A!5iCpPXx%SfHuclwHzu}$8 zyXFDOf%ZYU!JZ-Iq5fg5;gR@$hO8KhjYVVrP+Lv{w^}}yr8)O?#HX)lWTdG?V+qT<#JE7mnzCZl|`_Zv`V|Q-P z{U`d*gng#{ngfM{u|wO#!wZ*?b^Q^=4o!71q9^@z*?+o?J=%jF_vjqImOI&~{-;Sl+Uz1ab5q27c^=?hy)4|)+ye0~ z7ien5EnS>d;ZBIRA@+8NCuYE_M&Mn`@BQlUed>RDVQ%20_^*%hPwy~4-|$e4*&%!5 z!apE4nj=qpO>~IHBs`0fn@hQ{JrsWc^Kom4Qr~chMzl1SwAgY^niio+_Rt-lv7U-x zAJ+Mrs-6lEHY-*qHEVEF%gT$%iP}l8&3&(0v!B`fDr1>1MBEzo18+`vrSEu5%uS=F z?F?MLql~YkZ0Lb}t3>c825SwG4*AViHsbM}ec#4K(>5BuH2)iycBNdMjrZ3Kr{vde zO7s^TF5Wu`n(4bSD+DoVksXiBF6$Y6$`#WUq`#VcC*lhXD-HQZsr&tQNPJbAlwfK7Mrnd9*odMoLo>=e-|`-xjDnsD8@*`0_p}?5nVAbpK3- zZWpchh)X7sbX}D#y7!>ge(s9*E649J*2KM z-$7Q=ESUMCTkWk}K!=gs=KDd=4lhLGQgg}ut2X8SsAw>Y(#y}YnJ>0tAvJpi>A$0^ zK@0C%H2xak)nfH31vdeDp{g?!)PMv*!SV|tyZ4opd&+(A)7*fk+lu`J{%sy1M)$U) z7it>`LzWPMuj~|{fG#r~kq?5%j`&|0$3NI6R%CE8)-lqHCAvr^Cq1zqHa4MuwCyV< z!o_P;+Ej-eoRNE}qYeYZk9`PAhV{^eSfH>#hGML`kqNBKbvJV}H$5+Hx8cJ=|Dz-} z+$TLaH;vTvf2uQJWBN%9*?qXR@lK^Eph1fuK0}`WT~gZQWM11Pw?%RJCwc-lZsdyE zLD=rmkWS(KL)x6N=$JWduM19SB?dO^i<=+zr0D#$8MJViv6RgkXX{~7eKZTtxt&{D zaw+#e@y1VBl-6S6v62>>$fWaGMx+vw1%00GqD20{COt*!5iZOq`E8V<%kRs3D81%& zlnoa)+k_9wsg2*JCYg3Nwf+08Dr*E`3wbaCCbU&bq(1NAc;Y9smtUnhH^7=g!!L+_ z7!6$4V5oQzDw7aiP{i#My29@OrP1c%h8*r(zGBbL@uBoNnuSF zQK=KuGOTTy1tGVAzaz8mwDY9^T_W#t@tz+AiU+Z9cgGhw!tgm)$%zo(h>Lqn8LwPE z4LfAIOpUmYHpsY5fpS6~HZ_}$_-hULZD?!tbK&ZDW<(v3?f zP~<>hXq#oQkA$b686%R{DK{Yw`KM_UwkI4evc)*^3RI&)(hqx9sO18voo=&2 zE2cly6BE%&4bnAaU+j6a#KKAz91%Z9f@i=%^+Euo6n0Z_NlEajF4dDeu5NFNQWsf1 z2ptMOdmXdcxb5jCFGeEgr}fg8Y3rRsRDh;vQ^?zSI)ZSaE+yyIZ_Gs5A$PA9-S#eb zlV~g8wCvS}gVohOOHt#^65-|LY~3r7qrS1ok?Z1uM_PET>=V-mlDXF+M%%j782)U* z2ZXXQYztaE5nkn56}Gj^wX!>}6Zdc#bjPQ9{IAYDzkiKYw|X|P&J)7COW)`4sl&Zx zvO(C0=K>D3?d7aE<)}!S=>T=L+Q)HjZo1~ZareCHmgVK&&pul1v=c&0r+D$1JO^{c z-x8JIwiZ6t-Z_Vv0rwd z4pUc;A{t0`c@G3fJgK-7LgryVh6;jiuUKQle~WXD{Oc-84IEuepb}_bp>wy69oSck8U0@}K=I1Kf@LBbvDs zO0O4R8PGpzU7?i=&Gi@=N1_qA(zKfn5_eBv{vzwRF!iN3?Y#so!@-cYI+x%o6tx<) z9-_c()$!)`vhvTn8+RSG2IjuV*hS@J33Zvj_f;IE>AyK@FP(W`H4b}aaVO9 zusQGJ!2_!g-Qca88efTj)JZ*f@$q^hUws8ztKB2pIBOT{pL_Psqt??a}!#Ydbgd4>97`9g?Rt{spP9}=0%*q|ge^ z?FpvOZ3yO|@i^oNc~JgX4S6M`L2^j1pq$+Udg4tzEHqUmr5=Ba)T>stjwZ3PG3TLV zyrTfyk02>)XoXAYbXmFr0RdAhVT8lrrw#P${iJ@zrLb=X@a?S}!%gCW&>L6fGQL5q zhjZTbbkh|Y5QaY=OY2ckH1{JD)aODoaM77*kINc*9ZFT0$y*v`nn!QT@@Zrheb*;9 z@-z2=WjY5@urxlA7zT&ew82k%^fq_-lu2Z4$>E3ba9x2aq8hzH+aB-6y(f1+)?p7g zPmI)~Z|Ca`G0e$)!&)tr%_NQs)_(xTQrP)GXW6~9*#pf1&BE=zP%sfl;n#j##SUx% z64m6KwdV_H_^CaK_%5Y zq1wOo%SWqDLcA-XY<#vM3k5%E#-y%V_=v3<;B(bvj9pyz_>rZYSrL+ZZ*KpMJ8m$# zw83p{m64Pc(Gk2&v{z^bhdB z5hm4a&mqiY@b*gv@m)?=iJlOVOPo6NVlNlQC2pcNu9&SGVrei9F@xQmqrnLoN>i8A zaaup!Di$$wWO;k&YG{iV-NvIqmhU{z?3q`{xim<=3prP<^vOuh<7XLeU2AT z4W@HdU2S*rqM#*D6_=ZW!&{;8_aG(L;|21gRqj%z@l9n#$Vcr)Z)ERbz2Yd$y2ePH z|D>Hf(TSc)c)J!|VA5*!>wC@jVmzk%-2v^=apYox8^R*^8bSijKm4$?&G+y6nbb_vpJ%eSU00mfBN% z1Y%3iY7Q>XJ&ro4`^o+`B|9Y3jzs5$TSaWz(t82=0&ce*n{xN2132ZIsR{oksb}a9 z1FSxN9~ahAs?X1t-spa0*&=4kruF7a@=hZ|cduP4&W!XTwp12q!N|x^MJ1ei+a{$4 z6rWy77xSGE)k17i&1&wpoE3W`t*ynoFrgPvF3slyWQH%8m*`DBEeyD;>4K7D-taq= z@33}e-HBR9B6-ledwFZ*?fw4yPpjhH-^izv$Ab6<2f-jAYrS8plhVo8>?Em-6{T_T6bEm?-! zM)TLcfv>AA{oXgF5Q^bjjZE2&)3F>HMU!zI z#v2npBIFS?jKYC1>__%yy3>cHa6_Nxu=UXFo^*zC^fVKygGvtTt3fP2tAk>hk^5`? zckQW&obEVWRC<;?EcniC&>EocwmUtQX!+F98}^|kO4 z&57o^(FdR}w=Y%MMT2B{2qSj)A0zomlW_SELc`k_UU*N(2(?j4k6o(yu4DM{no3os z*n8-FXBQz6v3vGYjWP7H(Xd?eKq$N{m%or;ctnW382WB}wP^=rLD)#pxJh1-A&H@T z#i`7%C2)j7!$|GzTko!yZ^_9QRJmWTt#<`6Ex6PVU5!AyXCz`l%=mb-1h!ofnud9W zjeaC$rl=C=Q%Qq6;W`&cW zWq`zPZxU_J{VhnD3K_=%lQ!HH(>C=&Pb@Q|hme=SBF2L!NqU+o$~`OfHyioxznvZG z!I2JnzpySTn*2QCB+i;^nuI+tc~lPSqqEMNOH(+gBv+H{b*n4Gq#^Y;S>$7 zL;Sl7->5GoCt|bvsAA3ReoEP~$My=0XPoh#}tG;Y!8Y#m8<| z>X=LIpp9kE;BE+gp?$R$Lo&7nsjU^(kg7JjoUC2iV6A_DhBvZ>K=5tsKHh`k!>ey# zX?NGU^g~6uu8=;*x%F7|8U1tn$wUebeiN>b>(O2x?%pwI_=1a?6u{%jzzR)zxzbF= z`W>n2X^did$OlwO>&i|{TT4E z9{8+g8~M0#HPksapiZrRMOs;_6^noE+f#v+pSWScZ$XBUomm-pSgyQVIb9hQNsDCBDQ-P0V{as=LT_%+=Sq1O zep9P$imOi4a>*hQt8+g1Vdz4QHcTDJ{%E3X9P@f0F7%!cZ-k$16@IAgc$bh%PVzV! zl-t!e^5b-6{W{^Bb&W&ghF<^dg14{(Z`VB6P*JI{fT*yGqgDyvck<6d`7`{oOvK7_ zmp2_4w~=~uunRR@`Li#@Q_qgjCfC2{qE99SZfs@WiDLMEeOy1ecYm^e!hNz{ZntjL zuR?RdyDu?SXfkzwdBZF1?Z&=%9!9c&mys|Fkz(s|07)w? zA3H{(@8#X6%KdYjWMh@sW__s7QKmWP3_C4wmw&XHere@}`e~GwI5WDu7{;bQT#>?g zBGY+KY}ix(^+n8whUuG_wLsTzKd402^rNNUB(1F{oNah*ozPB2Qr0|S!pL;pKTl<8 zzap@@zlZb^s9g=&4+)jz#z^H#UrJaS`hx_6HKS?FM+~x32F+_p`NLk`X)pL9i!woU znK=Qr9$SO$=6f>q)VftoZqLcI9ylbR-%ffjci>%)m6?cLBlPCV2EFxsFJsx=Rh=PE zbUJB5tgD%wqtZHl-@AD#@gfvu;ICwi#Ry_e!?XP7Dg>+Me5BQ62|4Qd@N33+W-X~kSL6yN7)GZ~?N>0`SCR9s za?4doOqTEyNn1clkaitxZcCEJn8L$#XDaZu*S^=C?6!-`9j_uMoFBtkdKnh)yT~vPdpxi8D zZo^%?;lW{nzjkO89txR}3Y2&6%_DA(I^OTS59|9iW5P?t30CK^VJV#v>5qg{v!y{{S z%5GKsWu4&n)C${>7~1FZdP;EYYGd{rb=$F6izBRlT7f($zB8c=l@`y|$0an-vb_y4 zVu{pZJ}}``+{-0nb&<%nw@IQ!0k^0shPCMwS((he(;6mmPuu?_7M?|@kra(w*T#fq@(+g4wUi~^sp^?@l{_TCZ;4^#- zg=~r-XB&f9zV*f{f|Pk)q6(^sA<^;m_aw^j*mcy+t~K~@V+NQeFhPHGsohY}|DM*S z6!g59=%G3d(?tbmR1Aaa;;d*l&E?O#?`|=E-R!dB?43K~6rT8hwh~m+C6jTMGp?4^s#pvc3s`%Np0 z-UvAQdOJBEvIw9L+Qbl`^1iw0I1o5n9UXp<`z3F?K~*!;A&y!yZK_&QuUf9Tc9RSR z)ytIBNLSw2A@HJ%k(G>gVQJ&xdafjvlq@dV2g7fAUmvF*SmhM7ghi?GU`unvc0I2) zRx5+twlgc*a5kbA;cvgcJkgH#sA>_X!Pz7r2LlwBrCMCi_kD2V$@22$?3)sd6j%6_ zVmzV<^LgF8ia?T5BmP``R2d-)qD_xJVJPHVP8T006#Xn3?+@oCo5N3P@kokLi_Fn3 zw!M4z@bd?w{4VelGm}zHgEGhi8?~kV|>t(hkmNJH0r6(l0;*|s7{A~N#gaEdl8Ge&bzk^f2mGaak^WR`3p z0~W9Hg&zkU=_`(##zQ>U)QF7+)-i>BE?;?6esItf(?7E+LSi%n*~DX7%iw5Ju=aNG zLYw4+;Sf1S*yB)npK<3;s6W#-I%uYg^*8cOB1`&}vRm#N;G(diNS zDA@RM>CM&btuv&pc$G07=H>lw2Jq;v2?{l+O!y zcoY403ORXRdVV32b6_Py<#=`9>Fe#f8%y>YJ7fnJnM(_oNf)r#uxvy-&>o0=$OAvk zSJR7~csh!kZ^?4?s>#en&K$Ko+pzpATBxRUwA9d#aw*u=th50E0g<9rv_u3pbH*KR zU%#hp2;4~D<8y0CGr5>su>1u6SVS_!_2;hF#N4)S>%x3iE|31pbcI~W0x9rj%(Cpl zMUdG(d8382)lk`1v5oLjA$FX{&#V^UA9%vldr9y9b@^t^jOKV_t5ljk7w%NUNDbV&+S`FeKDzjuOpmzVGk{^!)FSmhhC@oMZ!(*72O{L?d_Eo)zC=L zI;>~^%a68WcX`$d{_1Pa&xtsO*#TEn6R=5;F6j!te1bWR^Fe*6I$u+TVU@CYJM7N zEpN(=LBC2f?@$7XHbof<9K{Pm@h`myh zRdZfDtL3HZ9;gxl!CCavfl42pYNj=Lsf1x`y-o3Lxap?XQ=a4vtb{&Zc^I-Ra5w#y zhJY9fO&M1^@?(vK{L#m=+=N$oD{MV$l{8aL2^cP6%!3$1YA|sZ&1(r|u=WLZZrvC5 zpIXu%^&8|Y;+H2VZ*q20FO4GMXzQuV7TDfqJ5b|!Av8jHz0Zi8AU@tZJChG<*>gJA zY+PK{fhIg#d0}wSCC+Q1cO=4^usq{yJO`bhR_gpj z?>}ChWqfdr$cQnl+m9u%wVCR$4wHGeTi}Cmf|}YBB_IFRX3~+xv8xkg%E1cSgZq{{ zaC?b)MRy%lOArQqH^1d-#BA>lg#e$yBxItG{Dti;)ho0~F5T_*AKs|1;s`op%yd*Q z584W3XFgk!DCiLyb>ZC}H&7AtXo5V$j1#|a0<%k@{<0z}<;CePw-w~^-j&kZ9N*A~ z@|KOdIGZPuSb4}@j2S+pBn^s2pU5=E%`dgmW+Jmz3!$B=mVpnVX-qb6g?oD%a~9vZ zGhC3BG@D@=YM?%(IH0)nLH5&~NtfZq!hQ6jH)%^nR+p%HYA@&A(W99HN4AWhi!9zQ zDbIUhR97X)iM(~4NV*NvNO>s6f~HvSJ!J3h?U0O(`d75YvTpKs_UhlH3%w7sn9Ijq z!}7o0Os6WBb@gW@YDwj#uI8wE?Ck&YZ~s#X}YY7RCY&- zm-Ul1Ecki5vJdFOBU22!x179(gWr<8ylZWeFwNOgFz^jcQ5o!qcmkmfZnF#KRwy{{ z+2v}?MtLpfKLv?!_%!Klj}!FN|AMWSDK2Yjm`u)@K(ipOy4JlGK~ViLKdh zeT?#$kCdNIlsgfbYX4PM=*1v3y-|~*d>>ovx=>?e0Y#vKB`T&gartSQH@w7uBAe9uZH?r*Q7#(M9s zl^Ng2ut#!?7i~4V6&4fFXIUxk6=7(O)@(>D*82k$1^&9^$|R?Nz1+}&_vVc|z;KMB(91BPtnAVh?8jN$mHmgd|&%^yG9ZRf~O+bv(y zp458b*17-Lv*@3%hh2oYj7bJFT+gvH=qYcY0k5{gd@y2gGmH@zf9*SaipS@jBv3;2=|+e0?T zAB{q9{qLz8%;L2h6=U>5t~n>33A_1or#B7<2s4Ot`mVc4wB@u0mfz zE2WirB3>|OO8H)nTEo>czaDM6(4BPi?(Ul{Rfe8>kzU%d)VXe>9-#5#s|3~w67{pS@Tz3 z@T0{My6&=jk)keWY6Jx)8$e6^)FQ7a7h-TnuDY@JYHwHJ&(GhLT3tqIu6OC~G><-- z#TkaEeC~B#Jy1xuRmiybq9_)e=Q#HA_1taYa00dW1YInov;yt; zWl6U!5WXV5Zc5uNm&y9z(!~qLnmWwWgF{PY7;g7){IcvA0|j06_oqHBVSDS`{7A&U z{@r27g`iNKMh^3$K5_i*#k)3QZ3~rmrsWQsKybZ#1R$DwnJ7w$WYnpADBML(0+h*v zSPB2gT_cXiw>Jm5$Ry%c{OtogCTwjz@Wg~gz8eN(}{vYUQ}hTw9K0=Qh6`$u4$YPGq` zq_6elz4DyNj;F)~;Stxxe4gdwczx=hx%b{-Vm%XCL@5ea^v?a1IbY!mQY!?jR6Cp1 z%Rxe^Rvj(mEQ9Nd=&V!O7%7U zWfe1L`#SSg8bwGn9<^}(vpf0HSM{@ch6fMtyFbdy)ahSWoNycUEjkR^a$2`t6m0!Y z#c4Yu-CLlmTTzm$mOmX|s+o8GdV{c3A=LD3+rJua$m-AsYO5gBW-Dr5b zahDoPvQ9!QNNQZQkLs$lee2{Jyk8AJ#8UU&(AB|pr^)2i%`Y4~VKOBbOBlh#(hORq zhFE)e2F3PRY+heKKje66NzaCl3RhFVc3Z#x%Y*Ht(U7QjM%r?)Z)zi3#wmuR_pHt5 zeFbl*eXuZEFA)iY2l;*MAjL)PXb61y(K6L6mydSf@B^9TJL(sXJi4(q`bym`c)YxI zRr|)at)Ca-khC$IC|Mt9NPeXVq`r{6`qsU=&i5OZcSml9ol}=)H^gNCjMR6?@G^ip znumD_W^U&Bl7@IWJyJeYn!m;vPsHilK3A0VYqf!zEdy^>(YCAoz8WRzD zt95H`z=arY6otj`BzV%QD`KNLYewIDZ>}kRF19=c&nhoLSz!+wZSFNk;hHi941C8r z3^^BtP|e9OP3)FA_-DjRcJIAf9tIVqxHv*=It3PqS8aD%np_D}iq#7|(I2|)OlWh; zfJ+Q+syw3~)9*3;{BolHg|VxWgu;B4H7P79S&S9~nNKPbvRz$RxCUGj5z0hd@_8Pe zA52AFY3XMX-0x*{nbLqdO|X!%v~R3icX8YGR@mY0*2-!D-xZ^1#ZV_=A>NgyWV>~t z8#6;&(E<}+bsM?`2wnw5nflgd8DHSb%}itrPthn@ZYlRWlm_EIe8X&^n=kF6=(|!^ z;oI?k=y366s?JOn1yKyj<6uTvxm(kC#JCWMikH1atA>cxpew&PHgHBF`jA11EL5v=~4kO9r5Bzl!p z+@eVra@#m{%+UuH#8}{&avC4=*Q$yiQw03Wuy)OfdcCN`_33ShsA7uJEE0Qmx|ha# zZfL2?GV3CBHF@9B{d|Qp2>6GY-KwT$8PZDk8no5j&5YkquwZ{1-+G6??n_X?uO(=VCvEdN$@Laqux}>lWhHbYkxntqv7_BC6)8qTDV~t zA&;2!04drn{u^SN2iLyYc~ome+xobfq{EJFn;qM>ZQHhO+qThB z#~rI<+wRztK7H;NzqxmM&dfjApV~WnJ@r`w1Rgn=%CO2gW;3w3V;(9e?oOV~Cq6&IhO?LjL*eD@07~}2T zCdL08yoyKX<~3tQ@d$62?y+Dp&Cb2Mb2SQ%)3IHgh4eEwQ7c#Yz5objn1egFXB zk=GgsHlo(bZE;XVG3xy>-~=+o-5qR4Ea>xhI%x=1Q~7Del8P%ZmrT3qL%&`#5C=9^ z6+W??XwaG7FUY3Asdg$L$(5DMt?h%f+qQB+= z=9?s6U#D(|O#@v)kYVY7OHCn){DbuEIG%6z8I+iIl$;D|Wf?Kg5fE7kLW(zwXd5&A zEqq*EK=?Ed8DD_;a-=B-xe8#Zuf9?aN>B>FC^*XR`2o7t)*x5|hi*#aZ zUHSL=O#@V*k*^Y~5EE>3QHo-8+sOhkw30Xb8G(p|xL4C-GPCf!%Ug)c^alkp_=W+G zG7!W770>)!x+4$Vl<{6~zDg7377Ah0{e*pBN)~E`YHYe>>js&S>L9nfS?QmX#fOlA zqT0(yjcEr?U}XvEUQWWyv(n~mz?G5j7WOG$0CpH}capNam{=wY$LHep+cQd{_d^U{ z%)-Xvd5rDWl_{&J5HI=VXXWp7jopbKzhKW>T<&vhAKRV_EPsTFMl)jKi0%)4*VE$> z_E%W2>}dC=MX~2t>6V)@bFz%r=*Tx;$gapf?jFdFEv#Q;wdGe!QIrBBH7lk?FHq*( z@;ZweJ!m5oA`NDWf&#)PGZa~FtJ>@oHRE_oBbiC*VVX^zx3yBZ+}V!n@SJ>HFRdi< zM}nrcl^5VA%Ja>YbSdg;v$J0!B)xxW(wQNrl?*J}<_rnYYwZIC+_G)fgxPNn%kRs~`CjQaI3vsY%k$eIayx&OY=|rx%aalCtub0kQAfHO!17A9=fa` zpCN7b_u4Z!3I@YNs$pcyY4*Oya)!YTbrMR=+sSfR7%?al6(ix`woYN{v=;9-v9u{h z1-a=<`sS+k)B1`jiIqf6B`PW(aXbuHfkdpGtsSz{LRk;W<$BF7%40vCwtjBbet`Wv zQGXce5ALkcqSvb~pIED)n*ij8#mbp`Eu0ZcfYve@q|J} z)jo@xuIs;}N5v#ZgqIDl>r122;>1~3J)yy|RfbWda7Bwau>N^SEZlI<4|luBkYjY! zSuS=Acl{L$M5%9nW@@b)AV734CK`(7$+)P+yS~;CEh}=$n7C)D1nLF@im=GRboMsm zIA>*kdM)GOVKKLmR+r%?nI1$57}QXiZb3P@Msad(XatTu z(&~-nXv$Ab9;_NlY?{ioEMg&X8MKT;1YN9U~fWhX*?`;IeIU!ro|$nq=~eJ z_yzJ0uTv691y_(ijg5G1@3WX9^<(te9Qi{D#_bB0ioub|O3 znj@)K+HBPB#Ve8;E9S)2hrPbhpWTR{jn0L9SdMyvW0x@Aq+y9(#}ui9q}J+5^RJB(0-nF)%Kgi2-5p^aO&a3Jyf z1hN!w<)i=XHROk5I87Y6Uyb63UkqDYx(@0h0E$R00o7K^s;@z8D?rzGiL8b1R-c4)4Vb5{~LV zILwAH>k%o2!zv|X1t~fzW7%E?s=+RDF~qj1_{f5V(?W%&<@W(unk7PKsLE ze&u}KrZT?6CwKC69(~o&A0NvZsvcP$J#Gy9D9yL^5?1M(dDzvB8!^n_X?`zOLXk28 z?h)~~M)CWm5=zYFO1RB&@$sUHYZyF=3@<4SB91Q5x+>l_{TCBtr zX_&$6pB>vE?b4|nV`NFk5(HQ{Ncq@e+*he+;&X3flon_!!2Ib-2c80nrn zDF=|)S)w)7GUQ*`*YY&7a)3kr8x-g#a%xy+`#_e|-9u-n6hW;I3>0VFZ%gsySh3b^k z_e<-DRb_m+l;n!#^F^HvqUWV{`wR~|x=j!U5muZx=i}8~N}Hi{^(rQ4cb2mrW`5sM zE+B6NQb;jSzlxv@dA~&s4V+d}98E?2eqaH)?fe-~t`~G^96dtWae8lE2}HB}h8uat zi|gTwE@uhvLAiy}f?iqc)G-X)xWLYChWP$0gs}h!)QPIb^~E37oged4Y4M@)CnCsM zAM4|2xa5G0;S*n&OJL@iFgTvDDi*{?PntS-)jk2Bp_aMoHj4&E>FI1ezVt)Q*^mBQ zP(VDE}8&EvSM&3F#|LoZ!Vh|at2aw|A$yu|}` z)Y|;i`+hU9O1qr0hOScUig>&)Wbx$Mj)p=l#J>sEs|2u z+4s%KLuJD6jqIWUtTUEkipIjO+kk)HbrQ<$piuM%4OR#dmZWrBd@V;h+InsJb^K!X z{4rOh(=>DX%LFEQ6L~2egSvodfr%nyUYeUan}ifunVQt)gs;}JC8wj~!`y;KBeQxH z#P|t%6gem7R*uq)F{z1z@Fz*mesCNf)ctr!_wVPCL^D%f;+oZ2Zp`f4BM>GQ0+dknM%pFM-xPfE{;N-Dsb#mv=_K_-;#iUR_D-O!Y;Jg{07VHq3(2zxpGA)SD>a5G6CYe{KSV)vJ?#%^L zl-0HMsBV}Cb5T5H2_RO7tDm7R%*oVL$~mSr1rIfbE1RKZBwRnZwsQzi`?KH$<^xe~ zMuwjA&F;>JQW}4bP@Jr?GEGzyr({9_GjOtHCuFFAAvf_i80nrWwb31#@!0Sx*;tz1 zk-uR_dW}#SnKk(`k^My$Su?9kt}4al%Y?bWj>AM9Tf_RXAY#}+Uw$ZK7@{lQEwzv; z_;e-=E;swbJW5c9h1_!abpv1hBbHeWKLWZRdGQi309CyBvp5jxoo+o? zA18fU-!gG%aY9T?!8U@OY-vTMBm=X6jaQAsdk1hUOkW`yqX!5 zq(KGSd%gMiQ!t2t@4;Fv6$L+=SL5(^$w|4jPZMn@5^_Pz?~rpQ2Z=sxY<3TeL%468 zKd(x5T1$$hvvRmy-0tkJfVv60Z11+4TK#KK!bcewC>@J#pUlh9Z}})17+n@uIL^Y? z2d>O?jGEe{^n9-N_GM&Z)K{@cO6LP_i$kY-)lu0}LSR9+9a+(h6zph)!m-Gk>FWZ+ zQ9Yhhus<$xjI!eyMy2di!Jr^!&ir7w?ioJnJ|uFo8CzjE>;VQeu4*}3#8NBiZ0b{9 zG4vxXpwaq9?^9=s(|$kcQ$d3|?xU7hX2v|?VF{ba-I;a;tRJhyd|x0TF}eRs#U!cob~k=Pz5#?tqErVUGSSX2tIKlmNoxG)Y0sF#1*Ou>=e`Sirc#sn3r zR?eD&Ec`k)QPEd$IhOJM-pkeD|&3 zOf2OVmV-59!K4H?@4*-TXa>WNPe!A?L};rrg@XbUcnX77RZ)6xcqkL-#WC*d`(Z-8B(Ua^&%W!)wLRY$kbJYLHwaRy#q+I(57acNPex6&J>sKv~{keg5M zOh4+v4kjG<>$7TuDdit*+r1WS@<*iapDQR~aBMKWSNq(A=BYoQN>=)HFvm zNGOmcC|LmGE3WkSa&bFKvr*FNr`V^V)M~8PU)rEhwk&-*5oy9~p7ZIbu(J?!aBcKl zK&6fgS-Hcp-asu_^(ow$DyvSdX^YNO3XtHzENM^8jd`9$p}_ksdf|PS|6RI4JH0r`&CtlC&k|{5>!M6w|sN zToq012mcH(sjPOM(B#X#hm(ByoqII=7JB@d(3!UH+&Pn;cIVuT)up59Y8CbbNs#K? zP>NEWt^H^5(n_FhcN)-dC*th!u5&-N>fw#&AA#4>SjWpE)<`ER45VFpc%JU@ja+Z~ zs6EnItSnS9)!U!?(i1h3eT0~;meqCUy7y4k#7e+AP8JslFGXp~zmwweL_Z3PgycZ= z=>CMcuT_Y?Y^n{zT{%^Fod4c+BHxz%$U9!+y*#%<%k08kn$3N@Fv9;-PeWO1Rwk5Iu@9 zqqqGGvYum_M10C3IV%?(c;Ru@+L-viohK~!y&t_W^I`uKQ4^xh(9q@bs-%-k(TN;MPwhL`}OjlJT;wNKXH{PSrol5^=`|hm`<8!gU-yN*%zI+ zEtGndw3O-WTY@bQbrXe!qu?-B^9d!@XLAQ`F(gX{BZYhQ^QL%}{ID_m@}NE?rOZ=B z)K(?|eq$|VzKpoUqNwf8?RsMrZ$L?>Tk;bb;q`qw#pB&X(k&t)27*iO1BU+wdEd|a z@oW`<4Bu`sfNt0x8Bs_-VGy7#J4g$LSmmhk(t6b-&_=PK1&SdLC)af?Dr!tIQRd8! zTyDpF27O%Hg?egnoV&D_oc44U8=FO(xy(3=?5;v0?g8M}-J5}Ew}=Z#4cVKg-W4A; z7aj`bxVRYfX>D-LgoGG8Oc-vv;GhL7s0sxOF7gGab$r@Dfgg;(q^}GCfC#UxdIYg3 zMJ#|VJZh?uOyrq#r0vNyWG81A*zVhh^kH@>O%}|Yscaly4udfHzN|mp-ejumqjmv9 z(B$V8V)@7pR;emoxmilg!tZ5VBvQTQzPvgmVY=BxX}O)yp(emtK7h$g&nNW%6i zaMa8Nyb%2JHeRk@wC!S_op&_aruw%3!4`q1IjZX-RBooeE?_q{Cy714;>$}r!T>KN zXK0E0W2$LFP!lf@z5Jatq|U|!(%NABkEp@P3If>1;9!<2 z*eb22y1Nj@*EX4Q-B8Anfx?p~ro1_P35gALZREOx?+s(V9?JI3NYe6l4L z?(=C=EE_7ak+G0P38lFe5fLyy!Hv@0XuQN%dnE1z!v_b2tjtujpv$BLlZr~zbuFUy zxEN;ghmXl(HJx&BFBOD!+b%aX_dzNx|Z6>0({+;srRZ4 z9@nqYIJIMQcgJrD=gRIj{_3#V0+5(cBFKvDxyjj`5YRUMCJfz{JR9{0D3FXVo85~Q zxF*CaT9^s!Xk6s?rR@7RnFSGSb1ux9C7;HnU~A%1P95CgOIG()vtdxR&H+IMoq)`E+`z_xwdCi|x4?4C%Vq zKUKhm%=9+cDjOghOK?ZLltYDRGsfPS?;8SKoh-)qurPz#Jf%4XM(T)3S&kb#t&syl z2*6aXJu%%EiJ*G2B%xMKa+O4VvG2>2D&aywV?bc3O3L)fmGVuhm7*QCpa(}BbMzCV zbLB)kA&&Cp%C+nHwsuJ8K#72q6$IHtO0lxTo`AbjzFnIhG!nJO@~$90?C_Grp2I|_ zmqDgb*I_NejT0gM=e4M>akIty_p}@4Ecao{$1`PUaXOh!EE;<_)-zJG-UZ zcLX!@^(g^=6IpW0C`>K1>5vy;Ci_d_XS6r0IRCr=CDc|(C90IN_gQUo`&RimiL!1O zq^4jQGGV0wf}+hy^-gUCO7W~y9EI>+prGpxbC!y7ALd&8ZBiyGqj2>BCyHD9reI1k zGQ;QkeA>zidnLerES);}-HJze%Ihwmo=H{8C@_n!F<2%Kj zsaays*JNrlnB2ugmEnjYh(HwwFr1m(~edk9wJvQ zXbx8Zr7{fH)viW%EuQjEeX;WS6RHsAuMh~2=@f-dlaLo^l3;*vs+L5j!ov?w5Znsy zWcXk04V}6k55Q>J3z%Ij-_i$zS50qS@nCW>fq_f67oA(7d!QM$<=V6I}Z6?LlX0Q*_`IR<92FPMX+Agx>k?<^^6VXf#XXW?sHJC6Ro zwI7qWY6Hjtn27wKA`m6;`YPg{ny$8Ek2uw5>7*=Jk{z|%qttw$oJ8*PzkKO+zv{44 zWs_l3y4p6Zw=a@S1|$3?!W!9EWHlMb4* z&Sl5N=rykAHOY6{K>c9Fhx;9(Lja~H6_AyaLScZ}P!m+mPTI^?Pb%ly2eNX14dALk zpeuBg(a7~=eG^$?>uOd0uLBPx##!>sM}L`XYgy_MFOCG zJvuMW<`X_%Bj)Y<_Ief$K|n)u(~dwLeT0DR(aayS{xpv9)HNX3BweDEb6k(iSCzek zi-Bk@px1=AvVm07P~*(B+EHE3URPS~-)_^m4qP~ST3=hktlB5In=JI78xVEY?DnS~ zRx4MS8#Ys~pR=Z8zaYn$1U8DAi;Wsrt=BOSq$w|?gLfWd=iT`LUs>VYI@{Yp%1on5 z-OC0UHp6s|gsJj34D*{`rg|MTBy6mD=pCG2ueju_G+S(Awv&8&!-APOE(9A-G^ zw4)18?XRw+e-;ikD>HA(OJbBNpR1QAj*IKvitNj3Z0}{k>S43EeDc(thi~IPY1V1r zsN(J-#Sp6JpXVc?FrO)>kf;*8Yw^34@>4RwNT~Fj+C>y z@=5C07Sbds0rVaPcI_J$P97#GD8*-i%Z)R3b9)_I&|_dg-$c>OJ`aCZ10gJ|1!>r^ z7#Hf=K&;ogH(fANQ`W-=o z<^+>t!;+dicQAir`>V8+uGPZgocfDr!&MK9(Zx_m&Zj<`^7_H86m!NKbnANMF4(6V zD(L2US=uOd(<>Mp?VnbcG?QE!oKW3C6ND>hqK`ASS(o(5bh6C#~MCY^|`c1>RuS>Hu z8oyR|FHG?nUN(xhEjiW;TUcoyrbW4Ho5V6fT#$gJvvkdUQ#{xd2&d86F4` zBsOPs(s=;rF}uQyi!+N=pskZljH5(&{Fn_EECaF)fg1pjKtq_!OsZsS+ap z=Uq`hf9{a6yoKkB{4i-|LaBhTlt^-5C)YbvqH+Y`1Vq`i3`V}@`(V;8w8)!Ir3!?i z;sUxi0~O6z|9tpR;VKCUL8xP~M)TDIoG^X)HP$-~?$?|i zw;hf~;B($iRRfEQHIea}m03<3ywSXFH=Gi19$uk>g<32Ea7kc!I781E<$^<@Gf>6P zUpt!$AVCEILGm>KC-W3NoG=_<7#^sG07Y>C1X!`t0j*+$H>!^O5@~Bcu6Be}s(?T$ zO=Xxj=H}=2_#xsi(K}>Vp7Fb!j%~TIb2Uu6yT&f)mBG+&zbEE)k@%}N6YAhoZJHL2 z)3#=aZ)!2!exbox08h{%!(?IB?;{EGBj($B#*!Yn9u(Qwk0l-Q>+q3HN^**=v0=ME zm(89U;UybMXr&F=inR@)kt`|U(*WS{s{urqTcc3gkTv7I4zQi|wceFP8jJ1!#6V%e z@!rUBpgsaSr8d>LK4iA@1-Y|{O3l)1t5iGHq#pr-qUSCv-Xh_t<8P*bGEkI#;H%^!gbF?&BfZV)pz1<>>`oWGrlj%P7 z#=xQga#LOuXBe^HAR>VvlrfI;MxpsG@b32Uz82)ENECDf-W=ryE^-HN*B$fL>trg5 z$Z=P!*&IQI((673MU!1A**mb-3rcn`v!PDjlML~m#X~(Y+)goEleT5uhKD)#8 z6WUyVl`o81r-ZmuIejhS=;(O=>NOS!ZY~=dw1+H?rcWm*s0IQCs*HKXo{-7AMjqvs z?z$S<35HVt2vW}%(3es(++Rg$L&O_?Y`du(N_-k40WPga1FE8+xT$tw@1KM9eoZ8L z=QcCjem6#?}9mY3U4tw5~$x?ePYTCH{5mp`LrEvUWFnE5lX zU$%CP>X_gKS_iD~I!kqYHOiaW?WundTu-gXqm`hv{eHIpfuvzTLD(%11zdXK&JKTC zlGMY;JSi%8HrCKZe605wBU5vB$#~SPEmTD*2pSKM6ax{veJK2#Pjh&i#)_I+wxU(y zQtFr!P!IjXW4>X5R?J`6E@K80@gnPyh>1G=Rm{wwH{mwFe%vM^_Cvp8kKO&|C(Wv$ zZtP^+29+TEm>&eWnhiPMCifR|`NdFi)6}wQJW)9dv~)gLJ|J?YA%;%S;!Xh*-l-rZ zFlV)v^yE=KMZ`W|YcruQRSOBP5KbWHvrkEqS;Kym2Uq=ues zXKw^eW=L-$GtYvO)CiF-6Q)&_rE0*y`nLQEvp79hq*7)IQvfClx(H>Dg3#5V0QPMA z^}U;e0dyJM`Hswv#qYL*hkx4l`XD>KbEJG$GDEXurp`4wTZC!is7X>J1hg4s2_jq1 zuG!afz#n)NOtuheY`SM4OuVO)6n6WQrSdIC62lE+r6V zbQVP&7Q7I2lx7=&K#>sy_cMs1^t)AWVVRvt=cpn(QBJ*sMxZjjj@xcGH@R2)=TA%UB2bi8V%Uk{n{agTH+X=uszP6 zC|O!|A)@IpyW$n+DY_$MERb|6M=uxSu8*Nh9rr73jt(SdAU`jQ8K;NB!72b#OTiOC z>&dHkp1dHHgw$ zlO7*WAboACLfvm1YRvZWINT)5el{~#7bYa{4nGL5!f_#C?dePW86N#DpE*6(SCqv4 zF}-r5m1I)e)}W{z*t>d(EDf~BUd%otXPIE3Z#QsP1?V_@CNVI^xF2vMNQ5f@)5tHr z4rXoFPfigCUQir#f_f-rDJl#O2HMG4s<}4IcLkeA3-nqhn+9GMHDpOA>)C8MRxS<+ zIWcw_z>JDIJ_;Sznv34DSb|u}pRC$^vKn`k zszXP%W+9=HSq8m+1(Jhy_uvUSr67-6SrUfACP_aB5&`4A6lQtvbOw33LYd*0Dl z#;}cmaPrhwsTNxcnw-tVbJj4x!U?<2F)3}HWYN>xbVA(qzI|t7{JqOezHdLHWgiNi zhJx&@)V;c~3FOro(Y^FEqzWb1uz4fMU2>eC^I_bZT$20Z8Oi$QY>VGiuH|9~#F6Vn z1+ay6M?qRmliRToZ61eJ6Cn5zSg~(;hg71QdOan(>~<`iDJ|FRVz-&s3I%DDx>9I# zVV#5)+3gmLVWHu>H}Dk?d|=RE*O#Di0|iWWj~j(7#6k9OWQtD7Vr=g7^4ri-uo!iY z_B{N2Nb$WsOM;IrTU3(KnzJCR7EGg_49KgYT!co)Zja(D6kG_As=u@hC7RwrfX;L{ zl26>yHXAI#H%WH<(`68+FAUY+e6u}fQUTz!fK;3;@7?U;v#;2_6v7ArE5nIZNxXAf z0==c-*G66%>O{V+6)!l2Tg|-VqJy!{{X?XMsX}Y>1ycU@OkbEmJL>W+`&vI zeL=z&56I9MAu36okmiB|7Ie!@_$pQ0d0(nzO1|6(Z8q)5E5|qW?UTH&!^6v$wK;U; zy`*51;ON92O9hV*MqhNpqx6qK0(B_o+-M{D%wzY2p5#=qW<+ zVDLn-frIJ$$j0$n2$Q?oQ8_E>Cu{FWMb0o;xlSe3xHEqH-@U!J~wM0r_sD ze8oS9p&%{*Ao&-p!+A+0Y?Fyd8)A&>^C#I7KtC~Jlmy3S9UU=jpv00~dO*6nex)QEI~;|4~%izfJRU;?5djIaC>cmz?a9AUbXR98?;d94H~qeiOMkF~xW5 zXw?T`s&^8t=&0-Fl;g*C650-TP*!=ukb~G@f;*3VkHfhA^8S@vI3cvc*Zw92Y|DT5 z<`83*g;kJ3r3?mVgy2YIZ{GzD8&fvu)>fIC)$qJyv8V#U0}TGMIJw4~b(C}8>8!gu z)pK0fZ#;i7xw%eUjVG+1(-ydxf2OSseo$tw*+t41_%xZM!wTa^o93;gqtY9u;EU{a zh+GB8{ry+&n$q(Oo6!%wfTbBSBBg1^CLukeK5B%Adi!_fYBxdV-Rkul!>T@odb-iY zz?E70NMm82HVf68VF$b+)(ZvT*>A0~p$GlDF0@6G+SoVnE7h5 zf-tb*p3o(YqfANcA%taTpV)iiZ1)>8T*@1Z>+;K8&U;lask77sR4seaC>0r09^S$8 zXQiJRhT1ZXP7)Su#OU(Z=VoHYyqA)bW`Y&6uE%B`!1zT3FY|*>*PgR?bkx>z;gcHX z$e{@c%FgMS4GjE|K0CD*+BAdMw45-g!n-R{v$D}bS(f>0m8d&3a}@KAqD>33fCh_` zmL%qI6k(v*3L>wClJ-O{7$Uqn#};;a^p0)g9M-uA!f>>htso*&TsR55ZhH#*p0fT9;f&zLbdZ zNrIW4q(vvoP_Hk?09iqM&EY779_ii4`DE~}u80zN2qQ%1Ap4Hu=9|28UzfeBXm-Mi z^faJ9Td9dSXdKw&b7<`&3mO*vs~){&mA_XFOoQ7=in!wGz7-xC&Ui&Y*Jqd%zMuYR z^o>(A2a2=}r&74=RFU`tPdpc*jPTN0va?};!2Sz1il&p24=Pg94_YW$%BPO-`4}|k zX(pZF9bI2qoeMf1`)tM8dk_w|uD3=Qg+KD$vYGDCWA80nTYmAkjsDDbCld_sy!^He zSCo~rSU4==|#Xo z+k0Uq9gvf5D399IfND}(xfDS@v5A6V*#^VZ6lX6Rym7R8N8u3jTkAQUT|Q6L;A+pjP_Xb@4{8!QVDQ#K?G$r8O~zh*#$7+UiS68Y?x5e$L>8{ZT#= z1R}WX$x>r@b{>_KiRp~tA&ruZq}OAQK(UK+6|~6kFdVkmV$e}X*V-%CFyKzHt!)DZ_^obHGUof;oC;YWwyEduQ-=a8~ z!gIY+gZnuwCGd~zw2>Mun1F1yY5j>TS)GQsBt%l=NRG_hdGckV>Y7_OX4xa>g&7hP z9SfYYv;vROQTEu+T|o;p$j>s2%K2oA$Z80Tr|Z(zFDwPzIC2TP0Ci429FA$lt~NJ1!WPD_-@@!+JkKB zHN2I>gDDDKz$9&eo=NBDD|_>0Fv32vmAx?Ug%K*Nup2uLfXdR2t(ZKRsO{M;jd!?4 zky4*fU@&RdOBj#pXNRAA7DmFwnZ(X7#rFk=)d?ooQ+*II8QhMM_!z0<`$}T&O>TS@ zAP)k7c_cY(M17#$J?4h|kF2-YkyoH0hP&XO7$(A*VsyKwUN|y;kP!vXaOWKq`R~um z*}0(#eOyd;VRy&)RBbb|zMTphO`URsmQD+gMWSS0S2#Eu*luC-Is7iq%5jbq$Ux!F zMMa$1+8d~zzgJ0mRG=3^Dx`i>P>ft^^Vp~Y=UE$3q3Wyi-Idh1z{6clN&T>4`sl(^ z3Fl`!#Zi#U{7+tlytIJMb$Ldv^404H!8<~(I_^z2KA`GZ@JayzkJ>bEZ-ev%U~vSV zFX2fTCLQk1vNc0ZdF#58Me>PGRZz@^s~# zbZZ@x-H>87d|eLVZJ?y`fe3R0K8LoKY*5B~GoD*pjmr=ns^C{0w=_jKybu(X;QA># zodu^#hIP2ssTS#}tnwAz8kjr1f9*B1X$w*si|BQ>niVn(gq~s26&S2S`3@OWwY)S& zeO~)6$V(z}j82ES4&y7oKhgd?mnZ2dze3CEqL_1;WS2@spSHJ0n63!dz#EAD`tdXbS3tGyd;73#Zb%|u=*O!r^9U&1 zdP6hLCv$4e*LpCNYkj)gfP#^6>0wG0Qf6jYgX{cw>F1;{Q)7gnBX4>eQ&$8B=btu9 z@A_Th>KWnrwBeilaKN{)p%yCEg78RzpJ`s;t6!o0yYetmL3)%dL@bIFCDhYJDVt%U z9O2u=B28VVe(NHhmg06iu8-1TBjZf#?Ixr%?b0C z5a+Zcg?AXzY&4vjWzV~9!L0G^fY?3h)PUXn>{bZk$OQ4Ye)OIr7&*rr{%UwF^}%+6jYAQj4Cj%Cr)1 zPiD63-_nGsr55VxG-Z&ojPXf#hQUO4gb0GhrU8wS0Eozj6_v)d?&j*Pg6HWg3pYhq zy@FLpUc1BnzT(IDwEG~Vb~1>_ZU&lf`&O|*tP>uBGY-R*ZPCY^d|>(-bm5#=cUbN{wI9}uNLMZn|@ z+&w|4dbX+;u4!w*jXmG%D8BhuB}aory&QVrA_BBw9)khk!a5_$%ahh`pH4GKB#@Gb zC<4(V6#@c4`dH2tnX0z;l3D!(3@i~~_OkZt+%Ihr9D5T=C?~UPayWQAPwoU;y$LpV zi!Yrk2jKO}j3Rwk?X1C`C&VHH-vP`#!BWuOTDu?-;0Xe!L?NM3(_Qk%82aEMy^gUh zNN2v3h%$3t8I%u@O*vu}^WoCPUaz@MY0KF>{%Yi=k?mqqvbVIeiB` zhI8N2iRv(ZNHn(+4T?c7=o3X^>qsTjY=8T_Pd^kunIa-vNneK+oT(qk8*jzy&;RoP zAczh;9PkmTAYLE7kChNx3KBV_xSzgh(YIM-gdPz22ci0nys0NS;NAv=wVF0Tek83g z#~e1wfmms=k04@?*u((;q0350wLx+NzH=ZXCafa`9<00{0~Pm_ItGe$u0s`X?=Z^p zeT`8MlyJBlCv&zNTN`Bg@Ld}8r$%);W4iDetZ2+2xBK@emz2<)sSFhOQW>7d=aYMY z9flL*f1?BW@JIe1em&U_EhQfG7g;^~UnUMV=6@MM<&7L{oa_yZ96n5SzipZSlCk6c z%i}6wZ)3}EYf^20zVX!K!IH2TXd`rp3JLgf`}Ocpq=533E~lCjx(>y5_gtd&12 zIRU!R)~+6$vk^=jnd9Ju9Tr_5kWLx6 zVRk!6iGecKciny=gMlQ|`Z>PcSf)a+wSL{km1tDcC}~3-N3eNzjHpe?0GdnjID--g zpwU7$e%DijOV-dIVc)1bV1b%!Ycp)*3&=lzPvu$_9& zt(w%j>?3n8=8JH=z5szCSn-1nQ+fc6Q(?DLo|br4%z?99w0ynX<|=Je- z8c{iysSnLt{OIijrR5LR09;hR=~4Ez?R{YEExH+-&h}6bgVFpYw!{EI-<6>GAIFR z?4Z4UxPnl4!+3Wm6N?Wy?&iGB`xq z@*n|2w}9T$-CNng(J$N39MQ=y6MK>7AeIx0w~gDENDlFn%kA)BU3<4| zY4a^PCd~!E*hnpMD>{{I zg>PMTlPF{lM8?1k(C#YZ7>~%VddQ}6^ad>Y?A(AOnoBN>^Aj)FR^@5fy`&IY)w7Ay zb}Ro#I088&slg(2r^jUGQJ8nNSh;ULahVc}3=w-ui{QXjM#n5!D(~}li%KXl0VHY1 z48ysm%24x@&^oZf4=$U}gE{4i@Q!5Mr?sp|jrKWPAM;Hw0XDUczxe>#cS5a?>W0!N zJAcN3eAEt$KZ!K+LTe9heu(Czd!l=Tv6Ft{m?Lomhv%b-AyUb7UOV4@k6mR28IIC= z7qqYD^^Eiwf3RZGZoa_%_VkH60DHE0K)310EnZu2vpvpb_7gr)2*2)iWQIgNwaV-) z0B5SsRq0cJB$YPIc9S_|TxKQewp}Yxdr@Oc=5@_yiFcF-$YHFWtP|bWtk6|I9!j!q z9RP1}dVsQpOBJw-&me5nOHx>Cwg={%4#}t<40CqUUn8`r1-r(F=h}a|OhxuA2&zG1 zzO@GWsF1C{sk8Pul(C+l4*YZuVfw;C(Ub4QbGn-Gp74&Jq~)DGikk;O_AOpZ;?z&2 zikdJ^e00_22iL#@+~CPio$D8Gh#Z1>#m{F+#DxgvEdyWx^$|{*>KEoL{a0NJJf8r% zzG@r%-%H^C&=>!!D*U+wGX6^k{ogh4Uk>U27e(;5;Q6=N`FE24?P;d_U28w;=C1<# zx0Raice$neU1aJ0R+`iOZiDW3BY&3)y5G(G?Y95hK>v~2f3^0vg8pykI{n|x(Eo0R z{&zDU*5<$d^>;IWOSKt(uMNZRW*C02&EMYWzueCs^6$Tu)eOIz`CAgr@Vl9h+WD)| z|1SA|NBRGy{qTP>|7o0bAN!V>-7Wv$3TDW zuKyFtNJIA#CLI&gKZ%ry?XRu-3;svwU!CFKQt6qQ+5QQYk?A+}gZ^jguRi^6sf_eY z%>RV?adiCZNz5PgKU4qLi1qL8`+E!1voib>>c?UK7xjbwXX^hNl>SdD8x!+C+OM<> zzo{SeKU4q5FcbR29QfCv`d6%M%nYpmAXX;UzkAaM{m<0@mCXMqm64H^?w?RUT-$$* z`akG@rvAIM^ea|I7FO1O6zhl7@Gt5I{m;~Ymze&hve5pMSQ-ERh4VrGGxgu4roX5k zIrtw@KPt&zv3}71O#P3!iH(K%A8p}}68RVPgZ@YAUv>1~W(hVHx_^@UnLZ?!e^Ec^ zf2RJ&+{DI8`%kEhY=8Hr5Bi^}|1meQvHqhv$H?-#H~pgjnfjk|6DvLaKj_1Z%)fin zFZ!RU|0y>yGBYy#lZ?p7_`5g#qW_utpK=o;0~_lL0}>COS6yzmrRRY|XDb{0sV@qW+qk|GU`4#7g(~o|WY{Yx)KK&r$y< zHZjq&G5nqHm67>3YhwIB|8vwoicP$rbwP4pjo^*7=$1N%R$=>z@GpY;!86FnpA z-}z6+!1kLp{eu4IsDBun=$ZcBv$FhVO~0W3IqDzACZ-Sa_3!L3^KaI~@PYp4sDBun zK2ZNo#li4V%>QD;3?Jx!iu&=ne_vgFc+OwXU_QPLe1;F6;#b%Y_&p^Ppf3?=Je~|`2U%G|6MGj{SW$`jfw5A(C-bZnx4xd@Lv0>WBIey3JvAY z`LyDa8iO|YhXDy-7$7PHMB#zj?@@1CKgOy+fCTOG^n64-FOSB)GNy3j!Rd6w;p=f> zfw*9Q+@buk5ixo9%Jzx1fjAN^Kow0HAR*k9O-?$zr~Ib~(B53P-=)#UVl)ycoj3L> z=DGA}GdCeK^@K|ln4Q&3_(`|j_{4T|z=EOke7{&W^EbB;)As&i+7@LoH;~P4lvQsR zJr4NTo^Dq|PH6laf!-$cz+RVjlT^4b6Sc%qIB7ao10Fcdqu?QNr$R?v<_CiJS%~^H`;(7%bwlnp)J@NtI^Mdj7G`0wNni=z%I^-r z%seF5$rVnSHmf9o8;<`x3;UuiEXYA-g~EJ(rS^OZ&6%MJxEM1g9Z z?VMt0S8pw_EPK-w1J2gfp~|(`UacpQ!q#$}eM&mdBjm_ejBP41W!*&KOjMIVylt}m$8L0c2{i%$nv%& zm#6wE%hVws=Y)u21HHsiRLGVz_{Pi9%Of2k8mA*GqJIo1{h+$gdnuEfp*NSYF+U^C z#e1I)gMrZmDmf4cL?>7nZ9v!l8hS{QyOH`udJmg8G!FlcGQ>>sZLlDx_8UM-nn57D zG?oW_I$nav`4~Inl_+sUwCp5i2nK)5^3Jzk$63T|^de(XR&r9n z>EO+8vfm82RRf#^moS8{PM3(Y1Nj^~h+|@w0*Npuj(#VKCafLxB46SVxmTJIKFJDw*j^fk|B)cEZL?V`a3fPdzhm{@u{9YRcWLLVnHgkv<8Ot>QMTjAV$m=;I(FWNU#F z<795(HljU;(zI$w%kiy--gR4zDKXhGN=Oz_eMNthVUFrtE&W$5DojwV1_k~>y(<#$ zUAT|w(mY_+)o$x*DCzPR7*|f3Li?{j)M}^sHo(~oA}vg00Lfu`v79yxV52;!vg+t} z-1YJG3g=TmyeGcdxjNh9Kd=aupNw@&yP%e}?X5@@)gNCY%B6ey)3CkV(I8`GP^*Y= zN?1y~Cm!r!-jry`saG%`w6LmRe07~X#Y79c{gNqPO<$OpEVn*RVr>}M{}d(O0e&kR zb1|I5vg3**oW4)|qFr@$NP4|P=^rctd#`(Nfl7zuo`n+LRVwbYVl>8}@^RrKXgmr1 zHMr%^IxTykx1N{oo2OzXM64a5yOO=m#BU%o{S*TksxjoGd%MBIS=*zwL3R}5N_!&r zmck_48Obril8i-U`f?+&uYhaYOb;x@xICHi%xdw$U;8-Y3M$@^O`j26n`&*Af(eD{+JiFA)Bch2QwjSb{SHjV%M$A91 z{J?SXnLvciw#9*+-$La!jjRtVYfWeOCh7;T4UTekxro9bLzMAOH;=bIeaT6iW zL2E-*h_iA3?4aFjL6rDX(fC?m1c6GL{wNW~JSDs*m~`~@ox&~V9&s$nQpZz!te${d zp}*0l@I|Ev{1S_sYjp1zCG%y0W4QhaVgw_yCQ2_}6>f>>bzM^v4dqGb%sHBLXWI;H z4~A67t6ppFtIXJJycYw{n|rWEPmn806GvO+)4lIN{f^GWgOp)3f|EA&0Qow)EPJbN zP#MRI2iJoS0OxY`#D8u0F#StnujKx5aQBDW;m<@5OuzMCU}*odA9Ek74?txBh~Pz$#wac7+Z)`1}clYXpoj zuhYwV9+oT?7j-Qh7ieKzp#?$?c--4toE?J2kWNq1gZye&@Fz;6M-89cy3%(V|IK2W zc+iw7H!?hn#w>yxMHCpRSNTeB8;H9E204#8OePXhGSk}%A7*R5>X6`!Hwz63GiG$F z)V{5T4O|X6riX^YAQ+D+ac?%hINQU-1 z75YpB0u2#4LNG?fBArf07ctKmWWS1o5!x@4{l;g`F<74a?!^`L1^dR_2fYX~6vEEq z4nFfnK3(68r*A)J9eE`S6z^KVppPc!)WQF_SsPal`k)0ElJ$Dn_2OPrger>8(!BJC z31eh_WXSWG7?8S5%G9mIxey~dw6Y+peD@+H`aDJIHneXndbE=jJ@Ij}_Isq0k2{{L5!QGUH!geko-BrHS}U9{t-Jf7_@2O#vv)M8i(Q@-fIv zM4*iBkN-9;9_p<`d7;{#*bbt^9S$wL9OAl(EX--`akN0eto)sy7zDW zieHz)$o#=%{^wE{XvA$Co%BCMOit#uHZ-;-G_rQaHj2_Ta{7jrAEE0nFYuRU%13kI zqoemBY-0HfHPycDuktF||Kkq+YGnW1!T*Z@`FqI~tq9YH{OUK8qZMKPXrcaQ%Ky_r z^jClQ$KwAZh%z!TvHX=Nny9*BvnqnhO8`WN)pT27lN-2R|Hm;-vGtAAbTj zCJD9!p99g#bItn(t<0KR+>W;XXTH9(vZ}K(4(GOIYn={eiSjk?ga`LLpojdJ*%GFC zZ?oC67I$ZEqB87I%#vIy)@tun3ujgn+>-2oB%%=hQbD5^KZ((@s z%~fd6wfS%CEgH{X4Luh|UuPfpifXvQlVTujH$6V7oVJ>+{&eNF_FlZ?tZKfBKE0() z=X(Xw^(pCI5aA}nDbc)LIrl4L(U`MHu;7(eN_-G6icV*Pd?8CPt`FlHPE z%`;zuZ|-sST^Tf{cG6?Tpkm}5dSIg2#ui%{pF0cV-X4138`}gpz{^zzX28-I3tL;m z+khC)0yq4*qh3~|dwv)!W56qwI8|GXgt%KQUp49x4aNdJmG6n3Xu(IJT8%pEqt+F9FO$v zdD2DNHN@%@E?VIcgsO;EqcMLeeN494tl#OqHqjt|bk;|z&hQLkfS5pBG3P0y4T5<% z+3L#u$!?=fXOC1y%%jr->k?GQ?1c#2u)#SJXkM1Mv~}?ab<&ov1Pv%J{S#d!J+=u_ za5VK4Kn-3`UR(JozAFT}lgN1x9<+G-)=cC~KWaplD=)-ft?8_7*p52f6D0do@f|7=HKJUmtW6OzcZkcfnF5KK=TIM} z64ieb;j^~@AH(nGFh|UdHHTv1z))_QX2*A;FYKA zB@PIU$pjb`AS=CO%hNt9PWjJ`s8Q!O2qE+y1aBn1NqO$7xt?w)B>UnMEfv_lW-@{n zDDS9_g$@8ZR*VBz&%*NB*TPkG^Be{AX=F^+eroO(n#9(h~zkpkc~7)j+|N>^TjchkIEWOvlA)0*sX?C{*!Itnqq-VCbuz zp1;@FLM>4hpqxh?Q%uT9D0^qdHID@y9V$vcun_N{6tsT$Xn3u8If}?2FzwOdK^xMg z0Kp(9FzFZGWo*8Rnx&(T%8orYlFtH5k+-urvJll72^(6hFi-iuT17n! zuA!uMizVTX!b0GI*qpE&&%4;L5& z#wtMM0$ z6bnjGSW~*~B+0O&6hKElAu7o7gFHd= z^%^%#=@b*vZTr=t#DzsET9?Lh4*-k})gDlVy(-59-<5;kv)MN_b+k(q4WZtepg$i> zsX{n;B1NKjm`QFND$Di! zk%<_AgBTk33~%ePn1BeHu+G$WsEiT9=8GLVjs-4WYRUYt^R2SFrOv>!I!JBvbkbJq zZr86>R5Nz6?A}W6TaA9HnKMOt z?-Aq2^)Ym8;-rtONw$w1 z)Ny(epta1)!x5wqH^tm~lw~2R#6iqUY-oRuNiQeT9*)ai?Uv=pl=vqHJi~qW7kO|s zO)JciSE3})64kHi=+I}GyLEbuDKYx=2zxv}4oYMn_$iWx-VZR{3~H*anIJ3Bh3aMs zl*sz$W{-)!JASbstb>MoGKaxc;6CnV~Q+bny z0nvPI))jxU)FWRAd-m%yZ=!5!z-pxqK!|wFBJJzbs+gpWI~%~AVFgTy<`ck zkrQ}Zkqz}-ha22Yn0|7_v=u|~Qs{16BBH7AfiynUq-c;!L=8XsM8j0`Duz1&Jd_py zTvkzPQf>hjAlchRD_idY&{r_#W?GD&eE!;zc;o8KDZzPIi@>$lwE_IoLbFvHuq_>l zF;)HMfN243j<#rEUuO$q@SyO9w{TSnwce!X_}$&$T+;B~8*~#{$0Wz7!hq8o^s(9Z zVCsVNfY+#1x?_rUV3)Y9XS4AlUWW)v{Nho2Ba+?evTlDEIrvA$^u))itt@C4a?Nu( z<5qBcRjhP9RVDAJ=;OEe6zdI(lrDzRW8gn&oCv$HLlDk!#oR-!dqaE0fkse2V|B9mroBavjKWJonQJJV*@uUaablN0Yf?BCF$S^M zPZ*_`RkAlSfgCDHckqni)7wnrW2v~;*^dad!e`QSFicC82fLa3xC@ign^<%igIkM* zxABq-^>p`dlSCOs&kBe2lu4a21-N=C)CF>V$p%iO3dh``30wBuG}N(>LzhBe_{wkL zM*~VNx^=uz0Bzb5lUHHup<0~2vzO4^y}GgEo8$RO94`}Cs(e8e`cf?%?BFQG-Qt_- zm8OfNpuYY(`hm6uFWn;%gAg5C%G>bfQBY`o>_)-3i}f_v$j|N-xLU<0ss}qD_oD?S z3UXEm)0tV~omnJG;kq&!l#P6vX1`8_AE+3m%V)gB`yWSsBhc57g3aKae|oe08b!jJ zjK01|xjqBQNU#lGazy;4%B8b53QRsU+Y)CPY3y2CkeIG}8506p)d zi+qk)O@~Khgx-zHu_ZJML@M$ank797HGm^HIm%DGvQE)MJ+V|#C}!5$P&Dbb3FKT^ zf(^|;qIaM-*Z%_eQP-|Sh(Vi4Okmbu10q~CiE!-rM*n)n>Wu$;Sf@M^?>Vez?&%NE zOwf5~jVp(s0`{(*aX+l{y7Er(R=)*=KnpR@J~|i4+({TP;kHf>VJoV`xW(nro#Nss`7ullKh=);GdNw zJJVk&B&`&NW%}sgJDw@`4zL+6-R_eF;$lbqo`TtO;3edjaR~skCl(#LrNU;119E zyy!bjd)cp!2&ruTK#m#22oYe)n-^YaeyP2+qoQRrRmlv$W4b9Rs;>cqCm~o9I3>Un zS`~U&EIc-gr!I9idP!4YdqoL61#N_Vgbe)Ub>$ksJ!Bw&BxDDwrB@H>h36PRDg6Gs z;*JUWAVa_s5e0JwL@cc-;#KVqGKVngvaWcO5@-p%X3P5M_93uC0=PKrxL_v&rr_ir zwv)>I#Lzs$Pe&tN(=Ke;ZFAKTri6OHA7uuW%W#ZxlTWn$X_`oMnHG zR>MzCgrB9&=NdB`?P$&@@KJvinGv~}R*G6%rb)?$KiKh7kT+ZuBo4;=f39|AxGrjq!uK`f#HU@xzBw z`_K8SUmxV3&ii}RzaxJBK>g6@eTW}EQ2&ash53)f9*loSuKEiq8v{PW2MzX@Bw-)4 z+3#c*{~u6c|I?DV>JW7SMp4l5@x zrgeeEhK!GuD+tdM!F`W>**ZldlW?&p69JiAJJ?@{8ob?Fn-DQ?T&KAz8BvDzxsgX# zHsX+o)WAbM=gD%I%Q#?CDK64%f1dbY$IKB#?X7$}a;v!%k4Lv0a|E=7NaV7kn>2&m z6F*ICGDOtzy?R47MvrvEZq|i|Z=Bcoo+e~4q)*OoPIs4aE?7SdKBe?`EmRB+CLPp1 zJscCLbagLeQ$#n&qZJz7R`9$dl#dHg7NZ75hietOC#D?L3{A61NUAqQP?dfhF$%@> z;QQVFD1}-cOKY&jtEFledq^5$lp$PlZ@^fkXUgKTrSsY}ISm|^QV-x+@y0^RMlc3c zxaAFrAeS9c9QA7%RpPt$y6pj1M7$P8rZ5MoynLLB#T#Bg;Ag<*Zt9+TYt44xvnr

,

,

,

,

,

,

,

,,,, + * 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) + */ +ib_api_status_t +__validate_requested_mgid(IN osm_mcmr_recv_t* const p_rcv, + IN const ib_member_rec_t* p_mcm_rec) +{ + uint16_t signature; + boolean_t valid = TRUE; + + OSM_LOG_ENTER( p_rcv->p_log, __validate_requested_mgid ); + + /* 14-a: mcast GID must start with 0xFF */ + if (p_mcm_rec->mgid.multicast.header[0] != 0xFF) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__validate_requested_mgid: 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( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_requested_mgid: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_requested_mgid: " + "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( p_rcv->p_log, OSM_LOG_ERROR, + "__validate_requested_mgid: 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) == MC_SCOPE_LINK_LOCAL) ) { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__validate_requested_mgid: 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( p_rcv->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. +**********************************************************************/ +boolean_t +__mgrp_request_is_realizable( + IN osm_mcmr_recv_t* const p_rcv, + IN ib_net64_t comp_mask, + IN ib_member_rec_t * p_mcm_rec, + IN const osm_physp_t* const p_physp) +{ + uint8_t mtu_sel = 2; /* exactly */ + uint8_t mtu_required, mtu, port_mtu; + uint8_t rate_sel = 2; /* exactly */ + uint8_t rate_required, rate, port_rate; + osm_log_t *p_log = p_rcv->p_log; + ib_port_info_t *p_pi = NULL; + + OSM_LOG_ENTER( p_rcv->p_log, __mgrp_request_is_realizable ); + + if (p_physp != NULL) + p_pi = osm_physp_get_port_info_ptr(p_physp); + + /* + * 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_pi ? ib_port_info_get_mtu_cap(p_pi) : 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 : p_rcv->p_subn->min_ca_mtu; + else + { + mtu_required = (uint8_t)(p_mcm_rec->mtu & 0x3F); + mtu = mtu_required; + switch (mtu_sel) + { + case 0: /* Greater than MTU specified */ + if (port_mtu && mtu_required >= port_mtu) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__mgrp_request_is_realizable: " + "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 < p_rcv->p_subn->min_ca_mtu) + mtu = p_rcv->p_subn->min_ca_mtu; + else + mtu++; + break; + case 1: /* Less than MTU specified */ + /* use the smaller of the two: + a. one lower then the required + b. the mtu of the requesting port (if exists) */ + if (port_mtu && mtu_required > port_mtu) + mtu = port_mtu; + else + mtu--; + break; + case 2: /* Exactly MTU specified */ + default: + break; + } + /* make sure it still be in the range */ + if (mtu < IB_MIN_MTU || mtu > IB_MAX_MTU) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__mgrp_request_is_realizable: " + "Calculated MTU %x is out of range\n", + mtu ); + return FALSE; + } + } + p_mcm_rec->mtu = (mtu_sel<<6) | mtu; + + port_rate = p_pi ? ib_port_info_compute_rate(p_pi) : 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 : p_rcv->p_subn->min_ca_rate; + else + { + rate_required = (uint8_t)(p_mcm_rec->rate & 0x3F); + rate = rate_required; + switch (rate_sel) + { + case 0: /* Greater than RATE specified */ + if (port_rate && rate_required >= port_rate) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__mgrp_request_is_realizable: " + "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 < p_rcv->p_subn->min_ca_rate) + rate = p_rcv->p_subn->min_ca_rate; + else + rate++; + break; + case 1: /* Less than RATE specified */ + /* use the smaller of the two: + a. one lower then the required + b. the rate of the requesting port (if exists) */ + if (port_rate && rate_required > port_rate) + rate = port_rate; + else + rate--; + break; + case 2: /* Exactly RATE specified */ + default: + break; + } + /* make sure it still is in the range */ + if (rate < IB_MIN_RATE || rate > IB_MAX_RATE) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__mgrp_request_is_realizable: " + "Calculated RATE %x is out of range\n", + rate ); + return FALSE; + } + } + p_mcm_rec->rate = (rate_sel<<6) | rate; + + OSM_LOG_EXIT( p_rcv->p_log ); + return TRUE; +} + +/********************************************************************** + Call this function to find or create a new mgrp. +**********************************************************************/ +ib_api_status_t +osm_mcmr_rcv_find_or_create_new_mgrp( + IN osm_mcmr_recv_t* const p_rcv, + IN ib_net64_t comp_mask, + IN ib_member_rec_t* const p_recvd_mcmember_rec, + OUT osm_mgrp_t **pp_mgrp) +{ + ib_api_status_t status; + + status = __get_mgrp_by_mgid(p_rcv, p_recvd_mcmember_rec, pp_mgrp); + if (status == IB_SUCCESS) + return status; + return osm_mcmr_rcv_create_new_mgrp(p_rcv, comp_mask, + p_recvd_mcmember_rec, NULL, pp_mgrp); +} + +/********************************************************************** + Call this function to create a new mgrp. +**********************************************************************/ +ib_api_status_t +osm_mcmr_rcv_create_new_mgrp( + IN osm_mcmr_recv_t* const p_rcv, + IN ib_net64_t comp_mask, + IN const ib_member_rec_t* const p_recvd_mcmember_rec, + IN const osm_physp_t* const p_physp, + OUT osm_mgrp_t **pp_mgrp) +{ + ib_net16_t mlid; + uint8_t zero_mgid, valid; + uint8_t scope, i; + ib_gid_t *p_mgid; + osm_mgrp_t *p_prev_mgrp; + ib_api_status_t status = IB_SUCCESS; + ib_member_rec_t mcm_rec = *p_recvd_mcmember_rec; /* copy for modifications */ + + OSM_LOG_ENTER( p_rcv->p_log, osm_mcmr_rcv_create_new_mgrp ); + + /* but what if the given MGID was not 0 ? */ + zero_mgid = 1; + for ( i = 0 ; i < sizeof(p_recvd_mcmember_rec->mgid); i++ ) + { + if (p_recvd_mcmember_rec->mgid.raw[i] != 0) + { + zero_mgid = 0; + break; + } + } + + /* + we allocate a new mlid number before we might use it + for MGID ... + */ + mlid = __get_new_mlid(p_rcv, mcm_rec.mlid); + if ( mlid == 0 ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mcmr_rcv_create_new_mgrp: ERR 1B19: " + "__get_new_mlid failed\n" ); + status = IB_SA_MAD_STATUS_NO_RESOURCES; + goto Exit; + } + + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_mcmr_rcv_create_new_mgrp: " + "Obtained new mlid 0x%X\n", cl_ntoh16(mlid) ); + + /* we need to create the new MGID if it was not defined */ + if (zero_mgid) + { + /* create a new MGID */ + + /* use the given scope state only if requested! */ + if (comp_mask & IB_MCR_COMPMASK_SCOPE) + { + ib_member_get_scope_state( + p_recvd_mcmember_rec->scope_state, &scope, NULL); + } + else + { + /* to guarantee no collision with other subnets use local scope! */ + scope = MC_SCOPE_LINK_LOCAL; + } + + p_mgid = &(mcm_rec.mgid); + p_mgid->raw[0] = 0xFF; + p_mgid->raw[1] = 0x10 | scope; + p_mgid->raw[2] = 0xA0; + p_mgid->raw[3] = 0x1B; + + /* HACK: use the SA port gid to make it globally unique */ + memcpy((&p_mgid->raw[4]), + &p_rcv->p_subn->opt.subnet_prefix, sizeof(uint64_t)); + + /* HACK: how do we get a unique number - use the mlid twice */ + memcpy(&p_mgid->raw[10], &mlid, sizeof(uint16_t)); + memcpy(&p_mgid->raw[12], &mlid, sizeof(uint16_t)); + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_mcmr_rcv_create_new_mgrp: " + "Allocated new MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 "\n", + cl_ntoh64(p_mgid->unicast.prefix), + cl_ntoh64(p_mgid->unicast.interface_id) ); + } + else + { + /* a specific MGID was requested so validate the resulting MGID */ + valid = __validate_requested_mgid(p_rcv, &mcm_rec); + if (!valid) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mcmr_rcv_create_new_mgrp: ERR 1B22: " + "Invalid requested MGID\n" ); + __free_mlid(p_rcv, mlid); + status = IB_SA_MAD_STATUS_REQ_INVALID; + goto Exit; + } + } + + /* check the requested parameters are realizable */ + if (__mgrp_request_is_realizable(p_rcv, comp_mask, &mcm_rec, p_physp) == FALSE) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mcmr_rcv_create_new_mgrp: ERR 1B26: " + "Requested MGRP parameters are not realizable\n" ); + __free_mlid(p_rcv, mlid); + status = IB_SA_MAD_STATUS_REQ_INVALID; + goto Exit; + } + + /* create a new MC Group */ + *pp_mgrp = osm_mgrp_new(mlid); + if (*pp_mgrp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mcmr_rcv_create_new_mgrp: ERR 1B08: " + "osm_mgrp_new failed\n" ); + __free_mlid(p_rcv, mlid); + status = IB_SA_MAD_STATUS_NO_RESOURCES; + goto Exit; + } + + /* Initialize the mgrp */ + (*pp_mgrp)->mcmember_rec = mcm_rec; + (*pp_mgrp)->mcmember_rec.mlid = mlid; + + /* the mcmember_record should have mtu_sel, rate_sel, and pkt_lifetime_sel = 2 */ + (*pp_mgrp)->mcmember_rec.mtu &= 0x3f; + (*pp_mgrp)->mcmember_rec.mtu |= 2<<6; /* exactly */ + (*pp_mgrp)->mcmember_rec.rate &= 0x3f; + (*pp_mgrp)->mcmember_rec.rate |= 2<<6; /* exactly */ + (*pp_mgrp)->mcmember_rec.pkt_life &= 0x3f; + (*pp_mgrp)->mcmember_rec.pkt_life |= 2<<6; /* exactly */ + + /* Insert the new group in the data base */ + + /* since we might have an old group by that mlid + one whose deletion was delayed for an idle time + we need to deallocate it first */ + p_prev_mgrp = (osm_mgrp_t *)cl_qmap_get(&p_rcv->p_subn->mgrp_mlid_tbl, mlid); + if (p_prev_mgrp != (osm_mgrp_t *)cl_qmap_end(&p_rcv->p_subn->mgrp_mlid_tbl)) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_mcmr_rcv_create_new_mgrp: " + "Found previous group for mlid:0x%04x - Need to destroy it\n", + cl_ntoh16(mlid) ); + cl_qmap_remove_item(&p_rcv->p_subn->mgrp_mlid_tbl, + (cl_map_item_t *)p_prev_mgrp ); + osm_mgrp_destroy( p_prev_mgrp ); + } + + cl_qmap_insert(&p_rcv->p_subn->mgrp_mlid_tbl, + mlid, + &(*pp_mgrp)->map_item); + + /* Send a Report to any InformInfo registerd for + Trap 66: MCGroup create */ + osm_mgrp_send_create_notice(p_rcv->p_subn, p_rcv->p_log, *pp_mgrp); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return status; + +} + +/********************************************************************* +Process a request for leaving the group +**********************************************************************/ +static void +__osm_mcmr_rcv_leave_mgrp( + IN osm_mcmr_recv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + boolean_t valid; + osm_mgrp_t *p_mgrp; + ib_api_status_t status; + ib_sa_mad_t *p_sa_mad; + ib_member_rec_t*p_recvd_mcmember_rec; + ib_member_rec_t mcmember_rec; + ib_net16_t mlid; + ib_net16_t sa_status; + ib_net64_t portguid; + osm_mcm_port_t *p_mcm_port; + uint8_t port_join_state; + uint8_t new_join_state; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mcmr_rcv_leave_mgrp ); + + p_mgrp = NULL; + 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( p_rcv->p_log, OSM_LOG_DEBUG ) ) { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mcmr_rcv_leave_mgrp: Dump of record\n" ); + osm_dump_mc_record( p_rcv->p_log, &mcmember_rec, OSM_LOG_DEBUG ); + } + + CL_PLOCK_EXCL_ACQUIRE(p_rcv->p_lock); + status = __get_mgrp_by_mgid(p_rcv,p_recvd_mcmember_rec, &p_mgrp); + if (status == IB_SUCCESS) + { + mlid = p_mgrp->mlid; + portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id; + + /* check validity of the delete request o15-0.1.14 */ + valid = __validate_delete(p_rcv, + p_mgrp, + osm_madw_get_mad_addr_ptr(p_madw), + p_recvd_mcmember_rec, + &p_mcm_port); + + if (valid) + { + /* + * 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 = p_mcm_port->scope_state & 0x0F; + new_join_state = + port_join_state & ~(p_recvd_mcmember_rec->scope_state & 0x0F); + if (new_join_state) + { + /* Just update the result JoinState */ + p_mcm_port->scope_state = + new_join_state | (p_mcm_port->scope_state & 0xf0); + + mcmember_rec.scope_state = p_mcm_port->scope_state; + + CL_PLOCK_RELEASE( p_rcv->p_lock ); + + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mcmr_rcv_leave_mgrp: " + "After update JoinState != 0. Updating from 0x%X to 0x%X\n", + port_join_state, + new_join_state + ); + } + else + { + /* we need to return the stored scope state */ + mcmember_rec.scope_state = p_mcm_port->scope_state; + + /* OK we can leave */ + /* note: osm_sm_mcgrp_leave() will release p_rcv->p_lock */ + + status = osm_sm_mcgrp_leave(p_rcv->p_sm, mlid, portguid); + if(status != IB_SUCCESS) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mcmr_rcv_leave_mgrp: ERR 1B09: " + "osm_sm_mcgrp_leave failed\n" ); + } + } + } + else + { + CL_PLOCK_RELEASE( p_rcv->p_lock ); + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mcmr_rcv_leave_mgrp: ERR 1B25: " + "Received an invalid delete request for " + "MGID: 0x%016" PRIx64 " : " + "0x%016" PRIx64 " for " + "PortGID: 0x%016" PRIx64 " : " + "0x%016" PRIx64 "\n", + cl_ntoh64( p_recvd_mcmember_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_mcmember_rec->mgid.unicast.interface_id ), + cl_ntoh64( p_recvd_mcmember_rec->port_gid.unicast.prefix ), + cl_ntoh64( p_recvd_mcmember_rec->port_gid.unicast.interface_id ) ); + sa_status = IB_SA_MAD_STATUS_REQ_INVALID; + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + } + else + { + CL_PLOCK_RELEASE( p_rcv->p_lock ); + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mcmr_rcv_leave_mgrp: " + "Failed since multicast group not present\n" ); + sa_status = IB_SA_MAD_STATUS_REQ_INVALID; + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + + /* Send an SA response */ + __osm_mcmr_rcv_respond( p_rcv, p_madw, &mcmember_rec ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return; +} + +/********************************************************************** + Handle a join (or create) request +**********************************************************************/ +static void +__osm_mcmr_rcv_join_mgrp( + IN osm_mcmr_recv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + boolean_t valid; + osm_mgrp_t *p_mgrp = NULL; + ib_api_status_t status; + ib_sa_mad_t *p_sa_mad; + ib_member_rec_t*p_recvd_mcmember_rec; + ib_member_rec_t mcmember_rec; + ib_net16_t sa_status; + ib_net16_t mlid; + osm_mcm_port_t *p_mcmr_port; + ib_net64_t portguid; + osm_port_t * p_port; + osm_physp_t* p_physp; + osm_physp_t* p_request_physp; + uint8_t is_new_group; /* TRUE = there is a need to create a group */ + osm_mcast_req_type_t req_type; + uint8_t join_state; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mcmr_rcv_join_mgrp ); + + p_mgrp = NULL; + 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 ); + + portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id; + + mcmember_rec = *p_recvd_mcmember_rec; + + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mcmr_rcv_join_mgrp: " + "Dump of incoming record\n" ); + osm_dump_mc_record( p_rcv->p_log, &mcmember_rec, OSM_LOG_DEBUG ); + } + + CL_PLOCK_EXCL_ACQUIRE(p_rcv->p_lock); + + /* make sure the requested port guid is known to the SM */ + p_port = (osm_port_t *)cl_qmap_get(&p_rcv->p_subn->port_guid_tbl, + portguid); + + if (p_port == (osm_port_t *)cl_qmap_end(&p_rcv->p_subn->port_guid_tbl)) + { + CL_PLOCK_RELEASE( p_rcv->p_lock ); + + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mcmr_rcv_join_mgrp: " + "Unknown port GUID 0x%016" PRIx64 "\n", + portguid ); + sa_status = IB_SA_MAD_STATUS_REQ_INVALID; + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + + p_physp = osm_port_get_default_phys_ptr(p_port); + /* Check that the p_physp and the requester physp are in the same + partition. */ + p_request_physp = + osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_request_physp == NULL) + { + CL_PLOCK_RELEASE( p_rcv->p_lock ); + goto Exit; + } + + if (!osm_physp_share_pkey( p_rcv->p_log, p_physp, p_request_physp)) + { + CL_PLOCK_RELEASE( p_rcv->p_lock ); + + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mcmr_rcv_join_mgrp: " + "Port and requester don't share pkey\n" ); + sa_status = IB_SA_MAD_STATUS_REQ_INVALID; + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + + ib_member_get_scope_state( + p_recvd_mcmember_rec->scope_state, NULL, &join_state); + + /* do we need to create a new group? */ + status = __get_mgrp_by_mgid(p_rcv, p_recvd_mcmember_rec, &p_mgrp); + if ((status == IB_NOT_FOUND) || p_mgrp->to_be_deleted) + { + /* check for JoinState.FullMember = 1 o15.0.1.9 */ + if ((join_state & 0x01) != 0x01) + { + CL_PLOCK_RELEASE( p_rcv->p_lock ); + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mcmr_rcv_join_mgrp: ERR 1B10: " + "Provided Join State != FullMember - required for create, " + "MGID: 0x%016" PRIx64 " : " + "0x%016" PRIx64 "\n", + cl_ntoh64( p_recvd_mcmember_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_mcmember_rec->mgid.unicast.interface_id ) ); + sa_status = IB_SA_MAD_STATUS_REQ_INVALID; + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + + /* check for the comp_mask */ + valid = __check_create_comp_mask(p_sa_mad->comp_mask, + p_recvd_mcmember_rec); + if (valid) + { + status = osm_mcmr_rcv_create_new_mgrp(p_rcv, + p_sa_mad->comp_mask, + p_recvd_mcmember_rec, + p_physp, + &p_mgrp); + if (status != IB_SUCCESS) + { + CL_PLOCK_RELEASE( p_rcv->p_lock ); + sa_status = status; + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + /* copy the MGID to the result */ + mcmember_rec.mgid = p_mgrp->mcmember_rec.mgid; + } + else + { + CL_PLOCK_RELEASE( p_rcv->p_lock ); + + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mcmr_rcv_join_mgrp: ERR 1B11: " + "method = %s, " + "scope_state = 0x%x, " + "component mask = 0x%016" PRIx64 ", " + "expected comp mask = 0x%016" PRIx64 ", " + "MGID: 0x%016" PRIx64 " : " + "0x%016" PRIx64 " from port 0x%016" PRIx64 "\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), + cl_ntoh64( p_recvd_mcmember_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_mcmember_rec->mgid.unicast.interface_id ), + cl_ntoh64( portguid ) ); + + sa_status = IB_SA_MAD_STATUS_INSUF_COMPS; + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + is_new_group = 1; + req_type = OSM_MCAST_REQ_TYPE_CREATE; + } + else + { + /* no need for a new group */ + is_new_group = 0; + req_type = OSM_MCAST_REQ_TYPE_JOIN; + } + + CL_ASSERT(p_mgrp); + mlid = p_mgrp->mlid; + + /* + * o15-0.2.4: If SA supports UD multicast, then SA shall cause an + * endport to join an existing multicast group if: + * 1. It receives a SubnAdmSet() method for a MCMemberRecord, and + * - WE KNOW THAT ALREADY + * 2. The MGID is specified and matches an existing multicast + * group, and + * - WE KNOW THAT ALREADY + * 3. The MCMemberRecord:JoinState is not all 0s, and + * 4. PortGID is specified and + * - WE KNOW THAT ALREADY (as it matched a real one) + * 5. All other components match that existing group, either by + * being wildcarded or by having values identical to those specified + * by the component mask and in use by the group with the exception + * of components such as ProxyJoin and Reserved, which are ignored + * by SA. + * + * We need to check #3 and #5 here: + */ + valid = __validate_more_comp_fields( + p_rcv->p_log, + p_mgrp, + p_recvd_mcmember_rec, + p_sa_mad->comp_mask) && __validate_port_caps( + p_rcv->p_log, + p_mgrp, + p_physp) && (join_state != 0); + + if (!valid) + { + /* since we might have created the new group we need to cleanup */ + __cleanup_mgrp(p_rcv, mlid); + + CL_PLOCK_RELEASE( p_rcv->p_lock ); + + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mcmr_rcv_join_mgrp: ERR 1B12: " + "__validate_more_comp_fields, __validate_port_caps, " + "or JoinState = 0 failed from port 0x%016" PRIx64 ", " + "sending IB_SA_MAD_STATUS_REQ_INVALID\n", + cl_ntoh64( portguid ) ); + + sa_status = IB_SA_MAD_STATUS_REQ_INVALID; + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + + /* + * Do some validation of the modification + */ + if (!is_new_group) + { + /* + * o15-0.2.1 requires validation of the requesting port + * in the case of modification: + */ + valid = __validate_modify(p_rcv, + p_mgrp, + osm_madw_get_mad_addr_ptr(p_madw), + p_recvd_mcmember_rec, + &p_mcmr_port); + if (!valid) + { + CL_PLOCK_RELEASE( p_rcv->p_lock ); + + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mcmr_rcv_join_mgrp: ERR 1B13: " + "__validate_modify failed, " + "sending IB_SA_MAD_STATUS_REQ_INVALID\n" ); + + sa_status = IB_SA_MAD_STATUS_REQ_INVALID; + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + } + + /* create or update existing port (join-state will be updated) */ + status = __add_new_mgrp_port( + p_rcv, + p_mgrp, + p_recvd_mcmember_rec, + osm_madw_get_mad_addr_ptr(p_madw), + &p_mcmr_port); + + if (status != IB_SUCCESS) + { + /* we fail to add the port so we might need to delete the group */ + __cleanup_mgrp(p_rcv, mlid); + + CL_PLOCK_RELEASE( p_rcv->p_lock ); + if (status == IB_INVALID_PARAMETER) + sa_status = IB_SA_MAD_STATUS_REQ_INVALID; + else + sa_status = IB_SA_MAD_STATUS_NO_RESOURCES; + + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + + /* o15.0.1.11: copy the join state */ + mcmember_rec.scope_state = p_mcmr_port->scope_state; + + /* copy qkey mlid tclass pkey sl_flow_hop mtu rate pkt_life sl_flow_hop */ + __copy_from_create_mc_rec(&mcmember_rec, &p_mgrp->mcmember_rec); + + /* Release the lock as we don't need it. */ + CL_PLOCK_RELEASE( p_rcv->p_lock ); + + /* do the actual routing (actually schedule the update) */ + status = + osm_sm_mcgrp_join(p_rcv->p_sm, + mlid, + p_recvd_mcmember_rec->port_gid.unicast.interface_id, + req_type); + + if (status != IB_SUCCESS) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mcmr_rcv_join_mgrp: ERR 1B14: " + "osm_sm_mcgrp_join failed, " + "sending IB_SA_MAD_STATUS_NO_RESOURCES\n" ); + + CL_PLOCK_EXCL_ACQUIRE(p_rcv->p_lock); + + /* the request for routing failed so we need to remove the port */ + p_mgrp = __get_mgrp_by_mlid(p_rcv, mlid); + if (p_mgrp != NULL) + { + osm_mgrp_remove_port( + p_rcv->p_subn, + p_rcv->p_log, + p_mgrp, + p_recvd_mcmember_rec->port_gid.unicast.interface_id); + __cleanup_mgrp(p_rcv, mlid); + } + CL_PLOCK_RELEASE( p_rcv->p_lock ); + sa_status = IB_SA_MAD_STATUS_NO_RESOURCES; + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + + } /* failed to route */ + + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + osm_dump_mc_record( p_rcv->p_log, &mcmember_rec, OSM_LOG_DEBUG ); + + __osm_mcmr_rcv_respond( p_rcv, p_madw, &mcmember_rec ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return; +} + +/********************************************************************** + Add a patched multicast group to the results list +**********************************************************************/ +static ib_api_status_t +__osm_mcmr_rcv_new_mcmr( + IN osm_mcmr_recv_t* const p_rcv, + IN const ib_member_rec_t* p_rcvd_rec, + IN cl_qlist_t* const p_list ) +{ + osm_mcmr_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mcmr_rcv_new_mcmr ); + + p_rec_item = (osm_mcmr_item_t*)cl_qlock_pool_get( &p_rcv->pool ); + if( p_rec_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mcmr_rcv_new_mcmr: ERR 1B15: " + "cl_qlock_pool_get failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + memset( &p_rec_item->rec, 0, sizeof( p_rec_item->rec ) ); + + /* HACK: Not trusted requesters should result with 0 Join + State, Port Guid, and Proxy */ + p_rec_item->rec = *p_rcvd_rec; + cl_qlist_insert_tail( p_list, (cl_list_item_t*)&p_rec_item->pool_item ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + Match the given mgrp to the requested mcmr +**********************************************************************/ +void +__osm_sa_mcm_by_comp_mask_cb( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + const osm_mgrp_t * const p_mgrp = (osm_mgrp_t *)p_map_item; + osm_sa_mcmr_search_ctxt_t* const p_ctxt = + (osm_sa_mcmr_search_ctxt_t *)context; + osm_mcmr_recv_t* const p_rcv = p_ctxt->p_rcv; + const ib_member_rec_t* p_rcvd_rec = p_ctxt->p_mcmember_rec; + const osm_physp_t* p_req_physp = p_ctxt->p_req_physp; + + /* since we might change scope_state */ + ib_member_rec_t match_rec; + ib_net64_t comp_mask = p_ctxt->comp_mask; + 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; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_mcm_by_comp_mask_cb ); + + osm_log(p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_mcm_by_comp_mask_cb: " + "Checking mlid:0x%X\n", + cl_ntoh16(p_mgrp->mlid)); + + /* the group might be marked for deletion */ + if (p_mgrp->to_be_deleted) + { + osm_log(p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_mcm_by_comp_mask_cb: " + "Group mlid:0x%X is marked to be deleted\n", + cl_ntoh16(p_mgrp->mlid)); + goto Exit; + } + + /* first try to eliminate the group by MGID, MLID, or P_Key */ + if ((IB_MCR_COMPMASK_MGID & comp_mask) && + memcmp(&p_rcvd_rec->mgid, &p_mgrp->mcmember_rec.mgid, sizeof(ib_gid_t))) + goto Exit; + + if ((IB_MCR_COMPMASK_MLID & comp_mask) && + memcmp(&p_rcvd_rec->mlid, &p_mgrp->mcmember_rec.mlid, sizeof(uint16_t))) + goto Exit; + + /* if the requester physical port doesn't have the pkey that is defined for + the group - exit. */ + if (!osm_physp_has_pkey( p_rcv->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 ) + if (query_sl != mgrp_sl) + goto Exit; + + if (IB_MCR_COMPMASK_FLOW & comp_mask) + if (query_flow != mgrp_flow) + goto Exit; + + if (IB_MCR_COMPMASK_HOP & comp_mask) + if (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; + + 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; + + /* need to validate mtu, rate, and pkt_lifetime fields. */ + if (__validate_more_comp_fields( p_rcv->p_log, + p_mgrp, + p_rcvd_rec, + comp_mask ) == FALSE) + goto Exit; + + /* Port specific fields */ + /* so did we get the PortGUID mask */ + if (IB_MCR_COMPMASK_PORT_GID & comp_mask) + { + /* try to find this port */ + if (osm_mgrp_is_port_present(p_mgrp, portguid, &p_mcm_port)) + { + scope_state = p_mcm_port->scope_state; + memcpy(&port_gid, &(p_mcm_port->port_gid), sizeof(ib_gid_t)); + proxy_join = p_mcm_port->proxy_join; + } + else + { + /* port not in group */ + goto Exit; + } + } + else + { + /* point to the group information */ + scope_state = p_mgrp->mcmember_rec.scope_state; + } + + /* Many MC records returned */ + if ( (p_ctxt->trusted_req == TRUE) && !(IB_MCR_COMPMASK_PORT_GID & comp_mask) ) + { + osm_log(p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_mcm_by_comp_mask_cb: " + "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(p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_mcm_by_comp_mask_cb: " + "Record of port_gid: 0x%016" PRIx64 "0x%016" PRIx64 + " in multicast_lid: 0x%X is returned\n", + cl_ntoh64(match_rec.port_gid.unicast.prefix), + cl_ntoh64(match_rec.port_gid.unicast.interface_id), + cl_ntoh16(p_mgrp->mlid) + ); + + match_rec.proxy_join = (uint8_t)(p_mcm_port->proxy_join); + + __osm_mcmr_rcv_new_mcmr(p_rcv, &match_rec, p_ctxt->p_list); + } + p_item = cl_qmap_next(p_item); + } + } + /* One MC record returned */ + else + { + if ((scope_state_mask & p_rcvd_rec->scope_state) != + (scope_state_mask & scope_state)) + goto Exit; + + /* add to the list */ + match_rec = p_mgrp->mcmember_rec; + match_rec.scope_state = scope_state; + memcpy(&(match_rec.port_gid), &port_gid, sizeof(ib_gid_t)); + match_rec.proxy_join = (uint8_t)proxy_join; + + __osm_mcmr_rcv_new_mcmr(p_rcv, &match_rec, p_ctxt->p_list); + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + Handle a query request +**********************************************************************/ +static void +__osm_mcmr_query_mgrp(IN osm_mcmr_recv_t* const p_rcv, + IN const osm_madw_t* const p_madw) +{ + const ib_sa_mad_t* p_rcvd_mad; + const ib_member_rec_t* p_rcvd_rec; + cl_qlist_t rec_list; + osm_madw_t* p_resp_madw; + ib_sa_mad_t* p_resp_sa_mad; + ib_member_rec_t* p_resp_rec; + uint32_t num_rec, pre_trim_num_rec; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t trim_num_rec; +#endif + uint32_t i; + osm_sa_mcmr_search_ctxt_t context; + osm_mcmr_item_t* p_rec_item; + ib_api_status_t status; + ib_net64_t comp_mask; + osm_physp_t* p_req_physp; + boolean_t trusted_req; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mcmr_query_mgrp ); + + 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(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mcmr_query_mgrp: ERR 1B04: " + "Cannot find requester physical port\n" ); + goto Exit; + } + + cl_qlist_init( &rec_list ); + + context.p_mcmember_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = p_rcvd_mad->comp_mask; + context.p_rcv = p_rcv; + context.p_req_physp = p_req_physp; + context.trusted_req = trusted_req; + + CL_PLOCK_ACQUIRE( p_rcv->p_lock ); + + /* simply go over all MCGs and match */ + cl_qmap_apply_func( &p_rcv->p_subn->mgrp_mlid_tbl, + __osm_sa_mcm_by_comp_mask_cb, + &context); + + CL_PLOCK_RELEASE( p_rcv->p_lock ); + + num_rec = cl_qlist_count( &rec_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if ( (p_rcvd_mad->method == IB_MAD_METHOD_GET) && + (num_rec > 1)) { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mcmr_query_mgrp: ERR 1B05: " + "Got more than one record for SubnAdmGet (%u)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS ); + + /* need to set the mem free ... */ + p_rec_item = (osm_mcmr_item_t*)cl_qlist_remove_head( &rec_list ); + while( p_rec_item != (osm_mcmr_item_t*)cl_qlist_end( &rec_list ) ) + { + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_rec_item = (osm_mcmr_item_t*)cl_qlist_remove_head( &rec_list ); + } + + goto Exit; + } + + pre_trim_num_rec = num_rec; +#ifndef VENDOR_RMPP_SUPPORT + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_member_rec_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_mcmr_query_mgrp: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mcmr_query_mgrp: " + "Returning %u records\n", num_rec ); + + if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0)) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_member_rec_t) + IB_SA_MAD_HDR_SIZE, + osm_madw_get_mad_addr_ptr(p_madw) ); + + if( !p_resp_madw ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mcmr_query_mgrp: ERR 1B16: " + "osm_mad_pool_get failed\n" ); + + for( i = 0; i < num_rec; i++ ) + { + p_rec_item = (osm_mcmr_item_t*)cl_qlist_remove_head( &rec_list ); + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES ); + goto Exit; + } + + p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_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( p_resp_sa_mad, p_rcvd_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; + + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_member_rec_t) ); + +#ifndef VENDOR_RMPP_SUPPORT + /* we support only one packet RMPP - so we will set the first and + last flags for gettable */ + if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + p_resp_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( p_resp_sa_mad ); + + /* + 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. + */ + + for ( i = 0; i < pre_trim_num_rec; i++ ) + { + p_rec_item = (osm_mcmr_item_t*)cl_qlist_remove_head( &rec_list ); + /* copy only if not trimmed */ + if (i < num_rec) + { + *p_resp_rec = p_rec_item->rec; + if (trusted_req == FALSE) + { + memset(&p_resp_rec->port_gid, 0, sizeof(ib_gid_t)); + ib_member_set_join_state(p_resp_rec, 0); + p_resp_rec->proxy_join = 0; + } + } + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_resp_rec++; + } + + CL_ASSERT( cl_is_qlist_empty( &rec_list ) ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + if(status != IB_SUCCESS) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mcmr_query_mgrp: ERR 1B17: " + "osm_vendor_send status = %s\n", + ib_get_err_str(status) ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcmr_rcv_process( + IN osm_mcmr_recv_t* const p_rcv, + const IN osm_madw_t* const p_madw ) +{ + ib_sa_mad_t *p_sa_mad; + ib_net16_t sa_status = IB_SA_MAD_STATUS_REQ_INVALID; + ib_member_rec_t *p_recvd_mcmember_rec; + boolean_t valid; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_mcmr_rcv_process ); + + 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: + valid = __check_join_comp_mask(p_sa_mad->comp_mask); + if(!valid) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mcmr_rcv_process: ERR 1B18: " + "component mask = 0x%016" PRIx64 ", " + "expected comp mask = 0x%016" PRIx64 " ," + "MGID: 0x%016" PRIx64 " : " + "0x%016" PRIx64 " for " + "PortGID: 0x%016" PRIx64 " : " + "0x%016" PRIx64 "\n", + cl_ntoh64(p_sa_mad->comp_mask), + CL_NTOH64(JOIN_MC_COMP_MASK), + cl_ntoh64( p_recvd_mcmember_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_mcmember_rec->mgid.unicast.interface_id ), + cl_ntoh64( p_recvd_mcmember_rec->port_gid.unicast.prefix ), + cl_ntoh64( p_recvd_mcmember_rec->port_gid.unicast.interface_id ) ); + + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + + /* + * Join or Create Multicast Group + */ + __osm_mcmr_rcv_join_mgrp(p_rcv, p_madw); + break; + case IB_MAD_METHOD_DELETE: + valid = __check_join_comp_mask(p_sa_mad->comp_mask); + if(!valid) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mcmr_rcv_process: 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( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + + /* + * Leave Multicast Group + */ + __osm_mcmr_rcv_leave_mgrp(p_rcv, p_madw); + break; + case IB_MAD_METHOD_GET: + case IB_MAD_METHOD_GETTABLE: + /* + * Querying a Multicast Group + */ + __osm_mcmr_query_mgrp(p_rcv, p_madw); + break; + default: + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mcmr_rcv_process: ERR 1B21: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_sa_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + break; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return; +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mcmember_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mcmember_record_ctrl.c new file mode 100644 index 00000000..19285e73 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mcmember_record_ctrl.c @@ -0,0 +1,132 @@ +/* + * 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: + * Implementation of osm_mcmr_rcv_ctrl_t. + * This object represents the Multicast member record controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_mcmr_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_mcmr_rcv_process( ((osm_mcmr_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcmr_rcv_ctrl_construct( + IN osm_mcmr_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcmr_rcv_ctrl_destroy( + IN osm_mcmr_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mcmr_rcv_ctrl_init( + IN osm_mcmr_rcv_ctrl_t* const p_ctrl, + IN osm_mcmr_recv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_mcmr_rcv_ctrl_init ); + + osm_mcmr_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_MCMEMBER_RECORD, + __osm_mcmr_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_mcmr_rcv_ctrl_init: ERR 1C01: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mft_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mft_record.c new file mode 100644 index 00000000..5cd6efad --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mft_record.c @@ -0,0 +1,547 @@ +/* + * 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: + * Implementation of osm_mftr_rcv_t. + * This object represents the MulticastForwardingTable Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_MFTR_RCV_POOL_MIN_SIZE 32 +#define OSM_MFTR_RCV_POOL_GROW_SIZE 32 + +typedef struct _osm_mftr_item +{ + cl_pool_item_t pool_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_mftr_rcv_t* p_rcv; + const osm_physp_t* p_req_physp; +} osm_mftr_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void +osm_mftr_rcv_construct( + IN osm_mftr_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mftr_rcv_destroy( + IN osm_mftr_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_mftr_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mftr_rcv_init( + IN osm_mftr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_mftr_rcv_init ); + + osm_mftr_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + status = cl_qlock_pool_init( &p_rcv->pool, + OSM_MFTR_RCV_POOL_MIN_SIZE, + 0, + OSM_MFTR_RCV_POOL_GROW_SIZE, + sizeof(osm_mftr_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_mftr_rcv_new_mftr( + IN osm_mftr_rcv_t* const p_rcv, + IN osm_switch_t* const p_sw, + IN cl_qlist_t* const p_list, + IN ib_net16_t const lid, + IN uint16_t const block, + IN uint8_t const position ) +{ + osm_mftr_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + uint16_t position_block_num; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mftr_rcv_new_mftr ); + + p_rec_item = (osm_mftr_item_t*)cl_qlock_pool_get( &p_rcv->pool ); + if( p_rec_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mftr_rcv_new_mftr: ERR 4A02: " + "cl_qlock_pool_get failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mftr_rcv_new_mftr: " + "New MulticastForwardingTable: sw 0x%016" PRIx64 + "\n\t\t\t\tblock %u position %u lid 0x%02X\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->rec, 0, sizeof(ib_mft_record_t) ); + + 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, (cl_list_item_t*)&p_rec_item->pool_item ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static osm_port_t* +__osm_mftr_get_port_by_guid( + IN osm_mftr_rcv_t* const p_rcv, + IN uint64_t port_guid ) +{ + osm_port_t* p_port; + + CL_PLOCK_ACQUIRE(p_rcv->p_lock); + + p_port = (osm_port_t *)cl_qmap_get(&p_rcv->p_subn->port_guid_tbl, + port_guid); + if (p_port == (osm_port_t *)cl_qmap_end(&p_rcv->p_subn->port_guid_tbl)) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mftr_get_port_by_guid ERR 4A04: " + "Invalid port GUID 0x%016" PRIx64 "\n", + port_guid ); + p_port = NULL; + } + + CL_PLOCK_RELEASE(p_rcv->p_lock); + return p_port; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_mftr_rcv_by_comp_mask( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + const osm_mftr_search_ctxt_t* const p_ctxt = + (osm_mftr_search_ctxt_t *)context; + osm_switch_t* const p_sw = (osm_switch_t*)p_map_item; + const ib_mft_record_t* const p_rcvd_rec = p_ctxt->p_rcvd_rec; + osm_mftr_rcv_t* const p_rcv = p_ctxt->p_rcv; + 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_mftr_get_port_by_guid( p_rcv, p_sw->p_node->node_info.port_guid ); + if (! p_port) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mftr_rcv_by_comp_mask: 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 = osm_port_get_default_phys_ptr( p_port ); + if (! p_physp) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mftr_rcv_by_comp_mask: 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( p_rcv->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( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mftr_rcv_by_comp_mask: " + "Comparing lid:0x%02X to port lid range: 0x%02X .. 0x%02X\n", + cl_ntoh16( p_rcvd_rec->lid ), min_lid_ho, max_lid_ho + ); + /* ok we are ready for range check */ + if (min_lid_ho > cl_ntoh16(p_rcvd_rec->lid) || + max_lid_ho < cl_ntoh16(p_rcvd_rec->lid)) + return; + } + + if ( !osm_switch_supports_mcast ( p_sw ) ) + return; + + /* Are there any blocks in use ? */ + if ( osm_switch_get_mft_max_block_in_use( p_sw ) == -1 ) + return; + + position_block_num_ho = cl_ntoh16( p_rcvd_rec->position_block_num ); + + /* now we need to decide which blocks to output */ + if( comp_mask & IB_MFTR_COMPMASK_BLOCK ) + { + max_block = min_block = position_block_num_ho & IB_MCAST_BLOCK_ID_MASK_HO; + if ( max_block > osm_switch_get_mft_max_block_in_use( p_sw ) ) + return; + } + else + { + /* use as many blocks as needed */ + min_block = 0; + max_block = osm_switch_get_mft_max_block_in_use( p_sw ); + } + + /* need to decide which positions to output */ + if ( comp_mask & IB_MFTR_COMPMASK_POSITION ) + { + min_position = max_position = (position_block_num_ho & 0xF000) >> 12; + if (max_position > osm_switch_get_mft_max_position( p_sw ) ) + return; + } + else + { + /* use as many positions as needed */ + min_position = 0; + max_position = osm_switch_get_mft_max_position( p_sw ); + } + + /* so we can add these one by one ... */ + for (block = min_block; block <= max_block; block++) + for (position = min_position; position <= max_position; position++) + __osm_mftr_rcv_new_mftr( p_rcv, p_sw, p_ctxt->p_list, + osm_port_get_base_lid(p_port), + block, position ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mftr_rcv_process( + IN osm_mftr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_sa_mad_t* p_rcvd_mad; + const ib_mft_record_t* p_rcvd_rec; + ib_mft_record_t* p_resp_rec; + cl_qlist_t rec_list; + osm_madw_t* p_resp_madw; + ib_sa_mad_t* p_resp_sa_mad; + uint32_t num_rec, pre_trim_num_rec; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t trim_num_rec; +#endif + uint32_t i; + osm_mftr_search_ctxt_t context; + osm_mftr_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + osm_physp_t* p_req_physp; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_mftr_rcv_process ); + + 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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mftr_rcv_process: ERR 4A08: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_rcvd_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mftr_rcv_process: 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.p_rcv = p_rcv; + context.p_req_physp = p_req_physp; + + cl_plock_acquire( p_rcv->p_lock ); + + /* Go over all switches */ + cl_qmap_apply_func( &p_rcv->p_subn->sw_guid_tbl, + __osm_mftr_rcv_by_comp_mask, + &context ); + + cl_plock_release( p_rcv->p_lock ); + + num_rec = cl_qlist_count( &rec_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if (p_rcvd_mad->method == IB_MAD_METHOD_GET) + { + if (num_rec == 0) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + if (num_rec > 1) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mftr_rcv_process: ERR 4A09: " + "Got more than one record for SubnAdmGet (%u)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS); + + /* need to set the mem free ... */ + p_rec_item = (osm_mftr_item_t*)cl_qlist_remove_head( &rec_list ); + while( p_rec_item != (osm_mftr_item_t*)cl_qlist_end( &rec_list ) ) + { + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_rec_item = (osm_mftr_item_t*)cl_qlist_remove_head( &rec_list ); + } + + goto Exit; + } + } + + pre_trim_num_rec = num_rec; +#ifndef VENDOR_RMPP_SUPPORT + /* we limit the number of records to a single packet */ + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_mft_record_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_mftr_rcv_process: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_mftr_rcv_process: " + "Returning %u records\n", num_rec ); + + if ((p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) && + (num_rec == 0)) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_mft_record_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + + if( !p_resp_madw ) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_mftr_rcv_process: ERR 4A10: " + "osm_mad_pool_get failed\n" ); + + for( i = 0; i < num_rec; i++ ) + { + p_rec_item = (osm_mftr_item_t*)cl_qlist_remove_head( &rec_list ); + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_NO_RESOURCES ); + + goto Exit; + } + + p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_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( p_resp_sa_mad, p_rcvd_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; + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_mft_record_t) ); + + p_resp_rec = (ib_mft_record_t*)ib_sa_mad_get_payload_ptr( p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + for( i = 0; i < pre_trim_num_rec; i++ ) + { + p_rec_item = (osm_mftr_item_t*)cl_qlist_remove_head( &rec_list ); + /* copy only if not trimmed */ + if (i < num_rec) + { + *p_resp_rec = p_rec_item->rec; + } + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_resp_rec++; + } + + CL_ASSERT( cl_is_qlist_empty( &rec_list ) ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + if (status != IB_SUCCESS) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_mftr_rcv_process: ERR 4A11: " + "osm_vendor_send status = %s\n", + ib_get_err_str(status)); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mft_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mft_record_ctrl.c new file mode 100644 index 00000000..3c0c39c7 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mft_record_ctrl.c @@ -0,0 +1,123 @@ +/* + * 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: + * Implementation of osm_mftr_rcv_ctrl_t. + * This object represents the MulticastForwardingTable request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_mftr_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_mftr_rcv_process( ((osm_mftr_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mftr_rcv_ctrl_construct( + IN osm_mftr_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_mftr_rcv_ctrl_destroy( + IN osm_mftr_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mftr_rcv_ctrl_init( + IN osm_mftr_rcv_ctrl_t* const p_ctrl, + IN osm_mftr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_mftr_rcv_ctrl_init ); + + osm_mftr_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_MFT_RECORD, + __osm_mftr_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_mftr_rcv_ctrl_init: ERR 4A01: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_multipath_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_multipath_record.c new file mode 100644 index 00000000..83404e0b --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_multipath_record.c @@ -0,0 +1,1652 @@ +/* + * 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: + * Implementation of osm_mpr_rcv_t. + * This object represents the MultiPath Record Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + +#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_MPR_RCV_POOL_MIN_SIZE 64 +#define OSM_MPR_RCV_POOL_GROW_SIZE 64 + +#define OSM_SA_MPR_MAX_NUM_PATH 127 + +typedef struct _osm_mpr_item +{ + cl_pool_item_t pool_item; + const osm_port_t *p_src_port; + const osm_port_t *p_dest_port; + int hops; + ib_path_rec_t path_rec; +} 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; + +/********************************************************************** + **********************************************************************/ +void +osm_mpr_rcv_construct( + IN osm_mpr_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pr_pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mpr_rcv_destroy( + IN osm_mpr_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_mpr_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->pr_pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mpr_rcv_init( + IN osm_mpr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_mpr_rcv_init ); + + osm_mpr_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + status = cl_qlock_pool_init( &p_rcv->pr_pool, + OSM_MPR_RCV_POOL_MIN_SIZE, + 0, + OSM_MPR_RCV_POOL_GROW_SIZE, + sizeof(osm_mpr_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static inline boolean_t +__osm_sa_multipath_rec_is_tavor_port( + IN const osm_port_t* const p_port) +{ + osm_node_t const* p_node; + ib_net32_t vend_id; + + p_node = osm_port_get_parent_node( p_port ); + 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))) ); +} + +/********************************************************************** + **********************************************************************/ +boolean_t + __osm_sa_multipath_rec_apply_tavor_mtu_limit( + IN const ib_multipath_rec_t* const p_mpr, + IN const osm_port_t* const p_src_port, + IN const osm_port_t* const p_dest_port, + IN const ib_net64_t comp_mask) +{ + uint8_t required_mtu; + + /* only if at least one of the ports is a Tavor device */ + if (! __osm_sa_multipath_rec_is_tavor_port(p_src_port) && + ! __osm_sa_multipath_rec_is_tavor_port(p_dest_port) ) + return( FALSE ); + + /* + we can apply the patch if either: + 1. No MTU required + 2. Required MTU < + 3. Required MTU = 1K or 512 or 256 + 4. Required MTU > 256 or 512 + */ + required_mtu = ib_multipath_rec_mtu( p_mpr ); + if ( ( comp_mask & IB_MPR_COMPMASK_MTUSELEC ) && + ( comp_mask & IB_PR_COMPMASK_MTU ) ) + { + switch( ib_multipath_rec_mtu_sel( p_mpr ) ) + { + case 0: /* must be greater than */ + case 2: /* exact match */ + if( IB_MTU_LEN_1024 < required_mtu ) + return(FALSE); + break; + + case 1: /* must be less than */ + /* can't be disqualified by this one */ + break; + + case 3: /* largest available */ + /* the ULP intentionally requested */ + /* the largest MTU possible */ + return(FALSE); + break; + + default: + /* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */ + CL_ASSERT( FALSE ); + break; + } + } + + return(TRUE); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_mpr_rcv_get_path_parms( + IN osm_mpr_rcv_t* const p_rcv, + IN const ib_multipath_rec_t* const p_mpr, + IN const osm_port_t* const p_src_port, + IN const osm_port_t* const p_dest_port, + IN const uint16_t dest_lid_ho, + IN const ib_net64_t comp_mask, + OUT osm_path_parms_t* const p_parms ) +{ + const osm_node_t* p_node; + const osm_physp_t* p_physp; + const osm_physp_t* p_dest_physp; + const osm_prtn_t* p_prtn; + 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; + uint16_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 vl; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_get_path_parms ); + + dest_lid = cl_hton16( dest_lid_ho ); + + p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port ); + p_physp = osm_port_get_default_phys_ptr( p_src_port ); + p_pi = osm_physp_get_port_info_ptr( p_physp ); + + 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 ( p_rcv->p_subn->opt.enable_quirks && + __osm_sa_multipath_rec_apply_tavor_mtu_limit( + p_mpr, p_src_port, p_dest_port, comp_mask) ) + if (mtu > IB_MTU_LEN_1024) + { + mtu = IB_MTU_LEN_1024; + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_path_parms: " + "Optimized Path MTU to 1K for Mellanox Tavor device\n"); + } + + if ( comp_mask & IB_MPR_COMPMASK_RAWTRAFFIC && + cl_ntoh32( p_mpr->hop_flow_raw ) & ( 1<<31 ) ) + required_pkey = osm_physp_find_common_pkey( p_physp, p_dest_physp ); + else if ( comp_mask & IB_MPR_COMPMASK_PKEY ) { + required_pkey = p_mpr->pkey; + if( !osm_physp_share_this_pkey( p_physp, p_dest_physp, required_pkey ) ) { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mpr_rcv_get_path_parms: 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_physp ) ), + cl_ntoh64( osm_physp_get_port_guid( p_dest_physp ) ) ); + status = IB_NOT_FOUND; + goto Exit; + } + } else { + required_pkey = osm_physp_find_common_pkey( p_physp, p_dest_physp ); + if ( !required_pkey ) { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mpr_rcv_get_path_parms: 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; + } + } + + required_sl = OSM_DEFAULT_SL; + + if (required_pkey) { + p_prtn = (osm_prtn_t *)cl_qmap_get(&p_rcv->p_subn->prtn_pkey_tbl, + required_pkey & cl_ntoh16((uint16_t)~0x8000)); + if ( p_prtn == (osm_prtn_t *)cl_qmap_end(&p_rcv->p_subn->prtn_pkey_tbl) ) + { + /* this may be possible when pkey tables are created somehow in + previous runs or things are going wrong here */ + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mpr_rcv_get_path_parms: 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; + + /* reset pkey when raw traffic */ + if( comp_mask & IB_PR_COMPMASK_RAWTRAFFIC && + cl_ntoh32( p_mpr->hop_flow_raw ) & ( 1<<31 ) ) + required_pkey = 0; + } + + if ( ( comp_mask & IB_MPR_COMPMASK_SL ) && ib_multipath_rec_sl( p_mpr ) != required_sl ) + { + status = IB_NOT_FOUND; + goto Exit; + } + + /* + 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 ) + { + + /* + * If the dest_lid_ho is equal to the lid of the switch pointed by + * p_sw then p_physp will be the physical port of the switch port zero. + */ + p_physp = osm_switch_get_route_by_lid( p_node->sw, cl_ntoh16( dest_lid_ho ) ); + if ( p_physp == 0 ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mpr_rcv_get_path_parms: ERR 4514: " + "Can't find routing to LID 0x%X 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; + } + } + + /* + * Same as above + */ + p_node = osm_physp_get_node_ptr( p_dest_physp ); + + if ( p_node->sw ) + { + + p_dest_physp = osm_switch_get_route_by_lid( p_node->sw, cl_ntoh16( dest_lid_ho ) ); + + if ( p_dest_physp == 0 ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mpr_rcv_get_path_parms: ERR 4515: " + "Can't find routing to LID 0x%X 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; + } + + } + + while ( p_physp != p_dest_physp ) + { + p_physp = osm_physp_get_remote( p_physp ); + + if ( p_physp == 0 ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mpr_rcv_get_path_parms: ERR 4505: " + "Can't find remote phys port when routing to LID 0x%X 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++; + + /* + 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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mpr_rcv_get_path_parms: ERR 4503: " + "Internal error, bad path\n" ); + status = IB_ERROR; + goto Exit; + } + + /* + Check parameters for the ingress port in this switch. + */ + p_pi = osm_physp_get_port_info_ptr( p_physp ); + + if ( mtu > ib_port_info_get_mtu_cap( p_pi ) ) + { + mtu = ib_port_info_get_mtu_cap( p_pi ); + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_path_parms: " + "New smallest MTU = %u at intervening port 0x%016" PRIx64 + " port num 0x%X\n", + mtu, + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ), + osm_physp_get_port_num( p_physp ) ); + } + } + + if ( rate > ib_port_info_compute_rate( p_pi ) ) + { + rate = ib_port_info_compute_rate( p_pi ); + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_path_parms: " + "New smallest rate = %u at intervening port 0x%016" PRIx64 + " port num 0x%X\n", + rate, + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ), + osm_physp_get_port_num( p_physp ) ); + } + } + + /* + 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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mpr_rcv_get_path_parms: ERR 4516: " + "Dead end on path to LID 0x%X 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; + } + + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + + if ( comp_mask & IB_MPR_COMPMASK_SL ) { + in_port_num = osm_physp_get_port_num( p_physp ); + p_slvl_tbl = osm_physp_get_slvl_tbl( p_physp, in_port_num ); + vl = ib_slvl_table_get( p_slvl_tbl, required_sl ); + if (vl == IB_DROP_VL) { /* discard packet */ + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_mpr_rcv_get_path_parms: Path not found for SL %d\n" + "\t\tin_port_num %d port_guid %" PRIx64 "\n", + required_sl, in_port_num, + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ) ); + status = IB_NOT_FOUND; + goto Exit; + } + } + + p_pi = osm_physp_get_port_info_ptr( p_physp ); + + if ( mtu > ib_port_info_get_mtu_cap( p_pi ) ) + { + mtu = ib_port_info_get_mtu_cap( p_pi ); + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_path_parms: " + "New smallest MTU = %u at intervening port 0x%016" PRIx64 + " port num 0x%X\n", + mtu, + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ), + osm_physp_get_port_num( p_physp ) ); + } + } + + if ( rate > ib_port_info_compute_rate( p_pi ) ) + { + rate = ib_port_info_compute_rate( p_pi ); + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_path_parms: " + "New smallest rate = %u at intervening port 0x%016" PRIx64 + " port num 0x%X\n", + rate, + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ), + osm_physp_get_port_num( p_physp ) ); + } + } + + } + + /* + p_physp now points to the destination + */ + p_pi = osm_physp_get_port_info_ptr( p_physp ); + + if ( mtu > ib_port_info_get_mtu_cap( p_pi ) ) + { + mtu = ib_port_info_get_mtu_cap( p_pi ); + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_path_parms: " + "New smallest MTU = %u at destination port 0x%016" PRIx64 "\n", + mtu, + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ) ); + } + } + + if ( rate > ib_port_info_compute_rate( p_pi ) ) + { + rate = ib_port_info_compute_rate( p_pi ); + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_path_parms: " + "New smallest rate = %u at destination port 0x%016" PRIx64 "\n", + rate, + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ) ); + } + } + + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_path_parms: " + "Path min MTU = %u, min rate = %u\n", mtu, rate ); + } + + /* + 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; + } + } + + /* we silently ignore cases where only the Rate selector is defined */ + if ( ( comp_mask & IB_MPR_COMPMASK_RATESELEC ) && + ( comp_mask & IB_PR_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; + } + } + + /* 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 + pkt_life = OSM_DEFAULT_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; + + 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; + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_mpr_rcv_build_pr( + IN osm_mpr_rcv_t* const p_rcv, + IN const osm_port_t* const p_src_port, + IN const osm_port_t* const p_dest_port, + IN const uint16_t src_lid_ho, + IN const uint16_t dest_lid_ho, + IN const uint8_t preference, + IN const osm_path_parms_t* const p_parms, + OUT ib_path_rec_t* const p_pr ) +{ + const osm_physp_t* p_src_physp; + const osm_physp_t* p_dest_physp; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_build_pr ); + + p_src_physp = osm_port_get_default_phys_ptr( p_src_port ); + p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port ); + + 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; + p_pr->sl = cl_hton16( 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( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static osm_mpr_item_t* +__osm_mpr_rcv_get_lid_pair_path( + IN osm_mpr_rcv_t* const p_rcv, + IN const ib_multipath_rec_t* const p_mpr, + IN const osm_port_t* const p_src_port, + IN const osm_port_t* const p_dest_port, + IN const uint16_t src_lid_ho, + IN const uint16_t dest_lid_ho, + IN const ib_net64_t comp_mask, + IN const uint8_t preference ) +{ + osm_path_parms_t path_parms; + osm_path_parms_t rev_path_parms; + osm_mpr_item_t *p_pr_item; + ib_api_status_t status, rev_path_status; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_get_lid_pair_path ); + + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_lid_pair_path: " + "Src LID 0x%X, Dest LID 0x%X\n", + src_lid_ho, dest_lid_ho ); + } + + p_pr_item = (osm_mpr_item_t*)cl_qlock_pool_get( &p_rcv->pr_pool ); + if ( p_pr_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mpr_rcv_get_lid_pair_path: ERR 4501: " + "Unable to allocate path record\n" ); + goto Exit; + } + + status = __osm_mpr_rcv_get_path_parms( p_rcv, p_mpr, p_src_port, + p_dest_port, dest_lid_ho, + comp_mask, &path_parms ); + + if ( status != IB_SUCCESS ) + { + cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item ); + p_pr_item = NULL; + goto Exit; + } + + /* now try the reversible path */ + rev_path_status = __osm_mpr_rcv_get_path_parms( p_rcv, 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( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_lid_pair_path: " + "Requested reversible path but failed to get one\n"); + + cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item ); + p_pr_item = NULL; + goto Exit; + } + } + + p_pr_item->p_src_port = p_src_port; + p_pr_item->p_dest_port = p_dest_port; + p_pr_item->hops = path_parms.hops; + + __osm_mpr_rcv_build_pr( p_rcv, p_src_port, p_dest_port, src_lid_ho, + dest_lid_ho, preference, &path_parms, + &p_pr_item->path_rec ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( p_pr_item ); +} + +/********************************************************************** + **********************************************************************/ +static uint32_t +__osm_mpr_rcv_get_port_pair_paths( + IN osm_mpr_rcv_t* const p_rcv, + IN const ib_multipath_rec_t* const p_mpr, + IN const osm_port_t* const p_req_port, + IN const osm_port_t* const p_src_port, + IN const osm_port_t* const p_dest_port, + IN const uint32_t rem_paths, + IN const ib_net64_t comp_mask, + IN cl_qlist_t* const p_list ) +{ + osm_mpr_item_t* p_pr_item; + uint16_t src_lid_min_ho; + uint16_t src_lid_max_ho; + uint16_t dest_lid_min_ho; + uint16_t dest_lid_max_ho; + uint16_t src_lid_ho; + uint16_t dest_lid_ho; + uint32_t path_num = 0; + uint8_t preference; + uintn_t src_offset; + uintn_t dest_offset; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_get_port_pair_paths ); + + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_port_pair_paths: " + "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(p_rcv->p_log, p_req_port, p_src_port ) == FALSE || + osm_port_share_pkey(p_rcv->p_log, p_req_port, p_dest_port ) == FALSE || + osm_port_share_pkey(p_rcv->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 ); + + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_port_pair_paths: " + "Src LID [0x%X-0x%X], " + "Dest LID [0x%X-0x%X]\n", + src_lid_min_ho, src_lid_max_ho, + dest_lid_min_ho, dest_lid_max_ho ); + } + + src_lid_ho = src_lid_min_ho; + dest_lid_ho = dest_lid_min_ho; + + /* + Preferred paths come first in OpenSM + */ + preference = 0; + + while ( path_num < rem_paths ) + { + /* + These paths are "fully redundant" + */ + p_pr_item = __osm_mpr_rcv_get_lid_pair_path( p_rcv, 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, + (cl_list_item_t*)&p_pr_item->pool_item ); + ++path_num; + } + + if ( ++src_lid_ho > src_lid_max_ho ) + break; + + if ( ++dest_lid_ho > dest_lid_max_ho ) + break; + } + + /* + Check if we've accumulated all the paths that the user cares to see + */ + if ( path_num == rem_paths ) + goto Exit; + + /* + Don't bother reporting preference 1 paths for now. + It's more trouble than it's worth and can only occur + if ports have different LMC values, which isn't supported + by OpenSM right now anyway. + */ + preference = 2; + src_lid_ho = src_lid_min_ho; + dest_lid_ho = dest_lid_min_ho; + src_offset = 0; + dest_offset = 0; + + /* + Iterate over the remaining paths + */ + while ( path_num < rem_paths ) + { + dest_offset++; + dest_lid_ho++; + + if ( dest_lid_ho > dest_lid_max_ho ) + { + src_offset++; + src_lid_ho++; + + if ( src_lid_ho > src_lid_max_ho ) + break; /* done */ + + dest_offset = 0; + dest_lid_ho = dest_lid_min_ho; + } + + /* + These paths are "fully non-redundant" with paths already + identified above and consequently not of much value. + + Don't return paths we already identified above, as indicated + by the offset values being equal. + */ + if ( src_offset == dest_offset ) + continue; /* already reported */ + + p_pr_item = __osm_mpr_rcv_get_lid_pair_path( p_rcv, 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, + (cl_list_item_t*)&p_pr_item->pool_item ); + ++path_num; + } + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return path_num; +} + +#undef min +#define min(x,y) (((x) < (y)) ? (x) : (y)) + +/********************************************************************** + **********************************************************************/ +static osm_mpr_item_t* +__osm_mpr_rcv_get_apm_port_pair_paths( + IN osm_mpr_rcv_t* const p_rcv, + IN const ib_multipath_rec_t* const p_mpr, + IN const osm_port_t* const p_src_port, + IN const osm_port_t* const p_dest_port, + IN int base_offs, + IN const ib_net64_t comp_mask, + IN cl_qlist_t* const p_list ) +{ + osm_mpr_item_t* p_pr_item = 0; + uint16_t src_lid_min_ho; + uint16_t src_lid_max_ho; + uint16_t dest_lid_min_ho; + uint16_t dest_lid_max_ho; + uint16_t src_lid_ho; + uint16_t dest_lid_ho; + uintn_t iterations; + int src_lids, dest_lids; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_get_apm_port_pair_paths ); + + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_apm_port_pair_paths: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_apm_port_pair_paths: " + "Src LIDs [0x%X-0x%X] hashed %d, " + "Dest LIDs [0x%X-0x%X] hashed %d\n", + src_lid_min_ho, src_lid_max_ho, src_lid_ho, + dest_lid_min_ho, dest_lid_max_ho, dest_lid_ho ); + + iterations = min( src_lids, dest_lids ); + + while ( iterations-- ) + { + /* + These paths are "fully redundant" + */ + p_pr_item = __osm_mpr_rcv_get_lid_pair_path( p_rcv, p_mpr, + p_src_port, p_dest_port, + src_lid_ho, dest_lid_ho, + comp_mask, 0 ); + + if ( p_pr_item ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_get_apm_port_pair_paths: " + "Found matching path from Src LID 0x%X to Dest LID 0x%X 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( p_rcv->p_log ); + return p_pr_item; +} + +/********************************************************************** + **********************************************************************/ +static ib_net16_t +__osm_mpr_rcv_get_gids( + IN osm_mpr_rcv_t* const p_rcv, + 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( p_rcv->p_log, __osm_mpr_rcv_get_gids ); + + 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 ) != p_rcv->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( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_mpr_rcv_get_gids: ERR 451B: " + "Non local %sGID subnet prefix 0x%016" PRIx64 "\n", + is_sgid ? "S" : "D", + cl_ntoh64( gids->unicast.prefix ) ); + + ib_status = IB_SA_MAD_STATUS_INVALID_GID; + goto Exit; + } + } + + p_port = (osm_port_t *)cl_qmap_get( &p_rcv->p_subn->port_guid_tbl, + gids->unicast.interface_id ); + if ( !p_port || + p_port == (osm_port_t *)cl_qmap_end( &p_rcv->p_subn->port_guid_tbl ) ) { + /* + 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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mpr_rcv_get_gids: 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(p_rcv->p_log); + + return ib_status; +} + +/********************************************************************** + **********************************************************************/ +static ib_net16_t +__osm_mpr_rcv_get_end_points( + IN osm_mpr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + OUT osm_port_t ** pp_ports, + OUT int * nsrc, + OUT int * ndest ) +{ + const ib_multipath_rec_t* p_mpr; + const ib_sa_mad_t* p_sa_mad; + ib_net64_t comp_mask; + ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS; + ib_gid_t * gids; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_get_end_points ); + + /* + Determine what fields are valid and then get a pointer + to the source and destination port objects, if possible. + */ + p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw ); + p_mpr = (ib_multipath_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad ); + gids = (ib_gid_t *)p_mpr->gids; + + comp_mask = p_sa_mad->comp_mask; + + /* + Check a few easy disqualifying cases up front before getting + into the endpoints. + */ + *nsrc = *ndest = 0; + + if ( comp_mask & IB_MPR_COMPMASK_SGIDCOUNT ) { + *nsrc = p_mpr->sgid_count; + if ( *nsrc > IB_MULTIPATH_MAX_GIDS ) + *nsrc = IB_MULTIPATH_MAX_GIDS; + sa_status = __osm_mpr_rcv_get_gids( p_rcv, gids, *nsrc, 1, pp_ports ); + if ( sa_status != IB_SUCCESS ) + goto Exit; + } + + if ( comp_mask & IB_MPR_COMPMASK_DGIDCOUNT ) { + *ndest = p_mpr->dgid_count; + if ( *ndest + *nsrc > IB_MULTIPATH_MAX_GIDS ) + *ndest = IB_MULTIPATH_MAX_GIDS - *nsrc; + sa_status = __osm_mpr_rcv_get_gids( p_rcv, gids + *nsrc, *ndest, 0, + pp_ports + *nsrc ); + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( sa_status ); +} + +#define __hash_lids(a, b, lmc) \ + (((((a) >> (lmc)) << 4) | ((b) >> (lmc))) % 103) + +/********************************************************************** + **********************************************************************/ +static void +__osm_mpr_rcv_get_apm_paths( + IN osm_mpr_rcv_t* const p_rcv, + IN const ib_multipath_rec_t* const p_mpr, + IN const osm_port_t* const p_req_port, + IN osm_port_t ** _pp_ports, + IN const ib_net64_t comp_mask, + IN cl_qlist_t* const p_list ) +{ + osm_port_t *pp_ports[4]; + osm_mpr_item_t *matrix[2][2]; + int base_offs, src_lid_ho, dest_lid_ho; + int sumA, sumB, minA, minB; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_get_apm_paths ); + + /* + * We want to: + * 1. use different lid offsets (from base) for the resultant paths + * to increase the probability of redundant paths or in case + * of Clos - to ensure it (different offset => different spine!) + * 2. keep consistent paths no matter of direction and order of ports + * 3. distibute the lid offsets to balance the load + * So, we sort the ports (within the srcs, and within the dests), + * hash the lids of S0, D0 (after the sort), and call __osm_mpr_rcv_get_apm_port_pair_paths + * with base_lid for S0, D0 and base_lid + 1 for S1, D1. This way we will get + * always the same offsets - order indepentent, and make sure different spines are used. + * Note that the diagonals on a Clos have the same number of hops, so it doesn't + * really matter which diagonal we use. + */ + if ( _pp_ports[0]->guid < _pp_ports[1]->guid ) { + pp_ports[0] = _pp_ports[0]; + pp_ports[1] = _pp_ports[1]; + } + else + { + pp_ports[0] = _pp_ports[1]; + pp_ports[1] = _pp_ports[0]; + } + if ( _pp_ports[2]->guid < _pp_ports[3]->guid ) { + pp_ports[2] = _pp_ports[2]; + pp_ports[3] = _pp_ports[3]; + } + else + { + pp_ports[2] = _pp_ports[3]; + pp_ports[3] = _pp_ports[2]; + } + + src_lid_ho = osm_port_get_base_lid( pp_ports[0] ); + dest_lid_ho = osm_port_get_base_lid( pp_ports[2] ); + + base_offs = src_lid_ho < dest_lid_ho ? + __hash_lids( src_lid_ho, dest_lid_ho, p_rcv->p_subn->opt.lmc ) : + __hash_lids( dest_lid_ho, src_lid_ho, p_rcv->p_subn->opt.lmc ); + + matrix[0][0] = __osm_mpr_rcv_get_apm_port_pair_paths( p_rcv, p_mpr, pp_ports[0], + pp_ports[2], base_offs, comp_mask , p_list ); + matrix[0][1] = __osm_mpr_rcv_get_apm_port_pair_paths( p_rcv, p_mpr, pp_ports[0], + pp_ports[3], base_offs, comp_mask, p_list ); + matrix[1][0] = __osm_mpr_rcv_get_apm_port_pair_paths( p_rcv, p_mpr, pp_ports[1], + pp_ports[2], base_offs+1, comp_mask, p_list ); + matrix[1][1] = __osm_mpr_rcv_get_apm_port_pair_paths( p_rcv, p_mpr, pp_ports[1], + pp_ports[3], base_offs+1, comp_mask, p_list ); + + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, "__osm_mpr_rcv_get_apm_paths: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, "__osm_mpr_rcv_get_apm_paths: " + "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, + (cl_list_item_t*)&matrix[0][0]->pool_item ); + cl_qlist_insert_tail( p_list, + (cl_list_item_t*)&matrix[1][1]->pool_item ); + cl_qlock_pool_put( &p_rcv->pr_pool, &matrix[0][1]->pool_item ); + cl_qlock_pool_put( &p_rcv->pr_pool, &matrix[1][0]->pool_item ); + } + else + { + /* Diag B */ + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, "__osm_mpr_rcv_get_apm_paths: " + "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, + (cl_list_item_t*)&matrix[0][1]->pool_item ); + cl_qlist_insert_tail( p_list, + (cl_list_item_t*)&matrix[1][0]->pool_item ); + cl_qlock_pool_put( &p_rcv->pr_pool, &matrix[0][0]->pool_item ); + cl_qlock_pool_put( &p_rcv->pr_pool, &matrix[1][1]->pool_item ); + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_mpr_rcv_process_pairs( + IN osm_mpr_rcv_t* const p_rcv, + IN const ib_multipath_rec_t* const p_mpr, + IN osm_port_t* const p_req_port, + IN osm_port_t ** pp_ports, + IN const int nsrc, + IN const int ndest, + IN const ib_net64_t comp_mask, + IN cl_qlist_t* const p_list ) +{ + osm_port_t **pp_src_port, **pp_es; + osm_port_t **pp_dest_port, **pp_ed; + uint32_t max_paths, num_paths, total_paths = 0; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_process_pairs ); + + if ( comp_mask & IB_MPR_COMPMASK_NUMBPATH ) + max_paths = p_mpr->num_path & 0x7F; + else + max_paths = OSM_SA_MPR_MAX_NUM_PATH; + + for ( pp_src_port = pp_ports, pp_es = pp_ports + nsrc; pp_src_port < pp_es; pp_src_port++ ) + { + for ( pp_dest_port = pp_es, pp_ed = pp_es + ndest; pp_dest_port < pp_ed; pp_dest_port++ ) + { + num_paths = __osm_mpr_rcv_get_port_pair_paths( p_rcv, 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( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_process_pairs: " + "%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( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_mpr_rcv_respond( + IN osm_mpr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + IN cl_qlist_t* const p_list ) +{ + osm_madw_t* p_resp_madw; + const ib_sa_mad_t* p_sa_mad; + ib_sa_mad_t* p_resp_sa_mad; + size_t num_rec; + size_t mad_size; + ib_path_rec_t* p_resp_pr; + ib_multipath_rec_t* p_mpr; + ib_api_status_t status; + osm_mpr_item_t* p_mpr_item; + uint32_t i; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_respond ); + + 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 ); + + num_rec = cl_qlist_count( p_list ); + + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_mpr_rcv_respond: " + "Generating response with %zu records\n", num_rec ); + + mad_size = IB_SA_MAD_HDR_SIZE + num_rec * sizeof(ib_path_rec_t); + + /* + Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, p_madw->h_bind, + mad_size, &p_madw->mad_addr ); + + if ( !p_resp_madw ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mpr_rcv_respond: " + "ERR 4502: Unable to allocate MAD\n" ); + + for ( i = 0; i < num_rec; i++ ) + { + p_mpr_item = (osm_mpr_item_t*)cl_qlist_remove_head( p_list ); + cl_qlock_pool_put( &p_rcv->pr_pool, &p_mpr_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES ); + goto Exit; + } + + 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; + + /* + 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_resp_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD; + p_resp_sa_mad->attr_offset = ib_get_attr_offset( sizeof(ib_path_rec_t) ); + + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; + + p_resp_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_resp_sa_mad ); + + for ( i = 0; i < num_rec; i++ ) + { + p_mpr_item = (osm_mpr_item_t*)cl_qlist_remove_head( p_list ); + + /* Copy the Path Records from the list into the MAD */ + *p_resp_pr = p_mpr_item->path_rec; + + cl_qlock_pool_put( &p_rcv->pr_pool, &p_mpr_item->pool_item ); + p_resp_pr++; + } + + CL_ASSERT( cl_is_qlist_empty( p_list ) ); + + osm_dump_sa_mad( p_rcv->p_log, p_resp_sa_mad, OSM_LOG_FRAMES ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + + if ( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mpr_rcv_respond: ERR 4507: " + "Unable to send MAD (%s)\n", ib_get_err_str( status ) ); + /* osm_mad_pool_put( p_rcv->p_mad_pool, p_resp_madw ); */ + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mpr_rcv_process( + IN osm_mpr_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ) +{ + const ib_multipath_rec_t* p_mpr; + const 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( p_rcv->p_log, osm_mpr_rcv_process ); + + 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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mpr_rcv_process: ERR 4510: " + "Invalid request since RMPP_FLAG_ACTIVE is not set\n" ); + osm_sa_send_error( p_rcv->p_resp, 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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mpr_rcv_process: ERR 4513: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_sa_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + /* update the requester physical port. */ + requester_port = osm_get_port_by_mad_addr( p_rcv->p_log, p_rcv->p_subn, + osm_madw_get_mad_addr_ptr( p_madw ) ); + if ( requester_port == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mpr_rcv_process: ERR 4517: " + "Cannot find requester physical port\n" ); + goto Exit; + } + + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + osm_dump_multipath_record( p_rcv->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( p_rcv->p_lock ); + + sa_status = __osm_mpr_rcv_get_end_points( p_rcv, 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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mpr_rcv_process_cb: ERR 4512: " + "__osm_mpr_rcv_get_end_points failed, not enough GIDs " + "(nsrc %d ndest %d)\n", + nsrc, ndest); + cl_plock_release( p_rcv->p_lock ); + if ( sa_status == IB_SA_MAD_STATUS_SUCCESS ) + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_REQ_INVALID ); + else + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + + /* APM request */ + if ( nsrc == 2 && ndest == 2 && ( p_mpr->num_path & 0x7F ) == 2 ) + __osm_mpr_rcv_get_apm_paths( p_rcv, p_mpr, requester_port, pp_ports, + p_sa_mad->comp_mask, &pr_list ); + else + __osm_mpr_rcv_process_pairs( p_rcv, p_mpr, requester_port, pp_ports, + nsrc, ndest, + p_sa_mad->comp_mask, &pr_list ); + + cl_plock_release( p_rcv->p_lock ); + __osm_mpr_rcv_respond( p_rcv, p_madw, &pr_list ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} +#endif + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_multipath_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_multipath_record_ctrl.c new file mode 100644 index 00000000..6a30be92 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_multipath_record_ctrl.c @@ -0,0 +1,128 @@ +/* + * 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: + * Implementation of osm_mpr_rcv_ctrl_t. + * This object represents the MultiPathRecord request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +static void +__osm_mpr_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_mpr_rcv_process( ((osm_mpr_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mpr_rcv_ctrl_construct( + IN osm_mpr_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_mpr_rcv_ctrl_destroy( + IN osm_mpr_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mpr_rcv_ctrl_init( + IN osm_mpr_rcv_ctrl_t* const p_ctrl, + IN osm_mpr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_mpr_rcv_ctrl_init ); + + osm_mpr_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_MULTIPATH_RECORD, + __osm_mpr_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_mpr_rcv_ctrl_init: ERR 4B01: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + +#endif + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_node_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_node_record.c new file mode 100644 index 00000000..0c752afe --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_node_record.c @@ -0,0 +1,600 @@ +/* + * 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: + * Implementation of osm_nr_rcv_t. + * This object represents the NodeInfo Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.8 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_NR_RCV_POOL_MIN_SIZE 32 +#define OSM_NR_RCV_POOL_GROW_SIZE 32 + +typedef struct _osm_nr_item +{ + cl_pool_item_t pool_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_nr_rcv_t* p_rcv; + const osm_physp_t* p_req_physp; +} osm_nr_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void +osm_nr_rcv_construct( + IN osm_nr_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_nr_rcv_destroy( + IN osm_nr_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_nr_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_nr_rcv_init( + IN osm_nr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN const osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_nr_rcv_init ); + + osm_nr_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + status = cl_qlock_pool_init( &p_rcv->pool, + OSM_NR_RCV_POOL_MIN_SIZE, + 0, + OSM_NR_RCV_POOL_GROW_SIZE, + sizeof(osm_nr_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_nr_rcv_new_nr( + IN osm_nr_rcv_t* const p_rcv, + IN const osm_node_t* const p_node, + IN cl_qlist_t* const p_list, + IN ib_net64_t const port_guid, + IN ib_net16_t const lid ) +{ + osm_nr_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_nr_rcv_new_nr ); + + p_rec_item = (osm_nr_item_t*)cl_qlock_pool_get( &p_rcv->pool ); + if( p_rec_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_nr_rcv_new_nr: ERR 1D02: " + "cl_qlock_pool_get failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_nr_rcv_new_nr: " + "New NodeRecord: node 0x%016" PRIx64 + "\n\t\t\t\tport 0x%016" PRIx64 ", lid 0x%X\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + cl_ntoh64( port_guid ), cl_ntoh16( lid ) + ); + } + + memset( &p_rec_item->rec, 0, sizeof(ib_node_record_t) ); + + 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, (cl_list_item_t*)&p_rec_item->pool_item ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_nr_rcv_create_nr( + IN osm_nr_rcv_t* const p_rcv, + IN const osm_node_t* const p_node, + IN cl_qlist_t* const p_list, + IN ib_net64_t const match_port_guid, + IN ib_net16_t const match_lid, + IN const osm_physp_t* const p_req_physp ) +{ + 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( p_rcv->p_log, __osm_nr_rcv_create_nr ); + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_nr_rcv_create_nr: " + "Looking for NodeRecord with LID: 0x%X 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( !osm_physp_is_valid( 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( p_rcv->p_log, p_physp, p_req_physp ) ) + continue; + + port_guid = osm_physp_get_port_guid( p_physp ); + + if( match_port_guid && ( port_guid != match_port_guid ) ) + continue; + + base_lid = osm_physp_get_base_lid( p_physp ); + base_lid_ho = cl_ntoh16( base_lid ); + lmc = osm_physp_get_lmc( p_physp ); + max_lid_ho = (uint16_t)( base_lid_ho + (1 << lmc) - 1 ); + match_lid_ho = cl_ntoh16( match_lid ); + + if( match_lid_ho ) + { + /* + We validate that the lid belongs to this node. + */ + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_nr_rcv_create_nr: " + "Comparing LID: 0x%X <= 0x%X <= 0x%X\n", + base_lid_ho, match_lid_ho, max_lid_ho + ); + } + + if ( match_lid_ho < base_lid_ho || match_lid_ho > max_lid_ho ) + continue; + } + + __osm_nr_rcv_new_nr( p_rcv, p_node, p_list, port_guid, base_lid ); + + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_nr_rcv_by_comp_mask( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + const osm_nr_search_ctxt_t* const p_ctxt = (osm_nr_search_ctxt_t *)context; + const osm_node_t* const p_node = (osm_node_t*)p_map_item; + const ib_node_record_t* const p_rcvd_rec = p_ctxt->p_rcvd_rec; + const osm_physp_t* const p_req_physp = p_ctxt->p_req_physp; + osm_nr_rcv_t* const p_rcv = p_ctxt->p_rcv; + ib_net64_t const comp_mask = p_ctxt->comp_mask; + ib_net64_t match_port_guid = 0; + ib_net16_t match_lid = 0; + + OSM_LOG_ENTER( p_ctxt->p_rcv->p_log, __osm_nr_rcv_by_comp_mask ); + + osm_dump_node_info( + p_ctxt->p_rcv->p_log, + &p_node->node_info, + OSM_LOG_VERBOSE ); + + if( comp_mask & IB_NR_COMPMASK_LID ) + match_lid = p_rcvd_rec->lid; + + if( comp_mask & IB_NR_COMPMASK_NODEGUID) + { + /* + DEBUG TOP + */ + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_nr_rcv_by_comp_mask: " + "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 ) ) + ); + } + /* + DEBUG BOTTOM + */ + if( (p_node->node_info.node_guid != p_rcvd_rec->node_info.node_guid) ) + goto Exit; + } + if( comp_mask & IB_NR_COMPMASK_PORTGUID ) + { + match_port_guid = p_rcvd_rec->node_info.port_guid; + } + if( comp_mask & IB_NR_COMPMASK_SYSIMAGEGUID ) + { + if( (p_node->node_info.sys_guid != p_rcvd_rec->node_info.sys_guid) ) + goto Exit; + } + if( comp_mask & IB_NR_COMPMASK_BASEVERSION ) + { + if( (p_node->node_info.base_version != p_rcvd_rec->node_info.base_version) ) + goto Exit; + } + if( comp_mask & IB_NR_COMPMASK_CLASSVERSION ) + { + if( (p_node->node_info.class_version != p_rcvd_rec->node_info.class_version) ) + goto Exit; + } + if( comp_mask & IB_NR_COMPMASK_NODETYPE ) + { + if( (p_node->node_info.node_type != p_rcvd_rec->node_info.node_type) ) + goto Exit; + } + if( comp_mask & IB_NR_COMPMASK_NUMPORTS ) + { + if( (p_node->node_info.num_ports != p_rcvd_rec->node_info.num_ports) ) + goto Exit; + } + if( comp_mask & IB_NR_COMPMASK_PARTCAP ) + { + if( (p_node->node_info.partition_cap != p_rcvd_rec->node_info.partition_cap) ) + goto Exit; + } + if( comp_mask & IB_NR_COMPMASK_DEVID ) + { + if( (p_node->node_info.device_id != p_rcvd_rec->node_info.device_id) ) + goto Exit; + } + if( comp_mask & IB_NR_COMPMASK_REV ) + { + if( (p_node->node_info.revision != p_rcvd_rec->node_info.revision) ) + goto Exit; + } + if( comp_mask & IB_NR_COMPMASK_PORTNUM ) + { + if( ib_node_info_get_local_port_num(&p_node->node_info) != + ib_node_info_get_local_port_num(&p_rcvd_rec->node_info) ) + goto Exit; + } + if( comp_mask & IB_NR_COMPMASK_VENDID ) + { + if( ib_node_info_get_vendor_id(&p_node->node_info) != + ib_node_info_get_vendor_id(&p_rcvd_rec->node_info) ) + goto Exit; + } + if( comp_mask & IB_NR_COMPMASK_NODEDESC ) + { + if( strncmp((char*) &p_node->node_desc, + (char*) &p_rcvd_rec->node_desc, sizeof(ib_node_desc_t)) ) + goto Exit; + } + + __osm_nr_rcv_create_nr( p_rcv, p_node, p_ctxt->p_list, + match_port_guid, match_lid, p_req_physp ); + + Exit: + OSM_LOG_EXIT( p_ctxt->p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_nr_rcv_process( + IN osm_nr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_sa_mad_t* p_rcvd_mad; + const ib_node_record_t* p_rcvd_rec; + ib_node_record_t* p_resp_rec; + cl_qlist_t rec_list; + osm_madw_t* p_resp_madw; + ib_sa_mad_t* p_resp_sa_mad; + uint32_t num_rec, pre_trim_num_rec; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t trim_num_rec; +#endif + uint32_t i; + osm_nr_search_ctxt_t context; + osm_nr_item_t* p_rec_item; + ib_api_status_t status; + osm_physp_t* p_req_physp; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_nr_rcv_process ); + + 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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_nr_rcv_process: ERR 1D05: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_rcvd_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_nr_rcv_process: ERR 1D04: " + "Cannot find requester physical port\n" ); + goto Exit; + } + + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + osm_dump_node_record( p_rcv->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.p_rcv = p_rcv; + context.p_req_physp = p_req_physp; + + cl_plock_acquire( p_rcv->p_lock ); + + cl_qmap_apply_func( &p_rcv->p_subn->node_guid_tbl, + __osm_nr_rcv_by_comp_mask, + &context ); + + cl_plock_release( p_rcv->p_lock ); + + num_rec = cl_qlist_count( &rec_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if ( (p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec > 1) ) { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_nr_rcv_process: ERR 1D03: " + "Got more than one record for SubnAdmGet (%u)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS ); + + /* need to set the mem free ... */ + p_rec_item = (osm_nr_item_t*)cl_qlist_remove_head( &rec_list ); + while( p_rec_item != (osm_nr_item_t*)cl_qlist_end( &rec_list ) ) + { + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_rec_item = (osm_nr_item_t*)cl_qlist_remove_head( &rec_list ); + } + + goto Exit; + } + + pre_trim_num_rec = num_rec; +#ifndef VENDOR_RMPP_SUPPORT + /* we limit the number of records to a single packet */ + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_node_record_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_nr_rcv_process: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_nr_rcv_process: " + "Returning %u records\n", num_rec ); + + if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0)) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_node_record_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + + if( !p_resp_madw ) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_nr_rcv_process: ERR 1D06: " + "osm_mad_pool_get failed\n" ); + + for( i = 0; i < num_rec; i++ ) + { + p_rec_item = (osm_nr_item_t*)cl_qlist_remove_head( &rec_list ); + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES ); + goto Exit; + } + + p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_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( p_resp_sa_mad, p_rcvd_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; + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_node_record_t) ); + + p_resp_rec = (ib_node_record_t*)ib_sa_mad_get_payload_ptr( p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + for( i = 0; i < pre_trim_num_rec; i++ ) + { + p_rec_item = (osm_nr_item_t*)cl_qlist_remove_head( &rec_list ); + /* copy only if not trimmed */ + if (i < num_rec) + { + *p_resp_rec = p_rec_item->rec; + } + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_resp_rec++; + } + + CL_ASSERT( cl_is_qlist_empty( &rec_list ) ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + if (status != IB_SUCCESS) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_nr_rcv_process: ERR 1D07: " + "osm_vendor_send status = %s\n", + ib_get_err_str(status)); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_node_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_node_record_ctrl.c new file mode 100644 index 00000000..5712c83c --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_node_record_ctrl.c @@ -0,0 +1,125 @@ +/* + * 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: + * Implementation of osm_nr_rcv_ctrl_t. + * This object represents the Node Record controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_nr_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_nr_rcv_process( ((osm_nr_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_nr_rcv_ctrl_construct( + IN osm_nr_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_nr_rcv_ctrl_destroy( + IN osm_nr_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_nr_rcv_ctrl_init( + IN osm_nr_rcv_ctrl_t* const p_ctrl, + IN osm_nr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_nr_rcv_ctrl_init ); + + osm_nr_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_NODE_RECORD, + __osm_nr_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_nr_rcv_ctrl_init: ERR 1E01: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_path_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_path_record.c new file mode 100644 index 00000000..7fb9fb7f --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_path_record.c @@ -0,0 +1,2006 @@ +/* + * 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: + * Implementation of osm_pr_rcv_t. + * This object represents the PathRecord Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.10 $ + */ + +#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 + +#define OSM_PR_RCV_POOL_MIN_SIZE 64 +#define OSM_PR_RCV_POOL_GROW_SIZE 64 + +typedef struct _osm_pr_item +{ + cl_pool_item_t pool_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; + +typedef struct osm_sa_pr_mcmr_search_ctxt { + ib_gid_t *p_mgid; + osm_mgrp_t *p_mgrp; + osm_pr_rcv_t *p_rcv; +} osm_sa_pr_mcmr_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void +osm_pr_rcv_construct( + IN osm_pr_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pr_pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pr_rcv_destroy( + IN osm_pr_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_pr_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->pr_pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pr_rcv_init( + IN osm_pr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_pr_rcv_init ); + + osm_pr_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + status = cl_qlock_pool_init( &p_rcv->pr_pool, + OSM_PR_RCV_POOL_MIN_SIZE, + 0, + OSM_PR_RCV_POOL_GROW_SIZE, + sizeof(osm_pr_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static inline boolean_t +__osm_sa_path_rec_is_tavor_port( + IN const osm_port_t* const p_port) +{ + osm_node_t const* p_node; + ib_net32_t vend_id; + + p_node = osm_port_get_parent_node( p_port ); + vend_id = ib_node_info_get_vendor_id( &p_node->node_info ); + + return( (p_node->node_info.device_id == CL_HTON16(23108)) && + ((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) || + (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) || + (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) || + (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))) ); +} + +/********************************************************************** + **********************************************************************/ +static boolean_t + __osm_sa_path_rec_apply_tavor_mtu_limit( + IN const ib_path_rec_t* const p_pr, + IN const osm_port_t* const p_src_port, + IN const osm_port_t* const p_dest_port, + IN const ib_net64_t comp_mask) +{ + uint8_t required_mtu; + + /* only if at least one of the ports is a Tavor device */ + if (! __osm_sa_path_rec_is_tavor_port(p_src_port) && + ! __osm_sa_path_rec_is_tavor_port(p_dest_port) ) + return( FALSE ); + + /* + we can apply the patch if either: + 1. No MTU required + 2. Required MTU < + 3. Required MTU = 1K or 512 or 256 + 4. Required MTU > 256 or 512 + */ + required_mtu = ib_path_rec_mtu( p_pr ); + if ( ( comp_mask & IB_PR_COMPMASK_MTUSELEC ) && + ( comp_mask & IB_PR_COMPMASK_MTU ) ) + { + switch( ib_path_rec_mtu_sel( p_pr ) ) + { + case 0: /* must be greater than */ + case 2: /* exact match */ + if( IB_MTU_LEN_1024 < required_mtu ) + return(FALSE); + break; + + case 1: /* must be less than */ + /* can't be disqualified by this one */ + break; + + case 3: /* largest available */ + /* the ULP intentionally requested */ + /* the largest MTU possible */ + return(FALSE); + break; + + default: + /* if we're here, there's a bug in ib_path_rec_mtu_sel() */ + CL_ASSERT( FALSE ); + break; + } + } + + return(TRUE); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_pr_rcv_get_path_parms( + IN osm_pr_rcv_t* const p_rcv, + IN const ib_path_rec_t* const p_pr, + IN const osm_port_t* const p_src_port, + IN const osm_port_t* const p_dest_port, + IN const uint16_t dest_lid_ho, + IN const ib_net64_t comp_mask, + OUT osm_path_parms_t* const p_parms ) +{ + const osm_node_t* p_node; + const osm_physp_t* p_physp; + const osm_physp_t* p_dest_physp; + const osm_prtn_t* p_prtn; + 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; + ib_net16_t dest_lid; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_path_parms ); + + dest_lid = cl_hton16( dest_lid_ho ); + + p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port ); + p_physp = osm_port_get_default_phys_ptr( p_src_port ); + p_pi = osm_physp_get_port_info_ptr( p_physp ); + + 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 ( p_rcv->p_subn->opt.enable_quirks && + __osm_sa_path_rec_apply_tavor_mtu_limit( + p_pr, p_src_port, p_dest_port, comp_mask) ) + if (mtu > IB_MTU_LEN_1024) + { + mtu = IB_MTU_LEN_1024; + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pr_rcv_get_path_parms: " + "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 ) + { + /* + * If the dest_lid_ho is equal to the lid of the switch pointed by + * p_sw then p_physp will be the physical port of the switch port zero. + */ + p_physp = osm_switch_get_route_by_lid(p_node->sw, cl_ntoh16( dest_lid_ho ) ); + if ( p_physp == 0 ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_get_path_parms: ERR 1F02: " + "Cannot find routing to LID 0x%X 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; + } + } + + /* + * Same as above + */ + p_node = osm_physp_get_node_ptr( p_dest_physp ); + + if( p_node->sw ) + { + p_dest_physp = osm_switch_get_route_by_lid( p_node->sw, cl_ntoh16( dest_lid_ho ) ); + + if ( p_dest_physp == 0 ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_get_path_parms: ERR 1F03: " + "Cannot find routing to LID 0x%X 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; + } + + } + + while( p_physp != p_dest_physp ) + { + p_physp = osm_physp_get_remote( p_physp ); + + if ( p_physp == 0 ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_get_path_parms: ERR 1F05: " + "Cannot find remote phys port when routing to LID 0x%X from node GUID 0x%016" PRIx64 "\n", + dest_lid_ho, + cl_ntoh64( osm_node_get_node_guid( p_node ) ) ); + status = IB_ERROR; + goto Exit; + } + + /* + 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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_get_path_parms: ERR 1F06: " + "Internal error, bad path\n" ); + status = IB_ERROR; + goto Exit; + } + + /* + Check parameters for the ingress port in this switch. + */ + p_pi = osm_physp_get_port_info_ptr( p_physp ); + + if( mtu > ib_port_info_get_mtu_cap( p_pi ) ) + { + mtu = ib_port_info_get_mtu_cap( p_pi ); + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pr_rcv_get_path_parms: " + "New smallest MTU = %u at intervening port 0x%016" PRIx64 + " port num 0x%X\n", + mtu, + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ), + osm_physp_get_port_num( p_physp ) ); + } + } + + if( rate > ib_port_info_compute_rate( p_pi ) ) + { + rate = ib_port_info_compute_rate( p_pi ); + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pr_rcv_get_path_parms: " + "New smallest rate = %u at intervening port 0x%016" PRIx64 + " port num 0x%X\n", + rate, + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ), + osm_physp_get_port_num( p_physp ) ); + } + } + + /* + 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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_get_path_parms: ERR 1F07: " + "Dead end on path to LID 0x%X 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; + } + + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + + p_pi = osm_physp_get_port_info_ptr( p_physp ); + + if( mtu > ib_port_info_get_mtu_cap( p_pi ) ) + { + mtu = ib_port_info_get_mtu_cap( p_pi ); + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pr_rcv_get_path_parms: " + "New smallest MTU = %u at intervening port 0x%016" PRIx64 + " port num 0x%X\n", + mtu, + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ), + osm_physp_get_port_num( p_physp ) ); + } + } + + if( rate > ib_port_info_compute_rate( p_pi ) ) + { + rate = ib_port_info_compute_rate( p_pi ); + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pr_rcv_get_path_parms: " + "New smallest rate = %u at intervening port 0x%016" PRIx64 + " port num 0x%X\n", + rate, + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ), + osm_physp_get_port_num( p_physp ) ); + } + } + + } + + /* + p_physp now points to the destination + */ + p_pi = osm_physp_get_port_info_ptr( p_physp ); + + if( mtu > ib_port_info_get_mtu_cap( p_pi ) ) + { + mtu = ib_port_info_get_mtu_cap( p_pi ); + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pr_rcv_get_path_parms: " + "New smallest MTU = %u at destination port 0x%016" PRIx64 "\n", + mtu, + cl_ntoh64(osm_physp_get_port_guid( p_physp )) ); + } + } + + if( rate > ib_port_info_compute_rate( p_pi ) ) + { + rate = ib_port_info_compute_rate( p_pi ); + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pr_rcv_get_path_parms: " + "New smallest rate = %u at destination port 0x%016" PRIx64 "\n", + rate, + cl_ntoh64(osm_physp_get_port_guid( p_physp )) ); + } + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pr_rcv_get_path_parms: " + "Path min MTU = %u, min rate = %u\n", mtu, rate ); + } + + /* + 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; + } + } + + /* 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; + } + } + + /* 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 + pkt_life = OSM_DEFAULT_SUBNET_TIMEOUT; + + /* 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; + + p_parms->mtu = mtu; + p_parms->rate = rate; + p_parms->pkt_life = pkt_life; + + if( comp_mask & IB_PR_COMPMASK_RAWTRAFFIC && + cl_ntoh32( p_pr->hop_flow_raw ) & ( 1<<31 ) ) + pkey = osm_physp_find_common_pkey( p_physp, p_dest_physp ); + else if( comp_mask & IB_PR_COMPMASK_PKEY ) + { + pkey = p_pr->pkey; + if( !osm_physp_share_this_pkey( p_physp, p_dest_physp, pkey ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_get_path_parms: ERR 1F1A: " + "Ports do not share specified PKey 0x%04x\n", cl_ntoh16(pkey)); + status = IB_NOT_FOUND; + goto Exit; + } + } + else + { + pkey = osm_physp_find_common_pkey( p_physp, p_dest_physp ); + if ( !pkey ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_get_path_parms: ERR 1F1B: " + "Ports do not have any shared PKeys\n"); + status = IB_NOT_FOUND; + goto Exit; + } + } + + sl = OSM_DEFAULT_SL; + + if (pkey) { + p_prtn = (osm_prtn_t *)cl_qmap_get(&p_rcv->p_subn->prtn_pkey_tbl, + pkey & cl_ntoh16((uint16_t)~0x8000)); + if ( p_prtn == (osm_prtn_t *)cl_qmap_end(&p_rcv->p_subn->prtn_pkey_tbl) ) + { + /* this may be possible when pkey tables are created somehow in + previous runs or things are going wrong here */ + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_get_path_parms: ERR 1F1C: " + "No partition found for PKey 0x%04x - using default SL %d\n", + cl_ntoh16(pkey), sl ); + } + else + sl = p_prtn->sl; + + /* reset pkey when raw traffic */ + if( comp_mask & IB_PR_COMPMASK_RAWTRAFFIC && + cl_ntoh32( p_pr->hop_flow_raw ) & ( 1<<31 ) ) + pkey = 0; + } + + if ( ( comp_mask & IB_PR_COMPMASK_SL ) && ib_path_rec_sl( p_pr ) != sl ) + { + status = IB_NOT_FOUND; + goto Exit; + } + + p_parms->pkey = pkey; + p_parms->sl = sl; + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pr_rcv_build_pr( + IN osm_pr_rcv_t* const p_rcv, + IN const osm_port_t* const p_src_port, + IN const osm_port_t* const p_dest_port, + IN const uint16_t src_lid_ho, + IN const uint16_t dest_lid_ho, + IN const uint8_t preference, + IN const osm_path_parms_t* const p_parms, + OUT ib_path_rec_t* const p_pr ) +{ + const osm_physp_t* p_src_physp; + const osm_physp_t* p_dest_physp; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_build_pr ); + + p_src_physp = osm_port_get_default_phys_ptr( p_src_port ); + p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port ); + + 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; + p_pr->qos_class_sl = cl_hton16(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( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static osm_pr_item_t* +__osm_pr_rcv_get_lid_pair_path( + IN osm_pr_rcv_t* const p_rcv, + IN const ib_path_rec_t* const p_pr, + IN const osm_port_t* const p_src_port, + IN const osm_port_t* const p_dest_port, + IN const uint16_t 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( p_rcv->p_log, __osm_pr_rcv_get_lid_pair_path ); + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pr_rcv_get_lid_pair_path: " + "Src LID 0x%X, Dest LID 0x%X\n", + src_lid_ho, dest_lid_ho ); + } + + p_pr_item = (osm_pr_item_t*)cl_qlock_pool_get( &p_rcv->pr_pool ); + if( p_pr_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_get_lid_pair_path: ERR 1F01: " + "Unable to allocate path record\n" ); + goto Exit; + } + + status = __osm_pr_rcv_get_path_parms( p_rcv, p_pr, p_src_port, + p_dest_port, dest_lid_ho, + comp_mask, &path_parms ); + + if( status != IB_SUCCESS ) + { + cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item ); + p_pr_item = NULL; + goto Exit; + } + + /* now try the reversible path */ + rev_path_status = __osm_pr_rcv_get_path_parms( p_rcv, p_pr, p_dest_port, + p_src_port, src_lid_ho, + comp_mask, &rev_path_parms ); + path_parms.reversible = ( rev_path_status == IB_SUCCESS ); + + /* did we get a Reversible Path compmask ? */ + /* + NOTE that if the reversible component = 0, it is a don't care + rather then requiring non-reversible paths ... + see Vol1 Ver1.2 p900 l16 + */ + if( comp_mask & IB_PR_COMPMASK_REVERSIBLE ) + { + if( (! path_parms.reversible && ( p_pr->num_path & 0x80 ) ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pr_rcv_get_lid_pair_path: " + "Requested reversible path but failed to get one\n"); + + cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item ); + p_pr_item = NULL; + goto Exit; + } + } + + __osm_pr_rcv_build_pr( p_rcv, p_src_port, p_dest_port, src_lid_ho, + dest_lid_ho, preference, &path_parms, + &p_pr_item->path_rec ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( p_pr_item ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pr_rcv_get_port_pair_paths( + IN osm_pr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + IN const osm_port_t* const p_req_port, + IN const osm_port_t* const p_src_port, + IN const osm_port_t* const p_dest_port, + IN const ib_net64_t comp_mask, + IN cl_qlist_t* const p_list ) +{ + const ib_path_rec_t* p_pr; + const ib_sa_mad_t* p_sa_mad; + osm_pr_item_t* p_pr_item; + uint16_t src_lid_min_ho; + uint16_t src_lid_max_ho; + uint16_t dest_lid_min_ho; + uint16_t dest_lid_max_ho; + uint16_t src_lid_ho; + uint16_t dest_lid_ho; + uint32_t path_num; + uint8_t preference; + uintn_t iterations; + uintn_t src_offset; + uintn_t dest_offset; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_port_pair_paths ); + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pr_rcv_get_port_pair_paths: " + "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(p_rcv->p_log, p_req_port, p_src_port) == FALSE || + osm_port_share_pkey(p_rcv->p_log, p_req_port, p_dest_port) == FALSE || + osm_port_share_pkey(p_rcv->p_log, p_src_port, p_dest_port) == FALSE ) + { + /* One of the pairs doesn't share a pkey so the path is disqualified. */ + goto Exit; + } + + p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw ); + p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad ); + + /* + We shouldn't be here if the paths are disqualified in some way... + Thus, we assume every possible connection is valid. + + We desire to return high-quality paths first. + In OpenSM, higher quality means least overlap with other paths. + This is acheived in practice by returning paths with + different LID value on each end, which means these + paths are more redundant that paths with the same LID repeated + on one side. For example, in OpenSM the paths between two + endpoints with LMC = 1 might be as follows: + + Port A, LID 1 <-> Port B, LID 3 + Port A, LID 1 <-> Port B, LID 4 + Port A, LID 2 <-> Port B, LID 3 + Port A, LID 2 <-> Port B, LID 4 + + The OpenSM unicast routing algorithms attempt to disperse each path + to as varied a physical path as is reasonable. 1<->3 and 1<->4 have + more physical overlap (hence less redundancy) than 1<->3 and 2<->4. + + OpenSM ranks paths in three preference groups: + + Preference Value Description + ---------------- ------------------------------------------- + 0 Redundant in both directions with other + pref value = 0 paths + + 1 Redundant in one direction with other + pref value = 0 and pref value = 1 paths + + 2 Not redundant in either direction with + other paths + + 3-FF Unused + + + SA clients don't need to know these details, only that the lower + preference paths are preferred, as stated in the spec. The paths + may not actually be physically redundant depending on the topology + of the subnet, but the point of LMC > 0 is to offer redundancy, + so it is assumed that the subnet is physically appropriate for the + specified LMC value. A more advanced implementation would inspect for + physical redundancy, but I'm not going to bother with that now. + */ + + /* + Refine our search if the client specified end-point LIDs + */ + if( comp_mask & IB_PR_COMPMASK_DLID ) + { + dest_lid_min_ho = cl_ntoh16( p_pr->dlid ); + dest_lid_max_ho = cl_ntoh16( p_pr->dlid ); + } + else + { + osm_port_get_lid_range_ho( p_dest_port, &dest_lid_min_ho, + &dest_lid_max_ho ); + } + + if( comp_mask & IB_PR_COMPMASK_SLID ) + { + src_lid_min_ho = cl_ntoh16( p_pr->slid ); + src_lid_max_ho = cl_ntoh16( p_pr->slid ); + } + else + { + osm_port_get_lid_range_ho( p_src_port, &src_lid_min_ho, + &src_lid_max_ho ); + } + + if ( src_lid_min_ho == 0 ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_get_port_pair_paths: ERR 1F20:" + "Obtained source LID of 0. No such LID possible\n"); + goto Exit; + } + + if ( dest_lid_min_ho == 0 ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_get_port_pair_paths: ERR 1F21:" + "Obtained destination LID of 0. No such LID possible\n"); + goto Exit; + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pr_rcv_get_port_pair_paths: " + "Src LIDs [0x%X-0x%X], " + "Dest LIDs [0x%X-0x%X]\n", + src_lid_min_ho, src_lid_max_ho, + dest_lid_min_ho, dest_lid_max_ho ); + } + + src_lid_ho = src_lid_min_ho; + dest_lid_ho = dest_lid_min_ho; + + /* + Preferred paths come first in OpenSM + */ + preference = 0; + path_num = 0; + + /* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */ + if( p_sa_mad->method != IB_MAD_METHOD_GET ) + if( comp_mask & IB_PR_COMPMASK_NUMBPATH ) + iterations = ib_path_rec_num_path( p_pr ); + else + iterations = (uintn_t)(-1); + else + iterations = 1; + + while( path_num < iterations ) + { + /* + These paths are "fully redundant" + */ + + p_pr_item = __osm_pr_rcv_get_lid_pair_path( p_rcv, p_pr, + 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, + (cl_list_item_t*)&p_pr_item->pool_item ); + ++path_num; + } + + if( ++src_lid_ho > src_lid_max_ho ) + break; + + if( ++dest_lid_ho > dest_lid_max_ho ) + break; + } + + /* + Check if we've accumulated all the paths that the user cares to see + */ + if( path_num == iterations ) + goto Exit; + + /* + Don't bother reporting preference 1 paths for now. + It's more trouble than it's worth and can only occur + if ports have different LMC values, which isn't supported + by OpenSM right now anyway. + */ + preference = 2; + src_lid_ho = src_lid_min_ho; + dest_lid_ho = dest_lid_min_ho; + src_offset = 0; + dest_offset = 0; + + /* + Iterate over the remaining paths + */ + while( path_num < iterations ) + { + dest_offset++; + dest_lid_ho++; + + if( dest_lid_ho > dest_lid_max_ho ) + { + src_offset++; + src_lid_ho++; + + if( src_lid_ho > src_lid_max_ho ) + break; /* done */ + + dest_offset = 0; + dest_lid_ho = dest_lid_min_ho; + } + + /* + These paths are "fully non-redundant" with paths already + identified above and consequently not of much value. + + Don't return paths we already identified above, as indicated + by the offset values being equal. + */ + if( src_offset == dest_offset ) + continue; /* already reported */ + + p_pr_item = __osm_pr_rcv_get_lid_pair_path( p_rcv, p_pr, + 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, + (cl_list_item_t*)&p_pr_item->pool_item ); + ++path_num; + } + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static ib_net16_t +__osm_pr_rcv_get_end_points( + IN osm_pr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + OUT const osm_port_t** const pp_src_port, + OUT const osm_port_t** const pp_dest_port ) +{ + const ib_path_rec_t* p_pr; + const ib_sa_mad_t* p_sa_mad; + ib_net64_t comp_mask; + ib_api_status_t status; + ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_end_points ); + + /* + Determine what fields are valid and then get a pointer + to the source and destination port objects, if possible. + */ + + p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw ); + p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad ); + + comp_mask = p_sa_mad->comp_mask; + + /* + Check a few easy disqualifying cases up front before getting + into the endpoints. + */ + + if( comp_mask & IB_PR_COMPMASK_SGID ) + { + if ( ! ib_gid_is_link_local ( &p_pr->sgid ) ) + { + if ( ib_gid_get_subnet_prefix ( &p_pr->sgid ) != p_rcv->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( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_pr_rcv_get_end_points: " + "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_port_t*)cl_qmap_get( + &p_rcv->p_subn->port_guid_tbl, + p_pr->sgid.unicast.interface_id ); + + if( *pp_src_port == (osm_port_t*)cl_qmap_end( + &p_rcv->p_subn->port_guid_tbl ) ) + { + /* + 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( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_pr_rcv_get_end_points: " + "No source port with GUID 0x%016" PRIx64 "\n", + cl_ntoh64( p_pr->sgid.unicast.interface_id) ); + + sa_status = IB_SA_MAD_STATUS_INVALID_GID; + goto Exit; + } + } + else + { + *pp_src_port = 0; + if( comp_mask & IB_PR_COMPMASK_SLID ) + { + status = cl_ptr_vector_at( &p_rcv->p_subn->port_lid_tbl, + cl_ntoh16(p_pr->slid), (void**)pp_src_port ); + + if( (status != CL_SUCCESS) || (*pp_src_port == NULL) ) + { + /* + This 'error' is the client's fault (bad lid) so + don't enter it as an error in our own log. + Return an error response to the client. + */ + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_pr_rcv_get_end_points: " + "No source port with LID = 0x%X\n", + cl_ntoh16( p_pr->slid) ); + + sa_status = IB_SA_MAD_STATUS_NO_RECORDS; + goto Exit; + } + } + } + + if( comp_mask & IB_PR_COMPMASK_DGID ) + { + if ( ! ib_gid_is_link_local ( &p_pr->dgid ) ) + { + if ( ! ib_gid_is_multicast ( &p_pr->dgid ) && + ib_gid_get_subnet_prefix ( &p_pr->dgid ) != p_rcv->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( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_pr_rcv_get_end_points: " + "Non local DGID subnet prefix 0x%016" PRIx64 "\n", + cl_ntoh64( p_pr->dgid.unicast.prefix ) ); + + sa_status = IB_SA_MAD_STATUS_INVALID_GID; + goto Exit; + } + } + + *pp_dest_port = (osm_port_t*)cl_qmap_get( + &p_rcv->p_subn->port_guid_tbl, + p_pr->dgid.unicast.interface_id ); + + if( *pp_dest_port == (osm_port_t*)cl_qmap_end( + &p_rcv->p_subn->port_guid_tbl ) ) + { + /* + 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( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_pr_rcv_get_end_points: " + "No dest port with GUID 0x%016" PRIx64 "\n", + cl_ntoh64( p_pr->dgid.unicast.interface_id) ); + + sa_status = IB_SA_MAD_STATUS_INVALID_GID; + goto Exit; + } + } + else + { + *pp_dest_port = 0; + if( comp_mask & IB_PR_COMPMASK_DLID ) + { + status = cl_ptr_vector_at( &p_rcv->p_subn->port_lid_tbl, + cl_ntoh16(p_pr->dlid), (void**)pp_dest_port ); + + if( (status != CL_SUCCESS) || (*pp_dest_port == NULL) ) + { + /* + This 'error' is the client's fault (bad lid) so + don't enter it as an error in our own log. + Return an error response to the client. + */ + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_pr_rcv_get_end_points: " + "No dest port with LID = 0x%X\n", + cl_ntoh16( p_pr->dlid) ); + + sa_status = IB_SA_MAD_STATUS_NO_RECORDS; + goto Exit; + } + } + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( sa_status ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pr_rcv_process_world( + IN osm_pr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + IN const osm_port_t* const requester_port, + IN const ib_net64_t comp_mask, + IN cl_qlist_t* const p_list ) +{ + const cl_qmap_t* p_tbl; + const osm_port_t* p_dest_port; + const osm_port_t* p_src_port; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_world ); + + /* + 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 = &p_rcv->p_subn->port_guid_tbl; + + p_dest_port = (osm_port_t*)cl_qmap_head( p_tbl ); + while( p_dest_port != (osm_port_t*)cl_qmap_end( p_tbl ) ) + { + p_src_port = (osm_port_t*)cl_qmap_head( p_tbl ); + while( p_src_port != (osm_port_t*)cl_qmap_end( p_tbl ) ) + { + __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_src_port, + p_dest_port, comp_mask, p_list ); + + p_src_port = (osm_port_t*)cl_qmap_next( &p_src_port->map_item ); + } + + p_dest_port = (osm_port_t*)cl_qmap_next( &p_dest_port->map_item ); + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pr_rcv_process_half( + IN osm_pr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + IN const osm_port_t* const requester_port, + IN const osm_port_t* const p_src_port, + IN const osm_port_t* const p_dest_port, + IN const ib_net64_t comp_mask, + IN cl_qlist_t* const p_list ) +{ + const cl_qmap_t* p_tbl; + const osm_port_t* p_port; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_half ); + + /* + 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 = &p_rcv->p_subn->port_guid_tbl; + + if( p_src_port ) + { + /* + The src port if fixed, so iterate over destination ports. + */ + p_port = (osm_port_t*)cl_qmap_head( p_tbl ); + while( p_port != (osm_port_t*)cl_qmap_end( p_tbl ) ) + { + __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw , requester_port, p_src_port, + p_port, comp_mask, p_list ); + p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item ); + } + } + else + { + /* + The dest port if fixed, so iterate over source ports. + */ + p_port = (osm_port_t*)cl_qmap_head( p_tbl ); + while( p_port != (osm_port_t*)cl_qmap_end( p_tbl ) ) + { + __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_port, + p_dest_port, comp_mask, p_list ); + p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item ); + } + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pr_rcv_process_pair( + IN osm_pr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + IN const osm_port_t* const requester_port, + IN const osm_port_t* const p_src_port, + IN const osm_port_t* const p_dest_port, + IN const ib_net64_t comp_mask, + IN cl_qlist_t* const p_list ) +{ + OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_pair ); + + __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_src_port, + p_dest_port, comp_mask, p_list ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + *********************************************************************/ +static void +__search_mgrp_by_mgid( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + osm_mgrp_t* p_mgrp = (osm_mgrp_t*)p_map_item; + osm_sa_pr_mcmr_search_ctxt_t *p_ctxt = (osm_sa_pr_mcmr_search_ctxt_t *) context; + const ib_gid_t *p_recvd_mgid; + osm_pr_rcv_t *p_rcv; + /* uint32_t i; */ + + p_recvd_mgid = p_ctxt->p_mgid; + p_rcv = p_ctxt->p_rcv; + + /* ignore groups marked for deletion */ + if ( p_mgrp->to_be_deleted ) + return; + + /* compare entire MGID so different scope will not sneak in for + the same MGID */ + if ( memcmp( &p_mgrp->mcmember_rec.mgid, + p_recvd_mgid, + sizeof(ib_gid_t) ) ) + return; + +#if 0 + for ( i = 0 ; i < sizeof(p_mgrp->mcmember_rec.mgid.multicast.raw_group_id); i++) + { + if ( p_mgrp->mcmember_rec.mgid.multicast.raw_group_id[i] != + p_recvd_mgid->mgid.multicast.raw_group_id[i] ) + return; + } +#endif + + if( p_ctxt->p_mgrp ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__search_mgrp_by_mgid: ERR 1F08: " + "Multiple MC groups for same MGID\n" ); + return; + } + p_ctxt->p_mgrp = p_mgrp; +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__get_mgrp_by_mgid( + IN osm_pr_rcv_t* const p_rcv, + IN ib_path_rec_t* p_recvd_path_rec, + OUT osm_mgrp_t ** pp_mgrp ) +{ + osm_sa_pr_mcmr_search_ctxt_t mcmr_search_context; + + mcmr_search_context.p_mgid = &p_recvd_path_rec->dgid; + mcmr_search_context.p_rcv = p_rcv; + mcmr_search_context.p_mgrp = NULL; + + cl_qmap_apply_func( &p_rcv->p_subn->mgrp_mlid_tbl, + __search_mgrp_by_mgid, + &mcmr_search_context); + + if( mcmr_search_context.p_mgrp == NULL ) + { + return IB_NOT_FOUND; + } + + *pp_mgrp = mcmr_search_context.p_mgrp; + return IB_SUCCESS; +} + +/********************************************************************** + **********************************************************************/ +static osm_mgrp_t * +__get_mgrp_by_mlid( + IN const osm_pr_rcv_t* const p_rcv, + IN ib_net16_t const mlid ) +{ + cl_map_item_t * map_item; + + map_item = cl_qmap_get( &p_rcv->p_subn->mgrp_mlid_tbl, mlid ); + + if( map_item == cl_qmap_end(&p_rcv->p_subn->mgrp_mlid_tbl) ) + { + return NULL; + } + + return (osm_mgrp_t *)map_item; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pr_get_mgrp( + IN osm_pr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + OUT osm_mgrp_t **pp_mgrp ) +{ + ib_path_rec_t* p_pr; + const ib_sa_mad_t* p_sa_mad; + ib_net64_t comp_mask; + ib_api_status_t status; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_get_mgrp ); + + p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw ); + p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad ); + + comp_mask = p_sa_mad->comp_mask; + + if( comp_mask & IB_PR_COMPMASK_DGID ) + { + status = __get_mgrp_by_mgid( p_rcv, p_pr, pp_mgrp ); + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_get_mgrp: ERR 1F09: " + "No MC group found for PathRecord destination GID\n" ); + goto Exit; + } + } + + if( comp_mask & IB_PR_COMPMASK_DLID ) + { + if( *pp_mgrp) + { + /* check that the MLID in the MC group is */ + /* the same as the DLID in the PathRecord */ + if( (*pp_mgrp)->mlid != p_pr->dlid ) + { + /* Note: perhaps this might be better indicated as an invalid request */ + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_get_mgrp: ERR 1F10: " + "MC group MLID does not match PathRecord destination LID\n" ); + *pp_mgrp = NULL; + goto Exit; + } + } + else + { + *pp_mgrp = __get_mgrp_by_mlid( p_rcv, p_pr->dlid ); + if( *pp_mgrp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_get_mgrp: ERR 1F11: " + "No MC group found for PathRecord destination LID\n" ); + } + } + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_pr_match_mgrp_attributes( + IN osm_pr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + IN const osm_mgrp_t* const p_mgrp ) +{ + const ib_path_rec_t* p_pr; + const ib_sa_mad_t* p_sa_mad; + ib_net64_t comp_mask; + ib_api_status_t status = IB_ERROR; + uint32_t flow_label; + uint8_t sl; + uint8_t hop_limit; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_match_mgrp_attributes ); + + p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw ); + p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad ); + + comp_mask = p_sa_mad->comp_mask; + + /* If SGID and/or SLID specified, should validate as member of MC group */ + /* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */ + if( comp_mask & IB_PR_COMPMASK_PKEY ) + { + if( p_pr->pkey != p_mgrp->mcmember_rec.pkey ) + goto Exit; + } + + ib_member_get_sl_flow_hop( p_mgrp->mcmember_rec.sl_flow_hop, + &sl, &flow_label, &hop_limit ); + + if( comp_mask & IB_PR_COMPMASK_SL ) + { + if( ib_path_rec_sl( p_pr ) != sl ) + goto Exit; + } + + /* If SubnAdmGet, assume NumbPaths of 1 (1.2 erratum) */ + if( ( comp_mask & IB_PR_COMPMASK_NUMBPATH ) && + ( p_sa_mad->method != IB_MAD_METHOD_GET ) ) + { + if( ib_path_rec_num_path( p_pr ) == 0 ) + goto Exit; + } + + if( comp_mask & IB_PR_COMPMASK_FLOWLABEL ) + { + if( ib_path_rec_flow_lbl( p_pr ) != flow_label ) + goto Exit; + } + + if( comp_mask & IB_PR_COMPMASK_HOPLIMIT ) + { + if( ib_path_rec_hop_limit( p_pr ) != hop_limit ) + goto Exit; + } + + if( comp_mask & IB_PR_COMPMASK_TCLASS ) + { + if( p_pr->tclass != p_mgrp->mcmember_rec.tclass ) + goto Exit; + } + + status = IB_SUCCESS; + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static int +__osm_pr_rcv_check_mcast_dest( + IN osm_pr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_path_rec_t* p_pr; + const ib_sa_mad_t* p_sa_mad; + ib_net64_t comp_mask; + int is_multicast = 0; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_check_mcast_dest ); + + p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw ); + p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad ); + + comp_mask = p_sa_mad->comp_mask; + + if( comp_mask & IB_PR_COMPMASK_DGID ) + { + is_multicast = ib_gid_is_multicast( &p_pr->dgid ); + if( !is_multicast ) + goto Exit; + } + + if( comp_mask & IB_PR_COMPMASK_DLID ) + { + if( cl_ntoh16( p_pr->dlid ) >= IB_LID_MCAST_START_HO && + cl_ntoh16( p_pr->dlid ) <= IB_LID_MCAST_END_HO ) + is_multicast = 1; + else if( is_multicast ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_check_mcast_dest: ERR 1F12: " + "PathRecord request indicates MGID but not MLID\n" ); + is_multicast = -1; + } + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( is_multicast ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pr_rcv_respond( + IN osm_pr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + IN cl_qlist_t* const p_list ) +{ + osm_madw_t* p_resp_madw; + const ib_sa_mad_t* p_sa_mad; + ib_sa_mad_t* p_resp_sa_mad; + size_t num_rec, pre_trim_num_rec; +#ifndef VENDOR_RMPP_SUPPORT + size_t trim_num_rec; +#endif + ib_path_rec_t* p_resp_pr; + ib_api_status_t status; + const ib_sa_mad_t* p_rcvd_mad = osm_madw_get_sa_mad_ptr( p_madw ); + osm_pr_item_t* p_pr_item; + uint32_t i; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_respond ); + + num_rec = cl_qlist_count( p_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if (p_rcvd_mad->method == IB_MAD_METHOD_GET) + { + if (num_rec == 0) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + if (num_rec > 1) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_respond: ERR 1F13: " + "Got more than one record for SubnAdmGet (%zu)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS ); + /* need to set the mem free ... */ + p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list ); + while( p_pr_item != (osm_pr_item_t*)cl_qlist_end( p_list ) ) + { + cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item ); + p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list ); + } + goto Exit; + } + } + + pre_trim_num_rec = num_rec; +#ifndef VENDOR_RMPP_SUPPORT + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_path_rec_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_pr_rcv_respond: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pr_rcv_respond: " + "Generating response with %zu records\n", num_rec ); + + if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0)) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, p_madw->h_bind, + num_rec * sizeof(ib_path_rec_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + if( !p_resp_madw ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_respond: ERR 1F14: " + "Unable to allocate MAD\n" ); + + for( i = 0; i < num_rec; i++ ) + { + p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list ); + cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES ); + 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; + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = ib_get_attr_offset( sizeof(ib_path_rec_t) ); + + p_resp_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + for ( i = 0; i < pre_trim_num_rec; i++ ) + { + p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list ); + /* copy only if not trimmed */ + if (i < num_rec) + *p_resp_pr = p_pr_item->path_rec; + + cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item ); + p_resp_pr++; + } + + CL_ASSERT( cl_is_qlist_empty( p_list ) ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pr_rcv_respond: ERR 1F15: " + "Unable to send MAD (%s)\n", ib_get_err_str( status ) ); + /* osm_mad_pool_put( p_rcv->p_mad_pool, p_resp_madw ); */ + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pr_rcv_process( + IN osm_pr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_path_rec_t* p_pr; + const ib_sa_mad_t* p_sa_mad; + const osm_port_t* p_src_port; + const osm_port_t* p_dest_port; + cl_qlist_t pr_list; + ib_net16_t sa_status; + osm_port_t* requester_port; + int ret; + + OSM_LOG_ENTER( p_rcv->p_log, osm_pr_rcv_process ); + + CL_ASSERT( p_madw ); + + p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw ); + p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad ); + + CL_ASSERT( p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD ); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if ((p_sa_mad->method != IB_MAD_METHOD_GET) && + (p_sa_mad->method != IB_MAD_METHOD_GETTABLE)) { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pr_rcv_process: ERR 1F17: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_sa_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + /* update the requester physical port. */ + requester_port = osm_get_port_by_mad_addr( p_rcv->p_log, p_rcv->p_subn, + osm_madw_get_mad_addr_ptr( p_madw ) ); + if( requester_port == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pr_rcv_process: ERR 1F16: " + "Cannot find requester physical port\n" ); + goto Exit; + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + osm_dump_path_record( p_rcv->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( p_rcv->p_lock ); + + /* Handle multicast destinations separately */ + if( (ret = __osm_pr_rcv_check_mcast_dest( p_rcv, p_madw )) < 0 ) + { + /* Multicast DGID with unicast DLID */ + cl_plock_release( p_rcv->p_lock ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_INVALID_FIELD ); + goto Exit; + } + + if(ret > 0) + goto McastDest; + + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_pr_rcv_process: " + "Unicast destination requested\n" ); + + sa_status = __osm_pr_rcv_get_end_points( p_rcv, p_madw, + &p_src_port, &p_dest_port ); + + if( sa_status == IB_SA_MAD_STATUS_SUCCESS ) + { + /* + What happens next depends on the type of endpoint information + that was specified.... + */ + if( p_src_port ) + { + if( p_dest_port ) + __osm_pr_rcv_process_pair( p_rcv, p_madw, requester_port, + p_src_port, p_dest_port, + p_sa_mad->comp_mask, &pr_list ); + else + __osm_pr_rcv_process_half( p_rcv, p_madw, requester_port, + p_src_port, NULL, + p_sa_mad->comp_mask, &pr_list ); + } + else + { + if( p_dest_port ) + __osm_pr_rcv_process_half( p_rcv, p_madw, requester_port, + NULL, p_dest_port, + p_sa_mad->comp_mask, &pr_list ); + else + /* + Katie, bar the door! + */ + __osm_pr_rcv_process_world( p_rcv, p_madw, requester_port, + p_sa_mad->comp_mask, &pr_list ); + } + } + goto Unlock; + + McastDest: + osm_log(p_rcv->p_log, OSM_LOG_DEBUG, + "osm_pr_rcv_process: " + "Multicast destination requested\n" ); + { + osm_mgrp_t *p_mgrp = NULL; + ib_api_status_t status; + osm_pr_item_t* p_pr_item; + uint32_t flow_label; + uint8_t sl; + uint8_t hop_limit; + + /* First, get the MC info */ + __osm_pr_get_mgrp( p_rcv, p_madw, &p_mgrp ); + + if ( p_mgrp ) + { + /* Make sure the rest of the PathRecord matches the MC group attributes */ + status = __osm_pr_match_mgrp_attributes( p_rcv, p_madw, p_mgrp ); + if ( status == IB_SUCCESS ) + { + p_pr_item = (osm_pr_item_t*)cl_qlock_pool_get( &p_rcv->pr_pool ); + if( p_pr_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pr_rcv_process: ERR 1F18: " + "Unable to allocate path record for MC group\n" ); + } + else + { + /* Copy PathRecord request into response */ + p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw ); + p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad ); + p_pr_item->path_rec = *p_pr; + + /* Now, use the MC info to cruft up the PathRecord response */ + p_pr_item->path_rec.dgid = p_mgrp->mcmember_rec.mgid; + p_pr_item->path_rec.dlid = p_mgrp->mcmember_rec.mlid; + p_pr_item->path_rec.tclass = p_mgrp->mcmember_rec.tclass; + p_pr_item->path_rec.num_path = 1; + p_pr_item->path_rec.pkey = p_mgrp->mcmember_rec.pkey; + + /* MTU, rate, and packet lifetime should be exactly */ + p_pr_item->path_rec.mtu = (2<<6) | p_mgrp->mcmember_rec.mtu; + p_pr_item->path_rec.rate = (2<<6) | p_mgrp->mcmember_rec.rate; + p_pr_item->path_rec.pkt_life = (2<<6) | p_mgrp->mcmember_rec.pkt_life; + + /* SL, Hop Limit, and Flow Label */ + ib_member_get_sl_flow_hop( p_mgrp->mcmember_rec.sl_flow_hop, + &sl, &flow_label, &hop_limit ); + p_pr_item->path_rec.qos_class_sl = cl_hton16( sl ); + p_pr_item->path_rec.hop_flow_raw = (uint32_t)(hop_limit) | + (flow_label << 8); + + cl_qlist_insert_tail( &pr_list, + (cl_list_item_t*)&p_pr_item->pool_item ); + + } + } + else + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pr_rcv_process: ERR 1F19: " + "MC group attributes don't match PathRecord request\n" ); + } + } + } + + Unlock: + cl_plock_release( p_rcv->p_lock ); + + /* Now, (finally) respond to the PathRecord request */ + __osm_pr_rcv_respond( p_rcv, p_madw, &pr_list ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_path_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_path_record_ctrl.c new file mode 100644 index 00000000..ec13fdc2 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_path_record_ctrl.c @@ -0,0 +1,126 @@ +/* + * 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: + * Implementation of osm_pr_rcv_ctrl_t. + * This object represents the PathRecord request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +static void +__osm_pr_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_pr_rcv_process( ((osm_pr_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pr_rcv_ctrl_construct( + IN osm_pr_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_pr_rcv_ctrl_destroy( + IN osm_pr_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pr_rcv_ctrl_init( + IN osm_pr_rcv_ctrl_t* const p_ctrl, + IN osm_pr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_pr_rcv_ctrl_init ); + + osm_pr_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_PATH_RECORD, + __osm_pr_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_pr_rcv_ctrl_init: ERR 2001: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_pkey_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_pkey_record.c new file mode 100644 index 00000000..60d8d937 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_pkey_record.c @@ -0,0 +1,590 @@ +/* + * 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$ + */ + + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_PKEY_REC_RCV_POOL_MIN_SIZE 32 +#define OSM_PKEY_REC_RCV_POOL_GROW_SIZE 32 + +typedef struct _osm_pkey_item +{ + cl_pool_item_t pool_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_pkey_rec_rcv_t* p_rcv; + const osm_physp_t* p_req_physp; +} osm_pkey_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void +osm_pkey_rec_rcv_construct( + IN osm_pkey_rec_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pkey_rec_rcv_destroy( + IN osm_pkey_rec_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_pkey_rec_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pkey_rec_rcv_init( + IN osm_pkey_rec_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN const osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_pkey_rec_rcv_init ); + + osm_pkey_rec_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + /* used for matching records collection */ + status = cl_qlock_pool_init( &p_rcv->pool, + OSM_PKEY_REC_RCV_POOL_MIN_SIZE, + 0, + OSM_PKEY_REC_RCV_POOL_GROW_SIZE, + sizeof(osm_pkey_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sa_pkey_create( + IN osm_pkey_rec_rcv_t* const p_rcv, + IN osm_physp_t* const p_physp, + IN osm_pkey_search_ctxt_t* const p_ctxt, + IN uint16_t block ) +{ + osm_pkey_item_t* p_rec_item; + uint16_t lid; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_pkey_create ); + + p_rec_item = (osm_pkey_item_t*)cl_qlock_pool_get( &p_rcv->pool ); + if( p_rec_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sa_pkey_create: ERR 4602: " + "cl_qlock_pool_get failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + if (p_physp->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) + { + lid = osm_physp_get_port_info_ptr( p_physp )->base_lid; + } + else + { + lid = osm_node_get_base_lid( p_physp->p_node, 0 ); + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_pkey_create: " + "New P_Key table for: port 0x%016" PRIx64 + ", lid 0x%X, port# 0x%X 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->rec, 0, sizeof( p_rec_item->rec ) ); + + 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, + (cl_list_item_t*)&p_rec_item->pool_item ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sa_pkey_check_physp( + IN osm_pkey_rec_rcv_t* const p_rcv, + IN osm_physp_t* const p_physp, + osm_pkey_search_ctxt_t* const p_ctxt ) +{ + ib_net64_t comp_mask = p_ctxt->comp_mask; + uint16_t block, num_blocks; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_pkey_check_physp ); + + /* we got here with the phys port - all is left is to get the right block */ + if ( comp_mask & IB_PKEY_COMPMASK_BLOCK ) + { + __osm_sa_pkey_create( p_rcv, p_physp, p_ctxt, p_ctxt->block_num); + } + else + { + num_blocks = + osm_pkey_tbl_get_num_blocks( osm_physp_get_pkey_tbl( p_physp )); + for (block = 0; block < num_blocks; block++) { + __osm_sa_pkey_create( p_rcv, p_physp, p_ctxt, block ); + } + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_pkey_by_comp_mask( + IN osm_pkey_rec_rcv_t* const p_rcv, + IN const osm_port_t* const p_port, + osm_pkey_search_ctxt_t* const p_ctxt ) +{ + const ib_pkey_table_record_t* p_rcvd_rec; + ib_net64_t comp_mask; + osm_physp_t * p_physp; + uint8_t port_num; + uint8_t num_ports; + const osm_physp_t* p_req_physp; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_pkey_by_comp_mask ); + + 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->default_port_num; + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_pkey_by_comp_mask: " + "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_port_get_num_physp( p_port )) + { + p_physp = osm_port_get_phys_ptr( p_port, 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_is_valid( p_physp ) && + (osm_physp_share_pkey(p_rcv->p_log, p_req_physp, p_physp)) ) + __osm_sa_pkey_check_physp( p_rcv, p_physp, p_ctxt ); + } + else + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sa_pkey_by_comp_mask: ERR 4603: " + "Given Physical Port Number: 0x%X is out of range should be < 0x%X\n", + port_num, osm_port_get_num_physp( p_port )); + goto Exit; + } + } + else + { + num_ports = osm_port_get_num_physp( p_port ); + for( port_num = 0; port_num < num_ports; port_num++ ) + { + p_physp = osm_port_get_phys_ptr( p_port, port_num ); + if( p_physp == NULL ) + continue; + + if( !osm_physp_is_valid( p_physp ) ) + continue; + + /* if the requester and the p_physp don't share a pkey - + continue */ + if (!osm_physp_share_pkey(p_rcv->p_log, p_req_physp, p_physp ) ) + continue; + + __osm_sa_pkey_check_physp( p_rcv, p_physp, p_ctxt ); + } + } + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_pkey_by_comp_mask_cb( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + const osm_port_t* const p_port = (osm_port_t*)p_map_item; + osm_pkey_search_ctxt_t* const p_ctxt = (osm_pkey_search_ctxt_t *)context; + + __osm_sa_pkey_by_comp_mask( p_ctxt->p_rcv, p_port, p_ctxt ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pkey_rec_rcv_process( + IN osm_pkey_rec_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_sa_mad_t* p_rcvd_mad; + const ib_pkey_table_record_t* p_rcvd_rec; + const cl_ptr_vector_t* p_tbl; + const osm_port_t* p_port = NULL; + const ib_pkey_table_t* p_pkey; + cl_qlist_t rec_list; + osm_madw_t* p_resp_madw; + ib_sa_mad_t* p_resp_sa_mad; + ib_pkey_table_record_t* p_resp_rec; + uint32_t num_rec, pre_trim_num_rec; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t trim_num_rec; +#endif + uint32_t i; + osm_pkey_search_ctxt_t context; + osm_pkey_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + ib_net64_t comp_mask; + osm_physp_t* p_req_physp; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_pkey_rec_rcv_process ); + + 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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pkey_rec_rcv_process: ERR 4605: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_rcvd_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, 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 != p_rcv->p_subn->opt.sm_key ) + { + /* This is not a trusted requester! */ + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pkey_rec_rcv_process 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( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_REQ_INVALID ); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pkey_rec_rcv_process: ERR 4604: " + "Cannot find requester physical port\n" ); + goto Exit; + } + + p_pkey = (ib_pkey_table_t*)ib_sa_mad_get_payload_ptr( p_rcvd_mad ); + + cl_qlist_init( &rec_list ); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = p_rcvd_mad->comp_mask; + context.p_rcv = p_rcv; + context.block_num = p_rcvd_rec->block_num; + context.p_req_physp = p_req_physp; + + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_pkey_rec_rcv_process: " + "Got Query Lid:0x%04X(%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( p_rcv->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_tbl = &p_rcv->p_subn->port_lid_tbl; + + CL_ASSERT( cl_ptr_vector_get_size(p_tbl) < 0x10000 ); + + status = osm_get_port_by_base_lid( p_rcv->p_subn, p_rcvd_rec->lid, &p_port ); + if ( ( status != IB_SUCCESS ) || ( p_port == NULL ) ) + { + status = IB_NOT_FOUND; + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pkey_rec_rcv_process: ERR 460B: " + "No port found with LID 0x%x\n", + cl_ntoh16(p_rcvd_rec->lid) ); + } + } + + if ( status == IB_SUCCESS ) + { + /* if we got a unique port - no need for a port search */ + if( p_port ) + /* this does the loop on all the port phys ports */ + __osm_sa_pkey_by_comp_mask( p_rcv, p_port, &context ); + else + { + cl_qmap_apply_func( &p_rcv->p_subn->port_guid_tbl, + __osm_sa_pkey_by_comp_mask_cb, + &context ); + } + } + + cl_plock_release( p_rcv->p_lock ); + + num_rec = cl_qlist_count( &rec_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if (p_rcvd_mad->method == IB_MAD_METHOD_GET) + { + if (num_rec == 0) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + if (num_rec > 1) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pkey_rec_rcv_process: ERR 460A: " + "Got more than one record for SubnAdmGet (%u)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS); + + /* need to set the mem free ... */ + p_rec_item = (osm_pkey_item_t*)cl_qlist_remove_head( &rec_list ); + while( p_rec_item != (osm_pkey_item_t*)cl_qlist_end( &rec_list ) ) + { + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_rec_item = (osm_pkey_item_t*)cl_qlist_remove_head( &rec_list ); + } + + goto Exit; + } + } + + pre_trim_num_rec = num_rec; +#ifndef VENDOR_RMPP_SUPPORT + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_pkey_table_record_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_pkey_rec_rcv_process: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_pkey_rec_rcv_process: " + "Returning %u records\n", num_rec ); + + if((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0)) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_pkey_table_record_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + + if( !p_resp_madw ) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_pkey_rec_rcv_process: ERR 4606: " + "osm_mad_pool_get failed\n" ); + + for( i = 0; i < num_rec; i++ ) + { + p_rec_item = (osm_pkey_item_t*)cl_qlist_remove_head( &rec_list ); + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES ); + goto Exit; + } + + p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_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( p_resp_sa_mad, p_rcvd_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; + + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_pkey_table_record_t) ); + + p_resp_rec = (ib_pkey_table_record_t*) + ib_sa_mad_get_payload_ptr( p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + for( i = 0; i < pre_trim_num_rec; i++ ) + { + p_rec_item = (osm_pkey_item_t*)cl_qlist_remove_head( &rec_list ); + /* copy only if not trimmed */ + if (i < num_rec) + { + *p_resp_rec = p_rec_item->rec; + } + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_resp_rec++; + } + + CL_ASSERT( cl_is_qlist_empty( &rec_list ) ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE); + if (status != IB_SUCCESS) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_pkey_rec_rcv_process: ERR 4607: " + "osm_vendor_send status = %s\n", + ib_get_err_str(status)); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_pkey_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_pkey_record_ctrl.c new file mode 100644 index 00000000..324b6edf --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_pkey_record_ctrl.c @@ -0,0 +1,113 @@ +/* + * 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$ + */ + + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_pkey_rec_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_pkey_rec_rcv_process( ((osm_pkey_rec_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pkey_rec_rcv_ctrl_construct( + IN osm_pkey_rec_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_pkey_rec_rcv_ctrl_destroy( + IN osm_pkey_rec_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pkey_rec_rcv_ctrl_init( + IN osm_pkey_rec_rcv_ctrl_t* const p_ctrl, + IN osm_pkey_rec_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_pkey_rec_rcv_ctrl_init ); + + osm_pkey_rec_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_PKEY_TBL_RECORD, + __osm_pkey_rec_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_pkey_rec_rcv_ctrl_init: ERR 4701: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_portinfo_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_portinfo_record.c new file mode 100644 index 00000000..bf868991 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_portinfo_record.c @@ -0,0 +1,878 @@ +/* + * 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: + * Implementation of osm_pir_rcv_t. + * This object represents the PortInfoRecord Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.10 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_PIR_RCV_POOL_MIN_SIZE 32 +#define OSM_PIR_RCV_POOL_GROW_SIZE 32 + +typedef struct _osm_pir_item +{ + cl_pool_item_t pool_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_pir_rcv_t* p_rcv; + const osm_physp_t* p_req_physp; + boolean_t is_enhanced_comp_mask; +} osm_pir_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void +osm_pir_rcv_construct( + IN osm_pir_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pir_rcv_destroy( + IN osm_pir_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_pir_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pir_rcv_init( + IN osm_pir_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_pir_rcv_init ); + + osm_pir_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + status = cl_qlock_pool_init( &p_rcv->pool, + OSM_PIR_RCV_POOL_MIN_SIZE, + 0, + OSM_PIR_RCV_POOL_GROW_SIZE, + sizeof(osm_pir_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_pir_rcv_new_pir( + IN osm_pir_rcv_t* const p_rcv, + IN const osm_physp_t* const p_physp, + IN cl_qlist_t* const p_list, + IN ib_net16_t const lid ) +{ + osm_pir_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pir_rcv_new_pir ); + + p_rec_item = (osm_pir_item_t*)cl_qlock_pool_get( &p_rcv->pool ); + if( p_rec_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pir_rcv_new_pir: ERR 2102: " + "cl_qlock_pool_get failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pir_rcv_new_pir: " + "New PortInfoRecord: port 0x%016" PRIx64 + ", lid 0x%X, port# 0x%X\n", + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ), + cl_ntoh16( lid ), osm_physp_get_port_num( p_physp ) ); + } + + memset( &p_rec_item->rec, 0, sizeof( p_rec_item->rec ) ); + + p_rec_item->rec.lid = lid; + p_rec_item->rec.port_info = *osm_physp_get_port_info_ptr( p_physp ); + p_rec_item->rec.port_num = osm_physp_get_port_num( p_physp ); + + cl_qlist_insert_tail( p_list, (cl_list_item_t*)&p_rec_item->pool_item ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sa_pir_create( + IN osm_pir_rcv_t* const p_rcv, + IN const osm_physp_t* const p_physp, + IN osm_pir_search_ctxt_t* const p_ctxt ) +{ + uint8_t lmc; + uint16_t max_lid_ho; + uint16_t base_lid_ho; + uint16_t match_lid_ho; + osm_physp_t *p_node_physp; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_pir_create ); + + 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, p_rcv->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. + */ + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_pir_create: " + "Comparing LID: 0x%X <= 0x%X <= 0x%X\n", + base_lid_ho, match_lid_ho, max_lid_ho + ); + } + + if ( match_lid_ho < base_lid_ho || match_lid_ho > max_lid_ho ) + goto Exit; + } + + __osm_pir_rcv_new_pir( p_rcv, p_physp, p_ctxt->p_list, + cl_hton16( base_lid_ho ) ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sa_pir_check_physp( + IN osm_pir_rcv_t* const p_rcv, + IN const osm_physp_t* const p_physp, + osm_pir_search_ctxt_t* const p_ctxt ) +{ + const ib_portinfo_record_t* p_rcvd_rec; + ib_net64_t comp_mask; + const ib_port_info_t* p_comp_pi; + const ib_port_info_t* p_pi; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_pir_check_physp ); + + p_rcvd_rec = p_ctxt->p_rcvd_rec; + comp_mask = p_ctxt->comp_mask; + p_comp_pi = &p_rcvd_rec->port_info; + p_pi = osm_physp_get_port_info_ptr( p_physp ); + + osm_dump_port_info( + p_rcv->p_log, + osm_node_get_node_guid( p_physp->p_node ), + p_physp->port_guid, + p_physp->port_num, + &p_physp->port_info, + OSM_LOG_DEBUG ); + + /* We have to re-check the base_lid, since if the given + base_lid in p_pi is zero - we are comparing on all ports. */ + if( comp_mask & IB_PIR_COMPMASK_BASELID ) + { + if( p_comp_pi->base_lid != p_pi->base_lid ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_MKEY ) + { + if( p_comp_pi->m_key != p_pi->m_key ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_GIDPRE ) + { + if( p_comp_pi->subnet_prefix != p_pi->subnet_prefix ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_SMLID ) + { + if( p_comp_pi->master_sm_base_lid != p_pi->master_sm_base_lid ) + goto Exit; + } + + /* IBTA 1.2 errata provides support for bitwise compare if the bit 31 + of the attribute modifier of the Get/GetTable is set */ + if( comp_mask & IB_PIR_COMPMASK_CAPMASK ) + { + if (p_ctxt->is_enhanced_comp_mask) + { + if ( ( ( p_comp_pi->capability_mask & p_pi->capability_mask ) != p_comp_pi->capability_mask) ) + goto Exit; + } + else + { + if( p_comp_pi->capability_mask != p_pi->capability_mask ) + goto Exit; + } + } + + if( comp_mask & IB_PIR_COMPMASK_DIAGCODE ) + { + if( p_comp_pi->diag_code != p_pi->diag_code ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_MKEYLEASEPRD ) + { + if( p_comp_pi->m_key_lease_period != p_pi->m_key_lease_period ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_LOCALPORTNUM ) + { + if( p_comp_pi->local_port_num != p_pi->local_port_num ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_LNKWIDTHSUPPORT ) + { + if( p_comp_pi->link_width_supported != p_pi->link_width_supported ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_LNKWIDTHACTIVE ) + { + if( p_comp_pi->link_width_active != p_pi->link_width_active ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_LINKWIDTHENABLED ) + { + if( p_comp_pi->link_width_enabled != p_pi->link_width_enabled ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_LNKSPEEDSUPPORT ) + { + if( ib_port_info_get_link_speed_sup( p_comp_pi )!= + ib_port_info_get_link_speed_sup( p_pi) ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_PORTSTATE ) + { + if( ib_port_info_get_port_state( p_comp_pi ) != + ib_port_info_get_port_state( p_pi ) ) + goto Exit; + } + if ( comp_mask & IB_PIR_COMPMASK_PORTPHYSTATE ) + { + if ( ib_port_info_get_port_phys_state( p_comp_pi ) != + ib_port_info_get_port_phys_state( p_pi ) ) + goto Exit; + } + if ( comp_mask & IB_PIR_COMPMASK_LINKDWNDFLTSTATE ) + { + if ( ib_port_info_get_link_down_def_state( p_comp_pi ) != + ib_port_info_get_link_down_def_state( p_pi ) ) + goto Exit; + } + if ( comp_mask & IB_PIR_COMPMASK_MKEYPROTBITS ) + { + if( ib_port_info_get_mpb( p_comp_pi ) != + ib_port_info_get_mpb( p_pi ) ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_LMC ) + { + if( ib_port_info_get_lmc( p_comp_pi ) != + ib_port_info_get_lmc( p_pi ) ) + goto Exit; + } + if ( comp_mask & IB_PIR_COMPMASK_LINKSPEEDACTIVE ) + { + if ( ib_port_info_get_link_speed_active( p_comp_pi ) != + ib_port_info_get_link_speed_active( p_pi ) ) + goto Exit; + } + if ( comp_mask & IB_PIR_COMPMASK_LINKSPEEDENABLE ) + { + if ( ib_port_info_get_link_speed_enabled( p_comp_pi ) != + ib_port_info_get_link_speed_enabled( p_pi ) ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_NEIGHBORMTU ) + { + if( ib_port_info_get_neighbor_mtu( p_comp_pi ) != + ib_port_info_get_neighbor_mtu( p_pi ) ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_MASTERSMSL ) + { + if( ib_port_info_get_master_smsl( p_comp_pi ) != + ib_port_info_get_master_smsl( p_pi ) ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_VLCAP ) + { + if( ib_port_info_get_vl_cap( p_comp_pi ) != + ib_port_info_get_vl_cap( p_pi ) ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_INITTYPE ) + { + if( ib_port_info_get_init_type( p_comp_pi ) != + ib_port_info_get_init_type( p_pi ) ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_VLHIGHLIMIT ) + { + if( p_comp_pi->vl_high_limit != p_pi->vl_high_limit ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_VLARBHIGHCAP ) + { + if( p_comp_pi->vl_arb_high_cap != p_pi->vl_arb_high_cap ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_VLARBLOWCAP ) + { + if( p_comp_pi->vl_arb_low_cap != p_pi->vl_arb_low_cap ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_MTUCAP ) + { + if( ib_port_info_get_mtu_cap( p_comp_pi ) != + ib_port_info_get_mtu_cap( p_pi ) ) + goto Exit; + } + if( comp_mask & IB_PIR_COMPMASK_VLSTALLCNT ) + { + if( ib_port_info_get_vl_stall_count( p_comp_pi ) != + ib_port_info_get_vl_stall_count( p_pi ) ) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_HOQLIFE ) + { + if ((p_comp_pi->vl_stall_life & 0x1F) != (p_pi->vl_stall_life & 0x1F) ) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_OPVLS ) + { + if ((p_comp_pi->vl_enforce & 0xF0) != (p_pi->vl_enforce & 0xF0) ) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_PARENFIN ) + { + if ((p_comp_pi->vl_enforce & 0x08) != (p_pi->vl_enforce & 0x08) ) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_PARENFOUT ) + { + if ((p_comp_pi->vl_enforce & 0x04) != (p_pi->vl_enforce & 0x04) ) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_FILTERRAWIN ) + { + if ((p_comp_pi->vl_enforce & 0x02) != (p_pi->vl_enforce & 0x02) ) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_FILTERRAWOUT ) + { + if ((p_comp_pi->vl_enforce & 0x01) != (p_pi->vl_enforce & 0x01) ) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_MKEYVIO ) + { + if (p_comp_pi->m_key_violations != p_pi->m_key_violations ) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_PKEYVIO ) + { + if (p_comp_pi->p_key_violations != p_pi->p_key_violations ) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_QKEYVIO ) + { + if (p_comp_pi->q_key_violations != p_pi->q_key_violations ) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_GUIDCAP ) + { + if (p_comp_pi->guid_cap != p_pi->guid_cap ) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_SUBNTO ) + { + if (ib_port_info_get_timeout(p_comp_pi) != ib_port_info_get_timeout(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_RESPTIME ) + { + if ((p_comp_pi->resp_time_value & 0x1F) != (p_pi->resp_time_value &0x1F) ) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_LOCALPHYERR ) + { + if( ib_port_info_get_local_phy_err_thd( p_comp_pi ) != + ib_port_info_get_local_phy_err_thd( p_pi ) ) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_OVERRUNERR) + { + if( ib_port_info_get_overrun_err_thd( p_comp_pi ) != + ib_port_info_get_overrun_err_thd( p_pi ) ) + goto Exit; + } + + __osm_sa_pir_create( p_rcv, p_physp, p_ctxt ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_pir_by_comp_mask( + IN osm_pir_rcv_t* const p_rcv, + IN const osm_port_t* const p_port, + osm_pir_search_ctxt_t* const p_ctxt ) +{ + const ib_portinfo_record_t* p_rcvd_rec; + ib_net64_t comp_mask; + const osm_physp_t* p_physp; + uint8_t port_num; + uint8_t num_ports; + const osm_physp_t* p_req_physp; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_pir_by_comp_mask ); + + 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_port_get_num_physp( p_port ); + + if( comp_mask & IB_PIR_COMPMASK_PORTNUM ) + { + if (p_rcvd_rec->port_num < num_ports) + { + p_physp = osm_port_get_phys_ptr( p_port, 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_is_valid( p_physp ) && + osm_physp_share_pkey(p_rcv->p_log, p_req_physp, p_physp)) + __osm_sa_pir_check_physp( p_rcv, p_physp, p_ctxt ); + } + } + else + { + for( port_num = 0; port_num < num_ports; port_num++ ) + { + p_physp = osm_port_get_phys_ptr( p_port, port_num ); + if( p_physp == NULL ) + continue; + + if( !osm_physp_is_valid( p_physp ) ) + continue; + + /* if the requester and the p_physp don't share a pkey - + continue */ + if (!osm_physp_share_pkey(p_rcv->p_log, p_req_physp, p_physp ) ) + continue; + + __osm_sa_pir_check_physp( p_rcv, p_physp, p_ctxt ); + } + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_pir_by_comp_mask_cb( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + const osm_port_t* const p_port = (osm_port_t*)p_map_item; + osm_pir_search_ctxt_t* const p_ctxt = (osm_pir_search_ctxt_t *)context; + + __osm_sa_pir_by_comp_mask( p_ctxt->p_rcv, p_port, p_ctxt ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pir_rcv_process( + IN osm_pir_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_sa_mad_t* p_rcvd_mad; + const ib_portinfo_record_t* p_rcvd_rec; + const cl_ptr_vector_t* p_tbl; + const osm_port_t* p_port = NULL; + const ib_port_info_t* p_pi; + cl_qlist_t rec_list; + osm_madw_t* p_resp_madw; + ib_sa_mad_t* p_resp_sa_mad; + ib_portinfo_record_t* p_resp_rec; + uint32_t num_rec, pre_trim_num_rec; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t trim_num_rec; +#endif + uint32_t i; + osm_pir_search_ctxt_t context; + osm_pir_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + ib_net64_t comp_mask; + osm_physp_t* p_req_physp; + boolean_t trusted_req = TRUE; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_pir_rcv_process ); + + 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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pir_rcv_process: ERR 2105: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_rcvd_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pir_rcv_process: ERR 2104: " + "Cannot find requester physical port\n" ); + goto Exit; + } + + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + osm_dump_portinfo_record( p_rcv->p_log, p_rcvd_rec, OSM_LOG_DEBUG ); + + p_tbl = &p_rcv->p_subn->port_lid_tbl; + p_pi = &p_rcvd_rec->port_info; + + cl_qlist_init( &rec_list ); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = p_rcvd_mad->comp_mask; + context.p_rcv = p_rcv; + context.p_req_physp = p_req_physp; + context.is_enhanced_comp_mask = cl_ntoh32(p_rcvd_mad->attr_mod) & (1 << 31); + + cl_plock_acquire( p_rcv->p_lock ); + + CL_ASSERT( cl_ptr_vector_get_size(p_tbl) < 0x10000 ); + + /* + If the user specified a LID, it obviously narrows our + work load, since we don't have to search every port + */ + if( comp_mask & IB_PIR_COMPMASK_LID ) + { + status = osm_get_port_by_base_lid( p_rcv->p_subn, p_rcvd_rec->lid, &p_port ); + if ( ( status != IB_SUCCESS ) || ( p_port == NULL ) ) + { + status = IB_NOT_FOUND; + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pir_rcv_process: ERR 2109: " + "No port found with LID 0x%x\n", + cl_ntoh16(p_rcvd_rec->lid) ); + } + } + else + { + if( comp_mask & IB_PIR_COMPMASK_BASELID ) + { + if ((uint16_t)cl_ptr_vector_get_size(p_tbl) > cl_ntoh16(p_pi->base_lid)) + { + p_port = cl_ptr_vector_get( p_tbl, cl_ntoh16(p_pi->base_lid) ); + } + else + { + status = IB_NOT_FOUND; + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pir_rcv_process: ERR 2103: " + "Given LID (0x%X) is out of range:0x%X\n", + cl_ntoh16(p_pi->base_lid), cl_ptr_vector_get_size(p_tbl)); + } + } + } + + if ( status == IB_SUCCESS ) + { + if( p_port ) + __osm_sa_pir_by_comp_mask( p_rcv, p_port, &context ); + else + { + cl_qmap_apply_func( &p_rcv->p_subn->port_guid_tbl, + __osm_sa_pir_by_comp_mask_cb, + &context ); + } + } + + cl_plock_release( p_rcv->p_lock ); + + num_rec = cl_qlist_count( &rec_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if (p_rcvd_mad->method == IB_MAD_METHOD_GET) + { + if (num_rec == 0) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + if (num_rec > 1) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pir_rcv_process: ERR 2108: " + "Got more than one record for SubnAdmGet (%u)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS); + + /* need to set the mem free ... */ + p_rec_item = (osm_pir_item_t*)cl_qlist_remove_head( &rec_list ); + while( p_rec_item != (osm_pir_item_t*)cl_qlist_end( &rec_list ) ) + { + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_rec_item = (osm_pir_item_t*)cl_qlist_remove_head( &rec_list ); + } + + goto Exit; + } + } + + pre_trim_num_rec = num_rec; +#ifndef VENDOR_RMPP_SUPPORT + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_portinfo_record_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_pir_rcv_process: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_pir_rcv_process: " + "Returning %u records\n", num_rec ); + + if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0)) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_portinfo_record_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + + if( !p_resp_madw ) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_pir_rcv_process: ERR 2106: " + "osm_mad_pool_get failed\n" ); + + for( i = 0; i < num_rec; i++ ) + { + p_rec_item = (osm_pir_item_t*)cl_qlist_remove_head( &rec_list ); + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_NO_RESOURCES ); + + goto Exit; + } + + p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_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( p_resp_sa_mad, p_rcvd_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; + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_portinfo_record_t) ); + + p_resp_rec = (ib_portinfo_record_t*) + ib_sa_mad_get_payload_ptr( p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + /* + 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 == 0) + trusted_req = FALSE; + + for( i = 0; i < pre_trim_num_rec; i++ ) + { + p_rec_item = (osm_pir_item_t*)cl_qlist_remove_head( &rec_list ); + /* copy only if not trimmed */ + if (i < num_rec) + { + *p_resp_rec = p_rec_item->rec; + if (trusted_req == FALSE) + p_resp_rec->port_info.m_key = 0; + } + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_resp_rec++; + } + + CL_ASSERT( cl_is_qlist_empty( &rec_list ) ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE); + if (status != IB_SUCCESS) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_pir_rcv_process: ERR 2107: " + "osm_vendor_send status = %s\n", + ib_get_err_str(status)); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_portinfo_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_portinfo_record_ctrl.c new file mode 100644 index 00000000..a097cb14 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_portinfo_record_ctrl.c @@ -0,0 +1,125 @@ +/* + * 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: + * Implementation of osm_pir_rcv_ctrl_t. + * This object represents the PortInfoRecord request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_pir_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_pir_rcv_process( ((osm_pir_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pir_rcv_ctrl_construct( + IN osm_pir_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_pir_rcv_ctrl_destroy( + IN osm_pir_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pir_rcv_ctrl_init( + IN osm_pir_rcv_ctrl_t* const p_ctrl, + IN osm_pir_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_pir_rcv_ctrl_init ); + + osm_pir_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_PORTINFO_RECORD, + __osm_pir_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_pir_rcv_ctrl_init: ERR 2201: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_response.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_response.c new file mode 100644 index 00000000..9106aa1f --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_response.c @@ -0,0 +1,175 @@ +/* + * 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: + * Implementation of osm_sa_resp_t. + * This object represents the SA query responder. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_sa_resp_construct( + IN osm_sa_resp_t* const p_resp ) +{ + memset( p_resp, 0, sizeof(*p_resp) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sa_resp_destroy( + IN osm_sa_resp_t* const p_resp ) +{ + CL_ASSERT( p_resp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sa_resp_init( + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_pool, + IN osm_log_t* const p_log ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_sa_resp_init ); + + osm_sa_resp_construct( p_resp ); + + p_resp->p_log = p_log; + p_resp->p_pool = p_pool; + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sa_send_error( + IN osm_sa_resp_t* const p_resp, + IN const osm_madw_t* const p_madw, + IN const ib_net16_t sa_status ) +{ + osm_madw_t* p_resp_madw; + ib_sa_mad_t* p_resp_sa_mad; + ib_sa_mad_t* p_sa_mad; + ib_api_status_t status; + + OSM_LOG_ENTER( p_resp->p_log, osm_sa_send_error ); + + /* avoid races - if we are exiting - exit */ + if (osm_exit_flag) + { + osm_log( p_resp->p_log, OSM_LOG_DEBUG, + "osm_sa_send_error: " + "Ignoring requested send after exit\n" ); + goto Exit; + } + + p_resp_madw = osm_mad_pool_get( p_resp->p_pool, + p_madw->h_bind, MAD_BLOCK_SIZE, &p_madw->mad_addr ); + + if( p_resp_madw == NULL ) + { + osm_log( p_resp->p_log, OSM_LOG_ERROR, + "osm_sa_send_error: ERR 2301: " + "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; + + 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( p_resp->p_log, OSM_LOG_FRAMES ) ) + osm_dump_sa_mad( p_resp->p_log, p_resp_sa_mad, OSM_LOG_FRAMES ); + + status = osm_vendor_send( osm_madw_get_bind_handle( p_resp_madw ), + p_resp_madw, FALSE ); + + if( status != IB_SUCCESS ) + { + osm_log( p_resp->p_log, OSM_LOG_ERROR, + "osm_sa_send_error: ERR 2302: " + "Error sending MAD (%s)\n", ib_get_err_str( status ) ); + /* osm_mad_pool_put( p_resp->p_pool, p_resp_madw ); */ + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_resp->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_service_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_service_record.c new file mode 100644 index 00000000..44ab006f --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_service_record.c @@ -0,0 +1,1204 @@ +/* + * 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: + * Implementation of osm_sr_rcv_t. + * This object represents the ServiceRecord Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.9 $ + */ + +#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 + +#define OSM_SR_RCV_POOL_MIN_SIZE 64 +#define OSM_SR_RCV_POOL_GROW_SIZE 64 + +typedef struct _osm_sr_item +{ + cl_pool_item_t pool_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_sr_rcv_t* p_rcv; + +} 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; + +/********************************************************************** + **********************************************************************/ +void +osm_sr_rcv_construct( + IN osm_sr_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->sr_pool ); + cl_timer_construct(&p_rcv->sr_timer ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sr_rcv_destroy( + IN osm_sr_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_sr_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->sr_pool ); + cl_timer_trim(&p_rcv->sr_timer, 1); + cl_timer_destroy(&p_rcv->sr_timer ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sr_rcv_init( + IN osm_sr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_ERROR; + cl_status_t cl_status; + + OSM_LOG_ENTER( p_log, osm_sr_rcv_init ); + + osm_sr_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + cl_status = cl_qlock_pool_init( &p_rcv->sr_pool, + OSM_SR_RCV_POOL_MIN_SIZE, + 0, + OSM_SR_RCV_POOL_GROW_SIZE, + sizeof(osm_sr_item_t), + NULL, NULL, NULL ); + if(cl_status != CL_SUCCESS) + goto Exit; + + status = cl_timer_init(&p_rcv->sr_timer, + osm_sr_rcv_lease_cb, + p_rcv ); + if(cl_status != CL_SUCCESS) + goto Exit; + + status = IB_SUCCESS; + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +__match_service_pkey_with_ports_pkey( + IN osm_sr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + ib_service_record_t * const p_service_rec, + ib_net64_t const comp_mask ) +{ + boolean_t valid = TRUE; + osm_physp_t * p_req_physp; + ib_net64_t service_guid; + osm_port_t * service_port; + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw)); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__match_service_pkey_with_ports_pkey: 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(p_rcv->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_port_t*)cl_qmap_get( &p_rcv->p_subn->port_guid_tbl, service_guid ); + if (service_port == (osm_port_t*)cl_qmap_end( &p_rcv->p_subn->port_guid_tbl )) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__match_service_pkey_with_ports_pkey: 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( p_rcv->p_log, + p_service_rec->service_pkey, + osm_port_get_default_phys_ptr(service_port) ) ) + { + valid = FALSE; + goto Exit; + } + } + } + + Exit: + return valid; +} + +/********************************************************************** + **********************************************************************/ +boolean_t +__match_name_to_key_association( + IN osm_sr_rcv_t* const p_rcv, + ib_service_record_t* p_service_rec, + ib_net64_t comp_mask ) +{ + UNUSED_PARAM( p_service_rec ); + UNUSED_PARAM( p_rcv ); + + 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_sr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + boolean_t valid = TRUE; + ib_sa_mad_t * p_sa_mad; + ib_service_record_t* p_recvd_service_rec; + + OSM_LOG_ENTER( p_rcv->p_log, __validate_sr ); + + 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( + p_rcv, + p_madw, + p_recvd_service_rec, + p_sa_mad->comp_mask ); + + if(!valid) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_sr: " + "No Match for Service Pkey\n" ); + valid = FALSE; + goto Exit; + } + + valid = __match_name_to_key_association( + p_rcv, + p_recvd_service_rec, + p_sa_mad->comp_mask ); + + if(!valid) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_sr: " + "Service Record Name to key matching failed\n" ); + valid = FALSE; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return valid; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sr_rcv_respond( + IN osm_sr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + IN cl_qlist_t* const p_list ) +{ + osm_madw_t* p_resp_madw; + const ib_sa_mad_t* p_sa_mad; + ib_sa_mad_t* p_resp_sa_mad; + uint32_t num_rec, num_copied; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t trim_num_rec; +#endif + ib_service_record_t* p_resp_sr; + ib_api_status_t status; + osm_sr_item_t* p_sr_item; + const ib_sa_mad_t* p_rcvd_mad = osm_madw_get_sa_mad_ptr( p_madw ); + boolean_t trusted_req = TRUE; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sr_rcv_respond ); + + num_rec = cl_qlist_count( p_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if ( (p_rcvd_mad->method == IB_MAD_METHOD_GET) && + (num_rec > 1)) { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sr_rcv_respond: ERR 2406: " + "Got more than one record for SubnAdmGet (%u).\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS ); + + /* need to set the mem free ... */ + p_sr_item = (osm_sr_item_t*)cl_qlist_remove_head( p_list ); + while( p_sr_item != (osm_sr_item_t*)cl_qlist_end( p_list ) ) + { + cl_qlock_pool_put( &p_rcv->sr_pool, &p_sr_item->pool_item ); + p_sr_item = (osm_sr_item_t*)cl_qlist_remove_head( p_list ); + } + + goto Exit; + } + +#ifndef VENDOR_RMPP_SUPPORT + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_service_record_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_sr_rcv_respond: " + "Number of records:%u trimmed to:%u to fit in one MAD\n", + num_rec, trim_num_rec ); + num_rec = trim_num_rec; + } +#endif + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sr_rcv_respond: " + "Generating response with %u records\n", num_rec ); + } + + /* + Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_service_record_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + if( !p_resp_madw ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sr_rcv_respond: ERR 2402: " + "Unable to allocate MAD\n" ); + /* Release the quick pool items */ + p_sr_item = (osm_sr_item_t*)cl_qlist_remove_head( p_list ); + while( p_sr_item != (osm_sr_item_t*)cl_qlist_end( p_list ) ) + { + cl_qlock_pool_put( &p_rcv->sr_pool, &p_sr_item->pool_item ); + p_sr_item = (osm_sr_item_t*)cl_qlist_remove_head( p_list ); + } + + 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 ); + + /* but what if it was a SET ? setting the response bit is not enough */ + if (p_rcvd_mad->method == IB_MAD_METHOD_SET) + { + p_resp_sa_mad->method = IB_MAD_METHOD_GET; + } + 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; + + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_service_record_t) ); + +#ifndef VENDOR_RMPP_SUPPORT + /* we support only one packet RMPP - so we will set the first and + last flags for gettable */ + if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + p_resp_sr = (ib_service_record_t*)ib_sa_mad_get_payload_ptr( p_resp_sa_mad ); + + if( (p_resp_sa_mad->method != IB_MAD_METHOD_GETTABLE_RESP) && + (num_rec == 0)) + { + p_resp_sa_mad->status = IB_SA_MAD_STATUS_NO_RECORDS; + memset( p_resp_sr, 0, sizeof(*p_resp_sr) ); + } + else + { + /* + 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 (p_sa_mad->sm_key == 0) + trusted_req = FALSE; + + p_sr_item = (osm_sr_item_t*)cl_qlist_remove_head( p_list ); + + /* we need to track the number of copied items so we can + * stop the copy - but clear them all + */ + num_copied = 0; + while( p_sr_item != (osm_sr_item_t*)cl_qlist_end( p_list ) ) + { + /* Copy the Link Records from the list into the MAD */ + if (num_copied < num_rec) + { + *p_resp_sr = p_sr_item->service_rec; + if (trusted_req == FALSE) + memset(p_resp_sr->service_key, 0, sizeof(p_resp_sr->service_key)); + + num_copied++; + } + cl_qlock_pool_put( &p_rcv->sr_pool, &p_sr_item->pool_item ); + p_resp_sr++; + p_sr_item = (osm_sr_item_t*)cl_qlist_remove_head( p_list ); + } + } + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sr_rcv_respond: ERR 2407: " + "Unable to send MAD (%s)\n", ib_get_err_str( status ) ); + /* osm_mad_pool_put( p_rcv->p_mad_pool, p_resp_madw ); */ + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__get_matching_sr( + IN cl_list_item_t* const p_list_item, + IN void* context ) +{ + osm_sr_search_ctxt_t* const p_ctxt = (osm_sr_search_ctxt_t*)context; + osm_svcr_t * p_svcr = (osm_svcr_t*)p_list_item; + osm_sr_item_t* p_sr_pool_item; + osm_sr_match_item_t* p_sr_item =p_ctxt->p_sr_item; + ib_net64_t comp_mask = p_sr_item->comp_mask; + const osm_physp_t* p_req_physp = p_ctxt->p_req_physp; + + if((comp_mask & IB_SR_COMPMASK_SID) == IB_SR_COMPMASK_SID) + { + if(p_sr_item->p_service_rec->service_id != + p_svcr->service_record.service_id) + return; + } + if((comp_mask & IB_SR_COMPMASK_SGID) == IB_SR_COMPMASK_SGID) + { + if( + memcmp(&p_sr_item->p_service_rec->service_gid, + &p_svcr->service_record.service_gid, + sizeof(p_svcr->service_record.service_gid)) != 0) + return; + } + if((comp_mask & IB_SR_COMPMASK_SPKEY) == IB_SR_COMPMASK_SPKEY ) + { + if(p_sr_item->p_service_rec->service_pkey != + p_svcr->service_record.service_pkey) + return; + } + + if((comp_mask & IB_SR_COMPMASK_SKEY) == IB_SR_COMPMASK_SKEY) + { + if(memcmp(p_sr_item->p_service_rec->service_key , + p_svcr->service_record.service_key, + 16*sizeof(uint8_t))) + return; + } + if((comp_mask & IB_SR_COMPMASK_SNAME) == IB_SR_COMPMASK_SNAME) + { + if( + memcmp(p_sr_item->p_service_rec->service_name, + p_svcr->service_record.service_name, + sizeof(p_svcr->service_record.service_name)) != 0 + ) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA8_0) == IB_SR_COMPMASK_SDATA8_0) + { + if(p_sr_item->p_service_rec->service_data8[0] != + p_svcr->service_record.service_data8[0]) + return; + } + + if((comp_mask & IB_SR_COMPMASK_SDATA8_1) == IB_SR_COMPMASK_SDATA8_1) + { + if(p_sr_item->p_service_rec->service_data8[1] != + p_svcr->service_record.service_data8[1]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA8_2) == IB_SR_COMPMASK_SDATA8_2) + { + if(p_sr_item->p_service_rec->service_data8[2] != + p_svcr->service_record.service_data8[2]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA8_3) == IB_SR_COMPMASK_SDATA8_3) + { + if(p_sr_item->p_service_rec->service_data8[3] != + p_svcr->service_record.service_data8[3]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA8_4)== IB_SR_COMPMASK_SDATA8_4) + { + if(p_sr_item->p_service_rec->service_data8[4] != + p_svcr->service_record.service_data8[4]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA8_5)== IB_SR_COMPMASK_SDATA8_5) + { + if(p_sr_item->p_service_rec->service_data8[5] != + p_svcr->service_record.service_data8[5]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA8_6)== IB_SR_COMPMASK_SDATA8_6) + { + if(p_sr_item->p_service_rec->service_data8[6]!= + p_svcr->service_record.service_data8[6]) + return; + } + + if((comp_mask & IB_SR_COMPMASK_SDATA8_7)== IB_SR_COMPMASK_SDATA8_7) + { + if(p_sr_item->p_service_rec->service_data8[7]!= + p_svcr->service_record.service_data8[7]) + return; + } + + if((comp_mask & IB_SR_COMPMASK_SDATA8_8)== IB_SR_COMPMASK_SDATA8_8) + { + if(p_sr_item->p_service_rec->service_data8[8]!= + p_svcr->service_record.service_data8[8]) + return; + } + + if((comp_mask & IB_SR_COMPMASK_SDATA8_9)== IB_SR_COMPMASK_SDATA8_9) + { + if(p_sr_item->p_service_rec->service_data8[9]!= + p_svcr->service_record.service_data8[9]) + return; + } + + if((comp_mask & IB_SR_COMPMASK_SDATA8_10)== IB_SR_COMPMASK_SDATA8_10) + { + if(p_sr_item->p_service_rec->service_data8[10]!= + p_svcr->service_record.service_data8[10]) + return; + } + + if((comp_mask & IB_SR_COMPMASK_SDATA8_11)== IB_SR_COMPMASK_SDATA8_11) + { + if(p_sr_item->p_service_rec->service_data8[11]!= + p_svcr->service_record.service_data8[11]) + return; + } + + if((comp_mask & IB_SR_COMPMASK_SDATA8_12)== IB_SR_COMPMASK_SDATA8_12) + { + if(p_sr_item->p_service_rec->service_data8[12]!= + p_svcr->service_record.service_data8[12]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA8_13)== IB_SR_COMPMASK_SDATA8_13) + { + if(p_sr_item->p_service_rec->service_data8[13]!= + p_svcr->service_record.service_data8[13]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA8_14)== IB_SR_COMPMASK_SDATA8_14) + { + if(p_sr_item->p_service_rec->service_data8[14]!= + p_svcr->service_record.service_data8[14]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA8_15)== IB_SR_COMPMASK_SDATA8_15) + { + if(p_sr_item->p_service_rec->service_data8[15]!= + p_svcr->service_record.service_data8[15]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA16_0)== IB_SR_COMPMASK_SDATA16_0) + { + if(p_sr_item->p_service_rec->service_data16[0]!= + p_svcr->service_record.service_data16[0]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA16_1)== IB_SR_COMPMASK_SDATA16_1) + { + if(p_sr_item->p_service_rec->service_data16[1]!= + p_svcr->service_record.service_data16[1]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA16_2)== IB_SR_COMPMASK_SDATA16_2) + { + if(p_sr_item->p_service_rec->service_data16[2]!= + p_svcr->service_record.service_data16[2]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA16_3)== IB_SR_COMPMASK_SDATA16_3) + { + if(p_sr_item->p_service_rec->service_data16[3]!= + p_svcr->service_record.service_data16[3]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA16_4)== IB_SR_COMPMASK_SDATA16_4) + { + if(p_sr_item->p_service_rec->service_data16[4]!= + p_svcr->service_record.service_data16[4]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA16_5)== IB_SR_COMPMASK_SDATA16_5) + { + if(p_sr_item->p_service_rec->service_data16[5]!= + p_svcr->service_record.service_data16[5]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA16_6)== IB_SR_COMPMASK_SDATA16_6) + { + if(p_sr_item->p_service_rec->service_data16[6]!= + p_svcr->service_record.service_data16[6]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA16_7)== IB_SR_COMPMASK_SDATA16_7) + { + if(p_sr_item->p_service_rec->service_data16[7]!= + p_svcr->service_record.service_data16[7]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA32_0)== IB_SR_COMPMASK_SDATA32_0) + { + if(p_sr_item->p_service_rec->service_data32[0]!= + p_svcr->service_record.service_data32[0]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA32_1)== IB_SR_COMPMASK_SDATA32_1) + { + if(p_sr_item->p_service_rec->service_data32[1]!= + p_svcr->service_record.service_data32[1]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA32_2)== IB_SR_COMPMASK_SDATA32_2) + { + if(p_sr_item->p_service_rec->service_data32[2]!= + p_svcr->service_record.service_data32[2]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA32_3)== IB_SR_COMPMASK_SDATA32_3) + { + if(p_sr_item->p_service_rec->service_data32[3]!= + p_svcr->service_record.service_data32[3]) + return; + } + + if((comp_mask & IB_SR_COMPMASK_SDATA64_0)== IB_SR_COMPMASK_SDATA64_0) + { + if(p_sr_item->p_service_rec->service_data64[0]!= + p_svcr->service_record.service_data64[0]) + return; + } + if((comp_mask & IB_SR_COMPMASK_SDATA64_1)== IB_SR_COMPMASK_SDATA64_1) + { + if(p_sr_item->p_service_rec->service_data64[1]!= + p_svcr->service_record.service_data64[1]) + return; + } + + /* Check that the requester port has the pkey which is the service_pkey. + If not - then it cannot receive this ServiceRecord. */ + /* The check is relevant only if the service_pkey is valid */ + if (!ib_pkey_is_invalid(p_svcr->service_record.service_pkey)) + { + if (!osm_physp_has_pkey( p_sr_item->p_rcv->p_log, + p_svcr->service_record.service_pkey, + p_req_physp ) ) + { + osm_log( p_sr_item->p_rcv->p_log, OSM_LOG_VERBOSE, + "__get_matching_sr: " + "requester port doesn't have the service_pkey: 0x%X\n", + cl_ntoh16(p_svcr->service_record.service_pkey) ); + return; + } + } + + p_sr_pool_item = (osm_sr_item_t*)cl_qlock_pool_get( &p_sr_item->p_rcv->sr_pool ); + + if( p_sr_pool_item == NULL ) + { + osm_log( p_sr_item->p_rcv->p_log, OSM_LOG_ERROR, + "__get_matching_sr: 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, + (cl_list_item_t*)&p_sr_pool_item->pool_item ); + + Exit: + return; +} + +/********************************************************************** + **********************************************************************/ +static void +osm_sr_rcv_process_get_method( + IN osm_sr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + ib_sa_mad_t * p_sa_mad; + ib_service_record_t* p_recvd_service_rec; + osm_sr_match_item_t sr_match_item; + osm_sr_search_ctxt_t context; + osm_physp_t* p_req_physp; + + OSM_LOG_ENTER( p_rcv->p_log, osm_sr_rcv_process_get_method ); + + CL_ASSERT( p_madw ); + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_sr_rcv_process_get_method: 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( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_dump_service_record( p_rcv->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.p_rcv = p_rcv; + + context.p_sr_item = &sr_match_item; + context.p_req_physp = p_req_physp; + + /* Grab the lock */ + cl_plock_excl_acquire(p_rcv->p_lock); + + cl_qlist_apply_func(&p_rcv->p_subn->sa_sr_list, + __get_matching_sr, + &context); + + cl_plock_release(p_rcv->p_lock); + + if ((p_sa_mad->method == IB_MAD_METHOD_GET) && + (cl_qlist_count( &sr_match_item.sr_list ) == 0)) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_sr_rcv_process_get_method: " + "No records matched the Service Record query\n"); + + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + __osm_sr_rcv_respond( p_rcv, p_madw, &sr_match_item.sr_list ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return; +} + +/********************************************************************** + **********************************************************************/ +static void +osm_sr_rcv_process_set_method( + IN osm_sr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + ib_sa_mad_t * p_sa_mad; + ib_net16_t sa_status = IB_SA_MAD_STATUS_REQ_INVALID; + 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( p_rcv->p_log, osm_sr_rcv_process_set_method ); + + 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( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_dump_service_record( p_rcv->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( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_sr_rcv_process_set_method: " + "Component Mask RID check failed for METHOD_SET\n"); + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + 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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_sr_rcv_process_set_method: " + "ServiceLease Component Mask not set - using infinite lease\n"); + p_recvd_service_rec->service_lease = 0xFFFFFFFF; + } + + /* Grab the lock */ + cl_plock_excl_acquire(p_rcv->p_lock); + + /* If Record exists with matching RID */ + p_svcr = osm_svcr_get_by_rid( + p_rcv->p_subn, + p_rcv->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(p_rcv->p_lock); + + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_sr_rcv_process_set_method: ERR 2411: " + "osm_svcr_get_by_rid failed\n" ); + + osm_sa_send_error( p_rcv->p_resp, 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( + p_rcv->p_subn, + p_rcv->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(p_rcv->p_lock); + + if( p_recvd_service_rec->service_lease != 0xFFFFFFFF ) + { +#if 0 + cl_timer_trim(&p_rcv->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(&p_rcv->sr_timer, 1000); + p_svcr->modified_time = cl_get_time_stamp_sec(); + } + + p_sr_item = (osm_sr_item_t*)cl_qlock_pool_get( &p_rcv->sr_pool ); + if( p_sr_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_sr_rcv_process_set_method: ERR 2412: " + "Unable to acquire Service record\n" ); + osm_sa_send_error( p_rcv->p_resp, 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, (cl_list_item_t*)&p_sr_item->pool_item ); + + __osm_sr_rcv_respond( p_rcv, p_madw, &sr_list ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return; +} + +/********************************************************************** + **********************************************************************/ +static void +osm_sr_rcv_process_delete_method( + IN osm_sr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + ib_sa_mad_t * p_sa_mad; + ib_service_record_t* p_recvd_service_rec; + ib_net64_t comp_mask; + osm_svcr_t* p_svcr; + osm_sr_item_t* p_sr_item; + cl_qlist_t sr_list; + + OSM_LOG_ENTER( p_rcv->p_log, osm_sr_rcv_process_delete_method ); + + 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( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_dump_service_record( p_rcv->p_log, + p_recvd_service_rec, + OSM_LOG_DEBUG ); + } + + /* Grab the lock */ + cl_plock_excl_acquire(p_rcv->p_lock); + + /* If Record exists with matching RID */ + p_svcr = osm_svcr_get_by_rid( + p_rcv->p_subn, + p_rcv->p_log, + p_recvd_service_rec ); + + if(p_svcr == NULL) + { + cl_plock_release(p_rcv->p_lock); + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_sr_rcv_process_delete_method: " + "No records matched the RID\n"); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + else + { + osm_svcr_remove_from_db(p_rcv->p_subn, + p_rcv->p_log, + p_svcr ); + } + + cl_plock_release(p_rcv->p_lock); + + p_sr_item = (osm_sr_item_t*)cl_qlock_pool_get( &p_rcv->sr_pool ); + if( p_sr_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_sr_rcv_process_delete_method: ERR 2413: " + "Unable to acquire Service record\n"); + osm_sa_send_error( p_rcv->p_resp, 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, (cl_list_item_t*)&p_sr_item->pool_item ); + + if(p_svcr) + osm_svcr_destroy(p_svcr); + + __osm_sr_rcv_respond( p_rcv, p_madw, &sr_list ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return; +} + +/********************************************************************** + **********************************************************************/ +void +osm_sr_rcv_process( + IN osm_sr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + ib_sa_mad_t * p_sa_mad; + ib_net16_t sa_status = IB_SA_MAD_STATUS_REQ_INVALID; + boolean_t valid; + + OSM_LOG_ENTER( p_rcv->p_log, osm_sr_rcv_process ); + + 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(p_rcv, p_madw); + if(!valid) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_sr_rcv_process: " + "Component Mask check failed for set request\n" ); + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + osm_sr_rcv_process_set_method(p_rcv, p_madw); + break; + case IB_MAD_METHOD_DELETE: + valid = __validate_sr(p_rcv, p_madw); + if(!valid) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_sr_rcv_process: " + "Component Mask check failed for delete request\n" ); + osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status ); + goto Exit; + } + osm_sr_rcv_process_delete_method(p_rcv, p_madw); + break; + case IB_MAD_METHOD_GET: + case IB_MAD_METHOD_GETTABLE: + osm_sr_rcv_process_get_method(p_rcv, p_madw); + break; + default: + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_sr_rcv_process: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_sa_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + break; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return; +} + +/********************************************************************** + **********************************************************************/ +void +osm_sr_rcv_lease_cb( + IN void* context ) +{ + osm_sr_rcv_t* p_rcv = (osm_sr_rcv_t*)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( p_rcv->p_log, osm_sr_rcv_lease_cb ); + + cl_plock_excl_acquire(p_rcv->p_lock); + + p_list_item = cl_qlist_head(&p_rcv->p_subn->sa_sr_list); + + while( p_list_item != cl_qlist_end(&p_rcv->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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_sr_rcv_lease_cb: " + "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(p_rcv->p_subn, + p_rcv->p_log, + p_svcr); + + osm_svcr_destroy(p_svcr); + + p_list_item = p_next_list_item; + continue; + } + } + + /* Release the Lock */ + cl_plock_release(p_rcv->p_lock); + + if(trim_time != 0xFFFFFFFF) + { + cl_timer_trim(&p_rcv->sr_timer, + trim_time * 1000); /* Convert to milli seconds */ + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_service_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_service_record_ctrl.c new file mode 100644 index 00000000..003a1f45 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_service_record_ctrl.c @@ -0,0 +1,125 @@ +/* + * 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: + * Implementation of osm_sr_rcv_ctrl_t. + * This object represents the ServiceRecord request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +static void +__osm_sr_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_sr_rcv_process( ((osm_sr_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sr_rcv_ctrl_construct( + IN osm_sr_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_sr_rcv_ctrl_destroy( + IN osm_sr_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sr_rcv_ctrl_init( + IN osm_sr_rcv_ctrl_t* const p_ctrl, + IN osm_sr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_sr_rcv_ctrl_init ); + + osm_sr_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_SERVICE_RECORD, + __osm_sr_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_sr_rcv_ctrl_init: ERR 2501: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_slvl_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_slvl_record.c new file mode 100644 index 00000000..4895b6be --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_slvl_record.c @@ -0,0 +1,557 @@ +/* + * 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: + * 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_SLVL_REC_RCV_POOL_MIN_SIZE 32 +#define OSM_SLVL_REC_RCV_POOL_GROW_SIZE 32 + +typedef struct _osm_slvl_item +{ + cl_pool_item_t pool_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_slvl_rec_rcv_t* p_rcv; + const osm_physp_t* p_req_physp; +} osm_slvl_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void +osm_slvl_rec_rcv_construct( + IN osm_slvl_rec_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_slvl_rec_rcv_destroy( + IN osm_slvl_rec_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_slvl_rec_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_slvl_rec_rcv_init( + IN osm_slvl_rec_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN const osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_slvl_rec_rcv_init ); + + osm_slvl_rec_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + /* used for matching records collection */ + status = cl_qlock_pool_init( &p_rcv->pool, + OSM_SLVL_REC_RCV_POOL_MIN_SIZE, + 0, + OSM_SLVL_REC_RCV_POOL_GROW_SIZE, + sizeof(osm_slvl_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sa_slvl_create( + IN osm_slvl_rec_rcv_t* const p_rcv, + IN const osm_physp_t* const p_physp, + IN osm_slvl_search_ctxt_t* const p_ctxt, + IN uint8_t in_port_idx ) +{ + osm_slvl_item_t* p_rec_item; + uint16_t lid; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_slvl_create ); + + p_rec_item = (osm_slvl_item_t*)cl_qlock_pool_get( &p_rcv->pool ); + if( p_rec_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sa_slvl_create: ERR 2602: " + "cl_qlock_pool_get failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + if (p_physp->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) + { + lid = osm_physp_get_port_info_ptr( p_physp )->base_lid; + } + else + { + lid = osm_node_get_base_lid( p_physp->p_node, 0 ); + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_slvl_create: " + "New SLtoVL Map for: OUT port 0x%016" PRIx64 + ", lid 0x%X, port# 0x%X 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->rec, 0, sizeof( p_rec_item->rec ) ); + + 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, (cl_list_item_t*)&p_rec_item->pool_item ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sa_slvl_by_comp_mask( + IN osm_slvl_rec_rcv_t* const p_rcv, + IN const osm_port_t* const p_port, + osm_slvl_search_ctxt_t* const p_ctxt ) +{ + const ib_slvl_table_record_t* p_rcvd_rec; + ib_net64_t comp_mask; + const osm_physp_t* p_out_physp, *p_in_physp; + uint8_t in_port_num, out_port_num; + uint8_t num_ports; + uint8_t in_port_start, in_port_end; + uint8_t out_port_start, out_port_end; + const osm_physp_t* p_req_physp; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_slvl_by_comp_mask ); + + p_rcvd_rec = p_ctxt->p_rcvd_rec; + comp_mask = p_ctxt->comp_mask; + num_ports = osm_port_get_num_physp( p_port ); + in_port_start = 0; + in_port_end = num_ports; + out_port_start = 0; + out_port_end = num_ports; + p_req_physp = p_ctxt->p_req_physp; + + if ( p_port->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_slvl_by_comp_mask: " + "Using Physical Default Port Number: 0x%X (for End Node)\n", + p_port->default_port_num ); + p_out_physp = osm_port_get_phys_ptr( p_port, p_port->default_port_num ); + /* check that the p_out_physp and the p_req_physp share a pkey */ + if (osm_physp_share_pkey( p_rcv->p_log, p_req_physp, p_out_physp )) + __osm_sa_slvl_create( p_rcv, 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_port_get_phys_ptr( p_port, out_port_num ); + if( p_out_physp == NULL ) + continue; + + if( !osm_physp_is_valid( 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_port_get_phys_ptr( p_port, in_port_num ); + if( p_in_physp == NULL ) + continue; + + if( !osm_physp_is_valid( p_in_physp ) ) + continue; + + /* if the requester and the p_out_physp don't share a pkey - + continue */ + if (!osm_physp_share_pkey(p_rcv->p_log, p_req_physp, p_out_physp ) ) + continue; + + __osm_sa_slvl_create(p_rcv, p_out_physp, p_ctxt, in_port_num); + } + } + } + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sa_slvl_by_comp_mask_cb( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + const osm_port_t* const p_port = (osm_port_t*)p_map_item; + osm_slvl_search_ctxt_t* const p_ctxt = (osm_slvl_search_ctxt_t *)context; + + __osm_sa_slvl_by_comp_mask( p_ctxt->p_rcv, p_port, p_ctxt ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_slvl_rec_rcv_process( + IN osm_slvl_rec_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_sa_mad_t* p_rcvd_mad; + const ib_slvl_table_record_t* p_rcvd_rec; + const cl_ptr_vector_t* p_tbl; + const osm_port_t* p_port = NULL; + const ib_slvl_table_t* p_slvl_tbl; + cl_qlist_t rec_list; + osm_madw_t* p_resp_madw; + ib_sa_mad_t* p_resp_sa_mad; + ib_slvl_table_record_t* p_resp_rec; + uint32_t num_rec, pre_trim_num_rec; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t trim_num_rec; +#endif + uint32_t i; + osm_slvl_search_ctxt_t context; + osm_slvl_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + ib_net64_t comp_mask; + osm_physp_t* p_req_physp; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_slvl_rec_rcv_process ); + + 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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_slvl_rec_rcv_process: ERR 2604: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_rcvd_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_slvl_rec_rcv_process: ERR 2603: " + "Cannot find requester physical port\n" ); + goto Exit; + } + + p_slvl_tbl = (ib_slvl_table_t*)ib_sa_mad_get_payload_ptr( p_rcvd_mad ); + + cl_qlist_init( &rec_list ); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = p_rcvd_mad->comp_mask; + context.p_rcv = p_rcv; + context.in_port_num = p_rcvd_rec->in_port_num; + context.p_req_physp = p_req_physp; + + cl_plock_acquire( p_rcv->p_lock ); + + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_slvl_rec_rcv_process: " + "Got Query Lid:0x%04X(%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_tbl = &p_rcv->p_subn->port_lid_tbl; + + CL_ASSERT( cl_ptr_vector_get_size(p_tbl) < 0x10000 ); + + status = osm_get_port_by_base_lid( p_rcv->p_subn, p_rcvd_rec->lid, &p_port ); + if ( ( status != IB_SUCCESS ) || ( p_port == NULL ) ) + { + status = IB_NOT_FOUND; + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_slvl_rec_rcv_process: ERR 2608: " + "No port found with LID 0x%x\n", + cl_ntoh16(p_rcvd_rec->lid) ); + } + } + + if ( status == IB_SUCCESS ) + { + /* if we have a unique port - no need for a port search */ + if( p_port ) + /* this does the loop on all the port phys ports */ + __osm_sa_slvl_by_comp_mask( p_rcv, p_port, &context ); + else + { + cl_qmap_apply_func( &p_rcv->p_subn->port_guid_tbl, + __osm_sa_slvl_by_comp_mask_cb, + &context ); + } + } + + cl_plock_release( p_rcv->p_lock ); + + num_rec = cl_qlist_count( &rec_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if (p_rcvd_mad->method == IB_MAD_METHOD_GET) + { + if (num_rec == 0) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + if (num_rec > 1) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_slvl_rec_rcv_process: ERR 2607: " + "Got more than one record for SubnAdmGet (%u)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS ); + + /* need to set the mem free ... */ + p_rec_item = (osm_slvl_item_t*)cl_qlist_remove_head( &rec_list ); + while( p_rec_item != (osm_slvl_item_t*)cl_qlist_end( &rec_list ) ) + { + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_rec_item = (osm_slvl_item_t*)cl_qlist_remove_head( &rec_list ); + } + + goto Exit; + } + } + + pre_trim_num_rec = num_rec; +#ifndef VENDOR_RMPP_SUPPORT + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_slvl_table_record_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_slvl_rec_rcv_process: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_slvl_rec_rcv_process: " + "Returning %u records\n", num_rec ); + + if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0)) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_slvl_table_record_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + + if( !p_resp_madw ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_slvl_rec_rcv_process: ERR 2605: " + "osm_mad_pool_get failed\n" ); + + for( i = 0; i < num_rec; i++ ) + { + p_rec_item = (osm_slvl_item_t*)cl_qlist_remove_head( &rec_list ); + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES ); + goto Exit; + } + + p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_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( p_resp_sa_mad, p_rcvd_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; + + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_slvl_table_record_t) ); + + p_resp_rec = (ib_slvl_table_record_t*) + ib_sa_mad_get_payload_ptr( p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + for( i = 0; i < pre_trim_num_rec; i++ ) + { + p_rec_item = (osm_slvl_item_t*)cl_qlist_remove_head( &rec_list ); + /* copy only if not trimmed */ + if (i < num_rec) + { + *p_resp_rec = p_rec_item->rec; + } + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_resp_rec++; + } + + CL_ASSERT( cl_is_qlist_empty( &rec_list ) ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE); + if(status != IB_SUCCESS) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_slvl_rec_rcv_process: ERR 2606: " + "osm_vendor_send status = %s\n", + ib_get_err_str(status) ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_slvl_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_slvl_record_ctrl.c new file mode 100644 index 00000000..5faee333 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_slvl_record_ctrl.c @@ -0,0 +1,126 @@ +/* + * 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: + * Implementation of osm_slvl_rec_rcv_ctrl_t. + * This object represents the SLtoVL Map Record SA request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_slvl_rec_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_slvl_rec_rcv_process( ((osm_slvl_rec_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_slvl_rec_rcv_ctrl_construct( + IN osm_slvl_rec_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_slvl_rec_rcv_ctrl_destroy( + IN osm_slvl_rec_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_slvl_rec_rcv_ctrl_init( + IN osm_slvl_rec_rcv_ctrl_t* const p_ctrl, + IN osm_slvl_rec_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_slvl_rec_rcv_ctrl_init ); + + osm_slvl_rec_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_SLVL_TBL_RECORD, + __osm_slvl_rec_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_slvl_rec_rcv_ctrl_init: ERR 2701: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sminfo_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sminfo_record.c new file mode 100644 index 00000000..258cd2a5 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sminfo_record.c @@ -0,0 +1,583 @@ +/* + * 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: + * Implementation of osm_smir_rcv_t. + * This object represents the SMInfo Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_SMIR_RCV_POOL_MIN_SIZE 32 +#define OSM_SMIR_RCV_POOL_GROW_SIZE 32 + +typedef struct _osm_smir_item +{ + cl_pool_item_t pool_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_smir_rcv_t* p_rcv; + const osm_physp_t* p_req_physp; +} osm_smir_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void +osm_smir_rcv_construct( + IN osm_smir_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_smir_rcv_destroy( + IN osm_smir_rcv_t* const p_rcv ) +{ + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_smir_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_smir_rcv_init( + IN osm_smir_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_stats_t* const p_stats, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_smir_rcv_init ); + + osm_smir_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_stats = p_stats; + p_rcv->p_mad_pool = p_mad_pool; + + status = cl_qlock_pool_init( &p_rcv->pool, + OSM_SMIR_RCV_POOL_MIN_SIZE, + 0, + OSM_SMIR_RCV_POOL_GROW_SIZE, + sizeof(osm_smir_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +static ib_api_status_t +__osm_smir_rcv_new_smir( + IN osm_smir_rcv_t* const p_rcv, + IN const osm_port_t* const p_port, + IN cl_qlist_t* const p_list, + IN ib_net64_t const guid, + IN ib_net32_t const act_count, + IN uint8_t const pri_state, + IN const osm_physp_t* const p_req_physp ) +{ + osm_smir_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_smir_rcv_new_smir ); + + p_rec_item = (osm_smir_item_t*)cl_qlock_pool_get( &p_rcv->pool ); + if( p_rec_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_smir_rcv_new_smir: ERR 2801: " + "cl_qlock_pool_get failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_smir_rcv_new_smir: " + "New SMInfo: GUID 0x%016" PRIx64 "\n", + cl_ntoh64( guid ) + ); + } + + memset( &p_rec_item->rec, 0, sizeof(ib_sminfo_record_t) ); + + 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, (cl_list_item_t*)&p_rec_item->pool_item ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_smir_by_comp_mask( + IN osm_smir_rcv_t* const p_rcv, + IN const osm_remote_sm_t* const p_rem_sm, + osm_smir_search_ctxt_t* const p_ctxt ) +{ + const ib_sminfo_record_t* const p_rcvd_rec = p_ctxt->p_rcvd_rec; + const osm_physp_t* const p_req_physp = p_ctxt->p_req_physp; + ib_net64_t const comp_mask = p_ctxt->comp_mask; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_smir_by_comp_mask ); + + if ( comp_mask & IB_SMIR_COMPMASK_GUID ) + { + if ( p_rem_sm->smi.guid != p_rcvd_rec->sm_info.guid ) + goto Exit; + } + + if ( comp_mask & IB_SMIR_COMPMASK_PRIORITY ) + { + if ( ib_sminfo_get_priority( &p_rem_sm->smi ) != + ib_sminfo_get_priority( &p_rcvd_rec->sm_info ) ) + goto Exit; + } + + if ( comp_mask & IB_SMIR_COMPMASK_SMSTATE ) + { + if ( ib_sminfo_get_state( &p_rem_sm->smi ) != + ib_sminfo_get_state( &p_rcvd_rec->sm_info ) ) + goto Exit; + } + + /* Implement any other needed search cases */ + + __osm_smir_rcv_new_smir( p_rcv, 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( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_smir_by_comp_mask_cb( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + const osm_remote_sm_t* const p_rem_sm = (osm_remote_sm_t*)p_map_item; + osm_smir_search_ctxt_t* const p_ctxt = (osm_smir_search_ctxt_t *)context; + + __osm_sa_smir_by_comp_mask( p_ctxt->p_rcv, p_rem_sm, p_ctxt ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_smir_rcv_process( + IN osm_smir_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_sa_mad_t* p_rcvd_mad; + const ib_sminfo_record_t* p_rcvd_rec; + const cl_qmap_t* p_tbl; + const osm_port_t* p_port = NULL; + const ib_sm_info_t* p_smi; + cl_qlist_t rec_list; + osm_madw_t* p_resp_madw; + ib_sa_mad_t* p_resp_sa_mad; + ib_sminfo_record_t* p_resp_rec; + uint32_t num_rec, pre_trim_num_rec; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t trim_num_rec; +#endif + uint32_t i; + osm_smir_search_ctxt_t context; + osm_smir_item_t* p_rec_item; + 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( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_smir_rcv_process ); + + CL_ASSERT( p_madw ); + + p_rcvd_mad = osm_madw_get_sa_mad_ptr( p_madw ); + p_rcvd_rec = (ib_sminfo_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_SMINFO_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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_smir_rcv_process: ERR 2804: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_rcvd_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_smir_rcv_process: ERR 2803: " + "Cannot find requester physical port\n" ); + goto Exit; + } + + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + osm_dump_sm_info_record( p_rcv->p_log, p_rcvd_rec, OSM_LOG_DEBUG ); + + p_tbl = &p_rcv->p_subn->sm_guid_tbl; + 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 = p_rcvd_mad->comp_mask; + context.p_rcv = p_rcv; + context.p_req_physp = p_req_physp; + + cl_plock_acquire( p_rcv->p_lock ); + + /* + If the user specified a LID, it obviously narrows our + work load, since we don't have to search every port + */ + if( comp_mask & IB_SMIR_COMPMASK_LID ) + { + status = osm_get_port_by_base_lid( p_rcv->p_subn, p_rcvd_rec->lid, &p_port ); + if ( ( status != IB_SUCCESS ) || ( p_port == NULL ) ) + { + status = IB_NOT_FOUND; + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_smir_rcv_process: ERR 2806: " + "No port found with LID 0x%x\n", + cl_ntoh16(p_rcvd_rec->lid) ); + } + } + + if ( status == IB_SUCCESS ) + { + /* Handle our own SM first */ + local_port = osm_get_port_by_guid( p_rcv->p_subn, p_rcv->p_subn->sm_port_guid ); + if ( !local_port ) + { + cl_plock_release( p_rcv->p_lock ); + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_smir_rcv_process: ERR 2809: " + "No port found with GUID 0x%016" PRIx64 "\n", + cl_ntoh64(p_rcv->p_subn->sm_port_guid ) ); + goto Exit; + } + + if ( !p_port || local_port == p_port ) + { + if (FALSE == + osm_physp_share_pkey( p_rcv->p_log, p_req_physp, + osm_port_get_default_phys_ptr( local_port ) ) ) + { + cl_plock_release( p_rcv->p_lock ); + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_smir_rcv_process: 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 ) + { + if ( p_rcv->p_subn->sm_port_guid != p_smi->guid ) + goto Remotes; + } + if ( comp_mask & IB_SMIR_COMPMASK_PRIORITY ) + { + if ( p_rcv->p_subn->opt.sm_priority != ib_sminfo_get_priority( p_smi ) ) + goto Remotes; + } + if ( comp_mask & IB_SMIR_COMPMASK_SMSTATE ) + { + if ( p_rcv->p_subn->sm_state != ib_sminfo_get_state( p_smi ) ) + goto Remotes; + } + + /* Now, add local SMInfo to list */ + pri_state = p_rcv->p_subn->sm_state & 0x0F; + pri_state |= (p_rcv->p_subn->opt.sm_priority & 0x0F) << 4; + __osm_smir_rcv_new_smir( p_rcv, local_port, context.p_list, + p_rcv->p_subn->sm_port_guid, + cl_ntoh32( p_rcv->p_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 = &p_rcv->p_subn->sm_guid_tbl; + p_rem_sm = (osm_remote_sm_t*)cl_qmap_get( p_sm_guid_tbl, port_guid ); + if (p_rem_sm != (osm_remote_sm_t*)cl_qmap_end( p_sm_guid_tbl ) ) + __osm_sa_smir_by_comp_mask( p_rcv, p_rem_sm, &context ); + else + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_smir_rcv_process: 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( &p_rcv->p_subn->sm_guid_tbl, + __osm_sa_smir_by_comp_mask_cb, + &context ); + } + } + + cl_plock_release( p_rcv->p_lock ); + + num_rec = cl_qlist_count( &rec_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if (p_rcvd_mad->method == IB_MAD_METHOD_GET) + { + if (num_rec == 0) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + if (num_rec > 1) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_smir_rcv_process: ERR 2808: " + "Got more than one record for SubnAdmGet (%u)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS); + + /* need to set the mem free ... */ + p_rec_item = (osm_smir_item_t*)cl_qlist_remove_head( &rec_list ); + while( p_rec_item != (osm_smir_item_t*)cl_qlist_end( &rec_list ) ) + { + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_rec_item = (osm_smir_item_t*)cl_qlist_remove_head( &rec_list ); + } + + goto Exit; + } + } + + pre_trim_num_rec = num_rec; +#ifndef VENDOR_RMPP_SUPPORT + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_sminfo_record_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_smir_rcv_process: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_smir_rcv_process: " + "Returning %u records\n", num_rec ); + + if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0)) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_sminfo_record_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + + if( !p_resp_madw ) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_smir_rcv_process: ERR 2807: " + "osm_mad_pool_get failed\n" ); + + for( i = 0; i < num_rec; i++ ) + { + p_rec_item = (osm_smir_item_t*)cl_qlist_remove_head( &rec_list ); + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_NO_RESOURCES ); + + goto Exit; + } + + p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_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( p_resp_sa_mad, p_rcvd_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; + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_sminfo_record_t) ); + + p_resp_rec = (ib_sminfo_record_t*) + ib_sa_mad_get_payload_ptr( p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + for( i = 0; i < pre_trim_num_rec; i++ ) + { + p_rec_item = (osm_smir_item_t*)cl_qlist_remove_head( &rec_list ); + /* copy only if not trimmed */ + if (i < num_rec) + { + *p_resp_rec = p_rec_item->rec; + p_resp_rec->sm_info.sm_key = 0; + } + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_resp_rec++; + } + + CL_ASSERT( cl_is_qlist_empty( &rec_list ) ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + if( status != IB_SUCCESS ) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_smir_rcv_process: ERR 2802: " + "Error sending MAD (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sminfo_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sminfo_record_ctrl.c new file mode 100644 index 00000000..de6a7c74 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sminfo_record_ctrl.c @@ -0,0 +1,125 @@ +/* + * 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: + * Implementation of osm_smir_ctrl_t. + * This object represents the SMInfo request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_smir_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_smir_rcv_process( ((osm_smir_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_smir_ctrl_construct( + IN osm_smir_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_smir_ctrl_destroy( + IN osm_smir_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_smir_ctrl_init( + IN osm_smir_ctrl_t* const p_ctrl, + IN osm_smir_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_smir_ctrl_init ); + + osm_smir_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_SMINFO_RECORD, + __osm_smir_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_smir_ctrl_init: ERR 2901: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sw_info_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sw_info_record.c new file mode 100644 index 00000000..8c893ad3 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sw_info_record.c @@ -0,0 +1,535 @@ +/* + * 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: + * Implementation of osm_sir_rcv_t. + * This object represents the SwitchInfo Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_SIR_RCV_POOL_MIN_SIZE 32 +#define OSM_SIR_RCV_POOL_GROW_SIZE 32 + +typedef struct _osm_sir_item +{ + cl_pool_item_t pool_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_sir_rcv_t* p_rcv; + const osm_physp_t* p_req_physp; +} osm_sir_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void +osm_sir_rcv_construct( + IN osm_sir_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sir_rcv_destroy( + IN osm_sir_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_sir_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sir_rcv_init( + IN osm_sir_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_sir_rcv_init ); + + osm_sir_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + status = cl_qlock_pool_init( &p_rcv->pool, + OSM_SIR_RCV_POOL_MIN_SIZE, + 0, + OSM_SIR_RCV_POOL_GROW_SIZE, + sizeof(osm_sir_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_sir_rcv_new_sir( + IN osm_sir_rcv_t* const p_rcv, + IN const osm_switch_t* const p_sw, + IN cl_qlist_t* const p_list, + IN ib_net16_t const lid ) +{ + osm_sir_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sir_rcv_new_sir ); + + p_rec_item = (osm_sir_item_t*)cl_qlock_pool_get( &p_rcv->pool ); + if( p_rec_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sir_rcv_new_sir: ERR 5308: " + "cl_qlock_pool_get failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sir_rcv_new_sir: " + "New SwitchInfoRecord: lid 0x%X\n", + cl_ntoh16( lid ) + ); + } + + memset( &p_rec_item->rec, 0, sizeof(ib_switch_info_record_t) ); + + p_rec_item->rec.lid = lid; + p_rec_item->rec.switch_info = p_sw->switch_info; + + cl_qlist_insert_tail( p_list, (cl_list_item_t*)&p_rec_item->pool_item ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static osm_port_t* +__osm_sir_get_port_by_guid( + IN osm_sir_rcv_t* const p_rcv, + IN uint64_t port_guid ) +{ + osm_port_t* p_port; + + CL_PLOCK_ACQUIRE(p_rcv->p_lock); + + p_port = (osm_port_t *)cl_qmap_get(&p_rcv->p_subn->port_guid_tbl, + port_guid); + if (p_port == (osm_port_t *)cl_qmap_end(&p_rcv->p_subn->port_guid_tbl)) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sir_get_port_by_guid ERR 5309: " + "Invalid port GUID 0x%016" PRIx64 "\n", + port_guid ); + p_port = NULL; + } + + CL_PLOCK_RELEASE(p_rcv->p_lock); + return p_port; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sir_rcv_create_sir( + IN osm_sir_rcv_t* const p_rcv, + IN const osm_switch_t* const p_sw, + IN cl_qlist_t* const p_list, + IN ib_net16_t const match_lid, + IN const osm_physp_t* const p_req_physp ) +{ + osm_port_t* p_port; + const osm_physp_t* p_physp; + uint16_t match_lid_ho; + ib_net16_t min_lid_ho; + ib_net16_t max_lid_ho; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sir_rcv_create_sir ); + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sir_rcv_create_sir: " + "Looking for SwitchInfoRecord with LID: 0x%X\n", + cl_ntoh16( match_lid ) + ); + } + + /* In switches, the port guid is the node guid. */ + p_port = + __osm_sir_get_port_by_guid( p_rcv, p_sw->p_node->node_info.port_guid ); + if (! p_port) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sir_rcv_create_sir: 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 = osm_port_get_default_phys_ptr( p_port ); + if (! p_physp) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sir_rcv_create_sir: 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( p_rcv->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. + */ + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sir_rcv_create_sir: " + "Comparing LID: 0x%X <= 0x%X <= 0x%X\n", + min_lid_ho, match_lid_ho, max_lid_ho + ); + } + + if ( match_lid_ho < min_lid_ho || match_lid_ho > max_lid_ho ) + goto Exit; + + } + + __osm_sir_rcv_new_sir( p_rcv, p_sw, p_list, osm_port_get_base_lid(p_port) ); + +Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sir_rcv_by_comp_mask( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + const osm_sir_search_ctxt_t* const p_ctxt = (osm_sir_search_ctxt_t *)context; + const osm_switch_t* const p_sw = (osm_switch_t*)p_map_item; + const ib_switch_info_record_t* const p_rcvd_rec = p_ctxt->p_rcvd_rec; + const osm_physp_t* const p_req_physp = p_ctxt->p_req_physp; + osm_sir_rcv_t* const p_rcv = p_ctxt->p_rcv; + ib_net64_t const comp_mask = p_ctxt->comp_mask; + ib_net16_t match_lid = 0; + + OSM_LOG_ENTER( p_ctxt->p_rcv->p_log, __osm_sir_rcv_by_comp_mask ); + + osm_dump_switch_info( + p_ctxt->p_rcv->p_log, + &p_sw->switch_info, + OSM_LOG_VERBOSE ); + + if( comp_mask & IB_SWIR_COMPMASK_LID ) + { + match_lid = p_rcvd_rec->lid; + if (!match_lid) + goto Exit; + } + + __osm_sir_rcv_create_sir( p_rcv, p_sw, p_ctxt->p_list, + match_lid, p_req_physp ); + +Exit: + OSM_LOG_EXIT( p_ctxt->p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sir_rcv_process( + IN osm_sir_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_sa_mad_t* p_rcvd_mad; + const ib_switch_info_record_t* p_rcvd_rec; + ib_switch_info_record_t* p_resp_rec; + cl_qlist_t rec_list; + osm_madw_t* p_resp_madw; + ib_sa_mad_t* p_resp_sa_mad; + uint32_t num_rec, pre_trim_num_rec; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t trim_num_rec; +#endif + uint32_t i; + osm_sir_search_ctxt_t context; + osm_sir_item_t* p_rec_item; + ib_api_status_t status; + osm_physp_t* p_req_physp; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_sir_rcv_process ); + + CL_ASSERT( p_madw ); + + p_rcvd_mad = osm_madw_get_sa_mad_ptr( p_madw ); + p_rcvd_rec = (ib_switch_info_record_t*)ib_sa_mad_get_payload_ptr( p_rcvd_mad ); + + CL_ASSERT( p_rcvd_mad->attr_id == IB_MAD_ATTR_SWITCH_INFO_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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_sir_rcv_process: ERR 5305: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_rcvd_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_sir_rcv_process: ERR 5304: " + "Cannot find requester physical port\n" ); + goto Exit; + } + + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + osm_dump_switch_info_record( p_rcv->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.p_rcv = p_rcv; + context.p_req_physp = p_req_physp; + + cl_plock_acquire( p_rcv->p_lock ); + + /* Go over all switches */ + cl_qmap_apply_func( &p_rcv->p_subn->sw_guid_tbl, + __osm_sir_rcv_by_comp_mask, + &context ); + + cl_plock_release( p_rcv->p_lock ); + + num_rec = cl_qlist_count( &rec_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if ( (p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec > 1) ) { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_sir_rcv_process: ERR 5303: " + "Got more than one record for SubnAdmGet (%u)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS ); + + /* need to set the mem free ... */ + p_rec_item = (osm_sir_item_t*)cl_qlist_remove_head( &rec_list ); + while( p_rec_item != (osm_sir_item_t*)cl_qlist_end( &rec_list ) ) + { + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_rec_item = (osm_sir_item_t*)cl_qlist_remove_head( &rec_list ); + } + + goto Exit; + } + + pre_trim_num_rec = num_rec; +#ifndef VENDOR_RMPP_SUPPORT + /* we limit the number of records to a single packet */ + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_switch_info_record_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_sir_rcv_process: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_sir_rcv_process: " + "Returning %u records\n", num_rec ); + + if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0)) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_switch_info_record_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + + if( !p_resp_madw ) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_sir_rcv_process: ERR 5306: " + "osm_mad_pool_get failed\n" ); + + for( i = 0; i < num_rec; i++ ) + { + p_rec_item = (osm_sir_item_t*)cl_qlist_remove_head( &rec_list ); + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES ); + goto Exit; + } + + p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_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( p_resp_sa_mad, p_rcvd_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; + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_switch_info_record_t) ); + + p_resp_rec = (ib_switch_info_record_t*)ib_sa_mad_get_payload_ptr( p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + for( i = 0; i < pre_trim_num_rec; i++ ) + { + p_rec_item = (osm_sir_item_t*)cl_qlist_remove_head( &rec_list ); + /* copy only if not trimmed */ + if (i < num_rec) + { + *p_resp_rec = p_rec_item->rec; + } + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_resp_rec++; + } + + CL_ASSERT( cl_is_qlist_empty( &rec_list ) ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + if (status != IB_SUCCESS) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_sir_rcv_process: ERR 5307: " + "osm_vendor_send status = %s\n", + ib_get_err_str(status)); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sw_info_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sw_info_record_ctrl.c new file mode 100644 index 00000000..726cd40a --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_sw_info_record_ctrl.c @@ -0,0 +1,123 @@ +/* + * 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: + * Implementation of osm_sir_rcv_ctrl_t. + * This object represents the SwitchInfo Record controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_sir_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_sir_rcv_process( ((osm_sir_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sir_rcv_ctrl_construct( + IN osm_sir_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_sir_rcv_ctrl_destroy( + IN osm_sir_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sir_rcv_ctrl_init( + IN osm_sir_rcv_ctrl_t* const p_ctrl, + IN osm_sir_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_sir_rcv_ctrl_init ); + + osm_sir_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_SWITCH_INFO_RECORD, + __osm_sir_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_sir_rcv_ctrl_init: ERR 5301: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_vlarb_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_vlarb_record.c new file mode 100644 index 00000000..1bad3db6 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_vlarb_record.c @@ -0,0 +1,577 @@ +/* + * 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: + * Implementation of osm_vlarb_rec_rcv_t. + * This object represents the VLArbitrationRecord Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_VLARB_REC_RCV_POOL_MIN_SIZE 32 +#define OSM_VLARB_REC_RCV_POOL_GROW_SIZE 32 + +typedef struct _osm_vl_arb_item +{ + cl_pool_item_t pool_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_vlarb_rec_rcv_t* p_rcv; + const osm_physp_t* p_req_physp; +} osm_vl_arb_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void +osm_vlarb_rec_rcv_construct( + IN osm_vlarb_rec_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_vlarb_rec_rcv_destroy( + IN osm_vlarb_rec_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_vlarb_rec_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vlarb_rec_rcv_init( + IN osm_vlarb_rec_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN const osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_vlarb_rec_rcv_init ); + + osm_vlarb_rec_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + /* used for matching records collection */ + status = cl_qlock_pool_init( &p_rcv->pool, + OSM_VLARB_REC_RCV_POOL_MIN_SIZE, + 0, + OSM_VLARB_REC_RCV_POOL_GROW_SIZE, + sizeof(osm_vl_arb_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sa_vl_arb_create( + IN osm_vlarb_rec_rcv_t* const p_rcv, + IN osm_physp_t* const p_physp, + IN osm_vl_arb_search_ctxt_t* const p_ctxt, + IN uint8_t block ) +{ + osm_vl_arb_item_t* p_rec_item; + uint16_t lid; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_vl_arb_create ); + + p_rec_item = (osm_vl_arb_item_t*)cl_qlock_pool_get( &p_rcv->pool ); + if( p_rec_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sa_vl_arb_create: ERR 2A02: " + "cl_qlock_pool_get failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + if (p_physp->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) + { + lid = osm_physp_get_port_info_ptr( p_physp )->base_lid; + } + else + { + lid = osm_node_get_base_lid( p_physp->p_node, 0 ); + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_vl_arb_create: " + "New VLArbitration for: port 0x%016" PRIx64 + ", lid 0x%X, port# 0x%X 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->rec, 0, sizeof( p_rec_item->rec ) ); + + 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, (cl_list_item_t*)&p_rec_item->pool_item ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sa_vl_arb_check_physp( + IN osm_vlarb_rec_rcv_t* const p_rcv, + IN osm_physp_t* const p_physp, + osm_vl_arb_search_ctxt_t* const p_ctxt ) +{ + ib_net64_t comp_mask = p_ctxt->comp_mask; + uint8_t block; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_vl_arb_check_physp ); + + /* we got here with the phys port - all that's left is to get the right block */ + for (block = 1; block <= 4; block++) { + if (!(comp_mask & IB_VLA_COMPMASK_BLOCK) || block == p_ctxt->block_num) + { + __osm_sa_vl_arb_create( p_rcv, p_physp, p_ctxt, block ); + } + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sa_vl_arb_by_comp_mask( + IN osm_vlarb_rec_rcv_t* const p_rcv, + IN const osm_port_t* const p_port, + osm_vl_arb_search_ctxt_t* const p_ctxt ) +{ + const ib_vl_arb_table_record_t* p_rcvd_rec; + ib_net64_t comp_mask; + osm_physp_t * p_physp; + uint8_t port_num; + uint8_t num_ports; + const osm_physp_t* p_req_physp; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_vl_arb_by_comp_mask ); + + 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->default_port_num; + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_vl_arb_by_comp_mask: " + "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_port_get_num_physp( p_port )) + { + p_physp = osm_port_get_phys_ptr( p_port, 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_is_valid( p_physp ) && + osm_physp_share_pkey(p_rcv->p_log, p_req_physp, p_physp) ) + __osm_sa_vl_arb_check_physp( p_rcv, p_physp, p_ctxt ); + } + else + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sa_vl_arb_by_comp_mask: ERR 2A03: " + "Given Physical Port Number: 0x%X is out of range should be < 0x%X\n", + port_num, osm_port_get_num_physp( p_port ) ); + goto Exit; + } + } + else + { + num_ports = osm_port_get_num_physp( p_port ); + for( port_num = 0; port_num < num_ports; port_num++ ) + { + p_physp = osm_port_get_phys_ptr( p_port, port_num ); + if( p_physp == NULL ) + continue; + + if( !osm_physp_is_valid( p_physp ) ) + continue; + + /* if the requester and the p_physp don't share a pkey - + continue */ + if (!osm_physp_share_pkey(p_rcv->p_log, p_req_physp, p_physp)) + continue; + + __osm_sa_vl_arb_check_physp( p_rcv, p_physp, p_ctxt ); + } + } + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sa_vl_arb_by_comp_mask_cb( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + const osm_port_t* const p_port = (osm_port_t*)p_map_item; + osm_vl_arb_search_ctxt_t* const p_ctxt = (osm_vl_arb_search_ctxt_t *)context; + + __osm_sa_vl_arb_by_comp_mask( p_ctxt->p_rcv, p_port, p_ctxt ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_vlarb_rec_rcv_process( + IN osm_vlarb_rec_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_sa_mad_t* p_rcvd_mad; + const ib_vl_arb_table_record_t* p_rcvd_rec; + const cl_ptr_vector_t* p_tbl; + const osm_port_t* p_port = NULL; + const ib_vl_arb_table_t* p_vl_arb; + cl_qlist_t rec_list; + osm_madw_t* p_resp_madw; + ib_sa_mad_t* p_resp_sa_mad; + ib_vl_arb_table_record_t* p_resp_rec; + uint32_t num_rec, pre_trim_num_rec; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t trim_num_rec; +#endif + uint32_t i; + osm_vl_arb_search_ctxt_t context; + osm_vl_arb_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + ib_net64_t comp_mask; + osm_physp_t* p_req_physp; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_vlarb_rec_rcv_process ); + + CL_ASSERT( p_madw ); + + p_rcvd_mad = osm_madw_get_sa_mad_ptr( p_madw ); + p_rcvd_rec = (ib_vl_arb_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_VLARB_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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_vlarb_rec_rcv_process: ERR 2A05: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_rcvd_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_vlarb_rec_rcv_process: ERR 2A04: " + "Cannot find requester physical port\n" ); + goto Exit; + } + + p_vl_arb = (ib_vl_arb_table_t*)ib_sa_mad_get_payload_ptr( p_rcvd_mad ); + + cl_qlist_init( &rec_list ); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = p_rcvd_mad->comp_mask; + context.p_rcv = p_rcv; + context.block_num = p_rcvd_rec->block_num; + context.p_req_physp = p_req_physp; + + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_vlarb_rec_rcv_process: " + "Got Query Lid:0x%04X(%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( p_rcv->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_tbl = &p_rcv->p_subn->port_lid_tbl; + + CL_ASSERT( cl_ptr_vector_get_size(p_tbl) < 0x10000 ); + + status = osm_get_port_by_base_lid( p_rcv->p_subn, p_rcvd_rec->lid, &p_port ); + if ( ( status != IB_SUCCESS ) || ( p_port == NULL ) ) + { + status = IB_NOT_FOUND; + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_vlarb_rec_rcv_process: ERR 2A09: " + "No port found with LID 0x%x\n", + cl_ntoh16(p_rcvd_rec->lid) ); + } + } + + if ( status == IB_SUCCESS ) + { + /* if we got a unique port - no need for a port search */ + if( p_port ) + /* this does the loop on all the port phys ports */ + __osm_sa_vl_arb_by_comp_mask( p_rcv, p_port, &context ); + else + { + cl_qmap_apply_func( &p_rcv->p_subn->port_guid_tbl, + __osm_sa_vl_arb_by_comp_mask_cb, + &context ); + } + } + + cl_plock_release( p_rcv->p_lock ); + + num_rec = cl_qlist_count( &rec_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if (p_rcvd_mad->method == IB_MAD_METHOD_GET) + { + if (num_rec == 0) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + if (num_rec > 1) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_vlarb_rec_rcv_process: ERR 2A08: " + "Got more than one record for SubnAdmGet (%u)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS ); + + /* need to set the mem free ... */ + p_rec_item = (osm_vl_arb_item_t*)cl_qlist_remove_head( &rec_list ); + while( p_rec_item != (osm_vl_arb_item_t*)cl_qlist_end( &rec_list ) ) + { + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_rec_item = (osm_vl_arb_item_t*)cl_qlist_remove_head( &rec_list ); + } + + goto Exit; + } + } + + pre_trim_num_rec = num_rec; +#ifndef VENDOR_RMPP_SUPPORT + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_vl_arb_table_record_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_vlarb_rec_rcv_process: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_vlarb_rec_rcv_process: " + "Returning %u records\n", num_rec ); + + if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0)) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_vl_arb_table_record_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + + if( !p_resp_madw ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_vlarb_rec_rcv_process: ERR 2A06: " + "osm_mad_pool_get failed\n" ); + + for( i = 0; i < num_rec; i++ ) + { + p_rec_item = (osm_vl_arb_item_t*)cl_qlist_remove_head( &rec_list ); + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES ); + goto Exit; + } + + p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_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( p_resp_sa_mad, p_rcvd_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; + + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_vl_arb_table_record_t) ); + + p_resp_rec = (ib_vl_arb_table_record_t*) + ib_sa_mad_get_payload_ptr( p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + for( i = 0; i < pre_trim_num_rec; i++ ) + { + p_rec_item = (osm_vl_arb_item_t*)cl_qlist_remove_head( &rec_list ); + /* copy only if not trimmed */ + if (i < num_rec) + { + *p_resp_rec = p_rec_item->rec; + } + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_resp_rec++; + } + + CL_ASSERT( cl_is_qlist_empty( &rec_list ) ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + if(status != IB_SUCCESS) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_vlarb_rec_rcv_process: ERR 2A07: " + "osm_vendor_send status = %s\n", + ib_get_err_str(status) ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_vlarb_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_vlarb_record_ctrl.c new file mode 100644 index 00000000..94a607a8 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_vlarb_record_ctrl.c @@ -0,0 +1,126 @@ +/* + * 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: + * Implementation of osm_vlarb_rec_rcv_ctrl_t. + * This object represents the VL Arbitration Record SA request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_vlarb_rec_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_vlarb_rec_rcv_process( ((osm_vlarb_rec_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_vlarb_rec_rcv_ctrl_construct( + IN osm_vlarb_rec_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_vlarb_rec_rcv_ctrl_destroy( + IN osm_vlarb_rec_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vlarb_rec_rcv_ctrl_init( + IN osm_vlarb_rec_rcv_ctrl_t* const p_ctrl, + IN osm_vlarb_rec_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_vlarb_rec_rcv_ctrl_init ); + + osm_vlarb_rec_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_VL_ARB_RECORD, + __osm_vlarb_rec_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_vlarb_rec_rcv_ctrl_init: ERR 2B01: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_service.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_service.c new file mode 100644 index 00000000..2f236b3c --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_service.c @@ -0,0 +1,202 @@ +/* + * 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: + * Implementation of service record functions. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_svcr_construct( + IN osm_svcr_t* const p_svcr ) +{ + memset( p_svcr, 0, sizeof(*p_svcr) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_svcr_destroy( + IN osm_svcr_t* const p_svcr ) +{ + free( p_svcr); +} + +/********************************************************************** + **********************************************************************/ +void +osm_svcr_init( + IN osm_svcr_t* const p_svcr, + IN const ib_service_record_t *p_svc_rec ) +{ + CL_ASSERT( p_svcr ); + + p_svcr->modified_time = cl_get_time_stamp_sec(); + + /* We track the time left for this service in + an external field to avoid extra cl_ntoh/hton + required for working with the MAD field */ + p_svcr->lease_period = cl_ntoh32(p_svc_rec->service_lease); + p_svcr->service_record = *p_svc_rec; +} + +/********************************************************************** + **********************************************************************/ +osm_svcr_t* +osm_svcr_new( + IN const ib_service_record_t *p_svc_rec ) +{ + osm_svcr_t* p_svcr; + + CL_ASSERT(p_svc_rec); + + p_svcr = (osm_svcr_t*)malloc( sizeof(*p_svcr) ); + if( p_svcr ) + { + osm_svcr_construct( p_svcr ); + osm_svcr_init( p_svcr, p_svc_rec ); + } + + return( p_svcr ); +} + +/********************************************************************** + **********************************************************************/ +static +cl_status_t +__match_rid_of_svc_rec( + + IN const cl_list_item_t* const p_list_item, + IN void* context ) +{ + ib_service_record_t* p_svc_rec = (ib_service_record_t *)context; + osm_svcr_t* p_svcr = (osm_svcr_t*)p_list_item; + int32_t count; + + count = memcmp( + &p_svcr->service_record, + p_svc_rec, + sizeof(p_svc_rec->service_id) + + sizeof(p_svc_rec->service_gid) + + sizeof(p_svc_rec->service_pkey) ); + + if(count == 0) + return CL_SUCCESS; + else + return CL_NOT_FOUND; + +} + +/********************************************************************** + **********************************************************************/ +osm_svcr_t* +osm_svcr_get_by_rid( + IN osm_subn_t const *p_subn, + IN osm_log_t *p_log, + IN ib_service_record_t* const p_svc_rec ) +{ + cl_list_item_t* p_list_item; + + OSM_LOG_ENTER( p_log, osm_svcr_get_by_rid ); + + 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_svcr_insert_to_db ); + + osm_log( p_log, OSM_LOG_DEBUG, + "osm_svcr_insert_to_db: " + "Inserting new Service Record into Database\n"); + + cl_qlist_insert_head(&p_subn->sa_sr_list, + &p_svcr->list_item); + + OSM_LOG_EXIT( p_log ); +} + +void +osm_svcr_remove_from_db( + IN osm_subn_t *p_subn, + IN osm_log_t *p_log, + IN osm_svcr_t *p_svcr) +{ + OSM_LOG_ENTER( p_log, osm_svcr_remove_from_db ); + + osm_log( p_log, OSM_LOG_DEBUG, + "osm_svcr_remove_from_db: " + "Removing Service Record Name:%s ID:0x%016" PRIx64" from Database\n", + p_svcr->service_record.service_name, p_svcr->service_record.service_id + ); + + cl_qlist_remove_item(&p_subn->sa_sr_list, + &p_svcr->list_item); + + OSM_LOG_EXIT( p_log ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_slvl_map_rcv.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_slvl_map_rcv.c new file mode 100644 index 00000000..7b5623fb --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_slvl_map_rcv.c @@ -0,0 +1,232 @@ +/* + * 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: + * Implementation of osm_slvl_rcv_t. + * This object represents the SLtoVL Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#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_slvl_rcv_construct( + IN osm_slvl_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_slvl_rcv_destroy( + IN osm_slvl_rcv_t* const p_rcv ) +{ + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_slvl_rcv_destroy ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_slvl_rcv_init( + IN osm_slvl_rcv_t* const p_rcv, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_slvl_rcv_init ); + + osm_slvl_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_req = p_req; + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +/* + * WE MIGHT ONLY RECEIVE A GET or SET responses + */ +void +osm_slvl_rcv_process( + IN const osm_slvl_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ) +{ + cl_qmap_t *p_guid_tbl; + ib_slvl_table_t *p_slvl_tbl; + ib_smp_t *p_smp; + osm_port_t *p_port; + osm_physp_t *p_physp; + osm_node_t *p_node; + osm_slvl_context_t *p_context; + ib_net64_t port_guid; + ib_net64_t node_guid; + uint8_t out_port_num, in_port_num; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_slvl_rcv_process ); + + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_context = osm_madw_get_slvl_context_ptr( p_madw ); + p_slvl_tbl = (ib_slvl_table_t*)ib_smp_get_payload_ptr( p_smp ); + + port_guid = p_context->port_guid; + node_guid = p_context->node_guid; + + CL_ASSERT( p_smp->attr_id == IB_MAD_ATTR_SLVL_TABLE ); + + p_guid_tbl = &p_rcv->p_subn->port_guid_tbl; + cl_plock_excl_acquire( p_rcv->p_lock ); + p_port = (osm_port_t*)cl_qmap_get( p_guid_tbl, port_guid ); + + if( p_port == (osm_port_t*)cl_qmap_end( p_guid_tbl) ) + { + cl_plock_release( p_rcv->p_lock ); + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_slvl_rcv_process: 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 = osm_port_get_parent_node( p_port ); + CL_ASSERT( p_node ); + + /* in case of a non switch node the attr modifier should be ignored */ + if (osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH) + { + out_port_num = (uint8_t)cl_ntoh32( p_smp->attr_mod & 0xFF000000); + in_port_num = (uint8_t)cl_ntoh32( (p_smp->attr_mod & 0x00FF0000) << 8); + p_physp = osm_node_get_physp_ptr( p_node, out_port_num ); + } + else + { + p_physp = osm_port_get_default_phys_ptr(p_port); + out_port_num = p_port->default_port_num; + in_port_num = 0; + } + + CL_ASSERT( p_physp ); + + /* + We do not mind if this is a result of a set or get - all we want is to update + the subnet. + */ + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_slvl_rcv_process: " + "Got SLtoVL get response in_port_num %u out_port_num %u with GUID 0x%" PRIx64 + " for parent node GUID 0x%" PRIx64 + ", TID 0x%" PRIx64 "\n", + in_port_num, out_port_num, + cl_ntoh64( port_guid ), + cl_ntoh64( node_guid ), + cl_ntoh64( p_smp->trans_id ) ); + } + + /* + Determine if we encountered a new Physical Port. + If so, Ignore it. + */ + if( !osm_physp_is_valid( p_physp ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_slvl_rcv_process: " + "Got invalid port number 0x%X\n", + out_port_num ); + goto Exit; + } + + osm_dump_slvl_map_table( p_rcv->p_log, + port_guid, in_port_num, + out_port_num, p_slvl_tbl, + OSM_LOG_DEBUG ); + + osm_physp_set_slvl_tbl( p_physp, p_slvl_tbl, in_port_num); + + Exit: + cl_plock_release( p_rcv->p_lock ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_slvl_map_rcv_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_slvl_map_rcv_ctrl.c new file mode 100644 index 00000000..cb96cbe0 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_slvl_map_rcv_ctrl.c @@ -0,0 +1,127 @@ +/* + * 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: + * Implementation of osm_slvl_rcv_ctrl_t. + * This object represents the SLtoVL request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_slvl_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_slvl_rcv_process( ((osm_slvl_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_slvl_rcv_ctrl_construct( + IN osm_slvl_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_slvl_rcv_ctrl_destroy( + IN osm_slvl_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_slvl_rcv_ctrl_init( + IN osm_slvl_rcv_ctrl_t* const p_ctrl, + IN osm_slvl_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_slvl_rcv_ctrl_init ); + + osm_slvl_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_SLVL, + __osm_slvl_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_slvl_rcv_ctrl_init: ERR 2D01: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sm.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sm.c new file mode 100644 index 00000000..ea8352eb --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sm.c @@ -0,0 +1,824 @@ +/* + * 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: + * Implementation of osm_sm_t. + * This object represents the SM Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.9 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_SM_INITIAL_TID_VALUE 0x1233 + +/********************************************************************** + **********************************************************************/ +void +__osm_sm_sweeper( + IN void *p_ptr ) +{ + ib_api_status_t status; + osm_sm_t *const p_sm = ( osm_sm_t * ) p_ptr; + + OSM_LOG_ENTER( p_sm->p_log, __osm_sm_sweeper ); + + if( p_sm->thread_state == OSM_THREAD_STATE_INIT ) + { + p_sm->thread_state = OSM_THREAD_STATE_RUN; + } + + /* If the sweep interval was updated before - then run only if + * it is not zero. */ + while( p_sm->thread_state == OSM_THREAD_STATE_RUN && + p_sm->p_subn->opt.sweep_interval != 0 ) + { + /* do the sweep only if we are in MASTER state */ + if( p_sm->p_subn->sm_state == IB_SMINFO_STATE_MASTER || + p_sm->p_subn->sm_state == IB_SMINFO_STATE_DISCOVERING ) + osm_state_mgr_process( &p_sm->state_mgr, OSM_SIGNAL_SWEEP ); + + /* + * 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, + p_sm->p_subn->opt.sweep_interval * 1000000, + TRUE ); + + if( status == CL_SUCCESS ) + { + if( osm_log_is_active( p_sm->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_sm->p_log, OSM_LOG_DEBUG, + "__osm_sm_sweeper: " "Off schedule sweep signalled\n" ); + } + } + else + { + if( status != CL_TIMEOUT ) + { + osm_log( p_sm->p_log, OSM_LOG_ERROR, + "__osm_sm_sweeper: ERR 2E01: " + "Event wait failed (%s)\n", CL_STATUS_MSG( status ) ); + } + } + } + + OSM_LOG_EXIT( p_sm->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sm_construct( + IN osm_sm_t * const p_sm ) +{ + memset( p_sm, 0, sizeof( *p_sm ) ); + p_sm->thread_state = OSM_THREAD_STATE_NONE; + p_sm->sm_trans_id = OSM_SM_INITIAL_TID_VALUE; + cl_event_construct( &p_sm->signal ); + cl_event_construct( &p_sm->subnet_up_event ); + cl_thread_construct( &p_sm->sweeper ); + osm_req_construct( &p_sm->req ); + osm_req_ctrl_construct( &p_sm->req_ctrl ); + osm_resp_construct( &p_sm->resp ); + osm_ni_rcv_construct( &p_sm->ni_rcv ); + osm_ni_rcv_ctrl_construct( &p_sm->ni_rcv_ctrl ); + osm_pi_rcv_construct( &p_sm->pi_rcv ); + osm_pi_rcv_ctrl_construct( &p_sm->pi_rcv_ctrl ); + osm_nd_rcv_construct( &p_sm->nd_rcv ); + osm_nd_rcv_ctrl_construct( &p_sm->nd_rcv_ctrl ); + osm_sm_mad_ctrl_construct( &p_sm->mad_ctrl ); + osm_si_rcv_construct( &p_sm->si_rcv ); + osm_si_rcv_ctrl_construct( &p_sm->si_rcv_ctrl ); + osm_lid_mgr_construct( &p_sm->lid_mgr ); + osm_ucast_mgr_construct( &p_sm->ucast_mgr ); + osm_link_mgr_construct( &p_sm->link_mgr ); + osm_state_mgr_construct( &p_sm->state_mgr ); + osm_state_mgr_ctrl_construct( &p_sm->state_mgr_ctrl ); + osm_drop_mgr_construct( &p_sm->drop_mgr ); + osm_lft_rcv_construct( &p_sm->lft_rcv ); + osm_lft_rcv_ctrl_construct( &p_sm->lft_rcv_ctrl ); + osm_mft_rcv_construct( &p_sm->mft_rcv ); + osm_mft_rcv_ctrl_construct( &p_sm->mft_rcv_ctrl ); + osm_sweep_fail_ctrl_construct( &p_sm->sweep_fail_ctrl ); + osm_sminfo_rcv_construct( &p_sm->sm_info_rcv ); + osm_sminfo_rcv_ctrl_construct( &p_sm->sm_info_rcv_ctrl ); + osm_trap_rcv_construct( &p_sm->trap_rcv ); + osm_trap_rcv_ctrl_construct( &p_sm->trap_rcv_ctrl ); + osm_sm_state_mgr_construct( &p_sm->sm_state_mgr ); + osm_slvl_rcv_construct( &p_sm->slvl_rcv ); + osm_slvl_rcv_ctrl_construct( &p_sm->slvl_rcv_ctrl ); + osm_vla_rcv_construct( &p_sm->vla_rcv ); + osm_vla_rcv_ctrl_construct( &p_sm->vla_rcv_ctrl ); + osm_pkey_rcv_construct( &p_sm->pkey_rcv ); + osm_pkey_rcv_ctrl_construct( &p_sm->pkey_rcv_ctrl ); + osm_mcast_mgr_construct( &p_sm->mcast_mgr ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sm_shutdown( + IN osm_sm_t * const p_sm ) +{ + boolean_t signal_event = FALSE; + + OSM_LOG_ENTER( p_sm->p_log, osm_sm_shutdown ); + + /* + * 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 ); + + 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 ); + osm_trap_rcv_ctrl_destroy( &p_sm->trap_rcv_ctrl ); + osm_sminfo_rcv_ctrl_destroy( &p_sm->sm_info_rcv_ctrl ); + osm_req_ctrl_destroy( &p_sm->req_ctrl ); + osm_ni_rcv_ctrl_destroy( &p_sm->ni_rcv_ctrl ); + osm_pi_rcv_ctrl_destroy( &p_sm->pi_rcv_ctrl ); + osm_si_rcv_ctrl_destroy( &p_sm->si_rcv_ctrl ); + osm_nd_rcv_ctrl_destroy( &p_sm->nd_rcv_ctrl ); + osm_lft_rcv_ctrl_destroy( &p_sm->lft_rcv_ctrl ); + osm_mft_rcv_ctrl_destroy( &p_sm->mft_rcv_ctrl ); + osm_slvl_rcv_ctrl_destroy( &p_sm->slvl_rcv_ctrl ); + osm_vla_rcv_ctrl_destroy( &p_sm->vla_rcv_ctrl ); + osm_pkey_rcv_ctrl_destroy( &p_sm->pkey_rcv_ctrl ); + osm_sweep_fail_ctrl_destroy( &p_sm->sweep_fail_ctrl ); + osm_state_mgr_ctrl_destroy( &p_sm->state_mgr_ctrl ); + + OSM_LOG_EXIT( p_sm->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sm_destroy( + IN osm_sm_t * const p_sm ) +{ + OSM_LOG_ENTER( p_sm->p_log, osm_sm_destroy ); + osm_trap_rcv_destroy( &p_sm->trap_rcv ); + osm_sminfo_rcv_destroy( &p_sm->sm_info_rcv ); + osm_req_destroy( &p_sm->req ); + osm_resp_destroy( &p_sm->resp ); + osm_ni_rcv_destroy( &p_sm->ni_rcv ); + osm_pi_rcv_destroy( &p_sm->pi_rcv ); + osm_si_rcv_destroy( &p_sm->si_rcv ); + osm_nd_rcv_destroy( &p_sm->nd_rcv ); + osm_lid_mgr_destroy( &p_sm->lid_mgr ); + osm_ucast_mgr_destroy( &p_sm->ucast_mgr ); + osm_link_mgr_destroy( &p_sm->link_mgr ); + osm_drop_mgr_destroy( &p_sm->drop_mgr ); + osm_lft_rcv_destroy( &p_sm->lft_rcv ); + osm_mft_rcv_destroy( &p_sm->mft_rcv ); + osm_slvl_rcv_destroy( &p_sm->slvl_rcv ); + osm_vla_rcv_destroy( &p_sm->vla_rcv ); + osm_pkey_rcv_destroy( &p_sm->pkey_rcv ); + osm_state_mgr_destroy( &p_sm->state_mgr ); + osm_sm_state_mgr_destroy( &p_sm->sm_state_mgr ); + osm_mcast_mgr_destroy( &p_sm->mcast_mgr ); + cl_event_destroy( &p_sm->signal ); + cl_event_destroy( &p_sm->subnet_up_event ); + + osm_log( p_sm->p_log, OSM_LOG_SYS, "Exiting SM\n" ); /* Format Waived */ + OSM_LOG_EXIT( p_sm->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_init( + IN osm_sm_t * const p_sm, + IN osm_subn_t * const p_subn, + IN osm_db_t * const p_db, + IN osm_vendor_t * const p_vendor, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vl15_t * const p_vl15, + IN osm_log_t * const p_log, + IN osm_stats_t * const p_stats, + IN cl_dispatcher_t * const p_disp, + IN cl_plock_t * const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_sm_init ); + + 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_event_init( &p_sm->signal, FALSE ); + if( status != CL_SUCCESS ) + goto Exit; + + status = cl_event_init( &p_sm->subnet_up_event, FALSE ); + if( status != CL_SUCCESS ) + goto Exit; + + status = osm_sm_mad_ctrl_init( &p_sm->mad_ctrl, + p_sm->p_subn, + p_sm->p_mad_pool, + p_sm->p_vl15, + p_sm->p_vendor, + p_log, p_stats, p_lock, p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_req_init( &p_sm->req, + p_mad_pool, + p_vl15, p_subn, p_log, &p_sm->sm_trans_id ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_req_ctrl_init( &p_sm->req_ctrl, &p_sm->req, p_log, p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_resp_init( &p_sm->resp, p_mad_pool, p_vl15, p_subn, p_log ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_ni_rcv_init( &p_sm->ni_rcv, + &p_sm->req, + p_subn, p_log, &p_sm->state_mgr, p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_ni_rcv_ctrl_init( &p_sm->ni_rcv_ctrl, + &p_sm->ni_rcv, p_log, p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_pi_rcv_init( &p_sm->pi_rcv, + &p_sm->req, + p_subn, p_log, &p_sm->state_mgr, p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_pi_rcv_ctrl_init( &p_sm->pi_rcv_ctrl, + &p_sm->pi_rcv, p_log, p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_si_rcv_init( &p_sm->si_rcv, + p_sm->p_subn, + p_sm->p_log, + &p_sm->req, &p_sm->state_mgr, p_sm->p_lock ); + + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_si_rcv_ctrl_init( &p_sm->si_rcv_ctrl, + &p_sm->si_rcv, p_sm->p_log, p_sm->p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_nd_rcv_init( &p_sm->nd_rcv, p_subn, p_log, p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_nd_rcv_ctrl_init( &p_sm->nd_rcv_ctrl, + &p_sm->nd_rcv, p_log, p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_lid_mgr_init( &p_sm->lid_mgr, + &p_sm->req, + p_sm->p_subn, + p_sm->p_db, p_sm->p_log, p_sm->p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_ucast_mgr_init( &p_sm->ucast_mgr, + &p_sm->req, + p_sm->p_subn, + p_sm->p_log, p_sm->p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_link_mgr_init( &p_sm->link_mgr, + &p_sm->req, + p_sm->p_subn, p_sm->p_log, p_sm->p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_state_mgr_init( &p_sm->state_mgr, + p_sm->p_subn, + &p_sm->lid_mgr, + &p_sm->ucast_mgr, + &p_sm->mcast_mgr, + &p_sm->link_mgr, + &p_sm->drop_mgr, + &p_sm->req, + p_stats, + &p_sm->sm_state_mgr, + &p_sm->mad_ctrl, + p_sm->p_lock, + &p_sm->subnet_up_event, + p_sm->p_log ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_state_mgr_ctrl_init( &p_sm->state_mgr_ctrl, + &p_sm->state_mgr, + p_sm->p_log, p_sm->p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_drop_mgr_init( &p_sm->drop_mgr, + p_sm->p_subn, + p_sm->p_log, &p_sm->req, p_sm->p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_lft_rcv_init( &p_sm->lft_rcv, p_subn, p_log, p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_lft_rcv_ctrl_init( &p_sm->lft_rcv_ctrl, + &p_sm->lft_rcv, p_log, p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_mft_rcv_init( &p_sm->mft_rcv, p_subn, p_log, p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_mft_rcv_ctrl_init( &p_sm->mft_rcv_ctrl, + &p_sm->mft_rcv, p_log, p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_sweep_fail_ctrl_init( &p_sm->sweep_fail_ctrl, + p_log, &p_sm->state_mgr, p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_sminfo_rcv_init( &p_sm->sm_info_rcv, + p_subn, + p_stats, + &p_sm->resp, + p_log, + &p_sm->state_mgr, + &p_sm->sm_state_mgr, p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_sminfo_rcv_ctrl_init( &p_sm->sm_info_rcv_ctrl, + &p_sm->sm_info_rcv, + p_sm->p_log, p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_trap_rcv_init( &p_sm->trap_rcv, + p_subn, + p_stats, + &p_sm->resp, p_log, &p_sm->state_mgr, p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_trap_rcv_ctrl_init( &p_sm->trap_rcv_ctrl, + &p_sm->trap_rcv, p_sm->p_log, p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_sm_state_mgr_init( &p_sm->sm_state_mgr, + &p_sm->state_mgr, + p_sm->p_subn, &p_sm->req, p_sm->p_log ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_mcast_mgr_init( &p_sm->mcast_mgr, + &p_sm->req, p_subn, p_log, p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_slvl_rcv_init( &p_sm->slvl_rcv, + &p_sm->req, p_subn, p_log, p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_slvl_rcv_ctrl_init( &p_sm->slvl_rcv_ctrl, + &p_sm->slvl_rcv, p_sm->p_log, p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_vla_rcv_init( &p_sm->vla_rcv, + &p_sm->req, p_subn, p_log, p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_vla_rcv_ctrl_init( &p_sm->vla_rcv_ctrl, + &p_sm->vla_rcv, p_sm->p_log, p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_pkey_rcv_init( &p_sm->pkey_rcv, + &p_sm->req, p_subn, p_log, p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_pkey_rcv_ctrl_init( &p_sm->pkey_rcv_ctrl, + &p_sm->pkey_rcv, p_sm->p_log, p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + /* + * Now that the component objects are initialized, start + * the sweeper thread if the user wants sweeping. + */ + if( p_sm->p_subn->opt.sweep_interval ) + { + p_sm->thread_state = OSM_THREAD_STATE_INIT; + status = cl_thread_init( &p_sm->sweeper, __osm_sm_sweeper, p_sm, + "opensm sweeper" ); + if( status != IB_SUCCESS ) + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return ( status ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sm_sweep( + IN osm_sm_t * const p_sm ) +{ + OSM_LOG_ENTER( p_sm->p_log, osm_sm_sweep ); + osm_state_mgr_process( &p_sm->state_mgr, OSM_SIGNAL_SWEEP ); + OSM_LOG_EXIT( p_sm->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_bind( + IN osm_sm_t * const p_sm, + IN const ib_net64_t port_guid ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_sm->p_log, osm_sm_bind ); + + 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, + "osm_sm_bind: ERR 2E10: " + "SM MAD Controller bind failed (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_sm->p_log ); + return ( status ); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_sm_mgrp_connect( + IN osm_sm_t * const p_sm, + IN osm_mgrp_t * const p_mgrp, + IN const ib_net64_t port_guid, + IN osm_mcast_req_type_t req_type ) +{ + ib_api_status_t status; + osm_mcast_mgr_ctxt_t *ctx2; + + OSM_LOG_ENTER( p_sm->p_log, __osm_sm_mgrp_connect ); + + /* + * 'Schedule' all the QP0 traffic for when the state manager + * isn't busy trying to do something else. + */ + ctx2 = + ( osm_mcast_mgr_ctxt_t * ) malloc( sizeof( osm_mcast_mgr_ctxt_t ) ); + memcpy( &ctx2->mlid, &p_mgrp->mlid, sizeof( p_mgrp->mlid ) ); + ctx2->req_type = req_type; + ctx2->port_guid = port_guid; + + status = osm_state_mgr_process_idle( &p_sm->state_mgr, + osm_mcast_mgr_process_mgrp_cb, + NULL, &p_sm->mcast_mgr, + ( void * )ctx2 ); + + OSM_LOG_EXIT( p_sm->p_log ); + return ( status ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sm_mgrp_disconnect( + IN osm_sm_t * const p_sm, + IN osm_mgrp_t * const p_mgrp, + IN const ib_net64_t port_guid ) +{ + ib_api_status_t status; + osm_mcast_mgr_ctxt_t *ctx2; + + OSM_LOG_ENTER( p_sm->p_log, __osm_sm_mgrp_disconnect ); + + /* + * 'Schedule' all the QP0 traffic for when the state manager + * isn't busy trying to do something else. + */ + ctx2 = + ( osm_mcast_mgr_ctxt_t * ) malloc( sizeof( osm_mcast_mgr_ctxt_t ) ); + memcpy( &ctx2->mlid, &p_mgrp->mlid, sizeof( p_mgrp->mlid ) ); + ctx2->req_type = OSM_MCAST_REQ_TYPE_LEAVE; + ctx2->port_guid = port_guid; + + status = osm_state_mgr_process_idle( &p_sm->state_mgr, + osm_mcast_mgr_process_mgrp_cb, + NULL, &p_sm->mcast_mgr, ctx2 ); + if( status != IB_SUCCESS ) + { + osm_log( p_sm->p_log, OSM_LOG_ERROR, + "__osm_sm_mgrp_disconnect: ERR 2E11: " + "Failure processing multicast group (%s)\n", + ib_get_err_str( status ) ); + } + + OSM_LOG_EXIT( p_sm->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_mcgrp_join( + IN osm_sm_t * const p_sm, + IN const ib_net16_t mlid, + IN const ib_net64_t port_guid, + IN osm_mcast_req_type_t req_type ) +{ + osm_mgrp_t *p_mgrp; + osm_port_t *p_port; + cl_qmap_t *p_tbl; + ib_api_status_t status = IB_SUCCESS; + osm_mcm_info_t *p_mcm; + + OSM_LOG_ENTER( p_sm->p_log, osm_sm_mcgrp_join ); + + osm_log( p_sm->p_log, OSM_LOG_VERBOSE, + "osm_sm_mcgrp_join: " + "Port 0x%016" PRIx64 " joining MLID 0x%X\n", + cl_ntoh64( port_guid ), cl_ntoh16( mlid ) ); + + /* + * Acquire the port object for the port joining this group. + */ + CL_PLOCK_EXCL_ACQUIRE( p_sm->p_lock ); + p_port = ( osm_port_t * ) cl_qmap_get( &p_sm->p_subn->port_guid_tbl, + port_guid ); + if( p_port == + ( osm_port_t * ) cl_qmap_end( &p_sm->p_subn->port_guid_tbl ) ) + { + CL_PLOCK_RELEASE( p_sm->p_lock ); + osm_log( p_sm->p_log, OSM_LOG_ERROR, + "osm_sm_mcgrp_join: ERR 2E05: " + "No port object for port 0x%016" PRIx64 "\n", + cl_ntoh64( port_guid ) ); + status = IB_INVALID_PARAMETER; + goto Exit; + } + + /* + * If this multicast group does not already exist, create it. + */ + p_tbl = &p_sm->p_subn->mgrp_mlid_tbl; + p_mgrp = ( osm_mgrp_t * ) cl_qmap_get( p_tbl, mlid ); + if( p_mgrp == ( osm_mgrp_t * ) cl_qmap_end( p_tbl ) ) + { + osm_log( p_sm->p_log, OSM_LOG_VERBOSE, + "osm_sm_mcgrp_join: " + "Creating group, MLID 0x%X\n", cl_ntoh16( mlid ) ); + + p_mgrp = osm_mgrp_new( mlid ); + if( p_mgrp == NULL ) + { + CL_PLOCK_RELEASE( p_sm->p_lock ); + osm_log( p_sm->p_log, OSM_LOG_ERROR, + "osm_sm_mcgrp_join: ERR 2E06: " + "Unable to allocate multicast group object\n" ); + status = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + + cl_qmap_insert( p_tbl, mlid, &p_mgrp->map_item ); + } + else + { + /* + * The group already exists. If the port is not a + * member of the group, then fail immediately. + * This can happen since the spinlock is released briefly + * before the SA calls this function. + */ + if( !osm_mgrp_is_guid( p_mgrp, port_guid ) ) + { + CL_PLOCK_RELEASE( p_sm->p_lock ); + osm_log( p_sm->p_log, OSM_LOG_ERROR, + "osm_sm_mcgrp_join: ERR 2E12: " + "Port 0x%016" PRIx64 " not in mcast group 0x%X\n", + cl_ntoh64( port_guid ), cl_ntoh16( mlid ) ); + status = IB_NOT_FOUND; + goto Exit; + } + } + + /* + * Check if the object (according to mlid) already exists on this port. + * If it does - then no need to update it again, and no need to + * create the mc tree again. Just goto Exit. + */ + p_mcm = ( osm_mcm_info_t * ) cl_qlist_head( &p_port->mcm_list ); + while( p_mcm != ( osm_mcm_info_t * ) cl_qlist_end( &p_port->mcm_list ) ) + { + if( p_mcm->mlid == mlid ) + { + CL_PLOCK_RELEASE( p_sm->p_lock ); + osm_log( p_sm->p_log, OSM_LOG_DEBUG, + "osm_sm_mcgrp_join: " + "Found mlid object for Port:" + "0x%016" PRIx64 " lid:0x%X\n", + cl_ntoh64( port_guid ), cl_ntoh16( mlid ) ); + goto Exit; + } + p_mcm = ( osm_mcm_info_t * ) cl_qlist_next( &p_mcm->list_item ); + } + + status = osm_port_add_mgrp( p_port, mlid ); + if( status != IB_SUCCESS ) + { + CL_PLOCK_RELEASE( p_sm->p_lock ); + osm_log( p_sm->p_log, OSM_LOG_ERROR, + "osm_sm_mcgrp_join: ERR 2E03: " + "Unable to associate port 0x%" PRIx64 " to mlid 0x%X\n", + cl_ntoh64( osm_port_get_guid( p_port ) ), + cl_ntoh16( osm_mgrp_get_mlid( p_mgrp ) ) ); + goto Exit; + } + + CL_PLOCK_RELEASE( p_sm->p_lock ); + status = __osm_sm_mgrp_connect( p_sm, p_mgrp, port_guid, req_type ); + + Exit: + OSM_LOG_EXIT( p_sm->p_log ); + return ( status ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_mcgrp_leave( + IN osm_sm_t * const p_sm, + IN const ib_net16_t mlid, + IN const ib_net64_t port_guid ) +{ + osm_mgrp_t *p_mgrp; + osm_port_t *p_port; + cl_qmap_t *p_tbl; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_sm->p_log, osm_sm_mcgrp_leave ); + + osm_log( p_sm->p_log, OSM_LOG_VERBOSE, + "osm_sm_mcgrp_leave: " + "Port 0x%" PRIx64 " leaving MLID 0x%X\n", + cl_ntoh64( port_guid ), cl_ntoh16( mlid ) ); + + /* + * Acquire the port object for the port leaving this group. + */ + /* note: p_sm->p_lock is locked by caller, but will be released later + this function */ + p_port = ( osm_port_t * ) cl_qmap_get( &p_sm->p_subn->port_guid_tbl, + port_guid ); + if( p_port == + ( osm_port_t * ) cl_qmap_end( &p_sm->p_subn->port_guid_tbl ) ) + { + CL_PLOCK_RELEASE( p_sm->p_lock ); + osm_log( p_sm->p_log, OSM_LOG_ERROR, + "osm_sm_mcgrp_leave: ERR 2E04: " + "No port object for port 0x%" PRIx64 "\n", + cl_ntoh64( port_guid ) ); + status = IB_INVALID_PARAMETER; + goto Exit; + } + + /* + * Get the multicast group object for this group. + */ + p_tbl = &p_sm->p_subn->mgrp_mlid_tbl; + p_mgrp = ( osm_mgrp_t * ) cl_qmap_get( p_tbl, mlid ); + if( p_mgrp == ( osm_mgrp_t * ) cl_qmap_end( p_tbl ) ) + { + CL_PLOCK_RELEASE( p_sm->p_lock ); + osm_log( p_sm->p_log, OSM_LOG_ERROR, + "osm_sm_mcgrp_leave: ERR 2E08: " + "No multicast group for MLID 0x%X\n", cl_ntoh16( mlid ) ); + status = IB_INVALID_PARAMETER; + goto Exit; + } + + /* + * Walk the list of ports in the group, and remove the appropriate one. + */ + osm_mgrp_remove_port( p_sm->p_subn, p_sm->p_log, p_mgrp, port_guid ); + + osm_port_remove_mgrp( p_port, mlid ); + + CL_PLOCK_RELEASE( p_sm->p_lock ); + + __osm_sm_mgrp_disconnect( p_sm, p_mgrp, port_guid ); + + Exit: + OSM_LOG_EXIT( p_sm->p_log ); + return ( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sm_mad_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sm_mad_ctrl.c new file mode 100644 index 00000000..a79e50b7 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sm_mad_ctrl.c @@ -0,0 +1,1049 @@ +/* + * 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: + * 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****f* opensm: SM/__osm_sm_mad_ctrl_retire_trans_mad + * NAME + * __osm_sm_mad_ctrl_retire_trans_mad + * + * DESCRIPTION + * This function handles clean-up of MADs associated with the SM's + * outstanding transactions on the wire. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_retire_trans_mad( + IN osm_sm_mad_ctrl_t* const p_ctrl, + IN osm_madw_t* const p_madw ) +{ + uint32_t outstanding; + cl_status_t status; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sm_mad_ctrl_retire_trans_mad ); + + CL_ASSERT( p_madw ); + /* + Return the MAD & wrapper to the pool. + */ + if( osm_log_is_active( p_ctrl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_DEBUG, + "__osm_sm_mad_ctrl_retire_trans_mad: " + "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 = cl_atomic_dec( &p_ctrl->p_stats->qp0_mads_outstanding ); + + if( osm_log_is_active( p_ctrl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_DEBUG, + "__osm_sm_mad_ctrl_retire_trans_mad: " + "%u QP0 MADs outstanding\n", + p_ctrl->p_stats->qp0_mads_outstanding ); + } + + if( outstanding == 0 ) + { + /* + The wire is clean. + Signal the state manager. + */ + if( osm_log_is_active( p_ctrl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_DEBUG, + "__osm_sm_mad_ctrl_retire_trans_mad: " + "Posting Dispatcher message %s\n", + osm_get_disp_msg_str( OSM_MSG_NO_SMPS_OUTSTANDING ) ); + } + + status = cl_disp_post( p_ctrl->h_disp, + OSM_MSG_NO_SMPS_OUTSTANDING, + (void *)OSM_SIGNAL_NO_PENDING_TRANSACTIONS, + NULL, + NULL ); + + if( status != CL_SUCCESS ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_retire_trans_mad: ERR 3101: " + "Dispatcher post message failed (%s)\n", + CL_STATUS_MSG( status ) ); + goto Exit; + } + } + + Exit: + OSM_LOG_EXIT( p_ctrl->p_log ); +} +/************/ + +/****f* opensm: SM/__osm_sm_mad_ctrl_disp_done_callback + * NAME + * __osm_sm_mad_ctrl_disp_done_callback + * + * DESCRIPTION + * This function is the Dispatcher callback that indicates + * a received MAD has been processed by the recipient. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_disp_done_callback( + IN void* context, + IN void* p_data ) +{ + osm_sm_mad_ctrl_t* const p_ctrl = (osm_sm_mad_ctrl_t*)context; + osm_madw_t* const p_madw = (osm_madw_t*)p_data; + ib_smp_t *p_smp; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sm_mad_ctrl_disp_done_callback ); + + /* + If the MAD that just finished processing was a response, + then retire the transaction, since we must have generated + the request. + + Otherwise, retire the transaction if a response was expected, + as in the case of a send failure. If a response was not expected, + just put the MAD back in the pool, because the MAD was a query + from some outside agent, e.g. Get(SMInfo) from another SM. + */ + p_smp = osm_madw_get_smp_ptr( p_madw ); + if( ib_smp_is_response( p_smp ) ) + { + CL_ASSERT( p_madw->resp_expected == FALSE ); + __osm_sm_mad_ctrl_retire_trans_mad( p_ctrl, p_madw ); + } + else + { + if( p_madw->resp_expected == TRUE ) + __osm_sm_mad_ctrl_retire_trans_mad( p_ctrl, p_madw ); + else + osm_mad_pool_put( p_ctrl->p_mad_pool, p_madw ); + } + + OSM_LOG_EXIT( p_ctrl->p_log ); +} +/************/ + +/****f* opensm: SM/__osm_sm_mad_ctrl_update_wire_stats + * NAME + * __osm_sm_mad_ctrl_update_wire_stats + * + * DESCRIPTION + * Updates wire stats for outstanding MADs and calls the VL15 poller. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_update_wire_stats( + IN osm_sm_mad_ctrl_t* const p_ctrl ) +{ + uint32_t mads_on_wire; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sm_mad_ctrl_update_wire_stats ); + + mads_on_wire = cl_atomic_dec( + &p_ctrl->p_stats->qp0_mads_outstanding_on_wire ); + + if( osm_log_is_active( p_ctrl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_DEBUG, + "__osm_sm_mad_ctrl_update_wire_stats: " + "%u SMPs on the wire, %u outstanding\n", mads_on_wire, + p_ctrl->p_stats->qp0_mads_outstanding ); + } + + /* + We can signal the VL15 controller to send another MAD + if any are waiting for transmission. + */ + osm_vl15_poll( p_ctrl->p_vl15 ); + OSM_LOG_EXIT( p_ctrl->p_log ); +} + +/****f* opensm: SM/__osm_sm_mad_ctrl_process_get_resp + * NAME + * __osm_sm_mad_ctrl_process_get_resp + * + * DESCRIPTION + * This function handles method GetResp() for received MADs. + * This is the most common path for QP0 MADs. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_process_get_resp( + IN osm_sm_mad_ctrl_t* const p_ctrl, + IN osm_madw_t *p_madw, + IN void* transaction_context ) +{ + ib_smp_t* p_smp; + cl_status_t status; + osm_madw_t* p_old_madw; + cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sm_mad_ctrl_process_get_resp ); + + 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 ) + { + if( !ib_smp_is_d( p_smp ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_process_get_resp: ERR 3102: " + "'D' bit not set in returned SMP\n" ); + osm_dump_dr_smp( p_ctrl->p_log, p_smp, OSM_LOG_ERROR ); + } + } + + p_old_madw = (osm_madw_t*)transaction_context; + + __osm_sm_mad_ctrl_update_wire_stats( p_ctrl ); + + /* + Copy the MAD Wrapper context from the requesting MAD + to the new MAD. This mechanism allows the recipient + controller to recover its own context regarding this + MAD transaction. Once we've copied the context, we + can return the original MAD to the pool. + */ + osm_madw_copy_context( p_madw, p_old_madw ); + osm_mad_pool_put( p_ctrl->p_mad_pool, p_old_madw ); + + /* + Note that attr_id (like the rest of the MAD) is in + network byte order. + */ + switch( p_smp->attr_id ) + { + case IB_MAD_ATTR_NODE_DESC: + msg_id = OSM_MSG_MAD_NODE_DESC; + break; + case IB_MAD_ATTR_NODE_INFO: + msg_id = OSM_MSG_MAD_NODE_INFO; + break; + case IB_MAD_ATTR_SWITCH_INFO: + msg_id = OSM_MSG_MAD_SWITCH_INFO; + break; + case IB_MAD_ATTR_PORT_INFO: + msg_id = OSM_MSG_MAD_PORT_INFO; + break; + case IB_MAD_ATTR_LIN_FWD_TBL: + msg_id = OSM_MSG_MAD_LFT; + break; + case IB_MAD_ATTR_MCAST_FWD_TBL: + msg_id = OSM_MSG_MAD_MFT; + break; + case IB_MAD_ATTR_SM_INFO: + msg_id = OSM_MSG_MAD_SM_INFO; + break; + case IB_MAD_ATTR_SLVL_TABLE: + msg_id = OSM_MSG_MAD_SLVL; + break; + case IB_MAD_ATTR_VL_ARBITRATION: + msg_id = OSM_MSG_MAD_VL_ARB; + break; + case IB_MAD_ATTR_P_KEY_TABLE: + msg_id = OSM_MSG_MAD_PKEY; + break; + + case IB_MAD_ATTR_GUID_INFO: + case IB_MAD_ATTR_CLASS_PORT_INFO: + case IB_MAD_ATTR_NOTICE: + case IB_MAD_ATTR_INFORM_INFO: + default: + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_process_get_resp: ERR 3103: " + "Unsupported attribute = 0x%X\n", + cl_ntoh16( p_smp->attr_id ) ); + osm_dump_dr_smp( p_ctrl->p_log, p_smp, OSM_LOG_ERROR ); + goto Exit; + } + + if( msg_id != CL_DISP_MSGID_NONE ) + { + /* + Post this MAD to the dispatcher for asynchronous + processing by the appropriate controller. + */ + + if( osm_log_is_active( p_ctrl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_DEBUG, + "__osm_sm_mad_ctrl_process_get_resp: " + "Posting Dispatcher message %s\n", + osm_get_disp_msg_str( msg_id ) ); + } + + status = cl_disp_post( p_ctrl->h_disp, + msg_id, + p_madw, + __osm_sm_mad_ctrl_disp_done_callback, + p_ctrl ); + + if( status != CL_SUCCESS ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_process_get_resp: ERR 3104: " + "Dispatcher post message failed (%s) for attribute = 0x%X\n", + CL_STATUS_MSG( status ), + cl_ntoh16( p_smp->attr_id ) ); + goto Exit; + } + } + + Exit: + OSM_LOG_EXIT( p_ctrl->p_log ); +} + +/****f* opensm: SM/__osm_sm_mad_ctrl_process_get + * NAME + * __osm_sm_mad_ctrl_process_get + * + * DESCRIPTION + * This function handles method Get() for received MADs. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_process_get( + IN osm_sm_mad_ctrl_t* const p_ctrl, + IN osm_madw_t *p_madw ) +{ + ib_smp_t* p_smp; + cl_status_t status; + cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sm_mad_ctrl_process_get ); + + 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: + osm_log( p_ctrl->p_log, OSM_LOG_VERBOSE, + "__osm_sm_mad_ctrl_process_get: " + "Ignoring SubnGet MAD - unsupported attribute = 0x%X\n", + cl_ntoh16( p_smp->attr_id ) ); + break; + } + + if( msg_id != CL_DISP_MSGID_NONE ) + { + /* + Post this MAD to the dispatcher for asynchronous + processing by the appropriate controller. + */ + + if( osm_log_is_active( p_ctrl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_DEBUG, + "__osm_sm_mad_ctrl_process_get: " + "Posting Dispatcher message %s\n", + osm_get_disp_msg_str( msg_id ) ); + } + + status = cl_disp_post( p_ctrl->h_disp, + msg_id, + p_madw, + __osm_sm_mad_ctrl_disp_done_callback, + p_ctrl ); + + if( status != CL_SUCCESS ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_process_get: ERR 3106: " + "Dispatcher post message failed (%s)\n", + CL_STATUS_MSG( status ) ); + goto Exit; + } + } + else + { + /* + There is an unknown MAD attribute type for which there is + no recipient. Simply retire the MAD here. + */ + osm_mad_pool_put( p_ctrl->p_mad_pool, p_madw ); + } + + Exit: + OSM_LOG_EXIT( p_ctrl->p_log ); +} +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* opensm: SM/__osm_sm_mad_ctrl_process_set + * NAME + * __osm_sm_mad_ctrl_process_set + * + * DESCRIPTION + * This function handles method Set() for received MADs. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_process_set( + IN osm_sm_mad_ctrl_t* const p_ctrl, + IN osm_madw_t *p_madw ) +{ + ib_smp_t* p_smp; + cl_status_t status; + cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sm_mad_ctrl_process_set ); + + 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: + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_process_set: ERR 3107: " + "Unsupported attribute = 0x%X\n", + cl_ntoh16( p_smp->attr_id ) ); + osm_dump_dr_smp( p_ctrl->p_log, p_smp, OSM_LOG_ERROR ); + break; + } + + if( msg_id != CL_DISP_MSGID_NONE ) + { + /* + Post this MAD to the dispatcher for asynchronous + processing by the appropriate controller. + */ + + if( osm_log_is_active( p_ctrl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_DEBUG, + "__osm_sm_mad_ctrl_process_set: " + "Posting Dispatcher message %s\n", + osm_get_disp_msg_str( msg_id ) ); + } + + status = cl_disp_post( p_ctrl->h_disp, + msg_id, + p_madw, + __osm_sm_mad_ctrl_disp_done_callback, + p_ctrl ); + + if( status != CL_SUCCESS ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_process_set: ERR 3108: " + "Dispatcher post message failed (%s)\n", + CL_STATUS_MSG( status ) ); + goto Exit; + } + } + else + { + /* + There is an unknown MAD attribute type for which there is + no recipient. Simply retire the MAD here. + */ + osm_mad_pool_put( p_ctrl->p_mad_pool, p_madw ); + } + + Exit: + OSM_LOG_EXIT( p_ctrl->p_log ); +} +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* opensm: SM/__osm_sm_mad_ctrl_process_trap + * NAME + * __osm_sm_mad_ctrl_process_trap + * + * DESCRIPTION + * This function handles method Trap() for received MADs. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_process_trap( + IN osm_sm_mad_ctrl_t* const p_ctrl, + IN osm_madw_t *p_madw ) +{ + ib_smp_t* p_smp; + cl_status_t status; + cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sm_mad_ctrl_process_trap ); + + 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, + "__osm_sm_mad_ctrl_process_trap: " + "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: + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_process_trap: ERR 3109: " + "Unsupported attribute = 0x%X\n", + cl_ntoh16( p_smp->attr_id ) ); + osm_dump_dr_smp( p_ctrl->p_log, p_smp, OSM_LOG_ERROR ); + break; + } + + if( msg_id != CL_DISP_MSGID_NONE ) + { + /* + Post this MAD to the dispatcher for asynchronous + processing by the appropriate controller. + */ + + if( osm_log_is_active( p_ctrl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_DEBUG, + "__osm_sm_mad_ctrl_process_trap: " + "Posting Dispatcher message %s\n", + osm_get_disp_msg_str( msg_id ) ); + } + + status = cl_disp_post( p_ctrl->h_disp, + msg_id, + p_madw, + __osm_sm_mad_ctrl_disp_done_callback, + p_ctrl ); + + if( status != CL_SUCCESS ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_process_trap: ERR 3110: " + "Dispatcher post message failed (%s)\n", + CL_STATUS_MSG( status ) ); + goto Exit; + } + } + else + { + /* + There is an unknown MAD attribute type for which there is + no recipient. Simply retire the MAD here. + */ + osm_mad_pool_put( p_ctrl->p_mad_pool, p_madw ); + } + + Exit: + OSM_LOG_EXIT( p_ctrl->p_log ); +} +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* opensm: SM/__osm_sm_mad_ctrl_rcv_callback + * NAME + * __osm_sm_mad_ctrl_rcv_callback + * + * DESCRIPTION + * This is the callback from the transport layer for received MADs. + * + * SYNOPSIS + */ +void +__osm_sm_mad_ctrl_rcv_callback( + IN osm_madw_t *p_madw, + IN void *bind_context, + IN osm_madw_t *p_req_madw ) +{ + osm_sm_mad_ctrl_t* p_ctrl = (osm_sm_mad_ctrl_t*)bind_context; + ib_smp_t* p_smp; + ib_net16_t status; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sm_mad_ctrl_rcv_callback ); + + 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 ); + + if( osm_log_is_active( p_ctrl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_DEBUG, + "__osm_sm_mad_ctrl_rcv_callback: " + "%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, + "__osm_sm_mad_ctrl_rcv_callback: " + "Ignoring received mad - since we are exiting\n"); + + osm_dump_dr_smp( p_ctrl->p_log, p_smp, OSM_LOG_DEBUG ); + + /* retire the mad or put it back */ + if( ib_smp_is_response( p_smp ) || + (p_smp->method == IB_MAD_METHOD_TRAP_REPRESS)) + { + CL_ASSERT( p_madw->resp_expected == FALSE ); + __osm_sm_mad_ctrl_retire_trans_mad( p_ctrl, p_madw ); + } + else + { + if( p_madw->resp_expected == TRUE ) + __osm_sm_mad_ctrl_retire_trans_mad( p_ctrl, p_madw ); + else + osm_mad_pool_put( p_ctrl->p_mad_pool, p_madw ); + } + + goto Exit; + } + + if( osm_log_is_active( p_ctrl->p_log, OSM_LOG_FRAMES ) ) + osm_dump_dr_smp( p_ctrl->p_log, p_smp, OSM_LOG_FRAMES ); + + if( p_smp->mgmt_class == IB_MCLASS_SUBN_DIR ) + { + status = ib_smp_get_status( p_smp ); + } + else + { + status = p_smp->status; + } + + if( status != 0 ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_rcv_callback: ERR 3111: " + "Error status = 0x%X\n", status ); + osm_dump_dr_smp( p_ctrl->p_log, p_smp, OSM_LOG_ERROR ); + } + + switch( p_smp->method ) + { + case IB_MAD_METHOD_GET_RESP: + CL_ASSERT( p_req_madw != NULL ); + __osm_sm_mad_ctrl_process_get_resp( p_ctrl, p_madw, p_req_madw ); + break; + + case IB_MAD_METHOD_GET: + CL_ASSERT( p_req_madw == NULL ); + __osm_sm_mad_ctrl_process_get( p_ctrl, p_madw ); + break; + + case IB_MAD_METHOD_TRAP: + CL_ASSERT( p_req_madw == NULL ); + __osm_sm_mad_ctrl_process_trap( p_ctrl, p_madw ); + break; + + case IB_MAD_METHOD_SET: + CL_ASSERT( p_req_madw == NULL ); + __osm_sm_mad_ctrl_process_set( p_ctrl, p_madw ); + break; + + case IB_MAD_METHOD_SEND: + case IB_MAD_METHOD_REPORT: + case IB_MAD_METHOD_REPORT_RESP: + case IB_MAD_METHOD_TRAP_REPRESS: + default: + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_rcv_callback: ERR 3112: " + "Unsupported method = 0x%X\n", p_smp->method ); + osm_dump_dr_smp( p_ctrl->p_log, p_smp, OSM_LOG_ERROR ); + osm_mad_pool_put( p_ctrl->p_mad_pool, p_madw ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_ctrl->p_log ); +} +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* opensm: SM/__osm_sm_mad_ctrl_send_err_cb + * NAME + * __osm_sm_mad_ctrl_send_err_cb + * + * DESCRIPTION + * This is the callback from the transport layer for send errors + * on MADs that were expecting a response. + * + * SYNOPSIS + */ +void +__osm_sm_mad_ctrl_send_err_cb( + IN void *bind_context, + IN osm_madw_t *p_madw ) +{ + osm_sm_mad_ctrl_t* p_ctrl = (osm_sm_mad_ctrl_t*)bind_context; +#if 0 + osm_physp_t* p_physp; +#endif + ib_api_status_t status; + ib_smp_t* p_smp; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sm_mad_ctrl_send_err_cb ); + + CL_ASSERT( p_madw ); + + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_send_err_cb: ERR 3113: " + "MAD completed in error (%s)\n", + ib_get_err_str( p_madw->status ) ); + + /* + If this was a SubnSet MAD, then this error might indicate a problem + in configuring the subnet. In this case - need to mark that there was + such a problem. The subnet will not be up, and the next sweep should + be a heavy sweep as well. + */ + p_smp = osm_madw_get_smp_ptr( p_madw ); + if (p_smp->method == IB_MAD_METHOD_SET && + ( p_smp->attr_id == IB_MAD_ATTR_PORT_INFO || + p_smp->attr_id == IB_MAD_ATTR_MCAST_FWD_TBL || + p_smp->attr_id == IB_MAD_ATTR_SWITCH_INFO || + p_smp->attr_id == IB_MAD_ATTR_LIN_FWD_TBL ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_send_err_cb: ERR 3119: " + "Set method failed\n" ); + p_ctrl->p_subn->subnet_initialization_error = TRUE; + } + + /* + Since we did not get any response we suspect the DR path + used for the target port. + Find it and replace it with an alternate path. + This is true only if the destination lid is not 0xFFFF, since + then we are aiming for a specific path and not specific destination + lid. + */ + /* For now - do not add the alternate dr path to the release */ +#if 0 + if ( p_madw->mad_addr.dest_lid != 0xFFFF ) + { + 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, + "__osm_sm_mad_ctrl_send_err_cb: ERR 3114: " + "Failed to find the corresponding phys port\n"); + } + else + { + osm_physp_replace_dr_path_with_alternate_dr_path( + p_ctrl->p_log, p_ctrl->p_subn, p_physp, p_madw->h_bind ); + } + } +#endif + + /* + An error occurred. No response was received to a request MAD. + Retire the original request MAD. + */ + + osm_dump_dr_smp( p_ctrl->p_log, osm_madw_get_smp_ptr( p_madw ), + OSM_LOG_ERROR ); + + __osm_sm_mad_ctrl_update_wire_stats( p_ctrl ); + + if( osm_madw_get_err_msg( p_madw ) != CL_DISP_MSGID_NONE ) + { + if( osm_log_is_active( p_ctrl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_DEBUG, + "__osm_sm_mad_ctrl_send_err_cb: " + "Posting Dispatcher message %s\n", + osm_get_disp_msg_str( osm_madw_get_err_msg( p_madw ) ) ); + } + + status = cl_disp_post( p_ctrl->h_disp, + osm_madw_get_err_msg( p_madw ), + p_madw, + __osm_sm_mad_ctrl_disp_done_callback, + p_ctrl ); + if( status != CL_SUCCESS ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sm_mad_ctrl_send_err_cb: ERR 3115: " + "Dispatcher post message failed (%s)\n", + CL_STATUS_MSG( status ) ); + } + } + else + { + /* + No error message was provided, just retire the MAD. + */ + __osm_sm_mad_ctrl_retire_trans_mad( p_ctrl, p_madw ); + } + + OSM_LOG_EXIT( p_ctrl->p_log ); +} +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/********************************************************************** + **********************************************************************/ +void +osm_sm_mad_ctrl_construct( + IN osm_sm_mad_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_sm_mad_ctrl_destroy( + IN osm_sm_mad_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + + if (p_ctrl->h_bind != CL_DISP_INVALID_HANDLE) + { + osm_vendor_unbind( p_ctrl->h_bind ); + } + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_mad_ctrl_init( + IN osm_sm_mad_ctrl_t* const p_ctrl, + IN osm_subn_t* const p_subn, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_vl15_t* const p_vl15, + IN osm_vendor_t* const p_vendor, + IN osm_log_t* const p_log, + IN osm_stats_t* const p_stats, + IN cl_plock_t* const p_lock, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_sm_mad_ctrl_init ); + + 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, + "osm_sm_mad_ctrl_init: ERR 3116: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_mad_ctrl_bind( + IN osm_sm_mad_ctrl_t* const p_ctrl, + IN const ib_net64_t port_guid ) +{ + osm_bind_info_t bind_info; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_ctrl->p_log, osm_sm_mad_ctrl_bind ); + + if( p_ctrl->h_bind != OSM_BIND_INVALID_HANDLE ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "osm_sm_mad_ctrl_bind: ERR 3117: " + "Multiple binds not allowed\n" ); + status = IB_ERROR; + goto Exit; + } + + bind_info.class_version = 1; + bind_info.is_report_processor = FALSE; + bind_info.is_responder = TRUE; + bind_info.is_trap_processor = TRUE; + bind_info.mad_class = IB_MCLASS_SUBN_DIR; + bind_info.port_guid = port_guid; + bind_info.recv_q_size = OSM_SM_DEFAULT_QP0_RCV_SIZE; + bind_info.send_q_size = OSM_SM_DEFAULT_QP0_SEND_SIZE; + + osm_log( p_ctrl->p_log, OSM_LOG_VERBOSE, + "osm_sm_mad_ctrl_bind: " + "Binding to port 0x%" PRIx64 "\n", + cl_ntoh64( port_guid ) ); + + p_ctrl->h_bind = osm_vendor_bind( p_ctrl->p_vendor, + &bind_info, + p_ctrl->p_mad_pool, + __osm_sm_mad_ctrl_rcv_callback, + __osm_sm_mad_ctrl_send_err_cb, + p_ctrl ); + + if( p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE ) + { + status = IB_ERROR; + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "osm_sm_mad_ctrl_bind: ERR 3118: " + "Vendor specific bind failed\n" ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_ctrl->p_log ); + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sm_state_mgr.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sm_state_mgr.c new file mode 100644 index 00000000..cf37caae --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sm_state_mgr.c @@ -0,0 +1,872 @@ +/* + * 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: + * Implementation of osm_state_mgr_t. + * This file implements the SM State Manager object. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#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 +__osm_sm_state_mgr_standby_msg( + IN const osm_sm_state_mgr_t * p_sm_mgr ) +{ + osm_log( p_sm_mgr->p_log, OSM_LOG_SYS, "Entering STANDBY state\n" ); /* Format Waived */ + + if( osm_log_is_active( p_sm_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_sm_state_mgr_standby_msg: " + "\n\n\n********************************" + "**********************************\n" + "******************** ENTERING SM STANDBY" + " STATE *******************\n" + "**************************************" + "****************************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sm_state_mgr_master_msg( + IN const osm_sm_state_mgr_t * p_sm_mgr ) +{ + osm_log( p_sm_mgr->p_log, OSM_LOG_SYS, "Entering MASTER state\n" ); /* Format Waived */ + + if( osm_log_is_active( p_sm_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_sm_state_mgr_master_msg: " + "\n\n\n********************************" + "**********************************\n" + "******************** ENTERING SM MASTER" + " STATE ********************\n" + "**************************************" + "****************************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sm_state_mgr_discovering_msg( + IN const osm_sm_state_mgr_t * p_sm_mgr ) +{ + if( osm_log_is_active( p_sm_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_sm_state_mgr_discovering_msg: " + "\n\n\n********************************" + "**********************************\n" + "******************** ENTERING SM DISCOVERING" + " STATE ***************\n" + "**************************************" + "****************************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sm_state_mgr_notactive_msg( + IN const osm_sm_state_mgr_t * p_sm_mgr ) +{ + if( osm_log_is_active( p_sm_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_sm_state_mgr_notactive_msg: " + "\n\n\n********************************" + "**********************************\n" + "******************** ENTERING SM NOT-ACTIVE" + " STATE **********************\n" + "**************************************" + "****************************\n\n\n" ); + } +} + +#if 0 +/********************************************************************** + **********************************************************************/ +static void +__osm_sm_state_mgr_send_local_port_info_req( + IN osm_sm_state_mgr_t * p_sm_mgr ) +{ + osm_madw_context_t context; + osm_port_t *p_port; + ib_net64_t port_guid = p_sm_mgr->p_subn->sm_port_guid; + ib_api_status_t status; + + OSM_LOG_ENTER( p_sm_mgr->p_log, + __osm_sm_state_mgr_send_local_port_info_req ); + /* + * Send a query of SubnGet(PortInfo) to our own port, in order to + * update the master_sm_base_lid of the subnet. + */ + memset( &context, 0, sizeof( context ) ); + p_port = ( osm_port_t * ) cl_qmap_get( &p_sm_mgr->p_subn->port_guid_tbl, + port_guid ); + if( p_port == + ( osm_port_t * ) cl_qmap_end( &p_sm_mgr->p_subn->port_guid_tbl ) ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_ERROR, + "__osm_sm_state_mgr_send_local_port_info_req: ERR 3205: " + "No port object for port 0x%016" PRIx64 "\n", + cl_ntoh64( port_guid ) ); + goto Exit; + } + + context.pi_context.port_guid = port_guid; + context.pi_context.node_guid = p_port->p_node->node_info.node_guid; + context.pi_context.set_method = FALSE; + context.pi_context.ignore_errors = FALSE; + /* mark the update_master_sm_base_lid with TRUE - we want to update it */ + /* with the new master lid value. */ + context.pi_context.update_master_sm_base_lid = TRUE; + context.pi_context.light_sweep = FALSE; + context.pi_context.active_transition = FALSE; + + status = osm_req_get( p_sm_mgr->p_req, + osm_physp_get_dr_path_ptr + ( osm_port_get_default_phys_ptr( p_port ) ), + IB_MAD_ATTR_PORT_INFO, + cl_hton32( p_port->default_port_num ), + CL_DISP_MSGID_NONE, &context ); + + if( status != IB_SUCCESS ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_ERROR, + "__osm_sm_state_mgr_send_local_port_info_req: ERR 3202: " + "Failure requesting PortInfo (%s)\n", + ib_get_err_str( status ) ); + } + + Exit: + OSM_LOG_EXIT( p_sm_mgr->p_log ); +} +#endif + +/********************************************************************** + **********************************************************************/ +static void +__osm_sm_state_mgr_send_master_sm_info_req( + IN osm_sm_state_mgr_t * p_sm_mgr ) +{ + osm_madw_context_t context; + const osm_port_t *p_port; + ib_api_status_t status; + + OSM_LOG_ENTER( p_sm_mgr->p_log, + __osm_sm_state_mgr_send_master_sm_info_req ); + + memset( &context, 0, sizeof( context ) ); + if( p_sm_mgr->p_subn->sm_state == IB_SMINFO_STATE_STANDBY ) + { + /* + * We are in STANDBY state - this means we need to poll on the master + * SM (according to master_guid) + * Send a query of SubnGet(SMInfo) to the subn master_sm_base_lid object. + */ + p_port = ( osm_port_t * ) cl_qmap_get( &p_sm_mgr->p_subn->port_guid_tbl, + p_sm_mgr->master_guid ); + } + else + { + /* + * We are not in STANDBY - this means we are in MASTER state - so we need + * to poll on the SM that is saved in p_polling_sm under p_sm_mgr. + * Send a query of SubnGet(SMInfo) to that SM. + */ + p_port = p_sm_mgr->p_polling_sm->p_port; + } + if( p_port == NULL ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_ERROR, + "__osm_sm_state_mgr_send_master_sm_info_req: ERR 3203: " + "No port object for GUID 0x%016" PRIx64 "\n", + cl_ntoh64(p_sm_mgr->master_guid) ); + goto Exit; + } + + context.smi_context.port_guid = p_port->guid; + context.smi_context.set_method = FALSE; + + status = osm_req_get( p_sm_mgr->p_req, + osm_physp_get_dr_path_ptr + ( osm_port_get_default_phys_ptr( p_port ) ), + IB_MAD_ATTR_SM_INFO, 0, CL_DISP_MSGID_NONE, + &context ); + + if( status != IB_SUCCESS ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_ERROR, + "__osm_sm_state_mgr_send_master_sm_info_req: ERR 3204: " + "Failure rquesting SMInfo (%s)\n", ib_get_err_str( status ) ); + } + + Exit: + OSM_LOG_EXIT( p_sm_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sm_state_mgr_start_polling( + IN osm_sm_state_mgr_t * p_sm_mgr ) +{ + uint32_t sminfo_polling_timeout = + p_sm_mgr->p_subn->opt.sminfo_polling_timeout; + cl_status_t cl_status; + + OSM_LOG_ENTER( p_sm_mgr->p_log, __osm_sm_state_mgr_start_polling ); + + /* + * Init the retry_nubmer back to zero - need to restart counting + */ + p_sm_mgr->retry_number = 0; + + /* + * Send a SubnGet(SMInfo) query to the current (or new) master found. + */ + __osm_sm_state_mgr_send_master_sm_info_req( p_sm_mgr ); + + /* + * 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( &p_sm_mgr->polling_timer, + sminfo_polling_timeout ); + if( cl_status != CL_SUCCESS ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_ERROR, + "__osm_sm_state_mgr_start_polling : ERR 3210: " + "Failed to start timer\n" ); + } + + OSM_LOG_EXIT( p_sm_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sm_state_mgr_polling_callback( + IN void *context ) +{ + osm_sm_state_mgr_t *p_sm_mgr = ( osm_sm_state_mgr_t * ) context; + uint32_t sminfo_polling_timeout = + p_sm_mgr->p_subn->opt.sminfo_polling_timeout; + cl_status_t cl_status; + + OSM_LOG_ENTER( p_sm_mgr->p_log, __osm_sm_state_mgr_polling_callback ); + + /* + * 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( !( ( p_sm_mgr->p_subn->sm_state == IB_SMINFO_STATE_MASTER && + p_sm_mgr->p_polling_sm != NULL ) || + ( p_sm_mgr->p_subn->sm_state == IB_SMINFO_STATE_STANDBY ) ) ) + { + goto Exit; + } + + /* + * If we are a STANDBY sm and the osm_exit_flag is 1, 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( p_sm_mgr->p_subn->sm_state == IB_SMINFO_STATE_STANDBY && + osm_exit_flag == 1 ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_sm_state_mgr_polling_callback : " + "Signalling subnet_up_event\n" ); + cl_event_signal( p_sm_mgr->p_state_mgr->p_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 + */ + p_sm_mgr->retry_number++; + osm_log( p_sm_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_sm_state_mgr_polling_callback : " + "Retry number:%d\n", p_sm_mgr->retry_number ); + + if( p_sm_mgr->retry_number >= p_sm_mgr->p_subn->opt.polling_retry_number ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_DEBUG, + "__osm_sm_state_mgr_polling_callback : " + "Reached polling_retry_number value in retry_number. " + "Go to DISCOVERY state\n" ); + osm_sm_state_mgr_process( p_sm_mgr, OSM_SM_SIGNAL_POLLING_TIMEOUT ); + goto Exit; + } + + /* Send a SubnGet(SMInfo) request to the remote sm (depends on our state) */ + __osm_sm_state_mgr_send_master_sm_info_req( p_sm_mgr ); + + /* restart the timer */ + cl_status = cl_timer_start( &p_sm_mgr->polling_timer, + sminfo_polling_timeout ); + if( cl_status != CL_SUCCESS ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_ERROR, + "__osm_sm_state_mgr_polling_callback : ERR 3211: " + "Failed to restart timer\n" ); + } + + Exit: + OSM_LOG_EXIT( p_sm_mgr->p_log ); + return; +} + +/********************************************************************** + **********************************************************************/ +void +osm_sm_state_mgr_construct( + IN osm_sm_state_mgr_t * const p_sm_mgr ) +{ + memset( p_sm_mgr, 0, sizeof( *p_sm_mgr ) ); + cl_spinlock_construct( &p_sm_mgr->state_lock ); + cl_timer_construct( &p_sm_mgr->polling_timer ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sm_state_mgr_destroy( + IN osm_sm_state_mgr_t * const p_sm_mgr ) +{ + CL_ASSERT( p_sm_mgr ); + + OSM_LOG_ENTER( p_sm_mgr->p_log, osm_sm_state_mgr_destroy ); + + cl_spinlock_destroy( &p_sm_mgr->state_lock ); + cl_timer_destroy( &p_sm_mgr->polling_timer ); + + OSM_LOG_EXIT( p_sm_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_state_mgr_init( + IN osm_sm_state_mgr_t * const p_sm_mgr, + IN osm_state_mgr_t * const p_state_mgr, + IN osm_subn_t * const p_subn, + IN osm_req_t * const p_req, + IN osm_log_t * const p_log ) +{ + cl_status_t status; + + OSM_LOG_ENTER( p_log, osm_sm_state_mgr_init ); + + CL_ASSERT( p_subn ); + CL_ASSERT( p_state_mgr ); + CL_ASSERT( p_req ); + + osm_sm_state_mgr_construct( p_sm_mgr ); + + p_sm_mgr->p_log = p_log; + p_sm_mgr->p_req = p_req; + p_sm_mgr->p_subn = p_subn; + p_sm_mgr->p_state_mgr = p_state_mgr; + + /* init the state of the SM to idle */ + p_sm_mgr->p_subn->sm_state = IB_SMINFO_STATE_INIT; + + status = cl_spinlock_init( &p_sm_mgr->state_lock ); + if( status != CL_SUCCESS ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_ERROR, + "osm_sm_state_mgr_init: ERR 3201: " + "Spinlock init failed (%s)\n", CL_STATUS_MSG( status ) ); + } + + status = cl_timer_init( &p_sm_mgr->polling_timer, + __osm_sm_state_mgr_polling_callback, p_sm_mgr ); + + if( status != CL_SUCCESS ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_ERROR, + "osm_sm_state_mgr_init: ERR 3206: " + "Timer init failed (%s)\n", CL_STATUS_MSG( status ) ); + } + + OSM_LOG_EXIT( p_sm_mgr->p_log ); + return ( status ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sm_state_mgr_signal_error( + IN const osm_sm_state_mgr_t * const p_sm_mgr, + IN const osm_sm_signal_t signal ) +{ + osm_log( p_sm_mgr->p_log, OSM_LOG_ERROR, + "__osm_sm_state_mgr_signal_error: ERR 3207: " + "Invalid signal %s in state %s\n", + osm_get_sm_mgr_signal_str( signal ), + osm_get_sm_mgr_state_str( p_sm_mgr->p_subn->sm_state ) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sm_state_mgr_signal_master_is_alive( + IN osm_sm_state_mgr_t * const p_sm_mgr ) +{ + OSM_LOG_ENTER( p_sm_mgr->p_log, osm_sm_state_mgr_signal_master_is_alive ); + p_sm_mgr->retry_number = 0; + OSM_LOG_EXIT( p_sm_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_state_mgr_process( + IN osm_sm_state_mgr_t * const p_sm_mgr, + IN osm_sm_signal_t signal ) +{ + ib_api_status_t status = IB_SUCCESS; + + CL_ASSERT( p_sm_mgr ); + + OSM_LOG_ENTER( p_sm_mgr->p_log, osm_sm_state_mgr_process ); + + /* + * The state lock prevents many race conditions from screwing + * up the state transition process. + */ + cl_spinlock_acquire( &p_sm_mgr->state_lock ); + + if( osm_log_is_active( p_sm_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_DEBUG, + "osm_sm_state_mgr_process: " + "Received signal %s in state %s\n", + osm_get_sm_mgr_signal_str( signal ), + osm_get_sm_mgr_state_str( p_sm_mgr->p_subn->sm_state ) ); + } + + switch ( p_sm_mgr->p_subn->sm_state ) + { + case IB_SMINFO_STATE_INIT: + switch ( signal ) + { + case OSM_SM_SIGNAL_INIT: + /* + * Update the state of the SM to DISCOVERING + */ + __osm_sm_state_mgr_discovering_msg( p_sm_mgr ); + p_sm_mgr->p_subn->sm_state = IB_SMINFO_STATE_DISCOVERING; + break; + + default: + __osm_sm_state_mgr_signal_error( p_sm_mgr, signal ); + status = IB_INVALID_PARAMETER; + break; + } + break; + + case IB_SMINFO_STATE_DISCOVERING: + switch ( signal ) + { + case OSM_SM_SIGNAL_DISCOVERY_COMPLETED: + /* + * Update the state of the SM to MASTER + */ + __osm_sm_state_mgr_master_msg( p_sm_mgr ); + /* Turn on the moved_to_master_state flag */ + p_sm_mgr->p_subn->moved_to_master_state = TRUE; + /* Turn on the first_time_master_sweep flag */ + if( p_sm_mgr->p_subn->first_time_master_sweep == FALSE ) + p_sm_mgr->p_subn->first_time_master_sweep = TRUE; + + p_sm_mgr->p_subn->sm_state = IB_SMINFO_STATE_MASTER; + /* + * Make sure to set the subnet master_sm_base_lid + * to the sm_base_lid value + */ + p_sm_mgr->p_subn->master_sm_base_lid = p_sm_mgr->p_subn->sm_base_lid; + break; + case OSM_SM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED: + /* + * Stop the discovering + */ + osm_state_mgr_process( p_sm_mgr->p_state_mgr, + OSM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED ); + break; + case OSM_SM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED_DONE: + /* + * Finished all discovery actions - move to STANDBY + * start the polling + */ + __osm_sm_state_mgr_standby_msg( p_sm_mgr ); + p_sm_mgr->p_subn->sm_state = IB_SMINFO_STATE_STANDBY; + /* + * Since another SM is doing the LFT config - we should not + * ignore the results of it + */ + p_sm_mgr->p_subn->ignore_existing_lfts = FALSE; + + __osm_sm_state_mgr_start_polling( p_sm_mgr ); + break; + case OSM_SM_SIGNAL_HANDOVER: + /* + * Do nothing. We will discover it later on. If we already discovered + * this SM, and got the HANDOVER - this means the remote SM is of + * lower priority. In this case we will stop polling it (since it is + * a lower priority SM in STANDBY state). + */ + break; + default: + __osm_sm_state_mgr_signal_error( p_sm_mgr, 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 + * no longer alive. + * case 2: Got a signal to move to DISCOVERING + * Move to DISCOVERING state, and start sweeping + */ + __osm_sm_state_mgr_discovering_msg( p_sm_mgr ); + p_sm_mgr->p_subn->sm_state = IB_SMINFO_STATE_DISCOVERING; + p_sm_mgr->p_subn->coming_out_of_standby = TRUE; + osm_state_mgr_process( p_sm_mgr->p_state_mgr, OSM_SIGNAL_EXIT_STBY ); + break; + case OSM_SM_SIGNAL_DISABLE: + /* + * Update the state to NOT_ACTIVE + */ + __osm_sm_state_mgr_notactive_msg( p_sm_mgr ); + p_sm_mgr->p_subn->sm_state = IB_SMINFO_STATE_NOTACTIVE; + break; + case OSM_SM_SIGNAL_HANDOVER: + /* + * Update state to MASTER, and start sweeping + * OPTIONAL: send ACKNOWLEDGE + */ + __osm_sm_state_mgr_master_msg( p_sm_mgr ); + /* Turn on the moved_to_master_state flag */ + p_sm_mgr->p_subn->moved_to_master_state = TRUE; + /* Turn on the first_time_master_sweep flag */ + if( p_sm_mgr->p_subn->first_time_master_sweep == FALSE ) + p_sm_mgr->p_subn->first_time_master_sweep = TRUE; + /* Turn on the force_immediate_heavy_sweep - we want a + * heavy sweep to occur on the first sweep of this SM. */ + p_sm_mgr->p_subn->force_immediate_heavy_sweep = TRUE; + + p_sm_mgr->p_subn->sm_state = IB_SMINFO_STATE_MASTER; + /* + * Make sure to set the subnet master_sm_base_lid + * to the sm_base_lid value + */ + p_sm_mgr->p_subn->master_sm_base_lid = p_sm_mgr->p_subn->sm_base_lid; + p_sm_mgr->p_subn->coming_out_of_standby = TRUE; + osm_state_mgr_process( p_sm_mgr->p_state_mgr, OSM_SIGNAL_EXIT_STBY ); + break; + case OSM_SM_SIGNAL_ACKNOWLEDGE: + /* + * Do nothing - already moved to STANDBY + */ + break; + default: + __osm_sm_state_mgr_signal_error( p_sm_mgr, 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 + */ + __osm_sm_state_mgr_standby_msg( p_sm_mgr ); + p_sm_mgr->p_subn->sm_state = IB_SMINFO_STATE_STANDBY; + __osm_sm_state_mgr_start_polling( p_sm_mgr ); + break; + default: + __osm_sm_state_mgr_signal_error( p_sm_mgr, 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( p_sm_mgr->p_log, OSM_LOG_VERBOSE, + "osm_sm_state_mgr_process: " + "Forcing immediate heavy sweep. " + "Received OSM_SM_SIGNAL_HANDOVER or OSM_SM_SIGNAL_POLLING_TIMEOUT\n" ); + p_sm_mgr->p_polling_sm = NULL; + p_sm_mgr->p_subn->force_immediate_heavy_sweep = TRUE; + osm_state_mgr_process( p_sm_mgr->p_state_mgr, OSM_SIGNAL_SWEEP ); + break; + case OSM_SM_SIGNAL_HANDOVER_SENT: + /* + * Just sent a HANDOVER signal - move to STANDBY + * start the polling + */ + __osm_sm_state_mgr_standby_msg( p_sm_mgr ); + p_sm_mgr->p_subn->sm_state = IB_SMINFO_STATE_STANDBY; + __osm_sm_state_mgr_start_polling( p_sm_mgr ); + break; + case OSM_SM_SIGNAL_WAIT_FOR_HANDOVER: + /* + * We found a remote master SM, and we are waiting for it + * to handover the mastership to us. Need to start polling + * on that SM, to make sure it is alive, if it isn't - then + * we should move back to discovering, since something must + * have happened to it. + */ + __osm_sm_state_mgr_start_polling( p_sm_mgr ); + break; + case OSM_SM_SIGNAL_DISCOVER: + __osm_sm_state_mgr_discovering_msg( p_sm_mgr ); + p_sm_mgr->p_subn->sm_state = IB_SMINFO_STATE_DISCOVERING; + break; + default: + __osm_sm_state_mgr_signal_error( p_sm_mgr, signal ); + status = IB_INVALID_PARAMETER; + break; + } + break; + + default: + osm_log( p_sm_mgr->p_log, OSM_LOG_ERROR, + "osm_sm_state_mgr_process: ERR 3208: " + "Invalid state %s\n", + osm_get_sm_mgr_state_str( p_sm_mgr->p_subn->sm_state ) ); + + } + + cl_spinlock_release( &p_sm_mgr->state_lock ); + + OSM_LOG_EXIT( p_sm_mgr->p_log ); + return ( status ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_state_mgr_check_legality( + IN osm_sm_state_mgr_t * const p_sm_mgr, + IN osm_sm_signal_t signal ) +{ + ib_api_status_t status = IB_SUCCESS; + + CL_ASSERT( p_sm_mgr ); + + OSM_LOG_ENTER( p_sm_mgr->p_log, osm_sm_state_mgr_check_legality ); + + /* + * The state lock prevents many race conditions from screwing + * up the state transition process. + */ + cl_spinlock_acquire( &p_sm_mgr->state_lock ); + + if( osm_log_is_active( p_sm_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_sm_mgr->p_log, OSM_LOG_DEBUG, + "osm_sm_state_mgr_check_legality: " + "Received signal %s in state %s\n", + osm_get_sm_mgr_signal_str( signal ), + osm_get_sm_mgr_state_str( p_sm_mgr->p_subn->sm_state ) ); + } + + switch ( p_sm_mgr->p_subn->sm_state ) + { + case IB_SMINFO_STATE_INIT: + switch ( signal ) + { + case OSM_SM_SIGNAL_INIT: + status = IB_SUCCESS; + break; + default: + __osm_sm_state_mgr_signal_error( p_sm_mgr, signal ); + status = IB_INVALID_PARAMETER; + break; + } + break; + + 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_MASTER_OR_HIGHER_SM_DETECTED_DONE: + case OSM_SM_SIGNAL_HANDOVER: + status = IB_SUCCESS; + break; + default: + __osm_sm_state_mgr_signal_error( p_sm_mgr, signal ); + status = IB_INVALID_PARAMETER; + break; + } + break; + + case IB_SMINFO_STATE_STANDBY: + switch ( signal ) + { + case OSM_SM_SIGNAL_POLLING_TIMEOUT: + case OSM_SM_SIGNAL_DISCOVER: + case OSM_SM_SIGNAL_DISABLE: + case OSM_SM_SIGNAL_HANDOVER: + case OSM_SM_SIGNAL_ACKNOWLEDGE: + status = IB_SUCCESS; + break; + default: + __osm_sm_state_mgr_signal_error( p_sm_mgr, signal ); + status = IB_INVALID_PARAMETER; + break; + } + break; + + case IB_SMINFO_STATE_NOTACTIVE: + switch ( signal ) + { + case OSM_SM_SIGNAL_STANDBY: + status = IB_SUCCESS; + break; + default: + __osm_sm_state_mgr_signal_error( p_sm_mgr, signal ); + status = IB_INVALID_PARAMETER; + break; + } + break; + + case IB_SMINFO_STATE_MASTER: + switch ( signal ) + { + case OSM_SM_SIGNAL_HANDOVER: + case OSM_SM_SIGNAL_HANDOVER_SENT: + status = IB_SUCCESS; + break; + default: + __osm_sm_state_mgr_signal_error( p_sm_mgr, signal ); + status = IB_INVALID_PARAMETER; + break; + } + break; + + default: + osm_log( p_sm_mgr->p_log, OSM_LOG_ERROR, + "osm_sm_state_mgr_check_legality: ERR 3209: " + "Invalid state %s\n", + osm_get_sm_mgr_state_str( p_sm_mgr->p_subn->sm_state ) ); + status = IB_INVALID_PARAMETER; + + } + + cl_spinlock_release( &p_sm_mgr->state_lock ); + + OSM_LOG_EXIT( p_sm_mgr->p_log ); + return ( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sminfo_rcv.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sminfo_rcv.c new file mode 100755 index 00000000..770b0ca9 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sminfo_rcv.c @@ -0,0 +1,768 @@ +/* + * 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: + * Implementation of osm_sminfo_rcv_t. + * This object represents the SMInfo Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_sminfo_rcv_construct( + IN osm_sminfo_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sminfo_rcv_destroy( + IN osm_sminfo_rcv_t* const p_rcv ) +{ + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_sminfo_rcv_destroy ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sminfo_rcv_init( + IN osm_sminfo_rcv_t* const p_rcv, + IN osm_subn_t* const p_subn, + IN osm_stats_t* const p_stats, + IN osm_resp_t* const p_resp, + IN osm_log_t* const p_log, + IN osm_state_mgr_t* const p_state_mgr, + IN osm_sm_state_mgr_t* const p_sm_state_mgr, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_sminfo_rcv_init ); + + osm_sminfo_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_stats = p_stats; + p_rcv->p_resp = p_resp; + p_rcv->p_state_mgr = p_state_mgr; + p_rcv->p_sm_state_mgr = p_sm_state_mgr; + + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + Return TRUE if the remote sm given (by ib_sm_info_t) is higher, + return FALSE otherwise. + By higher - we mean: SM with higher priority or with same priority + and lower GUID. +**********************************************************************/ +static inline boolean_t +__osm_sminfo_rcv_remote_sm_is_higher( + IN const osm_sminfo_rcv_t* p_rcv, + IN const ib_sm_info_t* p_remote_sm ) +{ + + return( osm_sm_is_greater_than( ib_sminfo_get_priority( p_remote_sm ), + p_remote_sm->guid, + p_rcv->p_subn->opt.sm_priority, + p_rcv->p_subn->sm_port_guid) ); + +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sminfo_rcv_process_get_request( + IN const osm_sminfo_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + uint8_t payload[IB_SMP_DATA_SIZE]; + ib_smp_t* p_smp; + ib_sm_info_t* p_smi = (ib_sm_info_t*)payload; + ib_api_status_t status; + ib_sm_info_t* p_remote_smi; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sminfo_rcv_process_get_request ); + + 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 = p_rcv->p_subn->sm_port_guid; + p_smi->act_count = cl_hton32( p_rcv->p_stats->qp0_mads_sent ); + p_smi->pri_state = (uint8_t)(p_rcv->p_subn->sm_state | + p_rcv->p_subn->opt.sm_priority << 4); + /* + p.750 row 11 - 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( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sminfo_rcv_process_get_request: " + "Responding to master SM with real sm_key\n" ); + p_smi->sm_key = p_rcv->p_subn->opt.sm_key; + } + else + { + /* The requester is not authenticated as master - set sm_key to zero. */ + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sminfo_rcv_process_get_request: " + "Responding to SM not master with zero sm_key\n" ); + p_smi->sm_key = 0; + } + + status = osm_resp_send( p_rcv->p_resp, p_madw, 0, payload ); + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_get_request: ERR 2F02: " + "Error sending response (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + * Check if the p_smp received is legal. + * Current checks: + * MADHeader:AttributeModifiers 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 is matching. + **********************************************************************/ +static ib_api_status_t +__osm_sminfo_rcv_check_set_req_legality( + IN const ib_smp_t* const p_smp ) +{ + ib_sm_info_t* p_smi; + + p_smi = ib_smp_get_payload_ptr( p_smp ); + + if (p_smp->attr_mod == IB_SMINFO_ATTR_MOD_ACKNOWLEDGE) + { + if ( ib_sminfo_get_state( p_smi ) == IB_SMINFO_STATE_STANDBY ) + { + return( IB_SUCCESS ); + } + } + else if ( p_smp->attr_mod == IB_SMINFO_ATTR_MOD_HANDOVER || + p_smp->attr_mod == IB_SMINFO_ATTR_MOD_DISABLE || + p_smp->attr_mod == IB_SMINFO_ATTR_MOD_STANDBY || + p_smp->attr_mod == IB_SMINFO_ATTR_MOD_DISCOVER ) + { + if ( ib_sminfo_get_state( p_smi ) == IB_SMINFO_STATE_MASTER ) + { + return( IB_SUCCESS ); + } + } + + return( IB_INVALID_PARAMETER ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sminfo_rcv_process_set_request( + IN const osm_sminfo_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + uint8_t payload[IB_SMP_DATA_SIZE]; + ib_smp_t* p_smp; + ib_sm_info_t* p_smi = (ib_sm_info_t*)payload; + ib_sm_info_t* p_rcv_smi; + ib_api_status_t status; + osm_sm_signal_t sm_signal; + ib_sm_info_t* p_remote_smi; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sminfo_rcv_process_set_request ); + + CL_ASSERT( p_madw ); + + /* + No real need to grab the lock for this function. + */ + memset( payload, 0, sizeof( payload ) ); + + /* get the lock */ + CL_PLOCK_EXCL_ACQUIRE( p_rcv->p_lock ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_rcv_smi = ib_smp_get_payload_ptr( p_smp ); + + if( p_smp->method != IB_MAD_METHOD_SET ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_set_request: ERR 2F03: " + "Unsupported method 0x%X\n", + p_smp->method ); + CL_PLOCK_RELEASE( p_rcv->p_lock ); + goto Exit; + } + + p_smi->guid = p_rcv->p_subn->sm_port_guid; + p_smi->act_count = cl_hton32( p_rcv->p_stats->qp0_mads_sent ); + p_smi->pri_state = (uint8_t)(p_rcv->p_subn->sm_state | + p_rcv->p_subn->opt.sm_priority << 4); + /* + p.750 row 11 - 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( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sminfo_rcv_process_set_request: " + "Responding to master SM with real sm_key\n" ); + p_smi->sm_key = p_rcv->p_subn->opt.sm_key; + } + else + { + /* The requester is not authenticated as master - set sm_key to zero. */ + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sminfo_rcv_process_set_request: " + "Responding to SM not master with zero sm_key\n" ); + p_smi->sm_key = 0; + } + + /* Check the legality of the packet */ + status = __osm_sminfo_rcv_check_set_req_legality( p_smp ); + if ( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_set_request: 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( p_rcv_smi ) ) ); + /* send a response with error code */ + status = osm_resp_send( p_rcv->p_resp, p_madw, 7, payload ); + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_set_request: ERR 2F05: " + "Error sending response (%s)\n", + ib_get_err_str( status ) ); + } + CL_PLOCK_RELEASE( p_rcv->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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_set_request: ERR 2F06: " + "THIS CODE SHOULD NOT BE REACHED!!\n"); + CL_PLOCK_RELEASE( p_rcv->p_lock ); + goto Exit; + } + + /* check legality of the needed transition in the SM state machine */ + status = osm_sm_state_mgr_check_legality( p_rcv->p_sm_state_mgr, + sm_signal ); + if ( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_set_request: ERR 2F07: " + "Check legality of SM needed transition. AttributeModifier:0x%X RemoteState:%s\n", + p_smp->attr_mod, + osm_get_sm_mgr_state_str(ib_sminfo_get_state( p_rcv_smi ) ) ); + /* send a response with error code */ + status = osm_resp_send( p_rcv->p_resp, p_madw, 7, payload ); + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_set_request: ERR 2F08: " + "Error sending response (%s)\n", + ib_get_err_str( status ) ); + } + CL_PLOCK_RELEASE( p_rcv->p_lock ); + goto Exit; + } + + /* the SubnSet(SMInfo) command is ok. Send a response. */ + status = osm_resp_send( p_rcv->p_resp, p_madw, 0, payload ); + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_set_request: 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 */ + /* p_sm_state_mgr in the master_guid variable - the guid of the */ + /* current master. */ + if ( p_smp->attr_mod == IB_SMINFO_ATTR_MOD_STANDBY ) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_sminfo_rcv_process_set_request: " + "Received a STANDBY signal. Updating " + "sm_state_mgr master_guid: 0x%016" PRIx64 "\n", + cl_ntoh64(p_rcv_smi->guid) ); + p_rcv->p_sm_state_mgr->master_guid = p_rcv_smi->guid; + } + + /* call osm_sm_state_mgr_process with the received signal. */ + CL_PLOCK_RELEASE( p_rcv->p_lock ); + status = osm_sm_state_mgr_process( p_rcv->p_sm_state_mgr, + sm_signal ); + + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_set_request: ERR 2F10: " + "Error in SM state transition (%s)\n", + ib_get_err_str( status ) ); + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + * Return a signal with which to call the osm_state_mgr_process. + * This is done since we are locked by p_rcv->p_lock in this function, + * and thus cannot call osm_state_mgr_process (that locks the state_lock). + * If return OSM_SIGNAL_NONE - do not call osm_state_mgr_process. + **********************************************************************/ +static osm_signal_t +__osm_sminfo_rcv_process_get_sm( + IN const osm_sminfo_rcv_t* const p_rcv, + IN const osm_remote_sm_t* const p_sm ) +{ + const ib_sm_info_t* p_smi; + osm_signal_t ret_val = OSM_SIGNAL_NONE; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sminfo_rcv_process_get_sm ); + + p_smi = &p_sm->smi; + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_sminfo_rcv_process_get_sm: " + "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( p_rcv->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: + ret_val = OSM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED; + /* save on the p_sm_state_mgr the guid of the current master. */ + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_sminfo_rcv_process_get_sm: " + "Found master SM. Updating sm_state_mgr master_guid: 0x%016" PRIx64 "\n", + cl_ntoh64( p_sm->p_port->guid ) ); + p_rcv->p_sm_state_mgr->master_guid = p_sm->p_port->guid; + break; + case IB_SMINFO_STATE_DISCOVERING: + case IB_SMINFO_STATE_STANDBY: + if ( __osm_sminfo_rcv_remote_sm_is_higher(p_rcv, p_smi) == TRUE ) + { + /* the remote is a higher sm - need to stop sweeping */ + ret_val = OSM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED; + /* save on the p_sm_state_mgr the guid of the higher SM we found - */ + /* we will poll it - as long as it lives - we should be in Standby. */ + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_sminfo_rcv_process_get_sm: " + "Found higher SM. Updating sm_state_mgr master_guid:" + " 0x%016" PRIx64 "\n", + cl_ntoh64(p_sm->p_port->guid) ); + p_rcv->p_sm_state_mgr->master_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( p_rcv->p_sm_state_mgr ); + 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 (p_rcv->p_sm_state_mgr->master_guid == p_sm->p_port->guid) + { + /* Make sure that it is an SM with higher priority than us. + If we started polling it when it was master, and it moved + to standby - then it might be with a lower priority than + us - and then we don't want to continue polling it. */ + if ( __osm_sminfo_rcv_remote_sm_is_higher(p_rcv, p_smi) == TRUE ) + osm_sm_state_mgr_signal_master_is_alive( p_rcv->p_sm_state_mgr ); + } + 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 ( p_rcv->p_sm_state_mgr->p_polling_sm != NULL ) + { + osm_sm_state_mgr_signal_master_is_alive( p_rcv->p_sm_state_mgr ); + } + 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; + default: + /* any other state - do nothing */ + break; + } + break; + + default: + break; + } + + OSM_LOG_EXIT( p_rcv->p_log ); + return ret_val; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sminfo_rcv_process_get_response( + IN const osm_sminfo_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_smp_t* p_smp; + const ib_sm_info_t* p_smi; + cl_qmap_t* p_sm_tbl; + cl_qmap_t* p_port_tbl; + osm_port_t* p_port; + ib_net64_t port_guid; + osm_remote_sm_t* p_sm; + osm_signal_t process_get_sm_ret_val = OSM_SIGNAL_NONE; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sminfo_rcv_process_get_response ); + + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + + if( p_smp->method != IB_MAD_METHOD_GET_RESP ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_get_response: ERR 2F11: " + "Unsupported method 0x%X\n", + p_smp->method ); + goto Exit; + } + + p_smi = ib_smp_get_payload_ptr( p_smp ); + p_sm_tbl = &p_rcv->p_subn->sm_guid_tbl; + p_port_tbl = &p_rcv->p_subn->port_guid_tbl; + port_guid = p_smi->guid; + + osm_dump_sm_info( p_rcv->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 != p_rcv->p_subn->opt.sm_key ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_get_response: ERR 2F18: " + "Got SM with sm_key that doesn't match our " + "local key. Exiting\n" ); + osm_log( p_rcv->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( p_rcv->p_lock ); + + p_port = (osm_port_t*)cl_qmap_get( p_port_tbl, port_guid ); + if( p_port == (osm_port_t*)cl_qmap_end( p_port_tbl ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_get_response: ERR 2F12: " + "No port object for this SM\n" ); + goto Exit; + } + + if( osm_port_get_guid( p_port ) != p_smi->guid ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_get_response: 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 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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_get_response: ERR 2F14: " + "Unable to allocate SM object\n" ); + goto 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; + } + + process_get_sm_ret_val = __osm_sminfo_rcv_process_get_sm( p_rcv, p_sm ); + + Exit: + CL_PLOCK_RELEASE( p_rcv->p_lock ); + + /* If process_get_sm_ret_val != OSM_SIGNAL_NONE then we have to signal + * to the state_mgr with that signal. */ + if (process_get_sm_ret_val != OSM_SIGNAL_NONE) + osm_state_mgr_process( p_rcv->p_state_mgr, + process_get_sm_ret_val ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sminfo_rcv_process_set_response( + IN const osm_sminfo_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_smp_t* p_smp; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sminfo_rcv_process_set_response ); + + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + + if( p_smp->method != IB_MAD_METHOD_GET_RESP ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_set_response: ERR 2F16: " + "Unsupported method 0x%X\n", + p_smp->method ); + goto Exit; + } + + /* Check the AttributeModifier */ + if ( p_smp->attr_mod != IB_SMINFO_ATTR_MOD_HANDOVER ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sminfo_rcv_process_set_response: 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( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sminfo_rcv_process( + IN const osm_sminfo_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ) +{ + ib_smp_t *p_smp; + osm_smi_context_t *p_smi_context; + + OSM_LOG_ENTER( p_rcv->p_log, osm_sminfo_rcv_process ); + + 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 ) ) + { + /* 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 ); + if ( p_smi_context->set_method == FALSE ) + { + /* this is a response to a Get method */ + __osm_sminfo_rcv_process_get_response( p_rcv, p_madw ); + } + else + { + /* this is a response to a Set method */ + __osm_sminfo_rcv_process_set_response( p_rcv, p_madw ); + } + } + else + { + /* This is a request */ + if ( p_smp->method == IB_MAD_METHOD_GET ) + { + /* This is a SubnGet request */ + __osm_sminfo_rcv_process_get_request( p_rcv, p_madw ); + } + else + { + /* This is a SubnSet request */ + __osm_sminfo_rcv_process_set_request( p_rcv, p_madw ); + } + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sminfo_rcv_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sminfo_rcv_ctrl.c new file mode 100644 index 00000000..61f444f0 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sminfo_rcv_ctrl.c @@ -0,0 +1,127 @@ +/* + * 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: + * Implementation of osm_sminfo_rcv_ctrl_t. + * This object represents the SMInfo request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_sminfo_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_sminfo_rcv_process( ((osm_sminfo_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sminfo_rcv_ctrl_construct( + IN osm_sminfo_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_sminfo_rcv_ctrl_destroy( + IN osm_sminfo_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sminfo_rcv_ctrl_init( + IN osm_sminfo_rcv_ctrl_t* const p_ctrl, + IN osm_sminfo_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_sminfo_rcv_ctrl_init ); + + osm_sminfo_rcv_ctrl_construct( p_ctrl ); + + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_SM_INFO, + __osm_sminfo_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_sminfo_rcv_ctrl_init: ERR 3001: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_state_mgr.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_state_mgr.c new file mode 100644 index 00000000..19ec46f0 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_state_mgr.c @@ -0,0 +1,2986 @@ +/* + * 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: + * Implementation of osm_state_mgr_t. + * This file implements the State Manager object. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.13 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SUBNET_LIST_FILENAME "/osm-subnet.lst" + +osm_signal_t osm_qos_setup(IN osm_opensm_t * p_osm); + +/********************************************************************** + **********************************************************************/ +void +osm_state_mgr_construct( + IN osm_state_mgr_t * const p_mgr ) +{ + memset( p_mgr, 0, sizeof( *p_mgr ) ); + cl_spinlock_construct( &p_mgr->state_lock ); + cl_spinlock_construct( &p_mgr->idle_lock ); + p_mgr->state = OSM_SM_STATE_INIT; +} + +/********************************************************************** + **********************************************************************/ +void +osm_state_mgr_destroy( + IN osm_state_mgr_t * const p_mgr ) +{ + CL_ASSERT( p_mgr ); + + OSM_LOG_ENTER( p_mgr->p_log, osm_state_mgr_destroy ); + + /* destroy the locks */ + cl_spinlock_destroy( &p_mgr->state_lock ); + cl_spinlock_destroy( &p_mgr->idle_lock ); + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_state_mgr_init( + IN osm_state_mgr_t * const p_mgr, + IN osm_subn_t * const p_subn, + IN osm_lid_mgr_t * const p_lid_mgr, + IN osm_ucast_mgr_t * const p_ucast_mgr, + IN osm_mcast_mgr_t * const p_mcast_mgr, + IN osm_link_mgr_t * const p_link_mgr, + IN osm_drop_mgr_t * const p_drop_mgr, + IN osm_req_t * const p_req, + IN osm_stats_t * const p_stats, + IN osm_sm_state_mgr_t * const p_sm_state_mgr, + IN const osm_sm_mad_ctrl_t * const p_mad_ctrl, + IN cl_plock_t * const p_lock, + IN cl_event_t * const p_subnet_up_event, + IN osm_log_t * const p_log ) +{ + cl_status_t status; + + OSM_LOG_ENTER( p_log, osm_state_mgr_init ); + + CL_ASSERT( p_subn ); + CL_ASSERT( p_lid_mgr ); + CL_ASSERT( p_ucast_mgr ); + CL_ASSERT( p_mcast_mgr ); + CL_ASSERT( p_link_mgr ); + CL_ASSERT( p_drop_mgr ); + CL_ASSERT( p_req ); + CL_ASSERT( p_stats ); + CL_ASSERT( p_sm_state_mgr ); + CL_ASSERT( p_mad_ctrl ); + CL_ASSERT( p_lock ); + + osm_state_mgr_construct( p_mgr ); + + p_mgr->p_log = p_log; + p_mgr->p_subn = p_subn; + p_mgr->p_lid_mgr = p_lid_mgr; + p_mgr->p_ucast_mgr = p_ucast_mgr; + p_mgr->p_mcast_mgr = p_mcast_mgr; + p_mgr->p_link_mgr = p_link_mgr; + p_mgr->p_drop_mgr = p_drop_mgr; + p_mgr->p_mad_ctrl = p_mad_ctrl; + p_mgr->p_req = p_req; + p_mgr->p_stats = p_stats; + p_mgr->p_sm_state_mgr = p_sm_state_mgr; + p_mgr->state = OSM_SM_STATE_IDLE; + p_mgr->p_lock = p_lock; + p_mgr->p_subnet_up_event = p_subnet_up_event; + p_mgr->state_step_mode = OSM_STATE_STEP_CONTINUOUS; + p_mgr->next_stage_signal = OSM_SIGNAL_NONE; + + status = cl_spinlock_init( &p_mgr->state_lock ); + if( status != CL_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_state_mgr_init: ERR 3301: " + "Spinlock init failed (%s)\n", CL_STATUS_MSG( status ) ); + } + + cl_qlist_init( &p_mgr->idle_time_list ); + + status = cl_spinlock_init( &p_mgr->idle_lock ); + if( status != CL_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_state_mgr_init: ERR 3302: " + "Spinlock init failed (%s)\n", CL_STATUS_MSG( status ) ); + } + + OSM_LOG_EXIT( p_mgr->p_log ); + return ( status ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_up_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + /* + * This message should be written only once - when the + * SM moves to Master state and the subnet is up for + * the first time. The change of state is marked with + * the subnet flag moved_to_master_state + */ + if( p_mgr->p_subn->moved_to_master_state == TRUE ) + { + osm_log( p_mgr->p_log, OSM_LOG_SYS, "SUBNET UP\n" ); /* Format Waived */ + /* clear the signal */ + p_mgr->p_subn->moved_to_master_state = FALSE; + } + else + { + osm_log( p_mgr->p_log, OSM_LOG_INFO, "SUBNET UP\n" ); /* Format Waived */ + } + + if( p_mgr->p_subn->opt.sweep_interval ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_up_msg: " + "\n\n\n********************************" + "**********************************\n" + "**************************** SUBNET UP " + "***************************\n" + "**************************************" + "****************************\n\n\n" ); + } + else + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_up_msg: " + "\n\n\n********************************" + "**********************************\n" + "******************* SUBNET UP " + "(sweep disabled) *******************\n" + "**************************************" + "****************************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_init_errors_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + osm_log( p_mgr->p_log, OSM_LOG_SYS, "Errors during initialization\n" ); /* Format Waived */ + + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_init_errors_msg: " + "\n\n\n********************************" + "**********************************\n" + "****************** ERRORS DURING INITI" + "ALIZATION ******************\n" + "**************************************" + "****************************\n\n\n" ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_light_sweep_done_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_light_sweep_done_msg: " + "\n\n\n********************************" + "**********************************\n" + "********************** LIGHT SWEEP " + "COMPLETE **********************\n" + "**************************************" + "****************************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_standby_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_standby_msg: " + "\n\n\n********************************" + "**********************************\n" + "******************** ENTERING STANDBY" + " STATE **********************\n" + "**************************************" + "****************************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_sm_port_down_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + osm_log( p_mgr->p_log, OSM_LOG_SYS, "SM port is down\n" ); /* Format Waived */ + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_sm_port_down_msg: " + "\n\n\n********************************" + "**********************************\n" + "************************** SM PORT DOWN " + "**************************\n" + "**************************************" + "****************************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_lid_assign_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_lid_assign_msg: " + "\n\n\n**************************************" + "****************************\n" + "***** LID ASSIGNMENT COMPLETE - STARTING SWITC" + "H TABLE CONFIG *****\n" + "*********************************************" + "*********************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_set_sm_lid_done_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_set_sm_lid_done_msg: " + "\n\n\n**************************************" + "****************************\n" + "**** SM LID ASSIGNMENT COMPLETE - STARTING SUBN" + "ET LID CONFIG *****\n" + "*********************************************" + "*********************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_switch_config_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_switch_config_msg: " + "\n\n\n**************************************" + "****************************\n" + "***************** SWITCHES CONFIGURED FOR UNICAST " + "****************\n" + "*********************************************" + "*********************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_multicast_config_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_multicast_config_msg: " + "\n\n\n**************************************" + "****************************\n" + "**************** SWITCHES CONFIGURED FOR MULTICAST " + "***************\n" + "*********************************************" + "*********************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_links_ports_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_links_ports_msg: " + "\n\n\n**************************************" + "****************************\n" + "******* LINKS PORTS CONFIGURED - SET LINKS TO ARMED " + "STATE ********\n" + "*********************************************" + "*********************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_links_armed_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_links_armed_msg: " + "\n\n\n**************************************" + "****************************\n" + "************* LINKS ARMED - SET LINKS TO ACTIVE " + "STATE ************\n" + "*********************************************" + "*********************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_sweep_heavy_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_sweep_heavy_msg: " + "\n\n\n**************************************" + "****************************\n" + "******************** INITIATING HEAVY SWEEP " + "**********************\n" + "*********************************************" + "*********************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_sweep_heavy_done_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_sweep_heavy_done_msg: " + "\n\n\n**************************************" + "****************************\n" + "********************* HEAVY SWEEP COMPLETE " + "***********************\n" + "*********************************************" + "*********************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_sweep_light_msg( + IN const osm_state_mgr_t * p_mgr ) +{ + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_sweep_light_msg: " + "\n\n\n**************************************" + "****************************\n" + "******************** INITIATING LIGHT SWEEP " + "**********************\n" + "*********************************************" + "*********************\n\n\n" ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_signal_warning( + IN const osm_state_mgr_t * const p_mgr, + IN const osm_signal_t signal ) +{ + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_signal_warning: " + "Invalid signal %s(%lu) in state %s\n", + osm_get_sm_signal_str( signal ), + signal, osm_get_sm_state_str( p_mgr->state ) ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_signal_error( + IN const osm_state_mgr_t * const p_mgr, + IN const osm_signal_t signal ) +{ + /* the Request for IDLE processing can come async to the state so it + * really is just verbose ... */ + if( signal == OSM_SIGNAL_IDLE_TIME_PROCESS_REQUEST ) + __osm_state_mgr_signal_warning( p_mgr, signal ); + else + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_signal_error: ERR 3303: " + "Invalid signal %s(%lu) in state %s\n", + osm_get_sm_signal_str( signal ), + signal, osm_get_sm_state_str( p_mgr->state ) ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_reset_node_count( + IN cl_map_item_t * const p_map_item, + IN void *context ) +{ + osm_node_t *p_node = ( osm_node_t * ) p_map_item; + osm_state_mgr_t *const p_mgr = ( osm_state_mgr_t * ) context; + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_state_mgr_reset_node_count: " + "Resetting discovery count for node 0x%" PRIx64 "\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) ) ); + } + + osm_node_discovery_count_reset( p_node ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_reset_port_count( + IN cl_map_item_t * const p_map_item, + IN void *context ) +{ + osm_port_t *p_port = ( osm_port_t * ) p_map_item; + osm_state_mgr_t *const p_mgr = ( osm_state_mgr_t * ) context; + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_state_mgr_reset_port_count: " + "Resetting discovery count for port 0x%" PRIx64 "\n", + cl_ntoh64( osm_port_get_guid( p_port ) ) ); + } + + osm_port_discovery_count_reset( p_port ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_reset_switch_count( + IN cl_map_item_t * const p_map_item, + IN void *context ) +{ + osm_switch_t *p_sw = ( osm_switch_t * ) p_map_item; + osm_state_mgr_t *const p_mgr = ( osm_state_mgr_t * ) context; + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_state_mgr_reset_switch_count: " + "Resetting discovery count for switch 0x%" PRIx64 "\n", + cl_ntoh64( osm_node_get_node_guid( p_sw->p_node ) ) ); + } + + osm_switch_discovery_count_reset( p_sw ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_get_sw_info( + IN cl_map_item_t * const p_object, + IN void *context ) +{ + osm_node_t *p_node; + osm_dr_path_t *p_dr_path; + osm_madw_context_t mad_context; + osm_switch_t *const p_sw = ( osm_switch_t * ) p_object; + osm_state_mgr_t *const p_mgr = ( osm_state_mgr_t * ) context; + ib_api_status_t status; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_state_mgr_get_sw_info ); + + p_node = osm_switch_get_node_ptr( p_sw ); + p_dr_path = osm_node_get_any_dr_path_ptr( p_node ); + + memset( &context, 0, sizeof( 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( p_mgr->p_req, + p_dr_path, + IB_MAD_ATTR_SWITCH_INFO, + 0, OSM_MSG_LIGHT_SWEEP_FAIL, &mad_context ); + + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_get_sw_info: ERR 3304: " + "Request SwitchInfo failed\n" ); + } + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + Initiate a remote port info request for the given physical port + **********************************************************************/ +static void +__osm_state_mgr_get_remote_port_info( + IN osm_state_mgr_t * const p_mgr, + IN osm_physp_t * const p_physp ) +{ + osm_dr_path_t *p_dr_path; + osm_dr_path_t rem_node_dr_path; + osm_madw_context_t mad_context; + ib_api_status_t status; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_state_mgr_get_remote_port_info ); + + /* generate a dr path leaving on the physp to the remote node */ + p_dr_path = osm_physp_get_dr_path_ptr( p_physp ); + memcpy( &rem_node_dr_path, p_dr_path, sizeof( osm_dr_path_t ) ); + osm_dr_path_extend( &rem_node_dr_path, osm_physp_get_port_num( p_physp ) ); + + memset( &mad_context, 0, sizeof( mad_context ) ); + + mad_context.pi_context.node_guid = + osm_node_get_node_guid( osm_physp_get_node_ptr( p_physp ) ); + mad_context.pi_context.port_guid = + cl_hton64( osm_physp_get_port_num( p_physp ) ); + mad_context.pi_context.set_method = FALSE; + mad_context.pi_context.light_sweep = TRUE; + mad_context.pi_context.ignore_errors = FALSE; + mad_context.pi_context.update_master_sm_base_lid = FALSE; + 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( p_mgr->p_req, + &rem_node_dr_path, + IB_MAD_ATTR_PORT_INFO, + 0, CL_DISP_MSGID_NONE, &mad_context ); + + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_get_remote_port_info: ERR 332E: " + "Request for PortInfo failed\n" ); + } + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + Initiates a thorough sweep of the subnet. + Used when there is suspicion that something on the subnet has changed. +**********************************************************************/ +static ib_api_status_t +__osm_state_mgr_sweep_hop_0( + IN osm_state_mgr_t * const p_mgr ) +{ + ib_api_status_t status; + osm_dr_path_t dr_path; + osm_bind_handle_t h_bind; + osm_ni_context_t ni_context; + uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX]; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_state_mgr_sweep_hop_0 ); + + memset( path_array, 0, sizeof( path_array ) ); + + /* + * First, get the bind handle. + */ + h_bind = osm_sm_mad_ctrl_get_bind_handle( p_mgr->p_mad_ctrl ); + if( h_bind != OSM_BIND_INVALID_HANDLE ) + { + __osm_state_mgr_sweep_heavy_msg( p_mgr ); + + /* + * Start the sweep by clearing the port counts, then + * get our own NodeInfo at 0 hops. + */ + CL_PLOCK_ACQUIRE( p_mgr->p_lock ); + + cl_qmap_apply_func( &p_mgr->p_subn->node_guid_tbl, + __osm_state_mgr_reset_node_count, p_mgr ); + + cl_qmap_apply_func( &p_mgr->p_subn->port_guid_tbl, + __osm_state_mgr_reset_port_count, p_mgr ); + + cl_qmap_apply_func( &p_mgr->p_subn->sw_guid_tbl, + __osm_state_mgr_reset_switch_count, p_mgr ); + + /* 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. */ + p_mgr->p_subn->in_sweep_hop_0 = TRUE; + + CL_PLOCK_RELEASE( p_mgr->p_lock ); + + memset( &ni_context, 0, sizeof( ni_context ) ); + osm_dr_path_init( &dr_path, h_bind, 0, path_array ); + status = osm_req_get( p_mgr->p_req, + &dr_path, + IB_MAD_ATTR_NODE_INFO, + 0, CL_DISP_MSGID_NONE, NULL ); + + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_sweep_hop_0: ERR 3305: " + "Request NodeInfo failed\n" ); + } + } + else + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_state_mgr_sweep_hop_0: " + "No bound ports. Deferring sweep...\n" ); + status = IB_INVALID_STATE; + } + + OSM_LOG_EXIT( p_mgr->p_log ); + return ( status ); +} + +/********************************************************************** + Clear out all existing port lid assignments +**********************************************************************/ +static ib_api_status_t +__osm_state_mgr_clean_known_lids( + IN osm_state_mgr_t * const p_mgr ) +{ + ib_api_status_t status = IB_SUCCESS; + cl_ptr_vector_t *p_vec = &( p_mgr->p_subn->port_lid_tbl ); + uint32_t i; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_state_mgr_clean_known_lids ); + + /* we need a lock here! */ + CL_PLOCK_ACQUIRE( p_mgr->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( p_mgr->p_lock ); + + OSM_LOG_EXIT( p_mgr->p_log ); + return ( status ); +} + +/********************************************************************** + Notifies the transport layer that the local LID has changed, + which give it a chance to update address vectors, etc.. +**********************************************************************/ +static ib_api_status_t +__osm_state_mgr_notify_lid_change( + IN osm_state_mgr_t * const p_mgr ) +{ + ib_api_status_t status; + osm_bind_handle_t h_bind; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_state_mgr_notify_lid_change ); + + /* + * First, get the bind handle. + */ + h_bind = osm_sm_mad_ctrl_get_bind_handle( p_mgr->p_mad_ctrl ); + if( h_bind == OSM_BIND_INVALID_HANDLE ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_notify_lid_change: 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( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_notify_lid_change: ERR 3307: " + "Vendor LID update failed (%s)\n", ib_get_err_str( status ) ); + } + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); + return ( status ); +} + +/********************************************************************** + Returns true if the SM port is down. + The SM's port object must exist in the port_guid table. +**********************************************************************/ +static boolean_t +__osm_state_mgr_is_sm_port_down( + IN osm_state_mgr_t * const p_mgr ) +{ + ib_net64_t port_guid; + osm_port_t *p_port; + osm_physp_t *p_physp; + cl_qmap_t *p_tbl; + uint8_t state; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_state_mgr_is_sm_port_down ); + + port_guid = p_mgr->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( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_is_sm_port_down: ERR 3308: " + "SM port GUID unknown\n" ); + state = IB_LINK_DOWN; + goto Exit; + } + + p_tbl = &p_mgr->p_subn->port_guid_tbl; + + CL_ASSERT( port_guid ); + + CL_PLOCK_ACQUIRE( p_mgr->p_lock ); + p_port = ( osm_port_t * ) cl_qmap_get( p_tbl, port_guid ); + if( p_port == ( osm_port_t * ) cl_qmap_end( p_tbl ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_is_sm_port_down: ERR 3309: " + "SM port with GUID:%016" PRIx64 " is unknown\n", + cl_ntoh64( port_guid ) ); + state = IB_LINK_DOWN; + CL_PLOCK_RELEASE( p_mgr->p_lock ); + goto Exit; + } + + p_physp = osm_port_get_default_phys_ptr( p_port ); + + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + + state = osm_physp_get_port_state( p_physp ); + CL_PLOCK_RELEASE( p_mgr->p_lock ); + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); + return ( state == IB_LINK_DOWN ); +} + +/********************************************************************** + Sweeps the node 1 hop away. + This sets off a "chain reaction" that causes discovery of the subnet. + Used when there is suspicion that something on the subnet has changed. +**********************************************************************/ +static ib_api_status_t +__osm_state_mgr_sweep_hop_1( + IN osm_state_mgr_t * const p_mgr ) +{ + 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; + cl_qmap_t *p_port_tbl; + uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX]; + uint8_t num_ports; + osm_physp_t *p_ext_physp; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_state_mgr_sweep_hop_1 ); + + /* + * First, get our own port and node objects. + */ + p_port_tbl = &p_mgr->p_subn->port_guid_tbl; + port_guid = p_mgr->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. */ + p_mgr->p_subn->in_sweep_hop_0 = FALSE; + + p_port = ( osm_port_t * ) cl_qmap_get( p_port_tbl, port_guid ); + if( p_port == ( osm_port_t * ) cl_qmap_end( p_port_tbl ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_sweep_hop_1: ERR 3310: " + "No SM port object\n" ); + status = IB_ERROR; + goto Exit; + } + + p_node = osm_port_get_parent_node( p_port ); + CL_ASSERT( p_node ); + + port_num = ib_node_info_get_local_port_num( &p_node->node_info ); + + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_state_mgr_sweep_hop_1: " + "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 ); + CL_ASSERT( osm_physp_is_valid( 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: + 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( p_mgr->p_req, + &hop_1_path, + IB_MAD_ATTR_NODE_INFO, + 0, CL_DISP_MSGID_NONE, &context ); + + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_sweep_hop_1: ERR 3311: " + "Request 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 ); + /* Make sure the physp object exists */ + if( !p_ext_physp ) + continue; + if( ib_port_info_get_port_state( &( p_ext_physp->port_info ) ) > + IB_LINK_DOWN ) + { + 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( p_mgr->p_req, + &hop_1_path, + IB_MAD_ATTR_NODE_INFO, + 0, CL_DISP_MSGID_NONE, &context ); + + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_sweep_hop_1: ERR 3312: " + "Request NodeInfo failed\n" ); + } + } + } + break; + + default: + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_sweep_hop_1: ERR 3313: Unknown node type %d\n", + osm_node_get_type( p_node ) ); + } + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); + return ( status ); +} + +/********************************************************************** + Initiates a lightweight sweep of the subnet. + Used during normal sweeps after the subnet is up. +**********************************************************************/ +static ib_api_status_t +__osm_state_mgr_light_sweep_start( + IN osm_state_mgr_t * const p_mgr ) +{ + ib_api_status_t status = IB_SUCCESS; + osm_bind_handle_t h_bind; + cl_qmap_t *p_sw_tbl; + cl_list_t *p_no_rem_port_list; + cl_list_iterator_t list_iter; + uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX]; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_state_mgr_light_sweep_start ); + + p_sw_tbl = &p_mgr->p_subn->sw_guid_tbl; + + memset( path_array, 0, sizeof( path_array ) ); + + /* + * First, get the bind handle. + */ + h_bind = osm_sm_mad_ctrl_get_bind_handle( p_mgr->p_mad_ctrl ); + if( h_bind != OSM_BIND_INVALID_HANDLE ) + { + __osm_state_mgr_sweep_light_msg( p_mgr ); + CL_PLOCK_ACQUIRE( p_mgr->p_lock ); + cl_qmap_apply_func( p_sw_tbl, __osm_state_mgr_get_sw_info, p_mgr ); + CL_PLOCK_RELEASE( p_mgr->p_lock ); + + /* now scan the list of physical ports that were not down but have no remote port */ + CL_PLOCK_ACQUIRE( p_mgr->p_lock ); + p_no_rem_port_list = &p_mgr->p_subn->light_sweep_physp_list; + list_iter = cl_list_head( p_no_rem_port_list ); + while( list_iter != cl_list_end( p_no_rem_port_list ) ) + { + __osm_state_mgr_get_remote_port_info( p_mgr, + ( osm_physp_t * ) + cl_list_obj( list_iter ) ); + list_iter = cl_list_next( list_iter ); + } + CL_PLOCK_RELEASE( p_mgr->p_lock ); + } + else + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_state_mgr_light_sweep_start: " + "No bound ports. Deferring sweep...\n" ); + status = IB_INVALID_STATE; + } + + OSM_LOG_EXIT( p_mgr->p_log ); + return ( status ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_topology_file_create( + IN osm_state_mgr_t * const p_mgr ) +{ + const osm_node_t *p_node; + char *file_name; + FILE *rc; + char desc[IB_NODE_DESCRIPTION_SIZE + 1]; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_topology_file_create ); + + CL_PLOCK_ACQUIRE( p_mgr->p_lock ); + + file_name = + ( char * )malloc( strlen( p_mgr->p_subn->opt.dump_files_dir ) + + strlen(SUBNET_LIST_FILENAME) + 1 ); + + CL_ASSERT( file_name ); + + strcpy( file_name, p_mgr->p_subn->opt.dump_files_dir ); + strcat( file_name, SUBNET_LIST_FILENAME ); + + if( ( rc = fopen( file_name, "w" ) ) == NULL ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_topology_file_create: " + "fopen failed for file:%s\n", file_name ); + + CL_PLOCK_RELEASE( p_mgr->p_lock ); + goto Exit; + } + + p_node = ( osm_node_t * ) cl_qmap_head( &p_mgr->p_subn->node_guid_tbl ); + while( p_node != + ( osm_node_t * ) cl_qmap_end( &p_mgr->p_subn->node_guid_tbl ) ) + { + if( p_node->node_info.num_ports ) + { + uint32_t cPort; + osm_node_t *p_nbnode; + osm_physp_t *p_physp; + osm_physp_t *p_default_physp; + osm_physp_t *p_rphysp; + uint8_t link_speed_act; + + 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 == NULL ) || ( !osm_physp_is_valid( p_physp ) ) ) + continue; + + p_rphysp = p_physp->p_remote_physp; + + if( ( p_rphysp == NULL ) || ( !osm_physp_is_valid( 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; + } + + memcpy(desc, p_node->node_desc.description, + IB_NODE_DESCRIPTION_SIZE); + desc[IB_NODE_DESCRIPTION_SIZE] = '\0'; + + fprintf( rc, "{ %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 ), + 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; + } + + memcpy(desc, p_nbnode->node_desc.description, + IB_NODE_DESCRIPTION_SIZE); + desc[IB_NODE_DESCRIPTION_SIZE] = '\0'; + + fprintf( rc, "{ %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 ), + 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( rc, "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" : "??" ); + } + } + p_node = ( osm_node_t * ) cl_qmap_next( &p_node->map_item ); + } + + CL_PLOCK_RELEASE( p_mgr->p_lock ); + + fclose( rc ); + + Exit: + free( file_name ); + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_report( + IN osm_state_mgr_t * const p_mgr ) +{ + const cl_qmap_t *p_tbl; + const osm_port_t *p_port; + const osm_node_t *p_node; + const osm_physp_t *p_physp; + const osm_physp_t *p_remote_physp; + const ib_port_info_t *p_pi; + uint8_t port_num; + uint8_t start_port; + uint32_t num_ports; + uint8_t node_type; + + if( !osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + return; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_state_mgr_report ); + + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, + "\n===================================================" + "====================================================" + "\nVendor : Ty " + ": # : Sta : LID : LMC : MTU : LWA : LSA : Port GUID " + " : Neighbor Port (Port #)\n" ); + + p_tbl = &p_mgr->p_subn->port_guid_tbl; + + /* + * Hold lock non-exclusively while we perform these read-only operations. + */ + + CL_PLOCK_ACQUIRE( p_mgr->p_lock ); + p_port = ( osm_port_t * ) cl_qmap_head( p_tbl ); + while( p_port != ( osm_port_t * ) cl_qmap_end( p_tbl ) ) + { + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_state_mgr_report: " + "Processing port 0x%016" PRIx64 "\n", + cl_ntoh64( osm_port_get_guid( p_port ) ) ); + } + + p_node = osm_port_get_parent_node( p_port ); + node_type = osm_node_get_type( p_node ); + if( node_type == IB_NODE_TYPE_SWITCH ) + start_port = 0; + else + start_port = 1; + + num_ports = osm_port_get_num_physp( p_port ); + for( port_num = start_port; port_num < num_ports; port_num++ ) + { + p_physp = osm_port_get_phys_ptr( p_port, port_num ); + if( ( p_physp == NULL ) || ( !osm_physp_is_valid( p_physp ) ) ) + continue; + + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, "%s : %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 = osm_physp_get_port_info_ptr( p_physp ); + + /* + * Port state is not defined for switch port 0 + */ + if( port_num == 0 ) + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, " :" ); + else + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, " %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 ) ) + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, " %04X : %01X :", + cl_ntoh16( p_pi->base_lid ), + ib_port_info_get_lmc( p_pi ) ); + else + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, " : :" ); + + if( port_num != 0 ) + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, " %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 + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, " : : " ); + + if( osm_physp_get_port_guid( p_physp ) == + p_mgr->p_subn->sm_port_guid ) + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, "* %016" PRIx64 " *", + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ) ); + else + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, ": %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 && osm_physp_is_valid( p_remote_physp ) ) + { + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, + " %016" PRIx64 " (%02X)", + cl_ntoh64( osm_physp_get_port_guid + ( p_remote_physp ) ), + osm_physp_get_port_num( p_remote_physp ) ); + } + else + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, " UNKNOWN" ); + } + + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, "\n" ); + } + + osm_log_printf( p_mgr->p_log, OSM_LOG_VERBOSE, + "------------------------------------------------------" + "------------------------------------------------\n" ); + p_port = ( osm_port_t * ) cl_qmap_next( &p_port->map_item ); + } + + CL_PLOCK_RELEASE( p_mgr->p_lock ); + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__process_idle_time_queue_done( + IN osm_state_mgr_t * const p_mgr ) +{ + cl_qlist_t *p_list = &p_mgr->idle_time_list; + cl_list_item_t *p_list_item; + osm_idle_item_t *p_process_item; + + OSM_LOG_ENTER( p_mgr->p_log, __process_idle_time_queue_done ); + + cl_spinlock_acquire( &p_mgr->idle_lock ); + p_list_item = cl_qlist_remove_head( p_list ); + + if( p_list_item == cl_qlist_end( p_list ) ) + { + cl_spinlock_release( &p_mgr->idle_lock ); + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__process_idle_time_queue_done: ERR 3314: " + "Idle time queue is empty\n" ); + return; + } + cl_spinlock_release( &p_mgr->idle_lock ); + + p_process_item = ( osm_idle_item_t * ) p_list_item; + + if( p_process_item->pfn_done ) + { + + p_process_item->pfn_done( p_process_item->context1, + p_process_item->context2 ); + } + + free( p_process_item ); + + OSM_LOG_EXIT( p_mgr->p_log ); + return; +} + +/********************************************************************** + **********************************************************************/ +static osm_signal_t +__process_idle_time_queue_start( + IN osm_state_mgr_t * const p_mgr ) +{ + cl_qlist_t *p_list = &p_mgr->idle_time_list; + cl_list_item_t *p_list_item; + osm_idle_item_t *p_process_item; + osm_signal_t signal; + + OSM_LOG_ENTER( p_mgr->p_log, __process_idle_time_queue_start ); + + cl_spinlock_acquire( &p_mgr->idle_lock ); + + p_list_item = cl_qlist_head( p_list ); + if( p_list_item == cl_qlist_end( p_list ) ) + { + cl_spinlock_release( &p_mgr->idle_lock ); + OSM_LOG_EXIT( p_mgr->p_log ); + return OSM_SIGNAL_NONE; + } + + cl_spinlock_release( &p_mgr->idle_lock ); + + p_process_item = ( osm_idle_item_t * ) p_list_item; + + CL_ASSERT( p_process_item->pfn_start ); + + signal = p_process_item->pfn_start( p_process_item->context1, + p_process_item->context2 ); + + CL_ASSERT( signal != OSM_SIGNAL_NONE ); + + OSM_LOG_EXIT( p_mgr->p_log ); + return signal; +} + +/********************************************************************** + * 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 TRUE, else - return FALSE. + **********************************************************************/ +static osm_remote_sm_t * +__osm_state_mgr_exists_other_master_sm( + IN osm_state_mgr_t * const p_mgr ) +{ + cl_qmap_t *p_sm_tbl; + osm_remote_sm_t *p_sm; + osm_remote_sm_t *p_sm_res = NULL; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_state_mgr_exists_other_master_sm ); + + p_sm_tbl = &p_mgr->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 TRUE */ + if( ib_sminfo_get_state( &p_sm->smi ) == IB_SMINFO_STATE_MASTER ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_exists_other_master_sm: " + "Found remote master SM with guid:0x%016" PRIx64 "\n", + cl_ntoh64(p_sm->smi.guid) ); + p_sm_res = p_sm; + goto Exit; + } + } + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); + return ( p_sm_res ); +} + +/********************************************************************** + * Go over all remote SMs (as updated in the sm_guid_tbl). + * Find the one with the highest priority and lowest guid. + * Compare this SM to the local SM. If the local SM is higher - + * return NULL, if the remote SM is higher - return a pointer to it. + **********************************************************************/ +static osm_remote_sm_t * +__osm_state_mgr_get_highest_sm( + IN osm_state_mgr_t * const p_mgr ) +{ + 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( p_mgr->p_log, __osm_state_mgr_get_highest_sm ); + + p_sm_tbl = &p_mgr->p_subn->sm_guid_tbl; + + /* Start with the local sm as the standard */ + p_highest_sm = NULL; + highest_sm_priority = p_mgr->p_subn->opt.sm_priority; + highest_sm_guid = p_mgr->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( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_state_mgr_get_highest_sm: " + "Found higher SM with guid: %016" PRIx64 "\n", + cl_ntoh64( p_highest_sm->smi.guid ) ); + } + + OSM_LOG_EXIT( p_mgr->p_log ); + return ( p_highest_sm ); +} + +/********************************************************************** + * Send SubnSet(SMInfo) SMP with HANDOVER attribute to the + * remote_sm indicated. + **********************************************************************/ +static void +__osm_state_mgr_send_handover( + IN osm_state_mgr_t * const p_mgr, + IN osm_remote_sm_t * const p_sm ) +{ + uint8_t payload[IB_SMP_DATA_SIZE]; + ib_sm_info_t *p_smi = ( ib_sm_info_t * ) payload; + osm_madw_context_t context; + const osm_port_t *p_port; + ib_api_status_t status; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_state_mgr_send_handover ); + + if( p_mgr->p_subn->opt.testability_mode == + OSM_TEST_MODE_EXIT_BEFORE_SEND_HANDOVER ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_send_handover: ERR 3315: " + "Exit on testability mode OSM_TEST_MODE_EXIT_BEFORE_SEND_HANDOVER\n" ); + osm_exit_flag = TRUE; + sleep( 3 ); + exit( 1 ); + } + + /* + * 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( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_send_handover: ERR 3316: " + "No port object on given remote_sm object\n" ); + goto Exit; + } + + /* update the master_guid in the p_sm_state_mgr object according to */ + /* the guid of the port where the new Master SM should reside. */ + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_state_mgr_send_handover: " + "Handing over mastership. Updating sm_state_mgr master_guid: %016" + PRIx64 "\n", cl_ntoh64( p_port->guid ) ); + p_mgr->p_sm_state_mgr->master_guid = p_port->guid; + + context.smi_context.port_guid = p_port->guid; + context.smi_context.set_method = TRUE; + + p_smi->guid = p_mgr->p_subn->sm_port_guid; + p_smi->act_count = cl_hton32( p_mgr->p_stats->qp0_mads_sent ); + p_smi->pri_state = ( uint8_t ) ( p_mgr->p_subn->sm_state | + p_mgr->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( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_state_mgr_send_handover: " + "Responding to master SM with real sm_key\n" ); + p_smi->sm_key = p_mgr->p_subn->opt.sm_key; + } + else + { + /* The requester is not authenticated as master - set sm_key to zero */ + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_state_mgr_send_handover: " + "Responding to SM not master with zero sm_key\n" ); + p_smi->sm_key = 0; + } + + status = osm_req_set( p_mgr->p_req, + osm_physp_get_dr_path_ptr + ( osm_port_get_default_phys_ptr( p_port ) ), payload, + sizeof(payload), + IB_MAD_ATTR_SM_INFO, IB_SMINFO_ATTR_MOD_HANDOVER, + CL_DISP_MSGID_NONE, &context ); + + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_send_handover: ERR 3317: " + "Failure requesting SMInfo (%s)\n", ib_get_err_str( status ) ); + } + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + * Send Trap 64 on all ports in new_ports_list. + **********************************************************************/ +static void +__osm_state_mgr_report_new_ports( + IN osm_state_mgr_t * const p_mgr ) +{ + osm_port_t *p_port; + ib_gid_t port_gid; + ib_mad_notice_attr_t notice; + ib_api_status_t status; + ib_net64_t port_guid; + uint16_t min_lid_ho; + uint16_t max_lid_ho; + char desc[IB_NODE_DESCRIPTION_SIZE + 1]; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_state_mgr_report_new_ports ); + + CL_PLOCK_ACQUIRE( p_mgr->p_lock ); + p_port = + ( osm_port_t + * ) ( cl_list_remove_head( &p_mgr->p_subn->new_ports_list ) ); + while( p_port != NULL ) + { + port_guid = osm_port_get_guid( p_port ); + /* issue a notice - trap 64 */ + + /* details of the notice */ + notice.generic_type = 0x83; /* is generic subn mgt type */ + ib_notice_set_prod_type_ho( ¬ice, 4 ); /* A Class Manager generator */ + /* endport becomes to be reachable */ + notice.g_or_v.generic.trap_num = CL_HTON16( 64 ); + /* The sm_base_lid is saved in network order already. */ + notice.issuer_lid = p_mgr->p_subn->sm_base_lid; + /* following C14-72.1.1 and table 119 p725 */ + /* we need to provide the GID */ + port_gid.unicast.prefix = p_mgr->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 = p_mgr->p_subn->opt.subnet_prefix; + notice.issuer_gid.unicast.interface_id = p_mgr->p_subn->sm_port_guid; + + status = osm_report_notice( p_mgr->p_log, p_mgr->p_subn, ¬ice ); + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_report_new_ports: 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 ); + if (p_port->p_node) + { + memcpy(desc, p_port->p_node->node_desc.description, + IB_NODE_DESCRIPTION_SIZE); + desc[IB_NODE_DESCRIPTION_SIZE] = '\0'; + } + osm_log( p_mgr->p_log, OSM_LOG_INFO, + "Discovered new port with GUID:0x%016" PRIx64 + " LID range [0x%X,0x%X] of node:%s\n", + cl_ntoh64( port_gid.unicast.interface_id ), + min_lid_ho, max_lid_ho, + p_port->p_node ? desc : "UNKNOWN" ); + + p_port = + ( osm_port_t + * ) ( cl_list_remove_head( &p_mgr->p_subn->new_ports_list ) ); + } + CL_PLOCK_RELEASE( p_mgr->p_lock ); + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + * Make sure that the lid_port_tbl of the subnet has only the ports + * that are recognized, and in the correct lid place. There could be + * errors if we wanted to assign a certain port with lid X, but that + * request didn't reach the port. In this case port_lid_tbl will have + * the port under lid X, though the port isn't updated with this lid. + * We will run a new heavy sweep (since there were errors in the + * initialization), but here we'll clean the database from incorrect + * information. + **********************************************************************/ +static void +__osm_state_mgr_check_tbl_consistency( + IN osm_state_mgr_t * const p_mgr ) +{ + 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( p_mgr->p_log, __osm_state_mgr_check_tbl_consistency ); + + cl_ptr_vector_construct( &ref_port_lid_tbl ); + cl_ptr_vector_init( &ref_port_lid_tbl, + cl_ptr_vector_get_size( &p_mgr->p_subn->port_lid_tbl ), + OSM_SUBNET_VECTOR_GROW_SIZE ); + + p_port_guid_tbl = &p_mgr->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 = &p_mgr->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( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_check_tbl_consistency: ERR 3322: " + "lid 0x%zX is wrongly assigned to port 0x%016" PRIx64 + " in port_lid_tbl\n", + lid, cl_ntoh64( osm_port_get_guid( p_port_stored ) ) ); + } + 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( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_check_tbl_consistency: ERR 3323: " + "port 0x%016" PRIx64 " exists in new port_lid_tbl under " + "lid 0x%zX, but missing in subnet port_lid_tbl db\n", + cl_ntoh64( osm_port_get_guid( p_port_ref ) ), 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( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_state_mgr_check_tbl_consistency: ERR 3324: " + "lid 0x%zX has port 0x%016" PRIx64 + " in new port_lid_tbl db, " "and port 0x%016" PRIx64 + " in subnet port_lid_tbl db\n", lid, + cl_ntoh64( osm_port_get_guid( p_port_ref ) ), + cl_ntoh64( osm_port_get_guid( p_port_stored ) ) ); + } + } + /* 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 ); + p_mgr->p_subn->subnet_initialization_error = TRUE; + } + + cl_ptr_vector_destroy( &ref_port_lid_tbl ); + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_state_mgr_process( + IN osm_state_mgr_t * const p_mgr, + IN osm_signal_t signal ) +{ + ib_api_status_t status; + osm_remote_sm_t *p_remote_sm; + osm_signal_t tmp_signal; + + CL_ASSERT( p_mgr ); + + OSM_LOG_ENTER( p_mgr->p_log, osm_state_mgr_process ); + + /* if we are exiting do nothing */ + if( osm_exit_flag ) + signal = OSM_SIGNAL_NONE; + + /* + * The state lock prevents many race conditions from screwing + * up the state transition process. For example, if an function + * puts transactions on the wire, the state lock guarantees this + * loop will see the return code ("DONE PENDING") of the function + * before the "NO OUTSTANDING TRANSACTIONS" signal is asynchronously + * received. + */ + cl_spinlock_acquire( &p_mgr->state_lock ); + + while( signal != OSM_SIGNAL_NONE ) + { + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_state_mgr_process: " + "Received signal %s in state %s\n", + osm_get_sm_signal_str( signal ), + osm_get_sm_state_str( p_mgr->state ) ); + } + + /* + * If we're already sweeping and we get the signal to sweep, + * just ignore it harmlessly. + */ + if( ( p_mgr->state != OSM_SM_STATE_IDLE ) && + ( p_mgr->state != OSM_SM_STATE_STANDBY ) && + ( signal == OSM_SIGNAL_SWEEP ) ) + { + break; + } + + switch ( p_mgr->state ) + { + case OSM_SM_STATE_IDLE: + switch ( signal ) + { + case OSM_SIGNAL_SWEEP: + /* + * If the osm_sm_state_mgr is in INIT state - signal + * it with a INIT signal to move it to DISCOVERY state. + */ + if( p_mgr->p_subn->sm_state == IB_SMINFO_STATE_INIT ) + osm_sm_state_mgr_process( p_mgr->p_sm_state_mgr, + OSM_SM_SIGNAL_INIT ); + + /* + * 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( &p_mgr->p_subn->sw_guid_tbl ) && + p_mgr->p_subn->sm_state != IB_SMINFO_STATE_DISCOVERING && + p_mgr->p_subn->opt.force_heavy_sweep == FALSE && + p_mgr->p_subn->force_immediate_heavy_sweep == FALSE && + p_mgr->p_subn->force_delayed_heavy_sweep == FALSE && + p_mgr->p_subn->subnet_initialization_error == FALSE ) + { + if( __osm_state_mgr_light_sweep_start( p_mgr ) == IB_SUCCESS ) + { + p_mgr->state = OSM_SM_STATE_SWEEP_LIGHT; + } + } + else + { + /* First of all - if force_immediate_heavy_sweep is TRUE then + * need to unset it */ + p_mgr->p_subn->force_immediate_heavy_sweep = FALSE; + /* If force_delayed_heavy_sweep is TRUE then + * need to unset it */ + p_mgr->p_subn->force_delayed_heavy_sweep = FALSE; + /* If subnet_initialization_error is TRUE then + * need to unset it. */ + p_mgr->p_subn->subnet_initialization_error = FALSE; + + /* rescan configuration updates */ + osm_subn_rescan_conf_file(&p_mgr->p_subn->opt); + + status = __osm_state_mgr_sweep_hop_0( p_mgr ); + if( status == IB_SUCCESS ) + { + p_mgr->state = OSM_SM_STATE_SWEEP_HEAVY_SELF; + } + } + signal = OSM_SIGNAL_NONE; + break; + + case OSM_SIGNAL_IDLE_TIME_PROCESS_REQUEST: + p_mgr->state = OSM_SM_STATE_PROCESS_REQUEST; + signal = OSM_SIGNAL_IDLE_TIME_PROCESS; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_PROCESS_REQUEST: + switch ( signal ) + { + case OSM_SIGNAL_IDLE_TIME_PROCESS: + signal = __process_idle_time_queue_start( p_mgr ); + switch ( signal ) + { + case OSM_SIGNAL_NONE: + p_mgr->state = OSM_SM_STATE_IDLE; + break; + + case OSM_SIGNAL_DONE_PENDING: + p_mgr->state = OSM_SM_STATE_PROCESS_REQUEST_WAIT; + signal = OSM_SIGNAL_NONE; + break; + + case OSM_SIGNAL_DONE: + p_mgr->state = OSM_SM_STATE_PROCESS_REQUEST_DONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_PROCESS_REQUEST_WAIT: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + p_mgr->state = OSM_SM_STATE_PROCESS_REQUEST_DONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_PROCESS_REQUEST_DONE: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + case OSM_SIGNAL_DONE: + /* CALL the done function */ + __process_idle_time_queue_done( p_mgr ); + + /* + * Set the signal to OSM_SIGNAL_IDLE_TIME_PROCESS + * so that the next element in the queue gets processed + */ + + signal = OSM_SIGNAL_IDLE_TIME_PROCESS; + p_mgr->state = OSM_SM_STATE_PROCESS_REQUEST; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SWEEP_LIGHT: + switch ( signal ) + { + case OSM_SIGNAL_LIGHT_SWEEP_FAIL: + case OSM_SIGNAL_CHANGE_DETECTED: + /* + * Nothing else to do yet except change state. + */ + p_mgr->state = OSM_SM_STATE_SWEEP_LIGHT_WAIT; + signal = OSM_SIGNAL_NONE; + break; + + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + /* + * No change was detected on the subnet. + * We can return to the idle state. + */ + __osm_state_mgr_light_sweep_done_msg( p_mgr ); + p_mgr->state = OSM_SM_STATE_PROCESS_REQUEST; + signal = OSM_SIGNAL_IDLE_TIME_PROCESS; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SWEEP_LIGHT_WAIT: + switch ( signal ) + { + case OSM_SIGNAL_LIGHT_SWEEP_FAIL: + case OSM_SIGNAL_CHANGE_DETECTED: + /* + * Nothing to do here. One subnet change typcially + * begets another.... But needs to wait for all transactions to + * complete + */ + break; + + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + /* + * A change was detected on the subnet. + * Initiate a heavy sweep. + */ + if( __osm_state_mgr_sweep_hop_0( p_mgr ) == IB_SUCCESS ) + { + p_mgr->state = OSM_SM_STATE_SWEEP_HEAVY_SELF; + } + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + break; + } + signal = OSM_SIGNAL_NONE; + break; + + case OSM_SM_STATE_SWEEP_HEAVY_SELF: + switch ( signal ) + { + case OSM_SIGNAL_CHANGE_DETECTED: + /* + * Nothing to do here. One subnet change typcially + * begets another.... But needs to wait for all transactions + */ + signal = OSM_SIGNAL_NONE; + break; + + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + if( __osm_state_mgr_is_sm_port_down( p_mgr ) == TRUE ) + { + __osm_state_mgr_sm_port_down_msg( p_mgr ); + + /* Run the drop manager - we want to clear all records */ + osm_drop_mgr_process( p_mgr->p_drop_mgr ); + + /* Move to DISCOVERING state */ + osm_sm_state_mgr_process( p_mgr->p_sm_state_mgr, + OSM_SM_SIGNAL_DISCOVER ); + + p_mgr->state = OSM_SM_STATE_PROCESS_REQUEST; + signal = OSM_SIGNAL_IDLE_TIME_PROCESS; + } + else + { + if( __osm_state_mgr_sweep_hop_1( p_mgr ) == IB_SUCCESS ) + { + p_mgr->state = OSM_SM_STATE_SWEEP_HEAVY_SUBNET; + } + signal = OSM_SIGNAL_NONE; + } + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + /* + * There is no 'OSM_SM_STATE_SWEEP_HEAVY_WAIT' state since we + * know that there are outstanding transactions on the wire already... + */ + case OSM_SM_STATE_SWEEP_HEAVY_SUBNET: + switch ( signal ) + { + case OSM_SIGNAL_CHANGE_DETECTED: + /* + * Nothing to do here. One subnet change typically + * begets another.... + */ + signal = OSM_SIGNAL_NONE; + break; + + case OSM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED: + p_mgr->state = OSM_SM_STATE_MASTER_OR_HIGHER_SM_DETECTED; + break; + + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + __osm_state_mgr_sweep_heavy_done_msg( p_mgr ); + + /* If we are MASTER - get the highest remote_sm, and + * see if it is higher than our local sm. If + */ + if( p_mgr->p_subn->sm_state == IB_SMINFO_STATE_MASTER ) + { + p_remote_sm = __osm_state_mgr_get_highest_sm( p_mgr ); + if( p_remote_sm != NULL ) + { + /* need to handover the mastership + * to the remote sm, and move to standby */ + __osm_state_mgr_send_handover( p_mgr, p_remote_sm ); + osm_sm_state_mgr_process( p_mgr->p_sm_state_mgr, + OSM_SM_SIGNAL_HANDOVER_SENT ); + p_mgr->state = OSM_SM_STATE_STANDBY; + signal = OSM_SIGNAL_NONE; + break; + } + else + { + /* We are the highest sm - check to see if there is + * a remote SM that is in master state. */ + p_remote_sm = __osm_state_mgr_exists_other_master_sm( p_mgr ); + 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. + * Also - need to start polling on that SM. */ + p_mgr->p_sm_state_mgr->p_polling_sm = p_remote_sm; + osm_sm_state_mgr_process( p_mgr->p_sm_state_mgr, + OSM_SM_SIGNAL_WAIT_FOR_HANDOVER ); + p_mgr->state = OSM_SM_STATE_PROCESS_REQUEST; + signal = OSM_SIGNAL_IDLE_TIME_PROCESS; + break; + } + } + } + + /* Need to continue with lid assignment */ + osm_drop_mgr_process( p_mgr->p_drop_mgr ); + + p_mgr->state = OSM_SM_STATE_SET_PKEY; + + /* + * If we are not MASTER already - this means that we are + * in discovery state. call osm_sm_state_mgr with signal + * DISCOVERY_COMPLETED + */ + if( p_mgr->p_subn->sm_state == IB_SMINFO_STATE_DISCOVERING ) + osm_sm_state_mgr_process( p_mgr->p_sm_state_mgr, + OSM_SM_SIGNAL_DISCOVERY_COMPLETED ); + + /* the returned signal might be DONE or DONE_PENDING */ + signal = osm_pkey_mgr_process( p_mgr->p_subn->p_osm ); + + /* the returned signal is always DONE */ + tmp_signal = osm_qos_setup(p_mgr->p_subn->p_osm); + + if (tmp_signal == OSM_SIGNAL_DONE_PENDING) + signal = OSM_SIGNAL_DONE_PENDING; + + /* 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(p_mgr->p_subn->p_osm); + + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_PKEY: + switch ( signal ) + { + case OSM_SIGNAL_DONE: + p_mgr->state = OSM_SM_STATE_SET_PKEY_DONE; + break; + + case OSM_SIGNAL_DONE_PENDING: + /* + * There are outstanding transactions, so we + * must wait for the wire to clear. + */ + p_mgr->state = OSM_SM_STATE_SET_PKEY_WAIT; + signal = OSM_SIGNAL_NONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_PKEY_WAIT: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + p_mgr->state = OSM_SM_STATE_SET_PKEY_DONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_PKEY_DONE: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + case OSM_SIGNAL_DONE: + p_mgr->state = OSM_SM_STATE_SET_SM_UCAST_LID; + signal = osm_lid_mgr_process_sm( p_mgr->p_lid_mgr ); + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_SM_UCAST_LID: + switch ( signal ) + { + case OSM_SIGNAL_DONE: + p_mgr->state = OSM_SM_STATE_SET_SM_UCAST_LID_DONE; + break; + + case OSM_SIGNAL_DONE_PENDING: + /* + * There are outstanding transactions, so we + * must wait for the wire to clear. + */ + p_mgr->state = OSM_SM_STATE_SET_SM_UCAST_LID_WAIT; + signal = OSM_SIGNAL_NONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_SM_UCAST_LID_WAIT: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + p_mgr->state = OSM_SM_STATE_SET_SM_UCAST_LID_DONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_SM_UCAST_LID_DONE: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + case OSM_SIGNAL_DONE: + /* If we run single step we have already done this */ + if( p_mgr->state_step_mode != OSM_STATE_STEP_TAKE_ONE ) + { + __osm_state_mgr_set_sm_lid_done_msg( p_mgr ); + __osm_state_mgr_notify_lid_change( p_mgr ); + } + + /* Break on single step mode - if not continuous */ + if( p_mgr->state_step_mode == OSM_STATE_STEP_BREAK ) + { + p_mgr->next_stage_signal = signal; + signal = OSM_SIGNAL_NONE; + break; + } + + p_mgr->state = OSM_SM_STATE_SET_SUBNET_UCAST_LIDS; + signal = osm_lid_mgr_process_subnet( p_mgr->p_lid_mgr ); + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + + case OSM_SM_STATE_SET_SUBNET_UCAST_LIDS: + switch ( signal ) + { + case OSM_SIGNAL_DONE: + /* + * The LID Manager is done processing. + * There are no outstanding transactions, so we + * can move on to configuring the forwarding tables. + */ + p_mgr->state = OSM_SM_STATE_SET_SUBNET_UCAST_LIDS_DONE; + break; + + case OSM_SIGNAL_DONE_PENDING: + /* + * The LID Manager is done processing. + * There are outstanding transactions, so we + * must wait for the wire to clear. + */ + p_mgr->state = OSM_SM_STATE_SET_SUBNET_UCAST_LIDS_WAIT; + signal = OSM_SIGNAL_NONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + /* + * In this state, the Unicast Manager has completed processing, + * but there are still transactions on the wire. Therefore, + * wait here until the wire clears. + */ + case OSM_SM_STATE_SET_SUBNET_UCAST_LIDS_WAIT: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + /* + * The LID Manager is done processing. + * There are no outstanding transactions, so we + * can move on to configuring the forwarding tables. + */ + p_mgr->state = OSM_SM_STATE_SET_SUBNET_UCAST_LIDS_DONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_SUBNET_UCAST_LIDS_DONE: + + switch ( signal ) + { + case OSM_SIGNAL_DONE: + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + /* 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 reqeusts didn't reach + * their destination. */ + __osm_state_mgr_check_tbl_consistency( p_mgr ); + + /* If we run single step we have already done this */ + if( p_mgr->state_step_mode != OSM_STATE_STEP_TAKE_ONE ) + __osm_state_mgr_lid_assign_msg( p_mgr ); + + /* Break on single step mode - just before taking next step */ + if( p_mgr->state_step_mode == OSM_STATE_STEP_BREAK ) + { + p_mgr->next_stage_signal = signal; + signal = OSM_SIGNAL_NONE; + break; + } + + /* + * OK, the wire is clear, so proceed with + * unicast forwarding table configuration. + * First - send trap 64 on newly discovered endports + */ + __osm_state_mgr_report_new_ports( p_mgr ); + + p_mgr->state = OSM_SM_STATE_SET_UCAST_TABLES; + signal = osm_ucast_mgr_process( p_mgr->p_ucast_mgr ); + + /* Break on single step mode */ + if( p_mgr->state_step_mode != OSM_STATE_STEP_CONTINUOUS ) + { + p_mgr->next_stage_signal = signal; + signal = OSM_SIGNAL_NONE; + } + + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_UCAST_TABLES: + switch ( signal ) + { + case OSM_SIGNAL_DONE: + p_mgr->state = OSM_SM_STATE_SET_UCAST_TABLES_DONE; + break; + + case OSM_SIGNAL_DONE_PENDING: + /* + * The Unicast Manager is done processing. + * There are outstanding transactions, so we + * must wait for the wire to clear. + */ + p_mgr->state = OSM_SM_STATE_SET_UCAST_TABLES_WAIT; + signal = OSM_SIGNAL_NONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_UCAST_TABLES_WAIT: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + p_mgr->state = OSM_SM_STATE_SET_UCAST_TABLES_DONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_UCAST_TABLES_DONE: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + case OSM_SIGNAL_DONE: + /* 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. */ + p_mgr->p_subn->ignore_existing_lfts = FALSE; + + /* If we run single step we have already done this */ + if( p_mgr->state_step_mode != OSM_STATE_STEP_TAKE_ONE ) + __osm_state_mgr_switch_config_msg( p_mgr ); + + /* Break on single step mode - just before taking next step */ + if( p_mgr->state_step_mode == OSM_STATE_STEP_BREAK ) + { + p_mgr->next_stage_signal = signal; + signal = OSM_SIGNAL_NONE; + break; + } + + if( !p_mgr->p_subn->opt.disable_multicast ) + { + p_mgr->state = OSM_SM_STATE_SET_MCAST_TABLES; + signal = osm_mcast_mgr_process( p_mgr->p_mcast_mgr ); + } + else + { + p_mgr->state = OSM_SM_STATE_SET_LINK_PORTS; + signal = osm_link_mgr_process( p_mgr->p_link_mgr, + IB_LINK_NO_CHANGE ); + } + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_MCAST_TABLES: + switch ( signal ) + { + case OSM_SIGNAL_DONE: + p_mgr->state = OSM_SM_STATE_SET_MCAST_TABLES_DONE; + break; + + case OSM_SIGNAL_DONE_PENDING: + /* + * The Multicast Manager is done processing. + * There are outstanding transactions, so we + * must wait for the wire to clear. + */ + p_mgr->state = OSM_SM_STATE_SET_MCAST_TABLES_WAIT; + signal = OSM_SIGNAL_NONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_MCAST_TABLES_WAIT: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + p_mgr->state = OSM_SM_STATE_SET_MCAST_TABLES_DONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_MCAST_TABLES_DONE: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + case OSM_SIGNAL_DONE: + /* If we run single step we have already done this */ + if( p_mgr->state_step_mode != OSM_STATE_STEP_TAKE_ONE ) + __osm_state_mgr_multicast_config_msg( p_mgr ); + + /* Break on single step mode - just before taking next step */ + if( p_mgr->state_step_mode == OSM_STATE_STEP_BREAK ) + { + p_mgr->next_stage_signal = signal; + signal = OSM_SIGNAL_NONE; + break; + } + + p_mgr->state = OSM_SM_STATE_SET_LINK_PORTS; + signal = osm_link_mgr_process( p_mgr->p_link_mgr, + IB_LINK_NO_CHANGE ); + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + /* + * The LINK_PORTS state is required since we can not 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. + */ + case OSM_SM_STATE_SET_LINK_PORTS: + switch ( signal ) + { + case OSM_SIGNAL_DONE: + p_mgr->state = OSM_SM_STATE_SET_LINK_PORTS_DONE; + break; + + case OSM_SIGNAL_DONE_PENDING: + /* + * The Link Manager is done processing. + * There are outstanding transactions, so we + * must wait for the wire to clear. + */ + p_mgr->state = OSM_SM_STATE_SET_LINK_PORTS_WAIT; + signal = OSM_SIGNAL_NONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_LINK_PORTS_WAIT: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + p_mgr->state = OSM_SM_STATE_SET_LINK_PORTS_DONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_LINK_PORTS_DONE: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + case OSM_SIGNAL_DONE: + + __osm_state_mgr_links_ports_msg( p_mgr ); + + p_mgr->state = OSM_SM_STATE_SET_ARMED; + signal = osm_link_mgr_process( p_mgr->p_link_mgr, IB_LINK_ARMED ); + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_ARMED: + switch ( signal ) + { + case OSM_SIGNAL_DONE: + p_mgr->state = OSM_SM_STATE_SET_ARMED_DONE; + break; + + case OSM_SIGNAL_DONE_PENDING: + /* + * The Link Manager is done processing. + * There are outstanding transactions, so we + * must wait for the wire to clear. + */ + p_mgr->state = OSM_SM_STATE_SET_ARMED_WAIT; + signal = OSM_SIGNAL_NONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_ARMED_WAIT: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + p_mgr->state = OSM_SM_STATE_SET_ARMED_DONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_ARMED_DONE: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + case OSM_SIGNAL_DONE: + + /* If we run single step we have already done this */ + if( p_mgr->state_step_mode != OSM_STATE_STEP_TAKE_ONE ) + __osm_state_mgr_links_armed_msg( p_mgr ); + + /* Break on single step mode - just before taking next step */ + if( p_mgr->state_step_mode == OSM_STATE_STEP_BREAK ) + { + p_mgr->next_stage_signal = signal; + signal = OSM_SIGNAL_NONE; + break; + } + + p_mgr->state = OSM_SM_STATE_SET_ACTIVE; + signal = osm_link_mgr_process( p_mgr->p_link_mgr, + IB_LINK_ACTIVE ); + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_ACTIVE: + switch ( signal ) + { + case OSM_SIGNAL_DONE: + /* + * Don't change the signal, just the state. + */ + p_mgr->state = OSM_SM_STATE_SUBNET_UP; + break; + + case OSM_SIGNAL_DONE_PENDING: + /* + * The Link Manager is done processing. + * There are outstanding transactions, so we + * must wait for the wire to clear. + */ + p_mgr->state = OSM_SM_STATE_SET_ACTIVE_WAIT; + signal = OSM_SIGNAL_NONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SET_ACTIVE_WAIT: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + /* + * Don't change the signal, just the state. + */ + p_mgr->state = OSM_SM_STATE_SUBNET_UP; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_SUBNET_UP: + switch ( signal ) + { + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + case OSM_SIGNAL_DONE: + /* + * The sweep completed! + */ + + /* in any case we zero this flag */ + p_mgr->p_subn->coming_out_of_standby = FALSE; + + /* If there were errors - then the subnet is not really up */ + if( p_mgr->p_subn->subnet_initialization_error == TRUE ) + { + __osm_state_mgr_init_errors_msg( p_mgr ); + } + else + { + /* The subnet is up correctly - set the first_time_master_sweep flag + * (if it is on) to FALSE. */ + if( p_mgr->p_subn->first_time_master_sweep == TRUE ) + { + p_mgr->p_subn->first_time_master_sweep = FALSE; + } + + __osm_topology_file_create( p_mgr ); + __osm_state_mgr_report( p_mgr ); + __osm_state_mgr_up_msg( p_mgr ); + + if( osm_log_is_active(p_mgr->p_log, OSM_LOG_VERBOSE) ) + osm_sa_db_file_dump(p_mgr->p_subn->p_osm); + } + p_mgr->state = OSM_SM_STATE_PROCESS_REQUEST; + signal = OSM_SIGNAL_IDLE_TIME_PROCESS; + + /* + * Finally signal the subnet up event + */ + status = cl_event_signal( p_mgr->p_subnet_up_event ); + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_state_mgr_process: ERR 3319: " + "Invalid SM state %u\n", p_mgr->state ); + } + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + break; + + case OSM_SM_STATE_MASTER_OR_HIGHER_SM_DETECTED: + switch ( signal ) + { + case OSM_SIGNAL_CHANGE_DETECTED: + /* + * Nothing to do here. One subnet change typically + * begets another.... + */ + break; + + case OSM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED: + /* + * If we lost once, we might lose again. Nothing to do. + */ + break; + + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + p_mgr->state = OSM_SM_STATE_STANDBY; + /* + * Call the sm_state_mgr with signal + * MASTER_OR_HIGHER_SM_DETECTED_DONE + */ + osm_sm_state_mgr_process( p_mgr->p_sm_state_mgr, + OSM_SM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED_DONE ); + __osm_state_mgr_standby_msg( p_mgr ); + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + break; + } + signal = OSM_SIGNAL_NONE; + break; + + case OSM_SM_STATE_STANDBY: + switch ( signal ) + { + case OSM_SIGNAL_EXIT_STBY: + /* + * Need to force re-write of sm_base_lid to all ports + * to do that we want all the ports to be considered + * foriegn + */ + signal = OSM_SIGNAL_SWEEP; + __osm_state_mgr_clean_known_lids( p_mgr ); + p_mgr->state = OSM_SM_STATE_IDLE; + break; + + case OSM_SIGNAL_NO_PENDING_TRANSACTIONS: + /* + * Nothing to do here - need to stay at this state + */ + signal = OSM_SIGNAL_NONE; + break; + + default: + __osm_state_mgr_signal_error( p_mgr, signal ); + signal = OSM_SIGNAL_NONE; + break; + } + /* stay with the same signal - so we can start the sweep */ + break; + + default: + CL_ASSERT( FALSE ); + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_state_mgr_process: ERR 3320: " + "Invalid SM state %u\n", p_mgr->state ); + p_mgr->state = OSM_SM_STATE_IDLE; + signal = OSM_SIGNAL_NONE; + break; + } + + /* if we got a signal to force immediate heavy sweep in the middle of the sweep - + * try another sweep. */ + if( ( p_mgr->p_subn->force_immediate_heavy_sweep ) && + ( p_mgr->state == OSM_SM_STATE_IDLE ) ) + { + signal = OSM_SIGNAL_SWEEP; + } + /* if we got errors during the initialization in the middle of the sweep - + * try another sweep. */ + if( ( p_mgr->p_subn->subnet_initialization_error ) && + ( p_mgr->state == OSM_SM_STATE_IDLE ) ) + { + signal = OSM_SIGNAL_SWEEP; + } + + /* + * for single step mode - some stages need to break only + * after evaluating a single step. + * For those we track the fact we have already performed + * a single loop + */ + if( p_mgr->state_step_mode == OSM_STATE_STEP_TAKE_ONE ) + p_mgr->state_step_mode = OSM_STATE_STEP_BREAK; + } + + cl_spinlock_release( &p_mgr->state_lock ); + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_state_mgr_process_idle( + IN osm_state_mgr_t * const p_mgr, + IN osm_pfn_start_t pfn_start, + IN osm_pfn_done_t pfn_done, + void *context1, + void *context2 ) +{ + osm_idle_item_t *p_idle_item; + + OSM_LOG_ENTER( p_mgr->p_log, osm_state_mgr_process_idle ); + + p_idle_item = malloc( sizeof( osm_idle_item_t ) ); + if( p_idle_item == NULL ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_state_mgr_process_idle: ERR 3321: " + "insufficient memory\n" ); + return IB_ERROR; + } + + memset( p_idle_item, 0, sizeof( osm_idle_item_t ) ); + p_idle_item->pfn_start = pfn_start; + p_idle_item->pfn_done = pfn_done; + p_idle_item->context1 = context1; + p_idle_item->context2 = context2; + + cl_spinlock_acquire( &p_mgr->idle_lock ); + cl_qlist_insert_tail( &p_mgr->idle_time_list, &p_idle_item->list_item ); + cl_spinlock_release( &p_mgr->idle_lock ); + + osm_state_mgr_process( p_mgr, OSM_SIGNAL_IDLE_TIME_PROCESS_REQUEST ); + + OSM_LOG_EXIT( p_mgr->p_log ); + + return IB_SUCCESS; +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_state_mgr_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_state_mgr_ctrl.c new file mode 100644 index 00000000..21aed85f --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_state_mgr_ctrl.c @@ -0,0 +1,127 @@ +/* + * 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: + * Implementation of osm_state_mgr_ctrl_t. + * This object represents the State Manager Controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_state_mgr_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_state_mgr_process( ((osm_state_mgr_ctrl_t*)context)->p_mgr, + (osm_signal_t)(p_data) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_state_mgr_ctrl_construct( + IN osm_state_mgr_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_state_mgr_ctrl_destroy( + IN osm_state_mgr_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_state_mgr_ctrl_init( + IN osm_state_mgr_ctrl_t* const p_ctrl, + IN osm_state_mgr_t* const p_mgr, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_state_mgr_ctrl_init ); + + osm_state_mgr_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + + p_ctrl->p_mgr = p_mgr; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_NO_SMPS_OUTSTANDING, + __osm_state_mgr_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_state_mgr_ctrl_init: ERR 3401: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_subnet.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_subnet.c new file mode 100644 index 00000000..5d3cb3e1 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_subnet.c @@ -0,0 +1,1272 @@ +/* + * 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: + * Implementation of osm_subn_t. + * This object represents an IBA subnet. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.9 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_subn_construct( + IN osm_subn_t* const p_subn ) +{ + memset( p_subn, 0, sizeof(*p_subn) ); + cl_ptr_vector_construct( &p_subn->node_lid_tbl ); + 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_qmap_init( &p_subn->rtr_guid_tbl ); + cl_qmap_init( &p_subn->prtn_pkey_tbl ); + cl_qmap_init( &p_subn->mgrp_mlid_tbl ); + cl_list_construct( &p_subn->new_ports_list ); + cl_list_init( &p_subn->new_ports_list, 10 ); + cl_list_construct( &p_subn->light_sweep_physp_list ); + cl_list_init( &p_subn->light_sweep_physp_list, 5 ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_subn_destroy( + IN osm_subn_t* const p_subn ) +{ + osm_node_t *p_node, *p_next_node; + osm_port_t *p_port, *p_next_port; + osm_switch_t *p_sw, *p_next_sw; + osm_remote_sm_t *p_rsm, *p_next_rsm; + osm_prtn_t *p_prtn, *p_next_prtn; + osm_mgrp_t *p_mgrp, *p_next_mgrp; + osm_infr_t *p_infr, *p_next_infr; + + /* it might be a good idea to de-allocate all known objects */ + p_next_node = (osm_node_t*)cl_qmap_head( &p_subn->node_guid_tbl ); + while( p_next_node != (osm_node_t*)cl_qmap_end( &p_subn->node_guid_tbl ) ) + { + p_node = p_next_node; + p_next_node = (osm_node_t*)cl_qmap_next( &p_node->map_item ); + osm_node_delete( &p_node ); + } + + cl_ptr_vector_destroy( &p_subn->node_lid_tbl ); + + 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 ); + } + + p_next_mgrp = (osm_mgrp_t*)cl_qmap_head( &p_subn->mgrp_mlid_tbl ); + while( p_next_mgrp != (osm_mgrp_t*)cl_qmap_end( &p_subn->mgrp_mlid_tbl ) ) + { + p_mgrp = p_next_mgrp; + p_next_mgrp = (osm_mgrp_t*)cl_qmap_next( &p_mgrp->map_item ); + osm_mgrp_destroy( p_mgrp ); + } + + p_next_infr = (osm_infr_t*)cl_qlist_head( &p_subn->sa_infr_list ); + while (p_next_infr != (osm_infr_t*)cl_qlist_end( &p_subn->sa_infr_list ) ) + { + p_infr = p_next_infr; + p_next_infr = (osm_infr_t*)cl_qlist_next( &p_infr->list_item ); + osm_infr_destroy( p_infr ); + } + + cl_list_remove_all( &p_subn->new_ports_list ); + cl_list_destroy( &p_subn->new_ports_list ); + + cl_list_remove_all( &p_subn->light_sweep_physp_list ); + cl_list_destroy( &p_subn->light_sweep_physp_list ); + + cl_ptr_vector_destroy( &p_subn->port_lid_tbl ); + cl_map_remove_all(&(p_subn->opt.port_prof_ignore_guids)); + cl_map_destroy(&(p_subn->opt.port_prof_ignore_guids)); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_subn_init( + IN osm_subn_t* const p_subn, + IN osm_opensm_t * const p_osm, + IN const osm_subn_opt_t* const p_opt ) +{ + cl_status_t status; + + p_subn->p_osm = p_osm; + + status = cl_ptr_vector_init( &p_subn->node_lid_tbl, + OSM_SUBNET_VECTOR_MIN_SIZE, + OSM_SUBNET_VECTOR_GROW_SIZE ); + if( status != CL_SUCCESS ) + return( status ); + + 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->node_lid_tbl, + OSM_SUBNET_VECTOR_CAPACITY ); + 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->node_lid_tbl, 0, NULL ); + cl_ptr_vector_set( &p_subn->port_lid_tbl, 0, NULL ); + + p_subn->opt = *p_opt; + p_subn->max_unicast_lid_ho = IB_LID_UCAST_END_HO; + p_subn->max_multicast_lid_ho = IB_LID_MCAST_END_HO; + p_subn->min_ca_mtu = IB_MAX_MTU; + p_subn->min_ca_rate = IB_MAX_RATE; + + /* note that insert and remove are part of the port_profile thing */ + cl_map_init(&(p_subn->opt.port_prof_ignore_guids), 10); + + /* ignore_existing_lfts follows reassign_lfts on first sweep */ + p_subn->ignore_existing_lfts = p_subn->opt.reassign_lfts; + + /* we assume master by default - so we only need to set it true if STANDBY */ + p_subn->coming_out_of_standby = FALSE; + + return( IB_SUCCESS ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_get_gid_by_mad_addr( + IN osm_log_t* p_log, + IN const osm_subn_t *p_subn, + IN const osm_mad_addr_t *p_mad_addr, + OUT ib_gid_t *p_gid) +{ + const cl_ptr_vector_t* p_tbl; + const osm_port_t* p_port = NULL; + const osm_physp_t* p_physp = NULL; + + if ( p_gid == NULL ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_get_gid_by_mad_addr: ERR 7505: " + "Provided output GID is NULL\n"); + return(IB_INVALID_PARAMETER); + } + + /* Find the port gid of the request in the subnet */ + p_tbl = &p_subn->port_lid_tbl; + + CL_ASSERT( cl_ptr_vector_get_size(p_tbl) < 0x10000 ); + + if ((uint16_t)cl_ptr_vector_get_size(p_tbl) > + cl_ntoh16(p_mad_addr->dest_lid)) + { + p_port = cl_ptr_vector_get( p_tbl, cl_ntoh16(p_mad_addr->dest_lid) ); + if ( p_port == NULL ) + { + osm_log( p_log, OSM_LOG_DEBUG, + "osm_get_gid_by_mad_addr: " + "Did not find any port with LID: 0x%X\n", + cl_ntoh16(p_mad_addr->dest_lid) + ); + return(IB_INVALID_PARAMETER); + } + p_physp = osm_port_get_phys_ptr( p_port, p_port->default_port_num); + p_gid->unicast.interface_id = p_physp->port_guid; + p_gid->unicast.prefix = p_subn->opt.subnet_prefix; + } + else + { + /* The dest_lid is not in the subnet table - this is an error */ + osm_log( p_log, OSM_LOG_ERROR, + "osm_get_gid_by_mad_addr: ERR 7501: " + "LID is out of range: 0x%X\n", + cl_ntoh16(p_mad_addr->dest_lid) + ); + return(IB_INVALID_PARAMETER); + } + + return( IB_SUCCESS ); +} + +/********************************************************************** + **********************************************************************/ +osm_physp_t* +osm_get_physp_by_mad_addr( + IN osm_log_t* p_log, + IN const osm_subn_t *p_subn, + IN osm_mad_addr_t *p_mad_addr ) +{ + const cl_ptr_vector_t* p_port_lid_tbl; + osm_port_t* p_port = NULL; + osm_physp_t* p_physp = NULL; + + /* Find the port gid of the request in the subnet */ + p_port_lid_tbl = &p_subn->port_lid_tbl; + + CL_ASSERT( cl_ptr_vector_get_size(p_port_lid_tbl) < 0x10000 ); + + if ((uint16_t)cl_ptr_vector_get_size(p_port_lid_tbl) > + cl_ntoh16(p_mad_addr->dest_lid)) + { + p_port = cl_ptr_vector_get( p_port_lid_tbl, cl_ntoh16(p_mad_addr->dest_lid) ); + if (p_port == NULL) + { + /* The port is not in the port_lid table - this is an error */ + osm_log( p_log, OSM_LOG_ERROR, + "osm_get_physp_by_mad_addr: ERR 7502: " + "Cannot locate port object by lid: 0x%X\n", + cl_ntoh16(p_mad_addr->dest_lid) + ); + + goto Exit; + } + p_physp = osm_port_get_phys_ptr( p_port, p_port->default_port_num); + } + else + { + /* The dest_lid is not in the subnet table - this is an error */ + osm_log( p_log, OSM_LOG_ERROR, + "osm_get_physp_by_mad_addr: ERR 7503: " + "Lid is out of range: 0x%X\n", + cl_ntoh16(p_mad_addr->dest_lid) + ); + } + + Exit: + return p_physp; +} + +/********************************************************************** + **********************************************************************/ +osm_port_t* +osm_get_port_by_mad_addr( + IN osm_log_t* p_log, + IN const osm_subn_t *p_subn, + IN osm_mad_addr_t *p_mad_addr ) +{ + const cl_ptr_vector_t* p_port_lid_tbl; + osm_port_t* p_port = NULL; + + /* Find the port gid of the request in the subnet */ + p_port_lid_tbl = &p_subn->port_lid_tbl; + + CL_ASSERT( cl_ptr_vector_get_size(p_port_lid_tbl) < 0x10000 ); + + if ((uint16_t)cl_ptr_vector_get_size(p_port_lid_tbl) > + cl_ntoh16(p_mad_addr->dest_lid)) + { + p_port = + cl_ptr_vector_get( p_port_lid_tbl, cl_ntoh16(p_mad_addr->dest_lid) ); + } + else + { + /* The dest_lid is not in the subnet table - this is an error */ + osm_log( p_log, OSM_LOG_ERROR, + "osm_get_port_by_mad_addr: ERR 7504: " + "Lid is out of range: 0x%X\n", + cl_ntoh16(p_mad_addr->dest_lid) + ); + } + + return p_port; +} + +/********************************************************************** + **********************************************************************/ +osm_switch_t * +osm_get_switch_by_guid( + IN const osm_subn_t *p_subn, + IN uint64_t guid) +{ + osm_switch_t *p_switch; + + p_switch = (osm_switch_t*)cl_qmap_get( &(p_subn->sw_guid_tbl), guid ); + if( p_switch == (osm_switch_t*)cl_qmap_end( &(p_subn->sw_guid_tbl)) ) + p_switch = NULL; + return p_switch; +} + +/********************************************************************** + **********************************************************************/ +osm_node_t * +osm_get_node_by_guid( + IN osm_subn_t const *p_subn, + IN uint64_t guid) +{ + osm_node_t *p_node; + + p_node = (osm_node_t*)cl_qmap_get( &(p_subn->node_guid_tbl), guid ); + if( p_node == (osm_node_t*)cl_qmap_end( &(p_subn->node_guid_tbl)) ) + p_node = NULL; + return p_node; +} + +/********************************************************************** + **********************************************************************/ +osm_port_t * +osm_get_port_by_guid( + IN osm_subn_t const *p_subn, + IN uint64_t guid) +{ + osm_port_t *p_port; + + p_port = (osm_port_t*)cl_qmap_get( &(p_subn->port_guid_tbl), guid ); + if( p_port == (osm_port_t*)cl_qmap_end( &(p_subn->port_guid_tbl)) ) + p_port = NULL; + return p_port; +} + +/********************************************************************** + **********************************************************************/ +static void +subn_set_default_qos_options( + IN osm_qos_options_t *opt) +{ + opt->max_vls = 15; + opt->high_limit = 0; + opt->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"; + opt->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"; + opt->sl2vl = "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7"; +} + +/********************************************************************** + **********************************************************************/ +void +osm_subn_set_default_opt( + IN osm_subn_opt_t* const p_opt ) +{ + memset(p_opt, 0, sizeof(osm_subn_opt_t)); + p_opt->guid = 0; + p_opt->m_key = OSM_DEFAULT_M_KEY; + p_opt->sm_key = OSM_DEFAULT_SM_KEY; + p_opt->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 = FALSE; + p_opt->transaction_timeout = OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC; + /* by default we will consider waiting for 50x transaction timeout normal */ + p_opt->max_msg_fifo_timeout = 50*OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC; + p_opt->sm_priority = OSM_DEFAULT_SM_PRIORITY; + p_opt->lmc = OSM_DEFAULT_LMC; + p_opt->lmc_esp0 = FALSE; + p_opt->max_op_vls = OSM_DEFAULT_MAX_OP_VLS; + p_opt->force_link_speed = 0; + p_opt->reassign_lids = FALSE; + p_opt->reassign_lfts = TRUE; + p_opt->ignore_other_sm = FALSE; + p_opt->single_thread = FALSE; + p_opt->no_multicast_option = 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 = 0; + p_opt->honor_guid2lid_file = FALSE; + + p_opt->dump_files_dir = getenv("OSM_TMP_DIR"); + if (!p_opt->dump_files_dir || !(*p_opt->dump_files_dir)) + p_opt->dump_files_dir = OSM_DEFAULT_TMP_DIR; + + p_opt->log_file = OSM_DEFAULT_LOG_FILE; + p_opt->log_max_size = 0; + p_opt->partition_config_file = OSM_DEFAULT_PARTITION_CONFIG_FILE; + p_opt->no_partition_enforcement = FALSE; + p_opt->no_qos = TRUE; + p_opt->accum_log_file = TRUE; + p_opt->port_profile_switch_nodes = FALSE; + p_opt->pfn_ui_pre_lid_assign = NULL; + p_opt->ui_pre_lid_assign_ctx = NULL; + p_opt->pfn_ui_mcast_fdb_assign = NULL; + p_opt->ui_mcast_fdb_assign_ctx = NULL; + p_opt->sweep_on_trap = TRUE; + p_opt->testability_mode = OSM_TEST_MODE_NONE; + p_opt->routing_engine_name = NULL; + p_opt->lid_matrix_dump_file = NULL; + p_opt->ucast_dump_file = NULL; + p_opt->updn_guid_file = NULL; + p_opt->sa_db_file = NULL; + p_opt->exit_on_fatal = TRUE; + p_opt->enable_quirks = FALSE; + p_opt->no_clients_rereg = FALSE; + subn_set_default_qos_options(&p_opt->qos_options); + subn_set_default_qos_options(&p_opt->qos_ca_options); + subn_set_default_qos_options(&p_opt->qos_sw0_options); + subn_set_default_qos_options(&p_opt->qos_swe_options); + subn_set_default_qos_options(&p_opt->qos_rtr_options); +} + +/********************************************************************** + **********************************************************************/ +static inline void +__osm_subn_opts_unpack_net64( + IN char *p_req_key, + IN char *p_key, + IN char *p_val_str, + IN uint64_t *p_val) +{ + uint64_t val; + if (!strcmp(p_req_key, p_key)) + { +#if __WORDSIZE == 64 + val = strtoul(p_val_str, NULL, 0); +#else + val = strtoull(p_val_str, NULL, 0); +#endif + if (cl_hton64(val) != *p_val) + { + char buff[128]; + sprintf(buff, " Using Cached Option:%s = 0x%016" PRIx64 "\n", + p_key, val); + printf(buff); + cl_log_event("OpenSM", LOG_INFO, buff, NULL, 0); + *p_val = cl_ntoh64(val); + } + } +} + +/********************************************************************** + **********************************************************************/ +static inline void +__osm_subn_opts_unpack_uint32( + IN char *p_req_key, + IN char *p_key, + IN char *p_val_str, + IN uint32_t *p_val) +{ + uint32_t val; + if (!strcmp(p_req_key, p_key)) + { + val = strtoul(p_val_str, NULL, 0); + if (val != *p_val) + { + char buff[128]; + sprintf(buff, " Using Cached Option:%s = %u\n", + p_key, val); + printf(buff); + cl_log_event("OpenSM", LOG_INFO, buff, NULL, 0); + *p_val = val; + } + } +} + +/********************************************************************** + **********************************************************************/ +static inline void +__osm_subn_opts_unpack_net16( + IN char *p_req_key, + IN char *p_key, + IN char *p_val_str, + IN uint16_t *p_val) +{ + if (!strcmp(p_req_key, p_key)) + { + uint32_t val; + val = strtoul(p_val_str, NULL, 0); + CL_ASSERT( val < 0x10000 ); + if (cl_hton32(val) != *p_val) + { + char buff[128]; + sprintf(buff, " Using Cached Option:%s = 0x%04x\n", + p_key, val); + printf(buff); + cl_log_event("OpenSM", LOG_INFO, buff, NULL, 0); + *p_val = cl_hton16((uint16_t)val); + } + } +} + +/********************************************************************** + **********************************************************************/ +static inline void +__osm_subn_opts_unpack_uint8( + IN char *p_req_key, + IN char *p_key, + IN char *p_val_str, + IN uint8_t *p_val) +{ + if (!strcmp(p_req_key, p_key)) + { + uint32_t val; + val = strtoul(p_val_str, NULL, 0); + CL_ASSERT( val < 0x100 ); + if (val != *p_val) + { + char buff[128]; + sprintf(buff, " Using Cached Option:%s = %u\n", + p_key, val); + printf(buff); + cl_log_event("OpenSM", LOG_INFO, buff, NULL, 0); + *p_val = (uint8_t)val; + } + } +} + +/********************************************************************** + **********************************************************************/ +static inline void +__osm_subn_opts_unpack_boolean( + IN char *p_req_key, + IN char *p_key, + IN char *p_val_str, + IN boolean_t *p_val) +{ + if (!strcmp(p_req_key, p_key) && p_val_str) + { + boolean_t val; + if (strcmp("TRUE", p_val_str)) + val = FALSE; + else + val = TRUE; + + if (val != *p_val) { + char buff[128]; + sprintf(buff, " Using Cached Option:%s = %s\n", + p_key, p_val_str); + printf(buff); + cl_log_event("OpenSM", LOG_INFO, buff, NULL, 0); + *p_val = val; + } + } +} + +/********************************************************************** + **********************************************************************/ +static inline void +__osm_subn_opts_unpack_charp( + IN char *p_req_key, + IN char *p_key, + IN char *p_val_str, + IN char **p_val) +{ + if (!strcmp(p_req_key, p_key) && p_val_str) + { + if ((*p_val == NULL) || strcmp(p_val_str, *p_val)) + { + char buff[128]; + sprintf(buff, " Using Cached Option:%s = %s\n", + p_key, p_val_str); + printf(buff); + cl_log_event("OpenSM", LOG_INFO, buff, NULL, 0); + + /* + Ignore the possible memory leak here; + the pointer may be to a static default. + */ + *p_val = (char *)malloc( strlen(p_val_str) +1 ); + strcpy( *p_val, p_val_str); + } + } +} + +/********************************************************************** + **********************************************************************/ +static void +subn_parse_qos_options( + IN const char *prefix, + IN char *p_key, + IN char *p_val_str, + IN osm_qos_options_t *opt) +{ + char name[256]; + + snprintf(name, sizeof(name), "%s_max_vls", prefix); + __osm_subn_opts_unpack_uint32(name, p_key, p_val_str, &opt->max_vls); + snprintf(name, sizeof(name), "%s_high_limit", prefix); + __osm_subn_opts_unpack_uint32(name, p_key, p_val_str, &opt->high_limit); + snprintf(name, sizeof(name), "%s_vlarb_high", prefix); + __osm_subn_opts_unpack_charp(name, p_key, p_val_str, &opt->vlarb_high); + snprintf(name, sizeof(name), "%s_vlarb_low", prefix); + __osm_subn_opts_unpack_charp(name, p_key, p_val_str, &opt->vlarb_low); + snprintf(name, sizeof(name), "%s_sl2vl", prefix); + __osm_subn_opts_unpack_charp(name, p_key, p_val_str, &opt->sl2vl); +} + +static int +subn_dump_qos_options( + FILE *file, + const char *set_name, + const char *prefix, + osm_qos_options_t *opt) +{ + return fprintf(file, "# %s\n" + "%s_max_vls %u\n" + "%s_high_limit %u\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); +} + +/********************************************************************** + **********************************************************************/ +void +osm_subn_rescan_conf_file( + IN osm_subn_opt_t* const p_opts ) +{ + char *p_cache_dir = getenv("OSM_CACHE_DIR"); + char file_name[256]; + FILE *opts_file; + char line[1024]; + char *p_key, *p_val ,*p_last; + + /* try to open the options file from the cache dir */ + if (!p_cache_dir || !(*p_cache_dir)) + p_cache_dir = OSM_DEFAULT_CACHE_DIR; + + strcpy(file_name, p_cache_dir); + strcat(file_name, "opensm.opts"); + + opts_file = fopen(file_name, "r"); + if (!opts_file) + return; + + while (fgets(line, 1023, opts_file) != NULL) + { + /* get the first token */ + p_key = strtok_r(line, " \t\n", &p_last); + if (p_key) + { + p_val = strtok_r(NULL, " \t\n", &p_last); + + subn_parse_qos_options("qos", + p_key, p_val, &p_opts->qos_options); + + subn_parse_qos_options("qos_ca", + p_key, p_val, &p_opts->qos_ca_options); + + subn_parse_qos_options("qos_sw0", + p_key, p_val, &p_opts->qos_sw0_options); + + subn_parse_qos_options("qos_swe", + p_key, p_val, &p_opts->qos_swe_options); + + subn_parse_qos_options("qos_rtr", + p_key, p_val, &p_opts->qos_rtr_options); + + } + } + fclose(opts_file); +} + +/********************************************************************** + **********************************************************************/ +void +osm_subn_parse_conf_file( + IN osm_subn_opt_t* const p_opts ) +{ + char *p_cache_dir = getenv("OSM_CACHE_DIR"); + char file_name[256]; + FILE *opts_file; + char line[1024]; + char *p_key, *p_val ,*p_last; + + /* try to open the options file from the cache dir */ + if (!p_cache_dir || !(*p_cache_dir)) + p_cache_dir = OSM_DEFAULT_CACHE_DIR; + + strcpy(file_name, p_cache_dir); + strcat(file_name, "opensm.opts"); + + opts_file = fopen(file_name, "r"); + if (!opts_file) return; + + while (fgets(line, 1023, opts_file) != NULL) + { + /* get the first token */ + p_key = strtok_r(line, " \t\n", &p_last); + if (p_key) + { + p_val = strtok_r(NULL, " \t\n", &p_last); + + __osm_subn_opts_unpack_net64( + "guid", p_key, p_val, &p_opts->guid); + + __osm_subn_opts_unpack_net64( + "m_key", p_key, p_val, &p_opts->m_key); + + __osm_subn_opts_unpack_net64( + "sm_key", p_key, p_val, &p_opts->sm_key); + + __osm_subn_opts_unpack_net64( + "subnet_prefix", + p_key, p_val, &p_opts->subnet_prefix); + + __osm_subn_opts_unpack_net16( + "m_key_lease_period", + p_key, p_val, &p_opts->m_key_lease_period); + + __osm_subn_opts_unpack_uint32( + "sweep_interval", + p_key, p_val, &p_opts->sweep_interval); + + __osm_subn_opts_unpack_uint32( + "max_wire_smps", + p_key, p_val, &p_opts->max_wire_smps); + + __osm_subn_opts_unpack_uint32( + "transaction_timeout", + p_key, p_val, &p_opts->transaction_timeout); + + __osm_subn_opts_unpack_uint32( + "max_msg_fifo_timeout", + p_key, p_val, &p_opts->max_msg_fifo_timeout); + + __osm_subn_opts_unpack_uint8( + "sm_priority", + p_key, p_val, &p_opts->sm_priority); + + __osm_subn_opts_unpack_uint8( + "lmc", + p_key, p_val, &p_opts->lmc); + + __osm_subn_opts_unpack_boolean( + "lmc_esp0", + p_key, p_val, &p_opts->lmc_esp0); + + __osm_subn_opts_unpack_uint8( + "max_op_vls", + p_key, p_val, &p_opts->max_op_vls); + + __osm_subn_opts_unpack_uint8( + "force_link_speed", + p_key, p_val, &p_opts->force_link_speed); + + __osm_subn_opts_unpack_boolean( + "reassign_lids", + p_key, p_val, &p_opts->reassign_lids); + + __osm_subn_opts_unpack_boolean( + "reassign_lfts", + p_key, p_val, &p_opts->reassign_lfts); + + __osm_subn_opts_unpack_boolean( + "ignore_other_sm", + p_key, p_val, &p_opts->ignore_other_sm); + + __osm_subn_opts_unpack_boolean( + "single_thread", + p_key, p_val, &p_opts->single_thread); + + __osm_subn_opts_unpack_boolean( + "no_multicast_option", + p_key, p_val, &p_opts->no_multicast_option); + + __osm_subn_opts_unpack_boolean( + "disable_multicast", + p_key, p_val, &p_opts->disable_multicast); + + __osm_subn_opts_unpack_boolean( + "force_log_flush", + p_key, p_val, &p_opts->force_log_flush); + + __osm_subn_opts_unpack_uint8( + "subnet_timeout", + p_key, p_val, &p_opts->subnet_timeout); + + __osm_subn_opts_unpack_uint8( + "packet_life_time", + p_key, p_val, &p_opts->packet_life_time); + + __osm_subn_opts_unpack_uint8( + "vl_stall_count", + p_key, p_val, &p_opts->vl_stall_count); + + __osm_subn_opts_unpack_uint8( + "leaf_vl_stall_count", + p_key, p_val, &p_opts->leaf_vl_stall_count); + + __osm_subn_opts_unpack_uint8( + "head_of_queue_lifetime", + p_key, p_val, &p_opts->head_of_queue_lifetime); + + __osm_subn_opts_unpack_uint8( + "leaf_head_of_queue_lifetime", + p_key, p_val, &p_opts->leaf_head_of_queue_lifetime); + + __osm_subn_opts_unpack_uint8( + "local_phy_errors_threshold", + p_key, p_val, &p_opts->local_phy_errors_threshold); + + __osm_subn_opts_unpack_uint8( + "overrun_errors_threshold", + p_key, p_val, &p_opts->overrun_errors_threshold); + + __osm_subn_opts_unpack_uint32( + "sminfo_polling_timeout", + p_key, p_val, &p_opts->sminfo_polling_timeout); + + __osm_subn_opts_unpack_uint32( + "polling_retry_number", + p_key, p_val, &p_opts->polling_retry_number); + + __osm_subn_opts_unpack_boolean( + "force_heavy_sweep", + p_key, p_val, &p_opts->force_heavy_sweep); + + __osm_subn_opts_unpack_uint8( + "log_flags", + p_key, p_val, &p_opts->log_flags); + + __osm_subn_opts_unpack_boolean( + "port_profile_switch_nodes", + p_key, p_val, &p_opts->port_profile_switch_nodes); + + __osm_subn_opts_unpack_boolean( + "sweep_on_trap", + p_key, p_val, &p_opts->sweep_on_trap); + + __osm_subn_opts_unpack_charp( + "routing_engine", + p_key, p_val, &p_opts->routing_engine_name); + + __osm_subn_opts_unpack_charp( + "log_file", p_key, p_val, &p_opts->log_file); + + __osm_subn_opts_unpack_uint32( + "log_max_size", + p_key, p_val, (uint32_t *)&p_opts->log_max_size); + + __osm_subn_opts_unpack_charp( + "partition_config_file", + p_key, p_val, &p_opts->partition_config_file); + + __osm_subn_opts_unpack_boolean( + "no_partition_enforcement", + p_key, p_val, &p_opts->no_partition_enforcement); + + __osm_subn_opts_unpack_boolean( + "no_qos", + p_key, p_val, &p_opts->no_qos); + + __osm_subn_opts_unpack_boolean( + "accum_log_file", + p_key, p_val, &p_opts->accum_log_file); + + __osm_subn_opts_unpack_charp( + "dump_files_dir", + p_key, p_val, &p_opts->dump_files_dir); + + __osm_subn_opts_unpack_charp( + "lid_matrix_dump_file", + p_key, p_val, &p_opts->lid_matrix_dump_file); + + __osm_subn_opts_unpack_charp( + "ucast_dump_file", + p_key, p_val, &p_opts->ucast_dump_file); + + __osm_subn_opts_unpack_charp( + "updn_guid_file", + p_key, p_val, &p_opts->updn_guid_file); + + __osm_subn_opts_unpack_charp( + "sa_db_file", + p_key, p_val, &p_opts->sa_db_file); + + __osm_subn_opts_unpack_boolean( + "exit_on_fatal", + p_key, p_val, &p_opts->exit_on_fatal); + + __osm_subn_opts_unpack_boolean( + "honor_guid2lid_file", + p_key, p_val, &p_opts->honor_guid2lid_file); + + subn_parse_qos_options("qos", + p_key, p_val, &p_opts->qos_options); + + subn_parse_qos_options("qos_ca", + p_key, p_val, &p_opts->qos_ca_options); + + subn_parse_qos_options("qos_sw0", + p_key, p_val, &p_opts->qos_sw0_options); + + subn_parse_qos_options("qos_swe", + p_key, p_val, &p_opts->qos_swe_options); + + subn_parse_qos_options("qos_rtr", + p_key, p_val, &p_opts->qos_rtr_options); + + __osm_subn_opts_unpack_boolean( + "enable_quirks", + p_key, p_val, &p_opts->enable_quirks); + + } + } + fclose(opts_file); +} + +/********************************************************************** + **********************************************************************/ +void +osm_subn_write_conf_file( + IN osm_subn_opt_t* const p_opts ) +{ + char *p_cache_dir = getenv("OSM_CACHE_DIR"); + char file_name[256]; + FILE *opts_file; + + /* try to open the options file from the cache dir */ + if (!p_cache_dir || !(*p_cache_dir)) + p_cache_dir = OSM_DEFAULT_CACHE_DIR; + + strcpy(file_name, p_cache_dir); + strcat(file_name, "opensm.opts"); + + opts_file = fopen(file_name, "w"); + if (!opts_file) return; + + fprintf( + opts_file, + "#\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 [msec]\n" + "m_key_lease_period %u\n\n" + "# SM_Key value of the SM to qualify rcv SA queries as 'trusted'\n" + "sm_key 0x%016" PRIx64 "\n\n" + "# Subnet prefix used on this subnet\n" + "subnet_prefix 0x%016" PRIx64 "\n\n" + "# The LMC value used on this subnet\n" + "lmc %u\n\n" + "# lmc_esp0 determines whether LMC value used on subnet is used for\n" + "#enhanced switch port 0. If TRUE, LMC value for subnet is used for\n" + "#ESP0. Otherwise, LMC value for ESP0s is 0.\n" + "lmc_esp0 %s\n\n" + "# The code of maximal time a packet can live in a switch\n" + "# The actual time is 4.096usec * 2^\n" + "# The value 0x14 disables this mechanism\n" + "packet_life_time 0x%02x\n\n" + "# The number of sequential packets dropped that cause the port\n" + "# to enter the VLStalled state. The result of setting this value to\n" + "# zero is undefined.\n" + "vl_stall_count 0x%02x\n\n" + "# The number of sequential packets dropped that cause the port\n" + "# to enter the VLStalled state. This value is for switch ports\n" + "# driving a CA or router port. The result of setting this value\n" + "# to zero is undefined.\n" + "leaf_vl_stall_count 0x%02x\n\n" + "# The code of maximal time a packet can wait at the head of\n" + "# transmission queue. \n" + "# The actual time is 4.096usec * 2^\n" + "# The value 0x14 disables this mechanism\n" + "head_of_queue_lifetime 0x%02x\n\n" + "# The maximal time a packet can wait at the head of queue on \n" + "# switch port connected to a CA or router port\n" + "leaf_head_of_queue_lifetime 0x%02x\n\n" + "# Limit the maximal operational VLs\n" + "max_op_vls %u\n\n" + "# Force switch links which are more than SDR capable to \n" + "# operate at SDR speed\n\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 credits over-run errors for sending Trap 129\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->subnet_prefix), + p_opts->lmc, + p_opts->lmc_esp0 ? "TRUE" : "FALSE", + p_opts->packet_life_time, + p_opts->vl_stall_count, + p_opts->leaf_vl_stall_count, + p_opts->head_of_queue_lifetime, + p_opts->leaf_head_of_queue_lifetime, + p_opts->max_op_vls, + p_opts->force_link_speed, + p_opts->subnet_timeout, + p_opts->local_phy_errors_threshold, + p_opts->overrun_errors_threshold + ); + + fprintf( + opts_file, + "#\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( + opts_file, + "#\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 ignore existing LFT entries on first sweep (default).\n" + "# Otherwise only non minimal hop cases are modified.\n" + "# NOTE: A standby SM clears its first sweep flag - since the\n" + "# master SM already sweeps...\n" + "reassign_lfts %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->reassign_lfts ? "TRUE" : "FALSE", + p_opts->force_heavy_sweep ? "TRUE" : "FALSE", + p_opts->sweep_on_trap ? "TRUE" : "FALSE" + ); + + fprintf( + opts_file, + "#\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"); + + if (p_opts->routing_engine_name) + fprintf( opts_file, + "# Routing engine\n" + "routing_engine %s\n\n", + p_opts->routing_engine_name); + if (p_opts->lid_matrix_dump_file) + fprintf( opts_file, + "# Lid matrix dump file name\n" + "lid_matrix_dump_file %s\n\n", + p_opts->lid_matrix_dump_file); + if (p_opts->ucast_dump_file) + fprintf( opts_file, + "# Ucast dump file name\n" + "ucast_dump_file %s\n\n", + p_opts->ucast_dump_file); + if (p_opts->updn_guid_file) + fprintf( opts_file, + "# The file holding the Up/Down root node guids\n" + "# One guid in each line\n" + "updn_guid_file %s\n\n", + p_opts->updn_guid_file); + if (p_opts->sa_db_file) + fprintf( opts_file, + "# SA database file name\n" + "sa_db_file %s\n\n", + p_opts->sa_db_file); + + fprintf( + opts_file, + "#\n# HANDOVER - MULTIPLE SMs OPTIONS\n#\n" + "# SM priority used for deciding who is the master\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( + opts_file, + "#\n# TIMING AND THREADING OPTIONS\n#\n" + "# Number of MADs sent in parallel\n" + "max_wire_smps %u\n\n" + "# The time taken to a transaction to finish in [msec]\n" + "transaction_timeout %u\n\n" + "# Maximal time in [msec] a message can stay in the incoming message queue.\n" + "# If there is more than one message in the queue and the last message\n" + "# stayed in the queue more than this value any SA request will be \n" + "# immediately returned with a BUSY status.\n" + "max_msg_fifo_timeout %u\n\n" + "# Use a single thread for handling SA queries\n" + "single_thread %s\n\n", + p_opts->max_wire_smps, + p_opts->transaction_timeout, + p_opts->max_msg_fifo_timeout, + p_opts->single_thread ? "TRUE" : "FALSE" + ); + + fprintf( + opts_file, + "#\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. 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 OpenSM should disable multicast support\n" + "no_multicast_option %s\n\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", + 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_multicast_option ? "TRUE" : "FALSE", + p_opts->disable_multicast ? "TRUE" : "FALSE", + p_opts->exit_on_fatal ? "TRUE" : "FALSE" + ); + + fprintf( + opts_file, + "#\n# QoS OPTIONS\n#\n" + "# Disable QoS setup\n" + "no_qos %s\n\n", + p_opts->no_qos ? "TRUE" : "FALSE"); + + subn_dump_qos_options(opts_file, + "QoS default options", "qos", &p_opts->qos_options); + fprintf(opts_file, "\n"); + subn_dump_qos_options(opts_file, + "QoS CA options", "qos_ca", &p_opts->qos_ca_options); + fprintf(opts_file, "\n"); + subn_dump_qos_options(opts_file, + "QoS Switch Port 0 options", "qos_sw0", &p_opts->qos_sw0_options); + fprintf(opts_file, "\n"); + subn_dump_qos_options(opts_file, + "QoS Switch external ports options", "qos_swe", &p_opts->qos_swe_options); + fprintf(opts_file, "\n"); + subn_dump_qos_options(opts_file, + "QoS Router ports options", "qos_rtr", &p_opts->qos_rtr_options); + + /* optional string attributes ... */ + + fclose(opts_file); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sw_info_rcv.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sw_info_rcv.c new file mode 100644 index 00000000..9fbdb145 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sw_info_rcv.c @@ -0,0 +1,681 @@ +/* + * 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: + * Implementation of osm_si_rcv_t. + * This object represents the SwitchInfo Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_si_rcv_get_port_info( + IN const osm_si_rcv_t* const p_rcv, + IN osm_switch_t* const p_sw, + IN const osm_madw_t* const p_madw ) +{ + osm_madw_context_t context; + uint8_t port_num; + osm_physp_t *p_physp; + osm_node_t *p_node; + uint8_t num_ports; + osm_dr_path_t dr_path; + const ib_smp_t* p_smp; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_si_rcv_get_port_info ); + + CL_ASSERT( p_sw ); + + p_node = osm_switch_get_node_ptr( p_sw ); + p_smp = osm_madw_get_smp_ptr( p_madw ); + + CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH ); + + /* + Request PortInfo attribute for each port on the switch. + Don't trust the port's own DR Path, since it may no longer + be a legitimate path through the subnet. + Build a path from the mad instead, since we know that path works. + The port's DR Path info gets updated when the PortInfo + attribute is received. + */ + p_physp = osm_node_get_any_physp_ptr( p_node ); + + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + + context.pi_context.node_guid = osm_node_get_node_guid( p_node ); + context.pi_context.port_guid = osm_physp_get_port_guid( p_physp ); + context.pi_context.set_method = FALSE; + context.pi_context.update_master_sm_base_lid = FALSE; + context.pi_context.ignore_errors = FALSE; + context.pi_context.light_sweep = FALSE; + context.pi_context.active_transition = FALSE; + + num_ports = osm_node_get_num_physp( p_node ); + osm_dr_path_init( &dr_path, + osm_madw_get_bind_handle( p_madw ), + p_smp->hop_count, p_smp->initial_path ); + + for( port_num = 0; port_num < num_ports; port_num++) + { + status = osm_req_get( + p_rcv->p_req, + &dr_path, + IB_MAD_ATTR_PORT_INFO, + cl_hton32( port_num ), + CL_DISP_MSGID_NONE, + &context ); + if( status != IB_SUCCESS ) + { + /* continue the loop despite the error */ + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_si_rcv_get_port_info: ERR 3602: " + "Failure initiating PortInfo request (%s)\n", + ib_get_err_str(status)); + } + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_si_rcv_get_fwd_tbl( + IN const osm_si_rcv_t* const p_rcv, + IN osm_switch_t* const p_sw ) +{ + osm_madw_context_t context; + osm_dr_path_t *p_dr_path; + osm_physp_t *p_physp; + osm_node_t *p_node; + uint32_t block_id_ho; + uint32_t max_block_id_ho; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_si_rcv_get_fwd_tbl ); + + CL_ASSERT( p_sw ); + + p_node = osm_switch_get_node_ptr( p_sw ); + + CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH ); + + p_physp = osm_node_get_any_physp_ptr( p_node ); + + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + + 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_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++) + { + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_si_rcv_get_fwd_tbl: " + "Retrieving FT block %u\n", block_id_ho ); + } + + status = osm_req_get( + p_rcv->p_req, + 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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_si_rcv_get_fwd_tbl: ERR 3603: " + "Failure initiating PortInfo request (%s)\n", + ib_get_err_str(status)); + } + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +#if 0 +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_si_rcv_get_mcast_fwd_tbl( + IN const osm_si_rcv_t* const p_rcv, + IN osm_switch_t* const p_sw ) +{ + osm_madw_context_t context; + osm_dr_path_t *p_dr_path; + osm_physp_t *p_physp; + osm_node_t *p_node; + osm_mcast_tbl_t* p_tbl; + uint32_t block_id_ho; + uint32_t max_block_id_ho; + uint32_t position; + uint32_t max_position; + uint32_t attr_mod_ho; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_si_rcv_get_mcast_fwd_tbl ); + + CL_ASSERT( p_sw ); + + p_node = osm_switch_get_node_ptr( p_sw ); + + 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( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_si_rcv_get_mcast_fwd_tbl: " + "Multicast not supported by switch 0x%016" PRIx64 "\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) ) ); + goto Exit; + } + + p_physp = osm_node_get_any_physp_ptr( p_node ); + p_tbl = osm_switch_get_mcast_tbl_ptr( p_sw ); + + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + + context.mft_context.node_guid = osm_node_get_node_guid( p_node ); + context.mft_context.set_method = FALSE; + + max_block_id_ho = osm_mcast_tbl_get_max_block( p_tbl ); + + if( max_block_id_ho > IB_MCAST_MAX_BLOCK_ID ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_si_rcv_get_mcast_fwd_tbl: 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( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_si_rcv_get_mcast_fwd_tbl: " + "Max MFT block = %u, Max position = %u\n", max_block_id_ho, + max_position ); + + 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++) + { + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_si_rcv_get_mcast_fwd_tbl: " + "Retrieving MFT block %u\n", block_id_ho ); + } + + for( position = 0; position <= max_position; position++ ) + { + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_si_rcv_get_mcast_fwd_tbl: " + "Retrieving MFT position %u\n", position ); + } + + attr_mod_ho = block_id_ho | position << IB_MCAST_POSITION_SHIFT; + status = osm_req_get( + p_rcv->p_req, + 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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_si_rcv_get_mcast_fwd_tbl: ERR 3607: " + "Failure initiating PortInfo request (%s)\n", + ib_get_err_str(status)); + } + } + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} +#endif + +/********************************************************************** + Lock must be held on entry to this function. +**********************************************************************/ +static void +__osm_si_rcv_process_new( + IN const osm_si_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ) +{ + osm_switch_t *p_sw; + osm_switch_t *p_check; + ib_switch_info_t *p_si; + ib_smp_t *p_smp; + cl_qmap_t *p_sw_guid_tbl; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, __osm_si_rcv_process_new ); + + CL_ASSERT( p_madw ); + + p_sw_guid_tbl = &p_rcv->p_subn->sw_guid_tbl; + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_si = (ib_switch_info_t*)ib_smp_get_payload_ptr( p_smp ); + + osm_dump_switch_info( p_rcv->p_log, p_si, OSM_LOG_DEBUG ); + + /* + Allocate a new switch object for this switch, + and place it in the switch table. + */ + p_sw = osm_switch_new( p_node, p_madw ); + if( p_sw == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_si_rcv_process_new: ERR 3608: " + "Unable to allocate new switch object\n" ); + goto Exit; + } + + /* set subnet max mlid to the minimum MulticastFDBCap of all switches */ + if ( p_sw->mcast_tbl.max_mlid_ho < p_rcv->p_subn->max_multicast_lid_ho ) + { + p_rcv->p_subn->max_multicast_lid_ho = p_sw->mcast_tbl.max_mlid_ho; + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_si_rcv_process_new: " + "Subnet max multicast lid is 0x%X\n", + p_rcv->p_subn->max_multicast_lid_ho ); + } + + /* set subnet max unicast lid to the minimum LinearFDBCap of all switches */ + if ( p_sw->fwd_tbl.p_lin_tbl->size < p_rcv->p_subn->max_unicast_lid_ho ) + { + p_rcv->p_subn->max_unicast_lid_ho = p_sw->fwd_tbl.p_lin_tbl->size; + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_si_rcv_process_new: " + "Subnet max unicast lid is 0x%X\n", + p_rcv->p_subn->max_unicast_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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_si_rcv_process_new: 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 ); + osm_switch_discovery_count_inc( p_sw ); + + /* + Get the PortInfo attribute for every port. + */ + __osm_si_rcv_get_port_info( p_rcv, p_sw, p_madw ); + __osm_si_rcv_get_fwd_tbl( p_rcv, p_sw ); + + /* + Don't bother retrieving the current multicast tables + from the switches. The current version of SM does + not support silent take-over of an existing multicast + configuration. + + Gathering the multicast tables can also generate large amounts + of extra subnet-init traffic. + + The code to retrieve the tables was fully debugged. + */ +#if 0 + if( !p_rcv->p_subn->opt.disable_multicast ) + __osm_si_rcv_get_mcast_fwd_tbl( p_rcv, p_sw ); +#endif + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + Lock must be held on entry to this function. + Return 1 if the caller is expected to send a change_detected event. + this can not be done internally as the event needs the lock... +**********************************************************************/ +static boolean_t +__osm_si_rcv_process_existing( + IN const osm_si_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ) +{ + osm_switch_t *p_sw = p_node->sw; + ib_switch_info_t *p_si; + osm_si_context_t *p_si_context; + ib_smp_t *p_smp; + boolean_t is_change_detected = FALSE; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_si_rcv_process_existing ); + + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_si = (ib_switch_info_t*)ib_smp_get_payload_ptr( p_smp ); + p_si_context = osm_madw_get_si_context_ptr( p_madw ); + + if( p_si_context->set_method ) + { + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_si_rcv_process_existing: " + "Received logical SetResp()\n" ); + } + + osm_switch_set_switch_info( p_sw, p_si ); + } + else + { + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_si_rcv_process_existing: " + "Received logical GetResp()\n" ); + } + + osm_switch_set_switch_info( p_sw, p_si ); + + /* + Check the port state change bit. If true, then this switch + has seen a port state transition, so continue probing. + */ + if( p_si_context->light_sweep == TRUE ) + { + /* This is a light sweep */ + /* If the mad was returned with an error - + signal a change to the state manager. */ + if ( ib_smp_get_status( p_smp ) != 0 ) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_si_rcv_process_existing: " + "GetResp() received with error in light sweep. " + "Commencing heavy sweep\n" ); + is_change_detected = TRUE; + } + else + { + /* + If something changed, then just signal the state + manager. Don't attempt to probe further during + a light sweep. + */ + if( ib_switch_info_get_state_change( p_si ) ) + { + osm_dump_switch_info( p_rcv->p_log, p_si, OSM_LOG_DEBUG ); + is_change_detected = TRUE; + } + } + } + else + { + /* + This is a heavy sweep. Get information regardless + of the state change bit. + */ + osm_switch_discovery_count_inc( p_sw ); + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_si_rcv_process_existing: " + "discovery_count is:%u\n", + osm_switch_discovery_count_get( p_sw ) ); + + /* If this is the first discovery - then get the port_info */ + if ( osm_switch_discovery_count_get( p_sw ) == 1 ) + __osm_si_rcv_get_port_info( p_rcv, p_sw, p_madw ); + else + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_si_rcv_process_existing: " + "Not discovering again through switch:0x%" + PRIx64 "\n", + osm_node_get_node_guid( p_sw->p_node) ); + } + } + } + + OSM_LOG_EXIT( p_rcv->p_log ); + return is_change_detected; +} + +/********************************************************************** + **********************************************************************/ +void +osm_si_rcv_construct( + IN osm_si_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_si_rcv_destroy( + IN osm_si_rcv_t* const p_rcv ) +{ + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_si_rcv_destroy ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_si_rcv_init( + IN osm_si_rcv_t* const p_rcv, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_req_t* const p_req, + IN osm_state_mgr_t* const p_state_mgr, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + OSM_LOG_ENTER( p_log, osm_si_rcv_init ); + + osm_si_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_req = p_req; + p_rcv->p_state_mgr = p_state_mgr; + + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_si_rcv_process( + IN const osm_si_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ) +{ + cl_qmap_t *p_node_guid_tbl; + 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( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_si_rcv_process ); + + CL_ASSERT( p_madw ); + + p_node_guid_tbl = &p_rcv->p_subn->node_guid_tbl; + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_si = (ib_switch_info_t*)ib_smp_get_payload_ptr( p_smp ); + + /* + Acquire the switch object and add the switch info. + */ + + p_context = osm_madw_get_si_context_ptr( p_madw ); + + node_guid = p_context->node_guid; + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_si_rcv_process: " + "Switch GUID 0x%016" PRIx64 + ", TID 0x%" PRIx64 "\n", + cl_ntoh64( node_guid ), + cl_ntoh64( p_smp->trans_id ) ); + } + + CL_PLOCK_EXCL_ACQUIRE( p_rcv->p_lock ); + + p_node = (osm_node_t*)cl_qmap_get( p_node_guid_tbl, node_guid ); + if( p_node == (osm_node_t*)cl_qmap_end( p_node_guid_tbl ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_si_rcv_process: ERR 3606: " + "SwitchInfo received for nonexistent node " + "with GUID 0x%" PRIx64 "\n", + cl_ntoh64( node_guid ) ); + } + else + { + + /* + Hack for bad value in Mellanox switch + */ + if( cl_ntoh16( p_si->lin_top ) > IB_LID_UCAST_END_HO ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_si_rcv_process: ERR 3610: " + "\n\t\t\t\tBad LinearFDBTop value = 0x%X " + "on switch 0x%" PRIx64 + "\n\t\t\t\tForcing correction to 0x%X\n", + cl_ntoh16( p_si->lin_top ), + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + 0 ); + + p_si->lin_top = 0; + } + + /* + Acquire the switch object for this switch. + */ + if( !p_node->sw ) + { + __osm_si_rcv_process_new( p_rcv, p_node, p_madw ); + /* + A new switch was found during the sweep so we need + to ignore the current LFT settings. + */ + p_rcv->p_subn->ignore_existing_lfts = TRUE; + } + else + { + /* we might get back a request for signaling change was detected */ + if (__osm_si_rcv_process_existing( p_rcv, p_node, p_madw )) + { + CL_PLOCK_RELEASE( p_rcv->p_lock ); + osm_state_mgr_process( p_rcv->p_state_mgr, + OSM_SIGNAL_CHANGE_DETECTED ); + goto Exit; + } + } + } + + CL_PLOCK_RELEASE( p_rcv->p_lock ); + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sw_info_rcv_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sw_info_rcv_ctrl.c new file mode 100644 index 00000000..4b2170de --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sw_info_rcv_ctrl.c @@ -0,0 +1,126 @@ +/* + * 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: + * Implementation of osm_si_rcv_ctrl_t. + * This object represents the SwitchInfo request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_si_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_si_rcv_process( ((osm_si_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_si_rcv_ctrl_construct( + IN osm_si_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_si_rcv_ctrl_destroy( + IN osm_si_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_si_rcv_ctrl_init( + IN osm_si_rcv_ctrl_t* const p_ctrl, + IN osm_si_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_si_rcv_ctrl_init ); + + osm_si_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_SWITCH_INFO, + __osm_si_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_si_rcv_ctrl_init: ERR 3701: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sweep_fail_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sweep_fail_ctrl.c new file mode 100644 index 00000000..547825cc --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sweep_fail_ctrl.c @@ -0,0 +1,133 @@ +/* + * 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: + * Implementation of osm_sweep_fail_ctrl_t. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_sweep_fail_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + osm_sweep_fail_ctrl_t* const p_ctrl = (osm_sweep_fail_ctrl_t*)context; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sweep_fail_ctrl_disp_callback ); + + UNUSED_PARAM( p_data ); + /* + Notify the state manager that we had a light sweep failure. + */ + osm_state_mgr_process( p_ctrl->p_state_mgr, + OSM_SIGNAL_LIGHT_SWEEP_FAIL ); + + OSM_LOG_EXIT( p_ctrl->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sweep_fail_ctrl_construct( + IN osm_sweep_fail_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_sweep_fail_ctrl_destroy( + IN osm_sweep_fail_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sweep_fail_ctrl_init( + IN osm_sweep_fail_ctrl_t* const p_ctrl, + IN osm_log_t* const p_log, + IN osm_state_mgr_t* const p_state_mgr, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_sweep_fail_ctrl_init ); + + osm_sweep_fail_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_disp = p_disp; + p_ctrl->p_state_mgr = p_state_mgr; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_LIGHT_SWEEP_FAIL, + __osm_sweep_fail_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_sweep_fail_ctrl_init: ERR 3501: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_switch.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_switch.c new file mode 100644 index 00000000..23bb8b68 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_switch.c @@ -0,0 +1,550 @@ +/* + * 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: + * Implementation of osm_switch_t. + * This object represents an Infiniband switch. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.13 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_switch_construct( + IN osm_switch_t* const p_sw ) +{ + CL_ASSERT( p_sw ); + memset( p_sw, 0, sizeof(*p_sw) ); + osm_lid_matrix_construct( &p_sw->lmx ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_switch_init( + IN osm_switch_t* const p_sw, + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ) +{ + ib_api_status_t status = IB_SUCCESS; + ib_switch_info_t *p_si; + ib_smp_t *p_smp; + uint8_t num_ports; + uint32_t port_num; + + CL_ASSERT( p_sw ); + CL_ASSERT( p_madw ); + CL_ASSERT( p_node ); + + osm_switch_construct( p_sw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_si = (ib_switch_info_t*)ib_smp_get_payload_ptr( p_smp ); + num_ports = osm_node_get_num_physp( p_node ); + + CL_ASSERT( p_smp->attr_id == IB_MAD_ATTR_SWITCH_INFO ); + + p_sw->p_node = p_node; + p_sw->switch_info = *p_si; + + status = osm_lid_matrix_init( &p_sw->lmx, num_ports ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_fwd_tbl_init( &p_sw->fwd_tbl, p_si ); + if( status != IB_SUCCESS ) + goto Exit; + + p_sw->p_prof = malloc( sizeof(*p_sw->p_prof) * num_ports ); + if( p_sw->p_prof == NULL ) + { + status = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + + memset( p_sw->p_prof, 0, sizeof(*p_sw->p_prof) * num_ports ); + + status = osm_mcast_tbl_init( &p_sw->mcast_tbl, + osm_node_get_num_physp( p_node ), cl_ntoh16( p_si->mcast_cap ) ); + if( status != IB_SUCCESS ) + goto Exit; + + for( port_num = 0; port_num < num_ports; port_num++ ) + osm_port_prof_construct( &p_sw->p_prof[port_num] ); + + Exit: + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_switch_destroy( + IN osm_switch_t* const p_sw ) +{ + /* free memory to avoid leaks */ + osm_mcast_tbl_destroy( &p_sw->mcast_tbl ); + free( p_sw->p_prof ); + osm_fwd_tbl_destroy( &p_sw->fwd_tbl ); + osm_lid_matrix_destroy( &p_sw->lmx ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_switch_delete( + IN OUT osm_switch_t** const pp_sw ) +{ + osm_switch_destroy( *pp_sw ); + free( *pp_sw ); + *pp_sw = NULL; +} + +/********************************************************************** + **********************************************************************/ +osm_switch_t* +osm_switch_new( + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ) +{ + ib_api_status_t status; + osm_switch_t *p_sw; + + p_sw = (osm_switch_t*)malloc( sizeof(*p_sw) ); + if( p_sw ) + { + memset( p_sw, 0, sizeof(*p_sw) ); + status = osm_switch_init( p_sw, p_node, p_madw ); + if( status != IB_SUCCESS ) + osm_switch_delete( &p_sw ); + } + + return( p_sw ); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_switch_get_fwd_tbl_block( + IN const osm_switch_t* const p_sw, + IN const uint32_t block_id, + OUT uint8_t* const p_block ) +{ + uint16_t base_lid_ho; + uint16_t max_lid_ho; + uint16_t lid_ho; + uint16_t block_top_lid_ho; + uint32_t lids_per_block; + osm_fwd_tbl_t *p_tbl; + boolean_t return_flag = FALSE; + + CL_ASSERT( p_sw ); + CL_ASSERT( p_block ); + + p_tbl = osm_switch_get_fwd_tbl_ptr( p_sw ); + max_lid_ho = osm_switch_get_max_lid_ho( p_sw ); + lids_per_block = osm_fwd_tbl_get_lids_per_block( &p_sw->fwd_tbl ); + base_lid_ho = (uint16_t)(block_id * lids_per_block); + + if( base_lid_ho <= max_lid_ho ) + { + /* Initialize LIDs in block to invalid port number. */ + memset( p_block, 0xff, IB_SMP_DATA_SIZE ); + /* + Determine the range of LIDs we can return with this block. + */ + block_top_lid_ho = (uint16_t)(base_lid_ho + lids_per_block - 1); + if( block_top_lid_ho > max_lid_ho ) + block_top_lid_ho = max_lid_ho; + + /* + Configure the forwarding table with the routing + information for the specified block of LIDs. + */ + for( lid_ho = base_lid_ho; lid_ho <= block_top_lid_ho; lid_ho++ ) + { + p_block[lid_ho - base_lid_ho] = osm_fwd_tbl_get( p_tbl, lid_ho ); + } + + return_flag = TRUE; + } + + return( return_flag ); +} + +/********************************************************************** + **********************************************************************/ +uint8_t +osm_switch_recommend_path( + IN const osm_switch_t* const p_sw, + IN const uint16_t lid_ho, + IN const boolean_t ignore_existing, + IN OUT uint64_t *remote_sys_guids, + IN OUT uint16_t *p_num_used_sys, + IN OUT uint64_t *remote_node_guids, + IN OUT uint16_t *p_num_used_nodes + ) +{ + /* + 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 the procedure is provided with the tracking arrays + and counters we can conduct this algorithm. + */ + boolean_t routing_for_lmc = remote_sys_guids && remote_node_guids && + p_num_used_sys && p_num_used_nodes; + boolean_t sys_used, node_used; + uint16_t i; + uint8_t hops; + uint8_t least_hops; + uint8_t port_num; + uint8_t num_ports; + uint32_t least_paths = 0xFFFFFFFF; + /* + 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 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; + + CL_ASSERT( lid_ho > 0 ); + + num_ports = osm_switch_get_num_ports( p_sw ); + + least_hops = osm_switch_get_least_hops( p_sw, lid_ho ); + 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_fwd_tbl_get( &p_sw->fwd_tbl, lid_ho ); + + if (port_num != OSM_NO_PATH) + { + 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( (port_num < num_ports ) && + osm_physp_is_valid(p_physp) && + osm_physp_is_healthy(p_physp) && + osm_physp_get_remote(p_physp) ) + { + hops = osm_switch_get_hop_count( p_sw, lid_ho, 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 zero and num_ports is 1 + num phys ports */ + for ( port_num = 0; port_num < num_ports; port_num++ ) + { + if ( osm_switch_get_hop_count( p_sw, lid_ho, port_num ) == least_hops) + { + /* let us make sure it is not down or unhealthy */ + p_physp = osm_node_get_physp_ptr(p_sw->p_node, port_num); + if (osm_physp_is_valid(p_physp) && + osm_physp_is_healthy(p_physp) && + /* + we require all - non sma ports to be linked + to be routed through + */ + (!port_num || osm_physp_get_remote(p_physp))) + { + + /* + We located a least-hop port, possibly one of many. + For this port, check the running total count of + the number of paths through this port. Select + the port routing the least number of paths. + */ + check_count = osm_port_prof_path_count_get( + &p_sw->p_prof[port_num] ); + + /* + Advanced LMC routing requires tracking of the + best port by the node connected to the other side of + it. + */ + if (routing_for_lmc && port_num) + { +#if 0 + printf("LID:0x%X SYS:%d NODE:%d\n", lid_ho, *p_num_used_sys, *p_num_used_nodes); +#endif + + /* Get the Remote Node */ + p_rem_physp = osm_physp_get_remote(p_physp); + p_rem_node = osm_physp_get_node_ptr(p_rem_physp); + + /* Is the sys guid already used ? */ + sys_used = FALSE; + for (i = 0; !sys_used && (i < *p_num_used_sys); i++) + if (!memcmp(&p_rem_node->node_info.sys_guid, + &remote_sys_guids[i], + sizeof(uint64_t))) + sys_used = TRUE; + + /* If not update the least hops for this case */ + if (!sys_used) + { + if (check_count < least_paths_other_sys) + { + least_paths_other_sys = check_count; + best_port_other_sys = port_num; + } + } + else + { /* same sys found - try node */ + + /* Else is the node guid already used ? */ + node_used = FALSE; + for (i = 0; !node_used && (i < *p_num_used_nodes); i++) + if (!memcmp(&p_rem_node->node_info.node_guid, + &remote_node_guids[i], + sizeof(uint64_t))) + node_used = TRUE; + + + /* If not update the least hops for this case */ + if (!node_used) + { + if (check_count < least_paths_other_nodes) + { + least_paths_other_nodes = check_count; + best_port_other_node = port_num; + } + } + + } /* 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 ( 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; + + /* track the remote node and system of the port used. */ + p_physp = osm_node_get_physp_ptr(p_sw->p_node, best_port); + p_rem_physp = osm_physp_get_remote(p_physp); + p_rem_node = osm_physp_get_node_ptr(p_rem_physp); + memcpy(&remote_node_guids[*p_num_used_nodes], + &(p_rem_node->node_info.node_guid), + sizeof(uint64_t)); + (*p_num_used_nodes)++; + memcpy(&remote_sys_guids[*p_num_used_sys], + &(p_rem_node->node_info.sys_guid), + sizeof(uint64_t)); + (*p_num_used_sys)++; + } + + return( best_port ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_switch_prepare_path_rebuild( + IN osm_switch_t* const p_sw ) +{ + uint8_t port_num; + uint8_t num_ports; + + num_ports = osm_switch_get_num_ports( p_sw ); + osm_lid_matrix_clear( &p_sw->lmx ); + for( port_num = 0; port_num < num_ports; port_num++ ) + osm_port_prof_construct( &p_sw->p_prof[port_num] ); +} + +/********************************************************************** + **********************************************************************/ +uint8_t +osm_switch_recommend_mcast_path( + IN osm_switch_t* const p_sw, + IN uint16_t const lid_ho, + IN uint16_t const mlid_ho, + IN boolean_t const ignore_existing ) +{ + uint8_t hops; + uint8_t port_num; + uint8_t num_ports; + uint8_t least_hops; + + CL_ASSERT( lid_ho > 0 ); + CL_ASSERT( mlid_ho >= IB_LID_MCAST_START_HO ); + + num_ports = osm_switch_get_num_ports( p_sw ); + + /* + 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 ) ) + { + /* + 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, lid_ho, 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, lid_ho ); + for( port_num = 0; port_num < num_ports; port_num++ ) + { + if( osm_switch_get_hop_count( p_sw, lid_ho, port_num ) == least_hops ) + break; + } + + CL_ASSERT( port_num < num_ports ); + return( port_num ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_trap_rcv.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_trap_rcv.c new file mode 100644 index 00000000..3fe79324 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_trap_rcv.c @@ -0,0 +1,771 @@ +/* + * 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: + * Implementation of osm_trap_rcv_t. + * This object represents the Trap Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.12 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + * + * TRAP HANDLING: + * + * Assuming traps can be caused by bad hardware we should provide + * a mechanism for filtering their propagation into the actual logic + * of OpenSM such that it is not overloaded by them. + * + * We will provide a trap filtering mechanism with "Aging" capability. + * This mechanism will track incoming traps, clasify them by their + * source and content and provide back their age. + * + * A timer running in the background will toggle a timer counter + * that should be referenced by the aging algorithm. + * To provide an efficient handling of aging. We also track all traps + * in a sorted list by their aging. + * + * The generic Aging Tracker mechanism is implemented in the + * cl_aging_tracker object. + * + **********************************************************************/ + +typedef struct _osm_trap_aging_tracker_context +{ + osm_log_t* p_log; + osm_physp_t* p_physp; +} osm_trap_aging_tracker_context_t; + +/********************************************************************** + **********************************************************************/ +osm_physp_t * +__get_physp_by_lid_and_num( + IN osm_trap_rcv_t* const p_rcv, + IN uint16_t lid, + IN uint8_t num) +{ + cl_ptr_vector_t *p_vec = &(p_rcv->p_subn->port_lid_tbl); + osm_port_t *p_port; + + if (lid > cl_ptr_vector_get_size(p_vec)) + return NULL; + + p_port = (osm_port_t *)cl_ptr_vector_get(p_vec, lid); + if (! p_port) + return NULL; + + if (osm_port_get_num_physp(p_port) < num) + return NULL; + + return( osm_port_get_phys_ptr(p_port, num) ); +} + +/********************************************************************** + **********************************************************************/ +uint64_t +osm_trap_rcv_aging_tracker_callback( + IN uint64_t key, + IN uint32_t num_regs, + IN void* context ) +{ + osm_trap_rcv_t* p_rcv = (osm_trap_rcv_t*)context; + uint16_t lid; + uint8_t port_num; + osm_physp_t* p_physp; + + OSM_LOG_ENTER( p_rcv->p_log, osm_trap_rcv_aging_tracker_callback ); + + if (osm_exit_flag) + /* We got an exit flag - do nothing */ + return 0; + + lid = cl_ntoh16((uint16_t)(( key & 0x0000FFFF00000000ULL) >> 32)); + port_num = (uint8_t)(( key & 0x00FF000000000000ULL) >> 48); + + p_physp = __get_physp_by_lid_and_num( p_rcv, lid, port_num ); + if (!p_physp) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_trap_rcv_aging_tracker_callback: " + "Cannot find port num:0x%X with lid:%u\n", + port_num, lid ); + } + else + { + /* make sure the physp is still valid */ + if ( osm_physp_is_valid(p_physp) ) + { + /* If the health port was false - set it to true */ + if (!osm_physp_is_healthy(p_physp) ) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_trap_rcv_aging_tracker_callback: " + "Clearing health bit of port num:%u with lid:%u\n", + port_num, lid ); + + /* Clear its health bit */ + osm_physp_set_health(p_physp, TRUE); + } + } + } + + OSM_LOG_EXIT (p_rcv->p_log ); + + /* We want to remove the event from the tracker - so + need to return zero. */ + return 0; +} + +/********************************************************************** + **********************************************************************/ +void +osm_trap_rcv_construct( + IN osm_trap_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_event_wheel_construct( &p_rcv->trap_aging_tracker ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_trap_rcv_destroy( + IN osm_trap_rcv_t* const p_rcv ) +{ + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_trap_rcv_destroy ); + + cl_event_wheel_destroy( &p_rcv->trap_aging_tracker ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_trap_rcv_init( + IN osm_trap_rcv_t* const p_rcv, + IN osm_subn_t* const p_subn, + IN osm_stats_t* const p_stats, + IN osm_resp_t* const p_resp, + IN osm_log_t* const p_log, + IN osm_state_mgr_t* const p_state_mgr, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_trap_rcv_init ); + + osm_trap_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_stats = p_stats; + p_rcv->p_resp = p_resp; + p_rcv->p_state_mgr = p_state_mgr; + + cl_event_wheel_init( &p_rcv->trap_aging_tracker, p_log ); + + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + * CRC calculation for notice identification + **********************************************************************/ + +#define CRC32_POLYNOMIAL 0xEDB88320L + +/* calculate the crc for a given buffer */ +static uint32_t +__osm_trap_calc_crc32(void *buffer, uint32_t count) +{ + uint32_t temp1, temp2; + uint32_t crc = -1L; + unsigned char *p = (unsigned char *)buffer; + /* pre - calculated table for faster crc calculation */ + static uint32_t crc_table[256]; + static boolean_t first = TRUE; + int i, j; + + /* if we need to initialize the lookup table */ + if (first) + { + /* calc the CRC table */ + for (i = 0; i <= 255; i++) + { + crc = i; + for (j = 8; j > 0; j--) + if (crc & 1) + crc = (crc >> 1) ^ CRC32_POLYNOMIAL; + else + crc >>= 1; + crc_table[i] = crc; + } + first = FALSE; + } + + crc = -1L; + /* do the calculation */ + while (count-- != 0) + { + temp1 = (crc >> 8) & 0x00FFFFFFL; + temp2 = crc_table[((int)crc ^ *p++) & 0xFF]; + crc = temp1 ^ temp2; + } + return crc; +} + +/******************************************************************** + ********************************************************************/ + +/* The key is created in the following manner: + port_num lid crc + \______/ \___/ \___/ + 16b 16b 32b +*/ +static void +__osm_trap_get_key( + IN uint16_t lid, + IN uint8_t port_num, + IN ib_mad_notice_attr_t* p_ntci, + OUT uint64_t *trap_key) +{ + uint32_t crc = 0; + + CL_ASSERT(trap_key); + + crc = __osm_trap_calc_crc32(p_ntci, sizeof(ib_mad_notice_attr_t)); + *trap_key = ((uint64_t)port_num << 48) | ((uint64_t)lid << 32) | crc; +} + +/********************************************************************** + **********************************************************************/ +static int +__print_num_received( + IN uint32_t num_received ) +{ + uint32_t i; + + /* Series is 10, 20, 50, 100, 200, 500, ... */ + i = num_received; + while (i >= 10) { + if (i % 10) + break; + i = i / 10; + } + if (i == 1 || i == 2 || i == 5) + return 1; + else + return 0; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_trap_rcv_process_request( + IN osm_trap_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + uint8_t payload[sizeof(ib_mad_notice_attr_t)]; + ib_smp_t* p_smp; + ib_mad_notice_attr_t* p_ntci = (ib_mad_notice_attr_t*)payload; + ib_api_status_t status; + osm_madw_t tmp_madw; /* we need a copy to last after repress */ + uint64_t trap_key; + uint32_t num_received; + osm_physp_t* p_physp; + cl_ptr_vector_t* p_tbl; + osm_port_t* p_port; + ib_net16_t source_lid = 0; + boolean_t is_gsi = TRUE; + uint8_t port_num = 0; + boolean_t physp_change_trap = FALSE; + uint64_t event_wheel_timeout = OSM_DEFAULT_TRAP_SUPRESSION_TIMEOUT; + boolean_t run_heavy_sweep = FALSE; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_trap_rcv_process_request ); + + 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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_trap_rcv_process_request: ERR 3801: " + "Unsupported method 0x%X\n", + p_smp->method ); + goto Exit; + } + + /* + * The NOTICE Attribute is part of the SMP CLASS attributes + * As such the actual attribute data resides inside the SMP + * payload. + */ + + memcpy(payload, &(p_smp->data), IB_SMP_DATA_SIZE); + memcpy(&tmp_madw, p_madw, sizeof( tmp_madw )); + + if (is_gsi == FALSE) + { + /* We are in smi flow */ + /* + * When we received a TRAP with dlid = 0 - it means it + * came from our own node. So we need to fix it. + */ + + if (p_madw->mad_addr.addr_type.smi.source_lid == 0) + { + /* Check if the sm_base_lid is 0. If yes - this means that + the local lid wasn't configured yet. Don't send a response + to the trap. */ + if (p_rcv->p_subn->sm_base_lid == 0) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_trap_rcv_process_request: " + "Received SLID=0 Trap with local LID=0. Ignoring MAD\n"); + goto Exit; + } + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_trap_rcv_process_request: " + "Received SLID=0 Trap. Using local LID:0x%04X instead\n", + cl_ntoh16(p_rcv->p_subn->sm_base_lid) + ); + tmp_madw.mad_addr.addr_type.smi.source_lid = p_rcv->p_subn->sm_base_lid; + } + + source_lid = tmp_madw.mad_addr.addr_type.smi.source_lid; + + /* Print some info about the incoming Trap */ + if (ib_notice_is_generic(p_ntci)) + { + if ((p_ntci->g_or_v.generic.trap_num == CL_HTON16(129)) || + (p_ntci->g_or_v.generic.trap_num == CL_HTON16(130)) || + (p_ntci->g_or_v.generic.trap_num == CL_HTON16(131))) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_trap_rcv_process_request: " + "Received Generic Notice type:0x%02X num:%u Producer:%u " + "from LID:0x%04X Port %d TID:0x%016" PRIx64 "\n", + ib_notice_get_type(p_ntci), + cl_ntoh16(p_ntci->g_or_v.generic.trap_num), + cl_ntoh32(ib_notice_get_prod_type(p_ntci)), + cl_hton16(source_lid), + p_ntci->data_details.ntc_129_131.port_num, + cl_ntoh64(p_smp->trans_id) + ); + } + else + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_trap_rcv_process_request: " + "Received Generic Notice type:0x%02X num:%u Producer:%u " + "from LID:0x%04X TID:0x%016" PRIx64 "\n", + ib_notice_get_type(p_ntci), + cl_ntoh16(p_ntci->g_or_v.generic.trap_num), + cl_ntoh32(ib_notice_get_prod_type(p_ntci)), + cl_hton16(source_lid), + cl_ntoh64(p_smp->trans_id) + ); + } + } + else + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_trap_rcv_process_request: " + "Received Vendor Notice type:0x%02X vend:0x%06X dev:%u " + "from LID:0x%04X TID:0x%016" PRIx64 "\n", + ib_notice_get_type(p_ntci), + cl_ntoh32(ib_notice_get_vend_id(p_ntci)), + cl_ntoh16(p_ntci->g_or_v.vend.dev_id), + cl_ntoh16(source_lid), + cl_ntoh64(p_smp->trans_id) + ); + } + } + + osm_dump_notice( p_rcv->p_log, p_ntci, OSM_LOG_VERBOSE ); + + status = osm_resp_send( p_rcv->p_resp, &tmp_madw, 0, payload ); + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_trap_rcv_process_request: 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 flag physp_change_trap as TRUE. */ + physp_change_trap = TRUE; + /* The source_lid should be based on the source_lid from the trap */ + source_lid = p_ntci->data_details.ntc_129_131.lid; + } + + /* If physp_change_trap is TRUE - the key will include the port number. + If not - the port_number in the key will be zero. */ + if ( physp_change_trap == TRUE ) + { + port_num = p_ntci->data_details.ntc_129_131.port_num; + __osm_trap_get_key(source_lid, port_num, p_ntci, &trap_key); + } + else + __osm_trap_get_key(source_lid, 0, p_ntci, &trap_key); + + /* try to find it in the aging tracker */ + num_received = cl_event_wheel_num_regs(&p_rcv->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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_trap_rcv_process_request: ERR 3804: " + "Received trap %u times consecutively\n", + num_received); + /* + * If the trap provides info about a bad port + * we mark it as unhealthy. + */ + if (physp_change_trap == TRUE) + { + /* get the port */ + p_physp = __get_physp_by_lid_and_num( + p_rcv, + cl_ntoh16(p_ntci->data_details.ntc_129_131.lid), + port_num + ); + + if (! p_physp) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_trap_rcv_process_request: ERR 3805: " + "Failed to find physical port by lid:0x%02X num:%u\n", + cl_ntoh16(p_ntci->data_details.ntc_129_131.lid), + p_ntci->data_details.ntc_129_131.port_num + ); + } + else + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_trap_rcv_process_request: " + "Marking unhealthy physical port by lid:0x%02X num:%u\n", + cl_ntoh16(p_ntci->data_details.ntc_129_131.lid), + p_ntci->data_details.ntc_129_131.port_num + ); + /* check if the current state of the p_physp is healthy. If + it is - then this is a first change of state. Run a heavy sweep. + if it is not - no need to mark it again - just restart the timer. */ + if ( osm_physp_is_healthy(p_physp) ) + { + osm_physp_set_health(p_physp, FALSE); + /* Make sure we sweep again - force a heavy sweep. */ + /* The sweep should be done only after the re-registration, or + else we'll be losing track of the timer. */ + run_heavy_sweep = TRUE; + } + /* If we are marking the port as unhealthy - we want to + keep this for a longer period of time than the + OSM_DEFAULT_TRAP_SUPRESSION_TIMEOUT. Use the + OSM_DEFAULT_UNHEALTHY_TIMEOUT */ + event_wheel_timeout = OSM_DEFAULT_UNHEALTHY_TIMEOUT; + } + } + } + + /* restart the aging anyway */ + /* If physp_change_trap is TRUE - then use a callback to unset the + healthy bit. If not - no need to use a callback. */ + if (physp_change_trap == TRUE ) + cl_event_wheel_reg(&p_rcv->trap_aging_tracker, + trap_key, + cl_get_time_stamp() + event_wheel_timeout, + osm_trap_rcv_aging_tracker_callback, /* no callback */ + p_rcv /* no context */ + ); + else + cl_event_wheel_reg(&p_rcv->trap_aging_tracker, + trap_key, + cl_get_time_stamp() + event_wheel_timeout, + NULL, /* no callback */ + NULL /* no context */ + ); + + /* If was already registered do nothing more */ + if ( num_received > 10 && run_heavy_sweep == FALSE ) + { + if (__print_num_received(num_received)) + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_trap_rcv_process_request: " + "Continuously received this trap %u times. Ignoring it\n", + num_received); + goto Exit; + } + } + + /* do a sweep if we received a trap */ + if (p_rcv->p_subn->opt.sweep_on_trap) + { + /* if this is trap number 128 or run_heavy_sweep is TRUE - update the + force_single_heavy_sweep flag of the subnet. + Sweep also on traps 144/145 - these traps signal a change on a certain + port capability/system image guid. + TODO: In the future we can change this to just getting PortInfo on + this port instead of sweeping the entire subnet. */ + if (ib_notice_is_generic(p_ntci) && + ( (cl_ntoh16(p_ntci->g_or_v.generic.trap_num) == 128) || + (cl_ntoh16(p_ntci->g_or_v.generic.trap_num) == 144) || + (cl_ntoh16(p_ntci->g_or_v.generic.trap_num) == 145) || + run_heavy_sweep )) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_trap_rcv_process_request: " + "Forcing immediate heavy sweep. " + "Received trap:%u\n", + cl_ntoh16(p_ntci->g_or_v.generic.trap_num) ); + + p_rcv->p_subn->force_immediate_heavy_sweep = TRUE; + } + osm_state_mgr_process( p_rcv->p_state_mgr, 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.1 P.653 or IBA 1.2 P.739 for details. */ + if (is_gsi) + { + if (tmp_madw.mad_addr.addr_type.gsi.global_route) + { + memcpy(&(p_ntci->issuer_gid), + &(tmp_madw.mad_addr.addr_type.gsi.grh_info.src_gid), + sizeof(ib_gid_t)); + } + else + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_trap_rcv_process_request: ERR 3806: " + "Received gsi trap with global_route FALSE. " + "Cannot update issuer_gid!\n" ); + goto Exit; + } + } + else + { + /* Need to use the IssuerLID */ + p_tbl = &p_rcv->p_subn->port_lid_tbl; + + CL_ASSERT( cl_ptr_vector_get_size(p_tbl) < 0x10000 ); + + if ((uint16_t)cl_ptr_vector_get_size(p_tbl) <= cl_ntoh16(source_lid) ) + { + /* the source lid is out of range */ + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_trap_rcv_process_request: " + "source lid is out of range:0x%X\n", + cl_ntoh16(source_lid) ); + + goto Exit; + } + p_port = cl_ptr_vector_get( p_tbl, cl_ntoh16(source_lid) ); + if ( p_port == 0) + { + /* We have the lid - but no corresponding port */ + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_trap_rcv_process_request: " + "Cannot find port according to lid:0x%X\n", + cl_ntoh16(source_lid) ); + + goto Exit; + } + + p_ntci->issuer_gid.unicast.prefix = p_rcv->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( p_rcv->p_lock ); + status = osm_report_notice(p_rcv->p_log, p_rcv->p_subn, p_ntci); + CL_PLOCK_RELEASE( p_rcv->p_lock ); + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_trap_rcv_process_request: ERR 3803: " + "Error sending trap reports (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +#if 0 +/********************************************************************** + CURRENTLY WE ARE NOT CREATING TRAPS - SO THIS CALL IS AN ERROR +**********************************************************************/ +static void +__osm_trap_rcv_process_sm( + IN const osm_trap_rcv_t* const p_rcv, + IN const osm_remote_sm_t* const p_sm ) +{ + /* const ib_sm_info_t* p_smi; */ + OSM_LOG_ENTER( p_rcv->p_log, __osm_trap_rcv_process_sm ); + + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_trap_rcv_process_sm: ERR 3807: " + "This function is not supported yet\n"); + + OSM_LOG_EXIT( p_rcv->p_log ); +} +#endif + +/********************************************************************** + CURRENTLY WE ARE NOT CREATING TRAPS - SO THIS CALL IN AN ERROR +**********************************************************************/ +static void +__osm_trap_rcv_process_response( + IN const osm_trap_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + + OSM_LOG_ENTER( p_rcv->p_log, __osm_trap_rcv_process_response ); + + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_trap_rcv_process_response: ERR 3808: " + "This function is not supported yet\n"); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_trap_rcv_process( + IN osm_trap_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ) +{ + ib_smp_t *p_smp; + + OSM_LOG_ENTER( p_rcv->p_log, osm_trap_rcv_process ); + + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + + /* + Determine if this is a request for our own Trap + or if this is a response to our request for another + SM's Trap. + */ + if( ib_smp_is_response( p_smp ) ) + { + __osm_trap_rcv_process_response( p_rcv, p_madw ); + } + else + { + __osm_trap_rcv_process_request( p_rcv, p_madw ); + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_trap_rcv_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_trap_rcv_ctrl.c new file mode 100644 index 00000000..d7803506 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_trap_rcv_ctrl.c @@ -0,0 +1,126 @@ +/* + * 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: + * Implementation of osm_trap_rcv_ctrl_t. + * This object represents the Trap request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_trap_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_trap_rcv_process( ((osm_trap_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_trap_rcv_ctrl_construct( + IN osm_trap_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_trap_rcv_ctrl_destroy( + IN osm_trap_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_trap_rcv_ctrl_init( + IN osm_trap_rcv_ctrl_t* const p_ctrl, + IN osm_trap_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_trap_rcv_ctrl_init ); + + osm_trap_rcv_ctrl_construct( p_ctrl ); + + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_NOTICE, + __osm_trap_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_trap_rcv_ctrl_init: ERR 3901: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_file.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_file.c new file mode 100644 index 00000000..424fed24 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_file.c @@ -0,0 +1,413 @@ +/* + * 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: + * Implementation of OpenSM unicast routing module which loads + * routes from the dump file + * + * Environment: + * Linux User Mode + * + */ + +#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_port_t *)cl_qmap_get(&p_osm->subn.port_guid_tbl, guid); + if (!p_port || + p_port == (osm_port_t *)cl_qmap_end(&p_osm->subn.port_guid_tbl)) { + osm_log(&p_osm->log, OSM_LOG_VERBOSE, + "remap_lid: 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_fwd_tbl_get(osm_switch_get_fwd_tbl_ptr(p_sw), new_lid); + if (old_port != OSM_NO_PATH && old_port != port_num) { + osm_log(&p_osm->log, OSM_LOG_VERBOSE, + "add_path: LID collision is detected on switch " + "0x016%" PRIx64 ", will overwrite LID 0x%x entry\n", + cl_ntoh64(osm_node_get_node_guid + (osm_switch_get_node_ptr(p_sw))), new_lid); + } + + p_osm->sm.ucast_mgr.lft_buf[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, + "add_path: 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 + (osm_switch_get_node_ptr(p_sw)))); +} + +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 > osm_switch_get_num_ports(p_sw)) + len = osm_switch_get_num_ports(p_sw); + + 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.ucast_dump_file; + if (!file_name) { + osm_log(&p_osm->log, OSM_LOG_ERROR|OSM_LOG_SYS, + "do_ucast_file_load: ERR 6301: " + "ucast dump file name is not defined; " + "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, + "do_ucast_file_load: ERR 6302: " + "cannot open ucast dump file \'%s\'; " + "using default routing algorithm\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, + "do_ucast_file_load: ERR 6303: " + "Multicast dump file detected; " + "skipping parsing. Using default " + "routing algorithm\n"); + } else if (!strncmp(p, "Unicast lids", 12)) { + if (p_sw) + osm_ucast_mgr_set_fwd_table(&p_osm->sm.ucast_mgr, p_sw); + q = strstr(p, " guid 0x"); + if (!q) { + osm_log(&p_osm->log, OSM_LOG_ERROR, + "PARSE ERROR: %s:%u: " + "cannot parse switch definition\n", + file_name, lineno); + return -1; + } + p = q + 8; + sw_guid = strtoull(p, &q, 16); + if (q == p || !isspace(*q)) { + osm_log(&p_osm->log, OSM_LOG_ERROR, + "PARSE ERROR: %s:%u: " + "cannot parse switch guid: \'%s\'\n", + file_name, lineno, p); + return -1; + } + sw_guid = cl_hton64(sw_guid); + + p_sw = osm_get_switch_by_guid(&p_osm->subn, sw_guid); + if (!p_sw) { + osm_log(&p_osm->log, OSM_LOG_VERBOSE, + "do_ucast_file_load: " + "cannot find switch %016" PRIx64 "\n", + cl_ntoh64(sw_guid)); + continue; + } + memset(p_osm->sm.ucast_mgr.lft_buf, 0xff, IB_LID_UCAST_END_HO + 1); + } else if (p_sw && !strncmp(p, "0x", 2)) { + p += 2; + lid = (uint16_t)strtoul(p, &q, 16); + if (q == p || !isspace(*q)) { + osm_log(&p_osm->log, OSM_LOG_ERROR, + "PARSE ERROR: %s:%u: " + "cannot parse lid: \'%s\'\n", + file_name, lineno, p); + return -1; + } + p = q; + while (isspace(*p)) + p++; + port_num = (uint8_t)strtoul(p, &q, 10); + if (q == p || !isspace(*q)) { + osm_log(&p_osm->log, OSM_LOG_ERROR, + "PARSE ERROR: %s:%u: " + "cannot parse port: \'%s\'\n", + file_name, lineno, p); + return -1; + } + p = q; + /* additionally try to exract guid */ + q = strstr(p, " portguid 0x"); + if (!q) { + osm_log(&p_osm->log, OSM_LOG_VERBOSE, + "PARSE WARNING: %s:%u: " + "cannot find port guid " + "(maybe broken dump): \'%s\'\n", + file_name, lineno, p); + port_guid = 0; + } + else { + p = q + 12; + port_guid = strtoull(p, &q, 16); + if (q == p || (!isspace(*q) && *q != ':')) { + osm_log(&p_osm->log, OSM_LOG_VERBOSE, + "PARSE WARNING: %s:%u: " + "cannot parse port guid " + "(maybe broken dump): \'%s\'\n", + file_name, lineno, p); + port_guid = 0; + } + } + port_guid = cl_hton64(port_guid); + add_path(p_osm, p_sw, lid, port_num, port_guid); + } + } + + if (p_sw) + osm_ucast_mgr_set_fwd_table(&p_osm->sm.ucast_mgr, p_sw); + + fclose(file); + return 0; +} + +static int do_lid_matrix_file_load(void *context) +{ + char line[1024]; + uint8_t hops[256]; + char *file_name; + FILE *file; + ib_net64_t guid; + osm_opensm_t *p_osm = context; + osm_switch_t *p_sw; + unsigned lineno; + uint16_t lid; + + file_name = p_osm->subn.opt.lid_matrix_dump_file; + if (!file_name) { + osm_log(&p_osm->log, OSM_LOG_ERROR|OSM_LOG_SYS, + "do_lid_matrix_file_load: ERR 6304: " + "lid matrix file name is not defined; " + "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, + "do_lid_matrix_file_load: ERR 6305: " + "cannot open lid matrix file \'%s\'; " + "using default lid matrix generation algorithm\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, + "do_lid_matrix_file_load: " + "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(osm_opensm_t * p_osm) +{ + p_osm->routing_engine.context = (void *)p_osm; + p_osm->routing_engine.build_lid_matrices = do_lid_matrix_file_load; + p_osm->routing_engine.ucast_build_fwd_tables = do_ucast_file_load; + return 0; +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_ftree.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_ftree.c new file mode 100644 index 00000000..6a8eae2d --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_ftree.c @@ -0,0 +1,3141 @@ +/* + * 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: + * Implementation of OpenSM FatTree routing + * + * Environment: + * Linux User Mode + * + */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#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 pathes, + * 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_fwd_tbl_t definition + ** + ***************************************************/ + +typedef uint8_t * ftree_fwd_tbl_t; +#define FTREE_FWD_TBL_LEN (IB_LID_UCAST_END_HO + 1) + +/*************************************************** + ** + ** ftree_port_t definition + ** + ***************************************************/ + +typedef struct ftree_port_t_ +{ + cl_map_item_t map_item; + uint8_t port_num; /* port number on the current node */ + uint8_t remote_port_num; /* port number on the remote node */ + uint32_t counter_up; /* number of allocated routs upwards */ + uint32_t counter_down; /* number of allocated routs downwards */ +} ftree_port_t; + +/*************************************************** + ** + ** ftree_port_group_t definition + ** + ***************************************************/ + +typedef struct ftree_port_group_t_ +{ + cl_map_item_t map_item; + ib_net16_t base_lid; /* base lid of the current node */ + ib_net16_t remote_base_lid; /* base lid of the remote node */ + ib_net64_t port_guid; /* port guid of this port */ + ib_net64_t 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,...} */ + union remote_hca_or_sw_ + { + struct ftree_hca_t_ * remote_hca; + struct ftree_sw_t_ * remote_sw; + } remote_hca_or_sw; /* pointer to remote hca/switch */ + cl_ptr_vector_t ports; /* vector of ports to the same lid */ +} 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; + uint8_t rank; + ftree_tuple_t tuple; + ib_net16_t base_lid; + ftree_port_group_t ** down_port_groups; + uint8_t down_port_groups_num; + ftree_port_group_t ** up_port_groups; + uint8_t up_port_groups_num; + ftree_fwd_tbl_t lft_buf; +} 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; +} 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; + uint8_t tree_rank; + ftree_sw_t ** leaf_switches; + uint32_t leaf_switches_num; + uint16_t max_hcas_per_leaf; + cl_pool_t sw_fwd_tbl_pool; + uint16_t lft_max_lid_ho; + boolean_t fabric_built; +} ftree_fabric_t; + +/*************************************************** + ** + ** comparators + ** + ***************************************************/ + +static int OSM_CDECL +__osm_ftree_compare_switches_by_index( + IN const void * p1, + IN const void * p2) +{ + ftree_sw_t ** pp_sw1 = (ftree_sw_t **)p1; + ftree_sw_t ** pp_sw2 = (ftree_sw_t **)p2; + + uint16_t i; + for (i = 0; i < FTREE_TUPLE_LEN; i++) + { + if ((*pp_sw1)->tuple[i] > (*pp_sw2)->tuple[i]) + return 1; + if ((*pp_sw1)->tuple[i] < (*pp_sw2)->tuple[i]) + return -1; + } + return 0; +} + +/***************************************************/ + +static int OSM_CDECL +__osm_ftree_compare_port_groups_by_remote_switch_index( + IN const void * p1, + IN const void * p2) +{ + ftree_port_group_t ** pp_g1 = (ftree_port_group_t **)p1; + ftree_port_group_t ** pp_g2 = (ftree_port_group_t **)p2; + + return __osm_ftree_compare_switches_by_index( + &((*pp_g1)->remote_hca_or_sw.remote_sw), + &((*pp_g2)->remote_hca_or_sw.remote_sw) ); +} + +/***************************************************/ + +boolean_t +__osm_ftree_sw_less_by_index( + IN ftree_sw_t * p_sw1, + IN ftree_sw_t * p_sw2) +{ + if (__osm_ftree_compare_switches_by_index((void *)&p_sw1, + (void *)&p_sw2) < 0) + return TRUE; + return FALSE; +} + +/***************************************************/ + +boolean_t +__osm_ftree_sw_greater_by_index( + IN ftree_sw_t * p_sw1, + IN ftree_sw_t * p_sw2) +{ + if (__osm_ftree_compare_switches_by_index((void *)&p_sw1, + (void *)&p_sw2) > 0) + return TRUE; + return FALSE; +} + +/*************************************************** + ** + ** ftree_tuple_t functions + ** + ***************************************************/ + +static void +__osm_ftree_tuple_init( + IN ftree_tuple_t tuple) +{ + memset(tuple, 0xFF, FTREE_TUPLE_LEN); +} + +/***************************************************/ + +static inline boolean_t +__osm_ftree_tuple_assigned( + IN ftree_tuple_t tuple) +{ + return (tuple[0] != 0xFF); +} + +/***************************************************/ + +#define FTREE_TUPLE_BUFFERS_NUM 6 + +static char * +__osm_ftree_tuple_to_str( + IN ftree_tuple_t tuple) +{ + static char buffer[FTREE_TUPLE_BUFFERS_NUM][FTREE_TUPLE_BUFF_LEN]; + static uint8_t ind = 0; + char * ret_buffer; + uint32_t i; + + if (!__osm_ftree_tuple_assigned(tuple)) + return "INDEX.NOT.ASSIGNED"; + + buffer[ind][0] = '\0'; + + for(i = 0; (i < FTREE_TUPLE_LEN) && (tuple[i] != 0xFF); i++) + { + if ((strlen(buffer[ind]) + 10) > FTREE_TUPLE_BUFF_LEN) + return "INDEX.TOO.LONG"; + if (i != 0) + strcat(buffer[ind],"."); + sprintf(&buffer[ind][strlen(buffer[ind])], "%u", tuple[i]); + } + + ret_buffer = buffer[ind]; + ind = (ind + 1) % FTREE_TUPLE_BUFFERS_NUM; + return ret_buffer; +} /* __osm_ftree_tuple_to_str() */ + +/***************************************************/ + +static inline ftree_tuple_key_t +__osm_ftree_tuple_to_key( + IN ftree_tuple_t tuple) +{ + ftree_tuple_key_t key; + memcpy(&key, tuple, FTREE_TUPLE_LEN); + return key; +} + +/***************************************************/ + +static inline void +__osm_ftree_tuple_from_key( + IN ftree_tuple_t tuple, + IN ftree_tuple_key_t key) +{ + memcpy(tuple, &key, FTREE_TUPLE_LEN); +} + +/*************************************************** + ** + ** ftree_sw_tbl_element_t functions + ** + ***************************************************/ + +static ftree_sw_tbl_element_t * +__osm_ftree_sw_tbl_element_create( + IN ftree_sw_t * p_sw) +{ + ftree_sw_tbl_element_t * p_element = + (ftree_sw_tbl_element_t *) malloc(sizeof(ftree_sw_tbl_element_t)); + if (!p_element) + return NULL; + memset(p_element, 0,sizeof(ftree_sw_tbl_element_t)); + + if (p_element) + p_element->p_sw = p_sw; + return p_element; +} + +/***************************************************/ + +static void +__osm_ftree_sw_tbl_element_destroy( + IN ftree_sw_tbl_element_t * p_element) +{ + if (!p_element) + return; + free(p_element); +} + +/*************************************************** + ** + ** ftree_port_t functions + ** + ***************************************************/ + +static ftree_port_t * +__osm_ftree_port_create( + IN uint8_t port_num, + IN uint8_t remote_port_num) +{ + ftree_port_t * p_port = (ftree_port_t *)malloc(sizeof(ftree_port_t)); + if (!p_port) + return NULL; + memset(p_port,0,sizeof(ftree_port_t)); + + p_port->port_num = port_num; + p_port->remote_port_num = remote_port_num; + + return p_port; +} + +/***************************************************/ + +static void +__osm_ftree_port_destroy( + IN ftree_port_t * p_port) +{ + if(p_port) + free(p_port); +} + +/*************************************************** + ** + ** ftree_port_group_t functions + ** + ***************************************************/ + +static ftree_port_group_t * +__osm_ftree_port_group_create( + IN ib_net16_t base_lid, + IN ib_net16_t remote_base_lid, + IN ib_net64_t * p_port_guid, + IN ib_net64_t * p_remote_port_guid, + IN ib_net64_t * p_remote_node_guid, + IN uint8_t remote_node_type, + IN void * p_remote_hca_or_sw) +{ + 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, p_port_guid, sizeof(ib_net64_t)); + memcpy(&p_group->remote_port_guid, p_remote_port_guid, sizeof(ib_net64_t)); + memcpy(&p_group->remote_node_guid, p_remote_node_guid, sizeof(ib_net64_t)); + + p_group->remote_node_type = remote_node_type; + switch (remote_node_type) + { + case IB_NODE_TYPE_CA: + p_group->remote_hca_or_sw.remote_hca = (ftree_hca_t *)p_remote_hca_or_sw; + break; + case IB_NODE_TYPE_SWITCH: + p_group->remote_hca_or_sw.remote_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 */ + return p_group; +} /* __osm_ftree_port_group_create() */ + +/***************************************************/ + +static void +__osm_ftree_port_group_destroy( + IN ftree_port_group_t * p_group) +{ + uint32_t i; + uint32_t size; + ftree_port_t * p_port; + + if (!p_group) + return; + + /* remove all the elements of p_group->ports vector */ + size = cl_ptr_vector_get_size(&p_group->ports); + for (i = 0; i < size; i++) + { + cl_ptr_vector_at(&p_group->ports, i, (void **)&p_port); + __osm_ftree_port_destroy(p_port); + } + cl_ptr_vector_destroy(&p_group->ports); + free(p_group); +} /* __osm_ftree_port_group_destroy() */ + +/***************************************************/ + +static void +__osm_ftree_port_group_dump( + IN ftree_fabric_t *p_ftree, + IN ftree_port_group_t * p_group, + IN ftree_direction_t direction) +{ + ftree_port_t * p_port; + uint32_t size; + uint32_t i; + char buff[10*1024]; + + if (!p_group) + return; + + if (!osm_log_is_active(&p_ftree->p_osm->log, OSM_LOG_DEBUG)) + return; + + size = cl_ptr_vector_get_size(&p_group->ports); + buff[0] = '\0'; + + for (i = 0; i < size; i++) + { + cl_ptr_vector_at(&p_group->ports, i, (void **)&p_port); + CL_ASSERT(p_port); + + if (i != 0) + strcat(buff,", "); + sprintf(buff + strlen(buff), "%u", p_port->port_num); + } + + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "__osm_ftree_port_group_dump:" + " Port Group of size %u, port(s): %s, direction: %s\n" + " Local <--> Remote GUID (LID):" + "0x%016" PRIx64 " (0x%x) <--> 0x%016" PRIx64 " (0x%x)\n", + size, + buff, + (direction == FTREE_DIRECTION_DOWN)? "DOWN" : "UP", + cl_ntoh64(p_group->port_guid), + cl_ntoh16(p_group->base_lid), + cl_ntoh64(p_group->remote_port_guid), + cl_ntoh16(p_group->remote_base_lid)); + +} /* __osm_ftree_port_group_dump() */ + +/***************************************************/ + +static void +__osm_ftree_port_group_add_port( + IN ftree_port_group_t * p_group, + IN uint8_t port_num, + IN uint8_t remote_port_num) +{ + uint16_t i; + ftree_port_t * p_port; + + for (i = 0; i < cl_ptr_vector_get_size(&p_group->ports); i++) + { + cl_ptr_vector_at(&p_group->ports, i, (void **)&p_port); + if (p_port->port_num == port_num) + return; + } + + p_port = __osm_ftree_port_create(port_num,remote_port_num); + cl_ptr_vector_insert(&p_group->ports, p_port, NULL); +} + +/*************************************************** + ** + ** ftree_sw_t functions + ** + ***************************************************/ + +static ftree_sw_t * +__osm_ftree_sw_create( + IN ftree_fabric_t * p_ftree, + IN osm_switch_t * p_osm_sw) +{ + ftree_sw_t * p_sw; + uint8_t ports_num; + + /* make sure that the switch has ports */ + if (osm_switch_get_num_ports(p_osm_sw) == 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 = 0xFF; + __osm_ftree_tuple_init(p_sw->tuple); + + p_sw->base_lid = osm_node_get_base_lid(osm_switch_get_node_ptr(p_sw->p_osm_sw),0); + + ports_num = osm_node_get_num_physp(osm_switch_get_node_ptr(p_sw->p_osm_sw)); + p_sw->down_port_groups = + (ftree_port_group_t **) malloc(ports_num * sizeof(ftree_port_group_t *)); + p_sw->up_port_groups = + (ftree_port_group_t **) malloc(ports_num * sizeof(ftree_port_group_t *)); + if (!p_sw->down_port_groups || !p_sw->up_port_groups) + return NULL; + p_sw->down_port_groups_num = 0; + p_sw->up_port_groups_num = 0; + + /* initialize lft buffer */ + p_sw->lft_buf = (ftree_fwd_tbl_t)cl_pool_get(&p_ftree->sw_fwd_tbl_pool); + memset(p_sw->lft_buf, OSM_NO_PATH, FTREE_FWD_TBL_LEN); + + return p_sw; +} /* __osm_ftree_sw_create() */ + +/***************************************************/ + +static void +__osm_ftree_sw_destroy( + IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw) +{ + uint8_t i; + + if (!p_sw) + return; + + for (i = 0; i < p_sw->down_port_groups_num; i++) + __osm_ftree_port_group_destroy(p_sw->down_port_groups[i]); + for (i = 0; i < p_sw->up_port_groups_num; i++) + __osm_ftree_port_group_destroy(p_sw->up_port_groups[i]); + if (p_sw->down_port_groups) + free(p_sw->down_port_groups); + if (p_sw->up_port_groups) + free(p_sw->up_port_groups); + + /* return switch fwd_tbl to pool */ + if (p_sw->lft_buf) + cl_pool_put(&p_ftree->sw_fwd_tbl_pool, (void *)p_sw->lft_buf); + + free(p_sw); +} /* __osm_ftree_sw_destroy() */ + +/***************************************************/ + +static void +__osm_ftree_sw_dump( + IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw) +{ + uint32_t i; + + if (!p_sw) + return; + + if (!osm_log_is_active(&p_ftree->p_osm->log, OSM_LOG_DEBUG)) + return; + + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "__osm_ftree_sw_dump: " + "Switch index: %s, GUID: 0x%016" PRIx64 ", Ports: %u DOWN, %u UP\n", + __osm_ftree_tuple_to_str(p_sw->tuple), + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(p_sw->p_osm_sw))), + p_sw->down_port_groups_num, + p_sw->up_port_groups_num); + + for( i = 0; i < p_sw->down_port_groups_num; i++ ) + __osm_ftree_port_group_dump(p_ftree, + p_sw->down_port_groups[i], + FTREE_DIRECTION_DOWN); + for( i = 0; i < p_sw->up_port_groups_num; i++ ) + __osm_ftree_port_group_dump(p_ftree, + p_sw->up_port_groups[i], + FTREE_DIRECTION_UP); + +} /* __osm_ftree_sw_dump() */ + +/***************************************************/ + +static boolean_t +__osm_ftree_sw_ranked( + IN ftree_sw_t * p_sw) +{ + return (p_sw->rank != 0xFF); +} + +/***************************************************/ + +static ftree_port_group_t * +__osm_ftree_sw_get_port_group_by_remote_lid( + IN ftree_sw_t * p_sw, + IN ib_net16_t remote_base_lid, + IN ftree_direction_t direction) +{ + uint32_t i; + uint32_t size; + ftree_port_group_t ** port_groups; + + if (direction == FTREE_DIRECTION_UP) + { + port_groups = p_sw->up_port_groups; + size = p_sw->up_port_groups_num; + } + else + { + port_groups = p_sw->down_port_groups; + size = p_sw->down_port_groups_num; + } + + for (i = 0; i < size; i++) + if (remote_base_lid == port_groups[i]->remote_base_lid) + return port_groups[i]; + + return NULL; +} /* __osm_ftree_sw_get_port_group_by_remote_lid() */ + +/***************************************************/ + +static void +__osm_ftree_sw_add_port( + IN ftree_sw_t * p_sw, + IN uint8_t port_num, + IN uint8_t remote_port_num, + IN ib_net16_t base_lid, + IN ib_net16_t remote_base_lid, + IN ib_net64_t port_guid, + IN ib_net64_t remote_port_guid, + IN ib_net64_t remote_node_guid, + IN uint8_t remote_node_type, + IN void * p_remote_hca_or_sw, + IN ftree_direction_t direction) +{ + ftree_port_group_t * p_group = + __osm_ftree_sw_get_port_group_by_remote_lid(p_sw,remote_base_lid,direction); + + if (!p_group) + { + p_group = __osm_ftree_port_group_create( + base_lid, + remote_base_lid, + &port_guid, + &remote_port_guid, + &remote_node_guid, + remote_node_type, + p_remote_hca_or_sw); + CL_ASSERT(p_group); + + if (direction == FTREE_DIRECTION_UP) + p_sw->up_port_groups[p_sw->up_port_groups_num++] = p_group; + else + p_sw->down_port_groups[p_sw->down_port_groups_num++] = p_group; + } + __osm_ftree_port_group_add_port(p_group,port_num,remote_port_num); + +} /* __osm_ftree_sw_add_port() */ + +/***************************************************/ + +static inline void +__osm_ftree_sw_set_fwd_table_block( + IN ftree_sw_t * p_sw, + IN uint16_t lid_ho, + IN uint8_t port_num) +{ + p_sw->lft_buf[lid_ho] = port_num; +} + +/***************************************************/ + +static inline uint8_t +__osm_ftree_sw_get_fwd_table_block( + IN ftree_sw_t * p_sw, + IN uint16_t lid_ho) +{ + return p_sw->lft_buf[lid_ho]; +} + +/***************************************************/ + +static inline cl_status_t +__osm_ftree_sw_set_hops( + IN ftree_sw_t * p_sw, + IN uint16_t max_lid_ho, + IN uint16_t lid_ho, + IN uint8_t port_num, + IN uint8_t hops) +{ + /* make sure the lid matrix has enough room */ + osm_switch_set_min_lid_size(p_sw->p_osm_sw, max_lid_ho); + + /* set local min hop table(LID) */ + return osm_switch_set_hops(p_sw->p_osm_sw, + lid_ho, + port_num, + hops); +} + +/*************************************************** + ** + ** ftree_hca_t functions + ** + ***************************************************/ + +static ftree_hca_t * +__osm_ftree_hca_create( + IN osm_node_t * p_osm_node) +{ + ftree_hca_t * p_hca = (ftree_hca_t *)malloc(sizeof(ftree_hca_t)); + if (p_hca == NULL) + return NULL; + memset(p_hca,0,sizeof(ftree_hca_t)); + + p_hca->p_osm_node = p_osm_node; + p_hca->up_port_groups = (ftree_port_group_t **) + malloc(osm_node_get_num_physp(p_hca->p_osm_node) * sizeof (ftree_port_group_t *)); + if (!p_hca->up_port_groups) + return NULL; + p_hca->up_port_groups_num = 0; + return p_hca; +} + +/***************************************************/ + +static void +__osm_ftree_hca_destroy( + IN ftree_hca_t * p_hca) +{ + uint32_t i; + + if (!p_hca) + return; + + for (i = 0; i < p_hca->up_port_groups_num; i++) + __osm_ftree_port_group_destroy(p_hca->up_port_groups[i]); + + if (p_hca->up_port_groups) + free(p_hca->up_port_groups); + + free(p_hca); +} + +/***************************************************/ + +static void +__osm_ftree_hca_dump( + IN ftree_fabric_t * p_ftree, + IN ftree_hca_t * p_hca) +{ + uint32_t i; + + if (!p_hca) + return; + + if (!osm_log_is_active(&p_ftree->p_osm->log,OSM_LOG_DEBUG)) + return; + + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "__osm_ftree_hca_dump: " + "HCA GUID: 0x%016" PRIx64 ", Ports: %u UP\n", + cl_ntoh64(osm_node_get_node_guid(p_hca->p_osm_node)), + p_hca->up_port_groups_num); + + for( i = 0; i < p_hca->up_port_groups_num; i++ ) + __osm_ftree_port_group_dump(p_ftree, + p_hca->up_port_groups[i], + FTREE_DIRECTION_UP); +} + +/***************************************************/ + +static ftree_port_group_t * +__osm_ftree_hca_get_port_group_by_remote_lid( + IN ftree_hca_t * p_hca, + IN ib_net16_t remote_base_lid) +{ + uint32_t i; + for (i = 0; i < p_hca->up_port_groups_num; i++) + if (remote_base_lid == p_hca->up_port_groups[i]->remote_base_lid) + return p_hca->up_port_groups[i]; + + return NULL; +} + +/***************************************************/ + +static void +__osm_ftree_hca_add_port( + IN ftree_hca_t * p_hca, + IN uint8_t port_num, + IN uint8_t remote_port_num, + IN ib_net16_t base_lid, + IN ib_net16_t remote_base_lid, + IN ib_net64_t port_guid, + IN ib_net64_t remote_port_guid, + IN ib_net64_t remote_node_guid, + IN uint8_t remote_node_type, + IN void * p_remote_hca_or_sw) +{ + ftree_port_group_t * p_group; + + /* this function is supposed to be called only for adding ports + in hca's that lead to switches */ + CL_ASSERT(remote_node_type == IB_NODE_TYPE_SWITCH); + + p_group = __osm_ftree_hca_get_port_group_by_remote_lid(p_hca,remote_base_lid); + + if (!p_group) + { + p_group = __osm_ftree_port_group_create( + base_lid, + remote_base_lid, + &port_guid, + &remote_port_guid, + &remote_node_guid, + remote_node_type, + p_remote_hca_or_sw); + p_hca->up_port_groups[p_hca->up_port_groups_num++] = p_group; + } + __osm_ftree_port_group_add_port(p_group, port_num, remote_port_num); + +} /* __osm_ftree_hca_add_port() */ + +/*************************************************** + ** + ** ftree_fabric_t functions + ** + ***************************************************/ + +static ftree_fabric_t * +__osm_ftree_fabric_create() +{ + cl_status_t status; + 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); + + status = cl_pool_init( &p_ftree->sw_fwd_tbl_pool, + 8, /* min pool size */ + 0, /* max pool size - unlimited */ + 8, /* grow size */ + FTREE_FWD_TBL_LEN, /* object_size */ + NULL, /* object initializer */ + NULL, /* object destructor */ + NULL ); /* context */ + if (status != CL_SUCCESS) + return NULL; + + p_ftree->tree_rank = 1; + return p_ftree; +} + +/***************************************************/ + +static void +__osm_ftree_fabric_clear(ftree_fabric_t * p_ftree) +{ + ftree_hca_t * p_hca; + ftree_hca_t * p_next_hca; + ftree_sw_t * p_sw; + ftree_sw_t * p_next_sw; + ftree_sw_tbl_element_t * p_element; + ftree_sw_tbl_element_t * p_next_element; + + if (!p_ftree) + return; + + /* remove all the elements of hca_tbl */ + + p_next_hca = (ftree_hca_t *)cl_qmap_head(&p_ftree->hca_tbl); + while( p_next_hca != (ftree_hca_t *)cl_qmap_end( &p_ftree->hca_tbl ) ) + { + p_hca = p_next_hca; + p_next_hca = (ftree_hca_t *)cl_qmap_next(&p_hca->map_item ); + __osm_ftree_hca_destroy(p_hca); + } + cl_qmap_remove_all(&p_ftree->hca_tbl); + + /* remove all the elements of sw_tbl */ + + p_next_sw = (ftree_sw_t *)cl_qmap_head(&p_ftree->sw_tbl); + while( p_next_sw != (ftree_sw_t *)cl_qmap_end( &p_ftree->sw_tbl ) ) + { + p_sw = p_next_sw; + p_next_sw = (ftree_sw_t *)cl_qmap_next(&p_sw->map_item ); + __osm_ftree_sw_destroy(p_ftree,p_sw); + } + cl_qmap_remove_all(&p_ftree->sw_tbl); + + /* remove all the elements of sw_by_tuple_tbl */ + + p_next_element = + (ftree_sw_tbl_element_t *)cl_qmap_head(&p_ftree->sw_by_tuple_tbl); + while( p_next_element != + (ftree_sw_tbl_element_t *)cl_qmap_end( &p_ftree->sw_by_tuple_tbl ) ) + { + p_element = p_next_element; + p_next_element = + (ftree_sw_tbl_element_t *)cl_qmap_next(&p_element->map_item); + __osm_ftree_sw_tbl_element_destroy(p_element); + } + cl_qmap_remove_all(&p_ftree->sw_by_tuple_tbl); + + /* 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->leaf_switches = NULL; + p_ftree->fabric_built = FALSE; + +} /* __osm_ftree_fabric_destroy() */ + +/***************************************************/ + +static void +__osm_ftree_fabric_destroy(ftree_fabric_t * p_ftree) +{ + if (!p_ftree) + return; + __osm_ftree_fabric_clear(p_ftree); + cl_pool_destroy(&p_ftree->sw_fwd_tbl_pool); + free(p_ftree); +} + +/***************************************************/ + +static void +__osm_ftree_fabric_set_rank(ftree_fabric_t * p_ftree, uint8_t rank) +{ + if (rank > p_ftree->tree_rank) + p_ftree->tree_rank = rank; +} + +/***************************************************/ + +static uint8_t +__osm_ftree_fabric_get_rank(ftree_fabric_t * p_ftree) +{ + return p_ftree->tree_rank; +} + +/***************************************************/ + +static void +__osm_ftree_fabric_add_hca(ftree_fabric_t * p_ftree, osm_node_t * p_osm_node) +{ + ftree_hca_t * p_hca = __osm_ftree_hca_create(p_osm_node); + + CL_ASSERT(osm_node_get_type(p_osm_node) == IB_NODE_TYPE_CA); + + cl_qmap_insert(&p_ftree->hca_tbl, + p_osm_node->node_info.node_guid, + &p_hca->map_item); +} + +/***************************************************/ + +static void +__osm_ftree_fabric_add_sw(ftree_fabric_t * p_ftree, osm_switch_t * p_osm_sw) +{ + ftree_sw_t * p_sw = __osm_ftree_sw_create(p_ftree,p_osm_sw); + + CL_ASSERT(osm_node_get_type(p_osm_sw->p_node) == IB_NODE_TYPE_SWITCH); + + cl_qmap_insert(&p_ftree->sw_tbl, + p_osm_sw->p_node->node_info.node_guid, + &p_sw->map_item); + + /* track the max lid (in host order) that exists in the fabric */ + if (cl_ntoh16(p_sw->base_lid) > p_ftree->lft_max_lid_ho) + p_ftree->lft_max_lid_ho = cl_ntoh16(p_sw->base_lid); +} + +/***************************************************/ + +static void +__osm_ftree_fabric_add_sw_by_tuple( + IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw) +{ + CL_ASSERT(__osm_ftree_tuple_assigned(p_sw->tuple)); + + cl_qmap_insert(&p_ftree->sw_by_tuple_tbl, + __osm_ftree_tuple_to_key(p_sw->tuple), + &__osm_ftree_sw_tbl_element_create(p_sw)->map_item); +} + +/***************************************************/ + +static ftree_sw_t * +__osm_ftree_fabric_get_sw_by_tuple( + IN ftree_fabric_t * p_ftree, + IN ftree_tuple_t tuple) +{ + ftree_sw_tbl_element_t * p_element; + + CL_ASSERT(__osm_ftree_tuple_assigned(tuple)); + + __osm_ftree_tuple_to_key(tuple); + + p_element = (ftree_sw_tbl_element_t * )cl_qmap_get(&p_ftree->sw_by_tuple_tbl, + __osm_ftree_tuple_to_key(tuple)); + if (p_element == (ftree_sw_tbl_element_t * )cl_qmap_end(&p_ftree->sw_by_tuple_tbl)) + return NULL; + + return p_element->p_sw; +} + +/***************************************************/ + +static void +__osm_ftree_fabric_dump(ftree_fabric_t * p_ftree) +{ + uint32_t i; + ftree_hca_t * p_hca; + ftree_sw_t * p_sw; + + if (!osm_log_is_active(&p_ftree->p_osm->log,OSM_LOG_DEBUG)) + return; + + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG,"__osm_ftree_fabric_dump: \n" + " |-------------------------------|\n" + " |- Full fabric topology dump -|\n" + " |-------------------------------|\n\n"); + + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "__osm_ftree_fabric_dump: -- HCAs:\n"); + + for ( p_hca = (ftree_hca_t *)cl_qmap_head(&p_ftree->hca_tbl); + p_hca != (ftree_hca_t *)cl_qmap_end(&p_ftree->hca_tbl); + p_hca = (ftree_hca_t *)cl_qmap_next(&p_hca->map_item) ) + { + __osm_ftree_hca_dump(p_ftree, p_hca); + } + + for (i = 0; i < __osm_ftree_fabric_get_rank(p_ftree); i++) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "__osm_ftree_fabric_dump: -- Rank %u switches\n", i); + for ( p_sw = (ftree_sw_t *)cl_qmap_head(&p_ftree->sw_tbl); + p_sw != (ftree_sw_t *)cl_qmap_end(&p_ftree->sw_tbl); + p_sw = (ftree_sw_t *)cl_qmap_next(&p_sw->map_item) ) + { + if (p_sw->rank == i) + __osm_ftree_sw_dump(p_ftree, p_sw); + } + } + + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG,"__osm_ftree_fabric_dump: \n" + " |---------------------------------------|\n" + " |- Full fabric topology dump completed -|\n" + " |---------------------------------------|\n\n"); +} /* __osm_ftree_fabric_dump() */ + +/***************************************************/ + +static void +__osm_ftree_fabric_dump_general_info( + IN ftree_fabric_t * p_ftree) +{ + uint32_t i,j; + ftree_sw_t * p_sw; + char * addition_str; + + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "__osm_ftree_fabric_dump_general_info: " + "General fabric topology info\n"); + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO,"__osm_ftree_fabric_dump_general_info: " + "============================\n"); + + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "__osm_ftree_fabric_dump_general_info: " + " - FatTree rank (switches only): %u\n", + p_ftree->tree_rank); + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "__osm_ftree_fabric_dump_general_info: " + " - Fabric has %u HCAs, %u switches\n", + cl_qmap_count(&p_ftree->hca_tbl), + cl_qmap_count(&p_ftree->sw_tbl)); + + for (i = 0; i < __osm_ftree_fabric_get_rank(p_ftree); 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) + addition_str = " (root) "; + else + if (i == (__osm_ftree_fabric_get_rank(p_ftree) - 1)) + addition_str = " (leaf) "; + else + addition_str = " "; + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "__osm_ftree_fabric_dump_general_info: " + " - Fabric has %u rank %u%s switches\n", + j, i, addition_str); + } + + if (osm_log_is_active(&p_ftree->p_osm->log, OSM_LOG_VERBOSE)) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "__osm_ftree_fabric_dump_general_info: " + " - 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, + "__osm_ftree_fabric_dump_general_info: " + " GUID: 0x%016" PRIx64 ", LID: 0x%x, Index %s\n", + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(p_sw->p_osm_sw))), + cl_ntoh16(p_sw->base_lid), + __osm_ftree_tuple_to_str(p_sw->tuple)); + } + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "__osm_ftree_fabric_dump_general_info: " + " - 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, + "__osm_ftree_fabric_dump_general_info: " + " GUID: 0x%016" PRIx64 ", LID: 0x%x, Index %s\n", + cl_ntoh64(osm_node_get_node_guid( + osm_switch_get_node_ptr( + p_ftree->leaf_switches[i]->p_osm_sw))), + cl_ntoh16(p_ftree->leaf_switches[i]->base_lid), + __osm_ftree_tuple_to_str(p_ftree->leaf_switches[i]->tuple)); + } + } +} /* __osm_ftree_fabric_dump_general_info() */ + +/***************************************************/ + +static void +__osm_ftree_fabric_dump_hca_ordering( + IN ftree_fabric_t * p_ftree) +{ + ftree_hca_t * p_hca; + ftree_sw_t * p_sw; + ftree_port_group_t * p_group; + uint32_t i; + uint32_t j; + + char desc[IB_NODE_DESCRIPTION_SIZE + 1]; + char path[1024]; + FILE * p_hca_ordering_file; + char * filename = "osm-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, + "__osm_ftree_fabric_dump_hca_ordering: ERR AB01: " + "cannot open file \'%s\': %s\n", + filename, strerror(errno)); + OSM_LOG_EXIT(&p_ftree->p_osm->log); + 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]; + /* for each real HCA connected to this switch */ + for (j = 0; j < p_sw->down_port_groups_num; j++) + { + p_group = p_sw->down_port_groups[j]; + p_hca = p_group->remote_hca_or_sw.remote_hca; + memcpy(desc,p_hca->p_osm_node->node_desc.description,IB_NODE_DESCRIPTION_SIZE); + desc[IB_NODE_DESCRIPTION_SIZE] = '\0'; + + fprintf(p_hca_ordering_file,"0x%x\t%s\n", + cl_ntoh16(p_group->remote_base_lid), desc); + } + + /* now print dummy HCAs */ + for (j = p_sw->down_port_groups_num; j < p_ftree->max_hcas_per_leaf; j++) + { + fprintf(p_hca_ordering_file,"0xFFFF\tDUMMY\n"); + } + + } + /* done going through all the leaf switches */ + + fclose(p_hca_ordering_file); +} /* __osm_ftree_fabric_dump_hca_ordering() */ + +/***************************************************/ + +static void +__osm_ftree_fabric_assign_tuple( + IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw, + IN ftree_tuple_t new_tuple) +{ + memcpy(p_sw->tuple, new_tuple, FTREE_TUPLE_LEN); + __osm_ftree_fabric_add_sw_by_tuple(p_ftree,p_sw); +} + +/***************************************************/ + +static void +__osm_ftree_fabric_assign_first_tuple( + IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw) +{ + uint8_t i; + ftree_tuple_t new_tuple; + + __osm_ftree_tuple_init(new_tuple); + new_tuple[0] = p_sw->rank; + for (i = 1; i <= p_sw->rank; i++) + new_tuple[i] = 0; + + __osm_ftree_fabric_assign_tuple(p_ftree,p_sw,new_tuple); +} + +/***************************************************/ + +static void +__osm_ftree_fabric_get_new_tuple( + IN ftree_fabric_t * p_ftree, + OUT ftree_tuple_t new_tuple, + IN ftree_tuple_t from_tuple, + IN ftree_direction_t direction) +{ + ftree_sw_t * p_sw; + ftree_tuple_t temp_tuple; + uint8_t var_index; + uint8_t i; + + __osm_ftree_tuple_init(new_tuple); + memcpy(temp_tuple, from_tuple, FTREE_TUPLE_LEN); + + if (direction == FTREE_DIRECTION_DOWN) + { + temp_tuple[0] ++; + var_index = from_tuple[0] + 1; + } + else + { + temp_tuple[0] --; + var_index = from_tuple[0]; + } + + for (i = 0; i < 0xFF; i++) + { + temp_tuple[var_index] = i; + p_sw = __osm_ftree_fabric_get_sw_by_tuple(p_ftree,temp_tuple); + if (p_sw == NULL) /* found free tuple */ + break; + } + + if (i == 0xFF) + { + /* new tuple not found - there are more than 255 ports in one direction */ + return; + } + memcpy(new_tuple, temp_tuple, FTREE_TUPLE_LEN); + +} /* __osm_ftree_fabric_get_new_tuple() */ + +/***************************************************/ + +static void +__osm_ftree_fabric_calculate_rank( + IN ftree_fabric_t * p_ftree) +{ + ftree_sw_t * p_sw; + ftree_sw_t * p_next_sw; + uint16_t max_rank = 0; + + /* go over all the switches and find maximal switch rank */ + + 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->rank > max_rank) + max_rank = p_sw->rank; + p_next_sw = (ftree_sw_t *)cl_qmap_next(&p_sw->map_item ); + } + + /* set FatTree rank */ + __osm_ftree_fabric_set_rank(p_ftree, max_rank + 1); +} + +/***************************************************/ + +static void +__osm_ftree_fabric_make_indexing( + IN ftree_fabric_t * p_ftree) +{ + ftree_sw_t * p_remote_sw; + ftree_sw_t * p_sw; + ftree_sw_t * p_next_sw; + ftree_tuple_t new_tuple; + uint32_t i; + cl_list_t bfs_list; + ftree_sw_tbl_element_t * p_sw_tbl_element; + + OSM_LOG_ENTER(&p_ftree->p_osm->log, __osm_ftree_fabric_make_indexing); + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE,"__osm_ftree_fabric_make_indexing: " + "Starting FatTree indexing\n"); + + /* create array of leaf switches */ + p_ftree->leaf_switches = (ftree_sw_t **) + malloc(cl_qmap_count(&p_ftree->sw_tbl) * sizeof(ftree_sw_t *)); + + /* Looking for a leaf switch - the one that has rank equal to (tree_rank - 1). + This switch will be used 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->rank == (__osm_ftree_fabric_get_rank(p_ftree) - 1)) + break; + p_next_sw = (ftree_sw_t *)cl_qmap_next(&p_sw->map_item ); + } + + CL_ASSERT(p_next_sw != (ftree_sw_t *)cl_qmap_end(&p_ftree->sw_tbl)); + + /* Assign the first tuple to the switch that is used as BFS starting point. + The tuple will be as follows: [rank].0.0.0... + This fuction also adds the switch it into the switch_by_tuple table. */ + __osm_ftree_fabric_assign_first_tuple(p_ftree,p_sw); + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "__osm_ftree_fabric_make_indexing: Indexing starting point:\n" + " - Switch rank : %u\n" + " - Switch index : %s\n" + " - Node LID : 0x%x\n" + " - Node GUID : 0x%016" PRIx64 "\n", + p_sw->rank, + __osm_ftree_tuple_to_str(p_sw->tuple), + cl_ntoh16(p_sw->base_lid), + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(p_sw->p_osm_sw)))); + + /* + * Now run BFS and assign indexes to all switches + * Pseudo code of the algorithm is as follows: + * + * * Add first switch to BFS queue + * * While (BFS queue not empty) + * - Pop the switch from the head of the queue + * - Scan all the downward and upward ports + * - For each port + * + Get the remote switch + * + Assign index to the remote switch + * + Add remote switch to the BFS queue + */ + + cl_list_init(&bfs_list, cl_qmap_count(&p_ftree->sw_tbl)); + cl_list_insert_tail(&bfs_list, &__osm_ftree_sw_tbl_element_create(p_sw)->map_item); + + while (!cl_is_list_empty(&bfs_list)) + { + p_sw_tbl_element = (ftree_sw_tbl_element_t *)cl_list_remove_head(&bfs_list); + p_sw = p_sw_tbl_element->p_sw; + __osm_ftree_sw_tbl_element_destroy(p_sw_tbl_element); + + /* Discover all the nodes from ports that are pointing down */ + + if (p_sw->rank == (__osm_ftree_fabric_get_rank(p_ftree) - 1)) + { + /* add switch to leaf switches array */ + p_ftree->leaf_switches[p_ftree->leaf_switches_num++] = p_sw; + /* update the max_hcas_per_leaf value */ + if (p_sw->down_port_groups_num > p_ftree->max_hcas_per_leaf) + p_ftree->max_hcas_per_leaf = p_sw->down_port_groups_num; + } + else + { + /* This is not the leaf switch, which means that all the + ports that point down are taking us to another switches. + No need to assign indexing to HCAs */ + for( i = 0; i < p_sw->down_port_groups_num; i++ ) + { + p_remote_sw = p_sw->down_port_groups[i]->remote_hca_or_sw.remote_sw; + if (__osm_ftree_tuple_assigned(p_remote_sw->tuple)) + { + /* this switch has been already indexed */ + continue; + } + /* allocate new tuple */ + __osm_ftree_fabric_get_new_tuple(p_ftree, + new_tuple, + p_sw->tuple, + FTREE_DIRECTION_DOWN); + /* Assign the new tuple to the remote switch. + This fuction also adds the switch into the switch_by_tuple table. */ + __osm_ftree_fabric_assign_tuple(p_ftree, + p_remote_sw, + new_tuple); + + /* add the newly discovered switch to the BFS queue */ + cl_list_insert_tail(&bfs_list, + &__osm_ftree_sw_tbl_element_create(p_remote_sw)->map_item); + } + /* Done assigning indexes to all the remote switches + that are pointed by the downgoing ports. + Now sort port groups according to remote index. */ + qsort(p_sw->down_port_groups, /* array */ + p_sw->down_port_groups_num, /* number of elements */ + sizeof(ftree_port_group_t *), /* size of each element */ + __osm_ftree_compare_port_groups_by_remote_switch_index); /* comparator */ + } + + /* Done indexing switches from ports that go down. + Now do the same with ports that are pointing up. */ + + if (p_sw->rank != 0) + { + /* This is not the root switch, which means that all the ports + that are pointing up are taking us to another switches. */ + for( i = 0; i < p_sw->up_port_groups_num; i++ ) + { + p_remote_sw = p_sw->up_port_groups[i]->remote_hca_or_sw.remote_sw; + if (__osm_ftree_tuple_assigned(p_remote_sw->tuple)) + continue; + /* allocate new tuple */ + __osm_ftree_fabric_get_new_tuple(p_ftree, + new_tuple, + p_sw->tuple, + FTREE_DIRECTION_UP); + /* Assign the new tuple to the remote switch. + This fuction also adds the switch to the + switch_by_tuple table. */ + __osm_ftree_fabric_assign_tuple(p_ftree, + p_remote_sw, + new_tuple); + /* add the newly discovered switch to the BFS queue */ + cl_list_insert_tail(&bfs_list, + &__osm_ftree_sw_tbl_element_create(p_remote_sw)->map_item); + } + /* Done assigning indexes to all the remote switches + that are pointed by the upgoing ports. + Now sort port groups according to remote index. */ + qsort(p_sw->up_port_groups, /* array */ + p_sw->up_port_groups_num, /* number of elements */ + sizeof(ftree_port_group_t *), /* size of each element */ + __osm_ftree_compare_port_groups_by_remote_switch_index); /* comparator */ + } + /* Done assigning indexes to all the switches that are directly connected + to the current switch - go to the next switch in the BFS queue */ + } + + /* sort array of leaf switches by index */ + qsort(p_ftree->leaf_switches, /* array */ + p_ftree->leaf_switches_num, /* number of elements */ + sizeof(ftree_sw_t *), /* size of each element */ + __osm_ftree_compare_switches_by_index); /* comparator */ + + OSM_LOG_EXIT(&p_ftree->p_osm->log); +} /* __osm_ftree_fabric_make_indexing() */ + +/***************************************************/ + +static boolean_t +__osm_ftree_fabric_validate_topology( + IN ftree_fabric_t * p_ftree) +{ + ftree_port_group_t * p_group; + ftree_port_group_t * p_ref_group; + ftree_sw_t * p_sw; + ftree_sw_t * p_next_sw; + ftree_sw_t ** reference_sw_arr; + uint16_t tree_rank = __osm_ftree_fabric_get_rank(p_ftree); + boolean_t res = TRUE; + uint8_t i; + + OSM_LOG_ENTER(&p_ftree->p_osm->log, __osm_ftree_fabric_validate_topology); + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "__osm_ftree_fabric_validate_topology: " + "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, + "__osm_ftree_fabric_validate_topology: " + "ERR AB09: Different number of upward port groups on switches:\n" + " GUID 0x%016" PRIx64 ", LID 0x%x, Index %s - %u groups\n" + " GUID 0x%016" PRIx64 ", LID 0x%x, Index %s - %u groups\n", + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(reference_sw_arr[p_sw->rank]->p_osm_sw))), + cl_ntoh16(reference_sw_arr[p_sw->rank]->base_lid), + __osm_ftree_tuple_to_str(reference_sw_arr[p_sw->rank]->tuple), + reference_sw_arr[p_sw->rank]->up_port_groups_num, + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(p_sw->p_osm_sw))), + cl_ntoh16(p_sw->base_lid), + __osm_ftree_tuple_to_str(p_sw->tuple), + p_sw->up_port_groups_num); + res = FALSE; + break; + } + + if ( p_sw->rank != (__osm_ftree_fabric_get_rank(p_ftree) - 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, + "__osm_ftree_fabric_validate_topology: " + "ERR AB0A: Different number of downward port groups on switches:\n" + " GUID 0x%016" PRIx64 ", LID 0x%x, Index %s - %u port groups\n" + " GUID 0x%016" PRIx64 ", LID 0x%x, Index %s - %u port groups\n", + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(reference_sw_arr[p_sw->rank]->p_osm_sw))), + cl_ntoh16(reference_sw_arr[p_sw->rank]->base_lid), + __osm_ftree_tuple_to_str(reference_sw_arr[p_sw->rank]->tuple), + reference_sw_arr[p_sw->rank]->down_port_groups_num, + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(p_sw->p_osm_sw))), + cl_ntoh16(p_sw->base_lid), + __osm_ftree_tuple_to_str(p_sw->tuple), + p_sw->down_port_groups_num); + res = FALSE; + break; + } + + if ( reference_sw_arr[p_sw->rank]->up_port_groups_num != 0 ) + { + p_ref_group = reference_sw_arr[p_sw->rank]->up_port_groups[0]; + for (i = 0; i < p_sw->up_port_groups_num; i++) + { + p_group = p_sw->up_port_groups[i]; + if (cl_ptr_vector_get_size(&p_ref_group->ports) != cl_ptr_vector_get_size(&p_group->ports)) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "__osm_ftree_fabric_validate_topology: " + "ERR AB0B: Different number of ports in an upward port group on switches:\n" + " GUID 0x%016" PRIx64 ", LID 0x%x, Index %s - %u ports\n" + " GUID 0x%016" PRIx64 ", LID 0x%x, Index %s - %u ports\n", + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(reference_sw_arr[p_sw->rank]->p_osm_sw))), + cl_ntoh16(reference_sw_arr[p_sw->rank]->base_lid), + __osm_ftree_tuple_to_str(reference_sw_arr[p_sw->rank]->tuple), + cl_ptr_vector_get_size(&p_ref_group->ports), + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(p_sw->p_osm_sw))), + cl_ntoh16(p_sw->base_lid), + __osm_ftree_tuple_to_str(p_sw->tuple), + cl_ptr_vector_get_size(&p_group->ports)); + res = FALSE; + break; + } + } + } + if ( reference_sw_arr[p_sw->rank]->down_port_groups_num != 0 && + p_sw->rank != (tree_rank - 1) ) + { + /* we're allowing some hca's to be missing */ + p_ref_group = reference_sw_arr[p_sw->rank]->down_port_groups[0]; + for (i = 0; i < p_sw->down_port_groups_num; i++) + { + p_group = p_sw->down_port_groups[0]; + if (cl_ptr_vector_get_size(&p_ref_group->ports) != cl_ptr_vector_get_size(&p_group->ports)) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "__osm_ftree_fabric_validate_topology: " + "ERR AB0C: Different number of ports in an downward port group on switches:\n" + " GUID 0x%016" PRIx64 ", LID 0x%x, Index %s - %u ports\n" + " GUID 0x%016" PRIx64 ", LID 0x%x, Index %s - %u ports\n", + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(reference_sw_arr[p_sw->rank]->p_osm_sw))), + cl_ntoh16(reference_sw_arr[p_sw->rank]->base_lid), + __osm_ftree_tuple_to_str(reference_sw_arr[p_sw->rank]->tuple), + cl_ptr_vector_get_size(&p_ref_group->ports), + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(p_sw->p_osm_sw))), + cl_ntoh16(p_sw->base_lid), + __osm_ftree_tuple_to_str(p_sw->tuple), + cl_ptr_vector_get_size(&p_group->ports)); + res = FALSE; + break; + } + } + } + } /* end of else */ + } /* end of while */ + + if (res == TRUE) + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "__osm_ftree_fabric_validate_topology: " + "Fabric topology has been identified as FatTree\n"); + else + osm_log(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "__osm_ftree_fabric_validate_topology: " + "ERR AB0D: Fabric topology hasn't been identified as FatTree\n"); + + free(reference_sw_arr); + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* __osm_ftree_fabric_validate_topology() */ + +/*************************************************** + ***************************************************/ + +static void +__osm_ftree_set_sw_fwd_table( + IN cl_map_item_t* const p_map_item, + IN void *context) +{ + ftree_sw_t * p_sw = (ftree_sw_t * const) p_map_item; + ftree_fabric_t * p_ftree = (ftree_fabric_t *)context; + + /* calculate lft length rounded up to a multiple of 64 (block length) */ + uint16_t lft_len = 64 * ((p_ftree->lft_max_lid_ho + 1 + 63) / 64); + + p_sw->p_osm_sw->max_lid_ho = p_ftree->lft_max_lid_ho; + + memcpy(p_ftree->p_osm->sm.ucast_mgr.lft_buf, + p_sw->lft_buf, + lft_len); + osm_ucast_mgr_set_fwd_table(&p_ftree->p_osm->sm.ucast_mgr, p_sw->p_osm_sw); +} + +/*************************************************** + ***************************************************/ + +/* + * Function: assign-up-going-port-by-descending-down + * Given : a switch and a LID + * Pseudo code: + * foreach down-going-port-group (in indexing order) + * skip this group if the LFT(LID) port is part of this group + * find the least loaded port of the group (scan in indexing order) + * r-port is the remote port connected to it + * assign the remote switch node LFT(LID) to r-port + * increase r-port usage counter + * assign-up-going-port-by-descending-down to r-port node (recursion) + */ + +static void +__osm_ftree_fabric_route_upgoing_by_going_down( + IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw, + IN ftree_sw_t * p_prev_sw, + IN ib_net16_t target_lid, + IN uint8_t target_rank, + IN boolean_t is_real_lid, + IN boolean_t is_main_path, + IN uint8_t highest_rank_in_route) +{ + ftree_sw_t * p_remote_sw; + uint16_t ports_num; + ftree_port_group_t * p_group; + ftree_port_t * p_port; + ftree_port_t * p_min_port; + uint16_t i; + uint16_t j; + + /* we shouldn't enter here if both real_lid and main_path are false */ + CL_ASSERT(is_real_lid || is_main_path); + + /* can't be here for leaf switch, */ + CL_ASSERT(p_sw->rank != (__osm_ftree_fabric_get_rank(p_ftree) - 1)); + + /* if there is no down-going ports */ + if (p_sw->down_port_groups_num == 0) + return; + + /* foreach down-going port group (in indexing order) */ + for (i = 0; i < p_sw->down_port_groups_num; i++) + { + p_group = p_sw->down_port_groups[i]; + + if ( p_prev_sw && (p_group->remote_base_lid == p_prev_sw->base_lid) ) + { + /* This port group has a port that was used when we entered this switch, + which means that the current group points to the switch where we were + at the previous step of the algorithm (before going up). + Skipping this group. */ + continue; + } + + /* find the least loaded port of the group (in indexing order) */ + p_min_port = NULL; + ports_num = (uint16_t)cl_ptr_vector_get_size(&p_group->ports); + /* ToDo: no need to select a least loaded port for non-main path. + Think about optimization. */ + for (j = 0; j < ports_num; j++) + { + cl_ptr_vector_at(&p_group->ports, j, (void **)&p_port); + if (!p_min_port) + { + /* first port that we're checking - set as port with the lowest load */ + p_min_port = p_port; + } + else if (p_port->counter_up < p_min_port->counter_up) + { + /* this port is less loaded - use it as min */ + p_min_port = p_port; + } + } + /* At this point we have selected a port in this group with the + lowest load of upgoing routes. + Set on the remote switch how to get to the target_lid - + set LFT(target_lid) on the remote switch to the remote port */ + p_remote_sw = p_group->remote_hca_or_sw.remote_sw; + + /* 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 (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 DOWN(FALSE,TRUE) through ALL the groups + * + promoting port counter + * + NOT setting path in remote switch fwd tbl + * + NOT setting hops in remote switch + * + * 4. is_real_lid == FALSE && is_main_path == FALSE: + * - illegal state - we shouldn't get here + */ + + /* second case: skip the port group if the remote (upper) + switch has been already configured for this target LID */ + if ( is_real_lid && !is_main_path && + __osm_ftree_sw_get_fwd_table_block(p_remote_sw, + cl_ntoh16(target_lid)) != OSM_NO_PATH ) + continue; + + /* setting fwd tbl port only if this is real LID */ + if (is_real_lid) + { + __osm_ftree_sw_set_fwd_table_block(p_remote_sw, + cl_ntoh16(target_lid), + p_min_port->remote_port_num); + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "__osm_ftree_fabric_route_upgoing_by_going_down: " + "Switch %s: set path to HCA LID 0x%x through port %u\n", + __osm_ftree_tuple_to_str(p_remote_sw->tuple), + cl_ntoh16(target_lid), + p_min_port->remote_port_num); + + /* On the remote switch that is pointed by the p_group, + set hops for ALL the ports in the remote group. */ + + for (j = 0; j < ports_num; j++) + { + cl_ptr_vector_at(&p_group->ports, j, (void **)&p_port); + + __osm_ftree_sw_set_hops(p_remote_sw, + p_ftree->lft_max_lid_ho, + cl_ntoh16(target_lid), + p_port->remote_port_num, + ( (target_rank - highest_rank_in_route) + + (p_remote_sw->rank - highest_rank_in_route) )); + } + + + } + + /* The number of upgoing routes is tracked in the + p_port->counter_up counter of the port that belongs to + the upper side of the link (on switch with lower rank). + Counter is promoted only if we're routing LID on the main + path (whether it's a real LID or a dummy one). */ + if (is_main_path) + p_min_port->counter_up++; + + /* Recursion step: + Assign upgoing ports by stepping down, starting on REMOTE switch. + Recursion stop condition - if the REMOTE switch is a leaf switch. */ + if (p_remote_sw->rank != (__osm_ftree_fabric_get_rank(p_ftree) - 1)) + { + __osm_ftree_fabric_route_upgoing_by_going_down( + p_ftree, + p_remote_sw, /* remote switch - used as a route-upgoing alg. start point */ + NULL, /* prev. position - NULL to mark that we went down and not up */ + target_lid, /* LID that we're routing to */ + target_rank, /* rank of the LID that we're routing to */ + is_real_lid, /* whether the target LID is real or dummy */ + is_main_path, /* whether this is path to HCA that should by tracked by counters */ + highest_rank_in_route); /* highest visited point in the tree before going down */ + } + } + /* done scanning all the down-going port groups */ + +} /* __osm_ftree_fabric_route_upgoing_by_going_down() */ + +/***************************************************/ + +/* + * Function: assign-down-going-port-by-descending-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-descending-up on REMOTE switch (recursion) + */ + +static void +__osm_ftree_fabric_route_downgoing_by_going_up( + IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw, + IN ftree_sw_t * p_prev_sw, + IN ib_net16_t target_lid, + IN uint8_t target_rank, + IN boolean_t is_real_lid, + IN boolean_t is_main_path) +{ + ftree_sw_t * p_remote_sw; + uint16_t ports_num; + ftree_port_group_t * p_group; + ftree_port_t * p_port; + ftree_port_group_t * p_min_group; + ftree_port_t * p_min_port; + uint16_t i; + uint16_t j; + + /* we shouldn't enter here if both real_lid and main_path are false */ + CL_ASSERT(is_real_lid || is_main_path); + + /* If this switch isn't a leaf switch: + Assign upgoing ports by stepping down, starting on THIS switch. */ + if (p_sw->rank != (__osm_ftree_fabric_get_rank(p_ftree) - 1)) + { + __osm_ftree_fabric_route_upgoing_by_going_down( + p_ftree, + p_sw, /* local switch - used as a route-upgoing alg. start point */ + p_prev_sw, /* switch that we went up from (NULL means that we went down) */ + target_lid, /* LID that we're routing to */ + target_rank, /* rank of the LID that we're routing to */ + is_real_lid, /* whether this target LID is real or dummy */ + is_main_path, /* whether this path to HCA should by tracked by counters */ + p_sw->rank); /* the highest visited point in the tree before going down */ + } + + /* recursion stop condition - if it's a root switch, */ + if (p_sw->rank == 0) + return; + + /* Find the least loaded port of all the upgoing port groups + (in indexing order of the remote switches). */ + p_min_group = NULL; + p_min_port = NULL; + for (i = 0; i < p_sw->up_port_groups_num; i++) + { + p_group = p_sw->up_port_groups[i]; + + 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_group) + { + /* first port that we're checking - use + it as a port with the lowest load */ + p_min_group = p_group; + 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_group = p_group; + 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.remote_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->rank == (__osm_ftree_fabric_get_rank(p_ftree) - 1)) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "__osm_ftree_fabric_route_downgoing_by_going_up: " + " - Routing MAIN path for %s HCA LID 0x%x: %s --> %s\n", + (is_real_lid)? "real" : "DUMMY", + cl_ntoh16(target_lid), + __osm_ftree_tuple_to_str(p_sw->tuple), + __osm_ftree_tuple_to_str(p_remote_sw->tuple)); + } + /* The number of downgoing routes is tracked in the + p_port->counter_down counter of the port that belongs to + the lower side of the link (on switch with higher rank) */ + p_min_port->counter_down++; + if (is_real_lid) + { + __osm_ftree_sw_set_fwd_table_block(p_remote_sw, + cl_ntoh16(target_lid), + p_min_port->remote_port_num); + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "__osm_ftree_fabric_route_downgoing_by_going_up: " + "Switch %s: set path to HCA LID 0x%x through port %u\n", + __osm_ftree_tuple_to_str(p_remote_sw->tuple), + cl_ntoh16(target_lid),p_min_port->remote_port_num); + + /* On the remote switch that is pointed by the min_group, + set hops for ALL the ports in the remote group. */ + + ports_num = (uint16_t)cl_ptr_vector_get_size(&p_min_group->ports); + for (j = 0; j < ports_num; j++) + { + cl_ptr_vector_at(&p_min_group->ports, j, (void **)&p_port); + __osm_ftree_sw_set_hops(p_remote_sw, + p_ftree->lft_max_lid_ho, + cl_ntoh16(target_lid), + p_port->remote_port_num, + target_rank - p_remote_sw->rank); + } + } + + /* Recursion step: + Assign downgoing ports by stepping up, starting on REMOTE switch. */ + __osm_ftree_fabric_route_downgoing_by_going_up( + p_ftree, + p_remote_sw, /* remote switch - used as a route-downgoing alg. next step point */ + p_sw, /* this switch - prev. position switch for the function */ + target_lid, /* LID that we're routing to */ + target_rank, /* rank of the LID that we're routing to */ + is_real_lid, /* whether this target LID is real or dummy */ + is_main_path); /* whether this is path to HCA that should by tracked by counters */ + } + + /* we're done for the third case */ + if (!is_real_lid) + return; + + /* What's left to do at this point: + * + * 1. is_real_lid == TRUE && is_main_path == TRUE: + * - going UP(TRUE,FALSE) on rest of the groups, each time on port 0, + * but only if the remote (upper) switch hasn't been already + * configured for this target LID + * + NOT promoting port counter + * + setting path in remote switch fwd tbl if it hasn't been set yet + * + setting hops in remote switch on all the ports of each group + * if it hasn't been set yet + * + * 2. is_real_lid == TRUE && is_main_path == FALSE: + * - going UP(TRUE,FALSE) on ALL the groups, each time on port 0, + * but only if the remote (upper) switch hasn't been already + * configured for this target LID + * + NOT promoting port counter + * + setting path in remote switch fwd tbl if it hasn't been set yet + * + setting hops in remote switch on all the ports of each group + * if it hasn't been set yet + * + * These two rules can be rephrased this way: + * - foreach UP port group + * + if remote switch has been set with the target LID + * - skip this port group + * + else + * - select port 0 + * - do NOT promote port counter + * - set path in remote switch fwd tbl + * - set hops in remote switch on all the ports of this group + * - go UP(TRUE,FALSE) to the remote switch + */ + + for (i = 0; i < p_sw->up_port_groups_num; i++) + { + p_group = p_sw->up_port_groups[i]; + p_remote_sw = p_group->remote_hca_or_sw.remote_sw; + + /* skip if target lid has been already set on remote switch fwd tbl */ + if (__osm_ftree_sw_get_fwd_table_block( + p_remote_sw,cl_ntoh16(target_lid)) != OSM_NO_PATH) + continue; + + if (p_sw->rank == (__osm_ftree_fabric_get_rank(p_ftree) - 1)) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "__osm_ftree_fabric_route_downgoing_by_going_up: " + " - Routing SECONDARY path for LID 0x%x: %s --> %s\n", + cl_ntoh16(target_lid), + __osm_ftree_tuple_to_str(p_sw->tuple), + __osm_ftree_tuple_to_str(p_remote_sw->tuple)); + } + + cl_ptr_vector_at(&p_group->ports, 0, (void **)&p_port); + __osm_ftree_sw_set_fwd_table_block(p_remote_sw, + cl_ntoh16(target_lid), + p_port->remote_port_num); + + /* On the remote switch that is pointed by the p_group, + set hops for ALL the ports in the remote group. */ + + ports_num = (uint16_t)cl_ptr_vector_get_size(&p_group->ports); + for (j = 0; j < ports_num; j++) + { + cl_ptr_vector_at(&p_group->ports, j, (void **)&p_port); + + __osm_ftree_sw_set_hops(p_remote_sw, + p_ftree->lft_max_lid_ho, + cl_ntoh16(target_lid), + p_port->remote_port_num, + target_rank - p_remote_sw->rank); + } + + /* Recursion step: + Assign downgoing ports by stepping up, starting on REMOTE switch. */ + __osm_ftree_fabric_route_downgoing_by_going_up( + p_ftree, + p_remote_sw, /* remote switch - used as a route-downgoing alg. next step point */ + p_sw, /* this switch - prev. position switch for the function */ + target_lid, /* LID that we're routing to */ + target_rank, /* rank of the LID that we're routing to */ + TRUE, /* whether the target LID is real or dummy */ + FALSE); /* whether this is path to HCA that should by tracked by counters */ + } + +} /* ftree_fabric_route_downgoing_by_going_up() */ + +/***************************************************/ + +/* + * Pseudo code: + * foreach leaf switch (in indexing order) + * for each compute node (in indexing order) + * obtain the LID of the compute node + * set local LFT(LID) of the port connecting to compute node + * call assign-down-going-port-by-descending-up(TRUE,TRUE) on CURRENT switch + * for each MISSING compute node + * call assign-down-going-port-by-descending-up(FALSE,TRUE) on CURRENT switch + */ + +static void +__osm_ftree_fabric_route_to_hcas( + IN ftree_fabric_t * p_ftree) +{ + ftree_sw_t * p_sw; + ftree_port_group_t * p_group; + ftree_port_t * p_port; + uint32_t i; + uint32_t j; + ib_net16_t remote_lid; + + OSM_LOG_ENTER(&p_ftree->p_osm->log, __osm_ftree_fabric_route_to_hcas); + + /* for each leaf switch (in indexing order) */ + for(i = 0; i < p_ftree->leaf_switches_num; i++) + { + p_sw = p_ftree->leaf_switches[i]; + + /* for each HCA connected to this switch */ + for (j = 0; j < p_sw->down_port_groups_num; j++) + { + /* obtain the LID of HCA port */ + p_group = p_sw->down_port_groups[j]; + remote_lid = p_group->remote_base_lid; + + /* set local LFT(LID) to the port that is connected to HCA */ + cl_ptr_vector_at(&p_group->ports, 0, (void **)&p_port); + __osm_ftree_sw_set_fwd_table_block(p_sw, + cl_ntoh16(remote_lid), + p_port->port_num); + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "__osm_ftree_fabric_route_to_hcas: " + "Switch %s: set path to HCA LID 0x%x through port %u\n", + __osm_ftree_tuple_to_str(p_sw->tuple), + cl_ntoh16(remote_lid), + p_port->port_num); + + /* set local min hop table(LID) to route to the CA */ + __osm_ftree_sw_set_hops(p_sw, + p_ftree->lft_max_lid_ho, + cl_ntoh16(remote_lid), + p_port->port_num, + 1); + + /* assign downgoing ports by stepping up */ + __osm_ftree_fabric_route_downgoing_by_going_up( + p_ftree, + p_sw, /* local switch - used as a route-downgoing alg. start point */ + NULL, /* prev. position switch */ + remote_lid, /* LID that we're routing to */ + __osm_ftree_fabric_get_rank(p_ftree), /* rank of the LID that we're routing to */ + TRUE, /* whether this HCA LID is real or dummy */ + TRUE); /* whether this path to HCA should by tracked by counters */ + } + + /* We're done with the real HCAs. Now route the dummy HCAs that are missing. + When routing to dummy HCAs we don't fill lid matrices. */ + + if (p_ftree->max_hcas_per_leaf > p_sw->down_port_groups_num) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG,"__osm_ftree_fabric_route_to_hcas: " + "Routing %u dummy HCAs\n", + p_ftree->max_hcas_per_leaf - p_sw->down_port_groups_num); + for ( j = 0; + ((int)j) < (p_ftree->max_hcas_per_leaf - p_sw->down_port_groups_num); + j++) + { + /* assign downgoing ports by stepping up */ + __osm_ftree_fabric_route_downgoing_by_going_up( + p_ftree, + p_sw, /* local switch - used as a route-downgoing alg. start point */ + NULL, /* prev. position switch */ + 0, /* LID that we're routing to - ignored for dummy HCA */ + 0, /* rank of the LID that we're routing to - ignored for dummy HCA */ + FALSE, /* whether this HCA LID is real or dummy */ + TRUE); /* whether this path to HCA should by tracked by counters */ + } + } + } + /* done going through all the leaf switches */ + OSM_LOG_EXIT(&p_ftree->p_osm->log); +} /* __osm_ftree_fabric_route_to_hcas() */ + +/***************************************************/ + +/* + * Pseudo code: + * foreach switch in fabric + * obtain its LID + * set local LFT(LID) to port 0 + * call assign-down-going-port-by-descending-up(TRUE,FALSE) on CURRENT switch + * + * Routing to switch is similar to routing a REAL hca lid on SECONDARY path: + * - we should set fwd tables + * - we should NOT update port counters + */ + +static void +__osm_ftree_fabric_route_to_switches( + IN ftree_fabric_t * p_ftree) +{ + ftree_sw_t * p_sw; + ftree_sw_t * p_next_sw; + + OSM_LOG_ENTER(&p_ftree->p_osm->log, __osm_ftree_fabric_route_to_switches); + + 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) */ + __osm_ftree_sw_set_fwd_table_block(p_sw, + cl_ntoh16(p_sw->base_lid), + 0); + + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "__osm_ftree_fabric_route_to_switches: " + "Switch %s (LID 0x%x): routing switch-to-switch pathes\n", + __osm_ftree_tuple_to_str(p_sw->tuple), + cl_ntoh16(p_sw->base_lid)); + + /* set min hop table of the switch to itself */ + __osm_ftree_sw_set_hops(p_sw, + p_ftree->lft_max_lid_ho, + cl_ntoh16(p_sw->base_lid), + 0, /* port_num */ + 0);/* hops */ + + __osm_ftree_fabric_route_downgoing_by_going_up( + p_ftree, + p_sw, /* local switch - used as a route-downgoing alg. start point */ + NULL, /* prev. position switch */ + p_sw->base_lid, /* LID that we're routing to */ + p_sw->rank, /* rank of the LID that we're routing to */ + TRUE, /* whether the target LID is a real or dummy */ + FALSE); /* whether this path should by tracked by counters */ + } + + OSM_LOG_EXIT(&p_ftree->p_osm->log); +} /* __osm_ftree_fabric_route_to_switches() */ + +/*************************************************** + ***************************************************/ + +static int +__osm_ftree_fabric_populate_switches( + IN ftree_fabric_t * p_ftree) +{ + osm_switch_t * p_osm_sw; + osm_switch_t * p_next_osm_sw; + + OSM_LOG_ENTER(&p_ftree->p_osm->log, __osm_ftree_fabric_populate_switches); + + p_next_osm_sw = (osm_switch_t *)cl_qmap_head(&p_ftree->p_osm->subn.sw_guid_tbl); + while( p_next_osm_sw != (osm_switch_t *)cl_qmap_end(&p_ftree->p_osm->subn.sw_guid_tbl) ) + { + p_osm_sw = p_next_osm_sw; + p_next_osm_sw = (osm_switch_t *)cl_qmap_next(&p_osm_sw->map_item ); + __osm_ftree_fabric_add_sw(p_ftree,p_osm_sw); + } + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return 0; +} /* __osm_ftree_fabric_populate_switches() */ + +/*************************************************** + ***************************************************/ + +static int +__osm_ftree_fabric_populate_hcas( + 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, __osm_ftree_fabric_populate_hcas); + + p_next_osm_node = (osm_node_t *)cl_qmap_head(&p_ftree->p_osm->subn.node_guid_tbl); + while( p_next_osm_node != (osm_node_t *)cl_qmap_end(&p_ftree->p_osm->subn.node_guid_tbl) ) + { + p_osm_node = p_next_osm_node; + p_next_osm_node = (osm_node_t *)cl_qmap_next(&p_osm_node->map_item); + switch (osm_node_get_type(p_osm_node)) + { + case IB_NODE_TYPE_CA: + __osm_ftree_fabric_add_hca(p_ftree,p_osm_node); + break; + case IB_NODE_TYPE_ROUTER: + break; + case IB_NODE_TYPE_SWITCH: + /* all the switches added separately */ + break; + default: + osm_log(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "__osm_ftree_fabric_populate_hcas: ERR AB0E: " + "Node GUID 0x%016" PRIx64 " - Unknown node type: %s\n", + cl_ntoh64(osm_node_get_node_guid(p_osm_node)), + ib_get_node_type_str(osm_node_get_type(p_osm_node))); + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return -1; + } + } + + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return 0; +} /* __osm_ftree_fabric_populate_hcas() */ + +/*************************************************** + ***************************************************/ + +static void +__osm_ftree_rank_from_switch( + IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_starting_sw) +{ + 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; + cl_list_t bfs_list; + ftree_sw_tbl_element_t * p_sw_tbl_element = NULL; + + p_starting_sw->rank = 0; + + /* Run BFS scan of the tree, starting from this switch */ + + cl_list_init(&bfs_list, cl_qmap_count(&p_ftree->sw_tbl)); + cl_list_insert_tail(&bfs_list, &__osm_ftree_sw_tbl_element_create(p_starting_sw)->map_item); + + while (!cl_is_list_empty(&bfs_list)) + { + p_sw_tbl_element = (ftree_sw_tbl_element_t *)cl_list_remove_head(&bfs_list); + p_sw = p_sw_tbl_element->p_sw; + __osm_ftree_sw_tbl_element_destroy(p_sw_tbl_element); + + p_node = osm_switch_get_node_ptr(p_sw->p_osm_sw); + + /* 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 (!osm_physp_is_valid(p_osm_port)) + continue; + if (!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 = (ftree_sw_t *)cl_qmap_get(&p_ftree->sw_tbl, + osm_node_get_node_guid(p_remote_node)); + if (p_remote_sw == (ftree_sw_t *)cl_qmap_end(&p_ftree->sw_tbl)) + { + /* remote node is not a switch */ + continue; + } + if (__osm_ftree_sw_ranked(p_remote_sw) && p_remote_sw->rank <= (p_sw->rank + 1)) + continue; + + /* rank the remote switch and add it to the BFS list */ + p_remote_sw->rank = p_sw->rank + 1; + cl_list_insert_tail(&bfs_list, + &__osm_ftree_sw_tbl_element_create(p_remote_sw)->map_item); + } + } +} /* __osm_ftree_rank_from_switch() */ + + +/*************************************************** + ***************************************************/ + +static int +__osm_ftree_rank_switches_from_hca( + IN ftree_fabric_t * p_ftree, + IN ftree_hca_t * p_hca) +{ + 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, __osm_ftree_rank_switches_from_hca); + + 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 (!osm_physp_is_valid(p_osm_port)) + continue; + if (!osm_link_is_healthy(p_osm_port)) + continue; + + p_remote_osm_node = osm_node_get_remote_node(p_osm_node,i,NULL); + + 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, + "__osm_ftree_rank_switches_from_hca: ERR AB0F: " + "HCA conected directly to another HCA: " + "0x%016" PRIx64 " <---> 0x%016" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(p_hca->p_osm_node)), + 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, + "__osm_ftree_rank_switches_from_hca: 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 = (ftree_sw_t *)cl_qmap_get(&p_ftree->sw_tbl, + p_osm_port->p_remote_physp->p_node->node_info.node_guid); + + CL_ASSERT(p_sw != (ftree_sw_t *)cl_qmap_end(&p_ftree->sw_tbl)); + + if (__osm_ftree_sw_ranked(p_sw) && p_sw->rank == 0) + continue; + + osm_log(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "__osm_ftree_rank_switches_from_hca: " + "Marking rank of switch that is directly connected to HCA:\n" + " - HCA guid : 0x%016" PRIx64 "\n" + " - Switch guid: 0x%016" PRIx64 "\n" + " - Switch LID : 0x%x\n", + cl_ntoh64(osm_node_get_node_guid(p_hca->p_osm_node)), + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(p_sw->p_osm_sw))), + cl_ntoh16(p_sw->base_lid)); + __osm_ftree_rank_from_switch(p_ftree, p_sw); + } + + Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* __osm_ftree_rank_switches_from_hca() */ + +/***************************************************/ + +static void +__osm_ftree_sw_reverse_rank( + IN cl_map_item_t* const p_map_item, + IN void *context) +{ + ftree_fabric_t * p_ftree = (ftree_fabric_t *)context; + ftree_sw_t * p_sw = (ftree_sw_t * const) p_map_item; + p_sw->rank = __osm_ftree_fabric_get_rank(p_ftree) - p_sw->rank - 1; +} + +/*************************************************** + ***************************************************/ + +static int +__osm_ftree_fabric_construct_hca_ports( + IN ftree_fabric_t * p_ftree, + IN ftree_hca_t * p_hca) +{ + ftree_sw_t * p_remote_sw; + osm_node_t * p_node = p_hca->p_osm_node; + osm_node_t * p_remote_node; + uint8_t remote_node_type; + ib_net64_t remote_node_guid; + osm_physp_t * p_remote_osm_port; + uint8_t i; + uint8_t remote_port_num; + 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 (!osm_physp_is_valid(p_osm_port)) + continue; + if (!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, + "__osm_ftree_fabric_construct_hca_ports: ERR AB11: " + "HCA conected directly to another HCA: " + "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, + "__osm_ftree_fabric_construct_hca_ports: 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 = (ftree_sw_t *)cl_qmap_get(&p_ftree->sw_tbl,remote_node_guid); + CL_ASSERT( p_remote_sw != (ftree_sw_t *)cl_qmap_end(&p_ftree->sw_tbl) ); + CL_ASSERT( (p_remote_sw->rank + 1) == __osm_ftree_fabric_get_rank(p_ftree) ); + + __osm_ftree_hca_add_port( + p_hca, /* local ftree_hca object */ + i, /* local port number */ + remote_port_num, /* remote port number */ + osm_node_get_base_lid(p_node, i), /* local lid */ + osm_node_get_base_lid(p_remote_node, 0), /* remote lid */ + osm_physp_get_port_guid(p_osm_port), /* local port guid */ + osm_physp_get_port_guid(p_remote_osm_port),/* remote port guid */ + remote_node_guid, /* remote node guid */ + remote_node_type, /* remote node type */ + (void *) p_remote_sw); /* remote ftree_hca/sw object */ + } + + Exit: + return res; +} /* __osm_ftree_fabric_construct_hca_ports() */ + +/*************************************************** + ***************************************************/ + +static int +__osm_ftree_fabric_construct_sw_ports( + IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw) +{ + ftree_hca_t * p_remote_hca; + ftree_sw_t * p_remote_sw; + osm_node_t * p_node = osm_switch_get_node_ptr(p_sw->p_osm_sw); + osm_node_t * p_remote_node; + ib_net16_t remote_base_lid; + uint8_t remote_node_type; + ib_net64_t remote_node_guid; + osm_physp_t * p_remote_osm_port; + ftree_direction_t direction; + void * p_remote_hca_or_sw; + uint8_t i; + uint8_t remote_port_num; + int res = 0; + + CL_ASSERT(osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH); + + for (i = 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 (!osm_physp_is_valid(p_osm_port)) + continue; + if (!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: + /* switch connected to hca */ + + CL_ASSERT((p_sw->rank + 1) == __osm_ftree_fabric_get_rank(p_ftree)); + + p_remote_hca = (ftree_hca_t *)cl_qmap_get(&p_ftree->hca_tbl,remote_node_guid); + CL_ASSERT(p_remote_hca != (ftree_hca_t *)cl_qmap_end(&p_ftree->hca_tbl)); + + p_remote_hca_or_sw = (void *)p_remote_hca; + direction = FTREE_DIRECTION_DOWN; + + remote_base_lid = osm_physp_get_base_lid(p_remote_osm_port); + break; + + case IB_NODE_TYPE_SWITCH: + /* switch connected to another switch */ + + p_remote_sw = (ftree_sw_t *)cl_qmap_get(&p_ftree->sw_tbl,remote_node_guid); + CL_ASSERT(p_remote_sw != (ftree_sw_t *)cl_qmap_end(&p_ftree->sw_tbl)); + p_remote_hca_or_sw = (void *)p_remote_sw; + + if (abs(p_sw->rank - p_remote_sw->rank) != 1) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "__osm_ftree_fabric_construct_sw_ports: ERR AB16: " + "Illegal link between switches with ranks %u and %u:\n" + " GUID 0x%016" PRIx64 ", LID 0x%x, rank %u\n" + " GUID 0x%016" PRIx64 ", LID 0x%x, rank %u\n", + p_sw->rank, + p_remote_sw->rank, + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(p_sw->p_osm_sw))), + cl_ntoh16(p_sw->base_lid), + p_sw->rank, + cl_ntoh64(osm_node_get_node_guid(osm_switch_get_node_ptr(p_remote_sw->p_osm_sw))), + cl_ntoh16(p_remote_sw->base_lid), + p_remote_sw->rank); + res = -1; + goto Exit; + } + + if (p_sw->rank > p_remote_sw->rank) + direction = FTREE_DIRECTION_UP; + else + direction = FTREE_DIRECTION_DOWN; + + /* switch LID is only in port 0 port_info structure */ + remote_base_lid = osm_node_get_base_lid(p_remote_node, 0); + + break; + + default: + osm_log(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "__osm_ftree_fabric_construct_sw_ports: ERR AB13: " + "Node GUID 0x%016" PRIx64 " - Unknown node type: %s\n", + cl_ntoh64(remote_node_guid), + ib_get_node_type_str(remote_node_type)); + res = -1; + goto Exit; + } + __osm_ftree_sw_add_port( + p_sw, /* local ftree_sw object */ + i, /* local port number */ + remote_port_num, /* remote port number */ + p_sw->base_lid, /* local lid */ + remote_base_lid, /* remote lid */ + osm_physp_get_port_guid(p_osm_port), /* local port guid */ + osm_physp_get_port_guid(p_remote_osm_port), /* remote port guid */ + remote_node_guid, /* remote node guid */ + remote_node_type, /* remote node type */ + p_remote_hca_or_sw, /* remote ftree_hca/sw object */ + direction); /* port direction (up or down) */ + + /* Track the max lid (in host order) that exists in the fabric */ + if (cl_ntoh16(remote_base_lid) > p_ftree->lft_max_lid_ho) + p_ftree->lft_max_lid_ho = cl_ntoh16(remote_base_lid); + } + + Exit: + return res; +} /* __osm_ftree_fabric_construct_sw_ports() */ + +/*************************************************** + ***************************************************/ + +/* ToDo: improve ranking algorithm complexity + by propogating BFS from more nodes */ +static int +__osm_ftree_fabric_perform_ranking( + IN ftree_fabric_t * p_ftree) +{ + ftree_hca_t * p_hca; + ftree_hca_t * p_next_hca; + int res = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log, __osm_ftree_fabric_perform_ranking); + + /* Mark REVERSED rank of all the switches in the subnet. + Start from switches that are connected to hca's, and + scan all the switches in the subnet. */ + p_next_hca = (ftree_hca_t *)cl_qmap_head(&p_ftree->hca_tbl); + while( p_next_hca != (ftree_hca_t *)cl_qmap_end( &p_ftree->hca_tbl ) ) + { + p_hca = p_next_hca; + p_next_hca = (ftree_hca_t *)cl_qmap_next(&p_hca->map_item ); + if (__osm_ftree_rank_switches_from_hca(p_ftree,p_hca) != 0) + { + res = -1; + osm_log(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "__osm_ftree_fabric_perform_ranking: ERR AB14: " + "Subnet ranking failed - subnet is not FatTree"); + goto Exit; + } + } + + /* calculate and set FatTree rank */ + __osm_ftree_fabric_calculate_rank(p_ftree); + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "__osm_ftree_fabric_perform_ranking: " + "FatTree rank is %u\n", __osm_ftree_fabric_get_rank(p_ftree)); + + /* fix ranking of the switches by reversing the ranking direction */ + cl_qmap_apply_func(&p_ftree->sw_tbl, __osm_ftree_sw_reverse_rank, (void *)p_ftree); + + if ( __osm_ftree_fabric_get_rank(p_ftree) > FAT_TREE_MAX_RANK || + __osm_ftree_fabric_get_rank(p_ftree) < FAT_TREE_MIN_RANK ) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "__osm_ftree_fabric_perform_ranking: ERR AB15: " + "Tree rank is %u (should be between %u and %u)\n", + __osm_ftree_fabric_get_rank(p_ftree), + FAT_TREE_MIN_RANK, + FAT_TREE_MAX_RANK); + res = -1; + goto Exit; + } + + Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* __osm_ftree_fabric_perform_ranking() */ + +/*************************************************** + ***************************************************/ + +static int +__osm_ftree_fabric_populate_ports( + IN ftree_fabric_t * p_ftree) +{ + ftree_hca_t * p_hca; + ftree_hca_t * p_next_hca; + ftree_sw_t * p_sw; + ftree_sw_t * p_next_sw; + int res = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log, __osm_ftree_fabric_populate_ports); + + p_next_hca = (ftree_hca_t *)cl_qmap_head(&p_ftree->hca_tbl); + while( p_next_hca != (ftree_hca_t *)cl_qmap_end( &p_ftree->hca_tbl ) ) + { + p_hca = p_next_hca; + p_next_hca = (ftree_hca_t *)cl_qmap_next(&p_hca->map_item ); + if (__osm_ftree_fabric_construct_hca_ports(p_ftree,p_hca) != 0) + { + res = -1; + goto Exit; + } + } + + p_next_sw = (ftree_sw_t *)cl_qmap_head(&p_ftree->sw_tbl); + while( p_next_sw != (ftree_sw_t *)cl_qmap_end( &p_ftree->sw_tbl ) ) + { + p_sw = p_next_sw; + p_next_sw = (ftree_sw_t *)cl_qmap_next(&p_sw->map_item ); + if (__osm_ftree_fabric_construct_sw_ports(p_ftree,p_sw) != 0) + { + res = -1; + goto Exit; + } + } + Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* __osm_ftree_fabric_populate_ports() */ + +/*************************************************** + ***************************************************/ + +static int +__osm_ftree_construct_fabric( + IN void * context) +{ + ftree_fabric_t * p_ftree = context; + int status = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log, __osm_ftree_construct_fabric); + + if (p_ftree->p_osm->subn.opt.lmc > 0) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "LMC > 0 is not supported by fat-tree routing.\n" + "Falling back to default routing.\n"); + status = -1; + goto Exit; + } + + if ( cl_qmap_count(&p_ftree->p_osm->subn.sw_guid_tbl) < 2 ) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric has %u switches - topology is not fat-tree.\n" + "Falling back to default routing.\n", + cl_qmap_count(&p_ftree->p_osm->subn.sw_guid_tbl)); + status = -1; + goto Exit; + } + + if ( (cl_qmap_count(&p_ftree->p_osm->subn.node_guid_tbl) - + cl_qmap_count(&p_ftree->p_osm->subn.sw_guid_tbl)) < 2) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric has %u nodes (%u switches) - topology is not fat-tree.\n" + "Falling back to default routing.\n", + cl_qmap_count(&p_ftree->p_osm->subn.node_guid_tbl), + cl_qmap_count(&p_ftree->p_osm->subn.sw_guid_tbl)); + status = -1; + goto Exit; + } + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE,"__osm_ftree_construct_fabric: \n" + " |----------------------------------------|\n" + " |- Starting FatTree fabric construction -|\n" + " |----------------------------------------|\n\n"); + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "__osm_ftree_construct_fabric: " + "Populating FatTree switch table\n"); + /* ToDo: now that the pointer from node to switch exists, + no need to fill the switch table in a separate loop */ + if (__osm_ftree_fabric_populate_switches(p_ftree) != 0) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric topology is not fat-tree - " + "falling back to default routing\n"); + status = -1; + goto Exit; + } + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "__osm_ftree_construct_fabric: " + "Populating FatTree HCA table\n"); + if (__osm_ftree_fabric_populate_hcas(p_ftree) != 0) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric topology is not fat-tree - " + "falling back to default routing\n"); + status = -1; + goto Exit; + } + + if (cl_qmap_count(&p_ftree->hca_tbl) < 2) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric has %u HCAa - topology is not fat-tree.\n" + "Falling back to default routing.\n", + cl_qmap_count(&p_ftree->hca_tbl)); + status = -1; + goto Exit; + } + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "__osm_ftree_construct_fabric: Ranking FatTree\n"); + + if (__osm_ftree_fabric_perform_ranking(p_ftree) != 0) + { + if (__osm_ftree_fabric_get_rank(p_ftree) > FAT_TREE_MAX_RANK) + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric rank is %u (>%u) - " + "fat-tree routing falls back to default routing\n", + __osm_ftree_fabric_get_rank(p_ftree), FAT_TREE_MAX_RANK); + else if (__osm_ftree_fabric_get_rank(p_ftree) < FAT_TREE_MIN_RANK) + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric rank is %u (<%u) - " + "fat-tree routing falls back to default routing\n", + __osm_ftree_fabric_get_rank(p_ftree), FAT_TREE_MIN_RANK); + 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.*/ + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "__osm_ftree_construct_fabric: " + "Populating HCA & switch ports\n"); + if (__osm_ftree_fabric_populate_ports(p_ftree) != 0) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric topology is not a fat-tree - " + "routing falls back to default routing\n"); + status = -1; + goto Exit; + } + + /* Assign index to all the switches and hca's in the fabric. + This function also sorts all the port arrays of the switches + by the remote switch index, creates a leaf switch array + sorted by the switch index, and tracks the maximal number of + hcas per leaf switch. */ + __osm_ftree_fabric_make_indexing(p_ftree); + + /* print general info about fabric topology */ + __osm_ftree_fabric_dump_general_info(p_ftree); + + /* dump full tree topology */ + if (osm_log_is_active(&p_ftree->p_osm->log, OSM_LOG_DEBUG)) + __osm_ftree_fabric_dump(p_ftree); + + if (! __osm_ftree_fabric_validate_topology(p_ftree)) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric topology is not a fat-tree - " + "routing falls back to default routing\n"); + status = -1; + goto Exit; + } + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "__osm_ftree_construct_fabric: " + "Max LID in switch LFTs (in host order): 0x%x\n", + p_ftree->lft_max_lid_ho); + + Exit: + if (status != 0) + { + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "__osm_ftree_construct_fabric: " + "Clearing FatTree Fabric data structures\n"); + __osm_ftree_fabric_clear(p_ftree); + } + else + p_ftree->fabric_built = TRUE; + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "__osm_ftree_construct_fabric: \n" + " |--------------------------------------------------|\n" + " |- Done constructing FatTree fabric (status = %d) -|\n" + " |--------------------------------------------------|\n\n", + status); + + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return status; +} /* __osm_ftree_construct_fabric() */ + +/*************************************************** + ***************************************************/ + +static int +__osm_ftree_do_routing( + IN void * context) +{ + ftree_fabric_t * p_ftree = context; + + OSM_LOG_ENTER(&p_ftree->p_osm->log, __osm_ftree_do_routing); + + if (!p_ftree->fabric_built) + goto Exit; + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE,"__osm_ftree_do_routing: " + "Starting FatTree routing\n"); + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE,"__osm_ftree_do_routing: " + "Filling switch forwarding tables for routes to HCAs\n"); + __osm_ftree_fabric_route_to_hcas(p_ftree); + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE,"__osm_ftree_do_routing: " + "Filling switch forwarding tables for switch-to-switch pathes\n"); + __osm_ftree_fabric_route_to_switches(p_ftree); + + /* for each switch, set its fwd table */ + cl_qmap_apply_func(&p_ftree->sw_tbl, __osm_ftree_set_sw_fwd_table, (void *)p_ftree); + + /* write out hca ordering file */ + __osm_ftree_fabric_dump_hca_ordering(p_ftree); + + osm_log(&p_ftree->p_osm->log, OSM_LOG_VERBOSE,"__osm_ftree_do_routing: " + "FatTree routing is done\n"); + + Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return 0; +} + +/*************************************************** + ***************************************************/ + +static void +__osm_ftree_delete( + IN void * context) +{ + if (!context) + return; + __osm_ftree_fabric_destroy((ftree_fabric_t *)context); +} + +/*************************************************** + ***************************************************/ + +int osm_ucast_ftree_setup(osm_opensm_t * p_osm) +{ + ftree_fabric_t * p_ftree = __osm_ftree_fabric_create(); + if (!p_ftree) + return -1; + + p_ftree->p_osm = p_osm; + + p_osm->routing_engine.context = (void *)p_ftree; + p_osm->routing_engine.build_lid_matrices = __osm_ftree_construct_fabric; + p_osm->routing_engine.ucast_build_fwd_tables = __osm_ftree_do_routing; + p_osm->routing_engine.delete = __osm_ftree_delete; + return 0; +} + +/*************************************************** + ***************************************************/ + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_mgr.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_mgr.c new file mode 100644 index 00000000..27c87680 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_mgr.c @@ -0,0 +1,1277 @@ +/* + * 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: + * Implementation of osm_ucast_mgr_t. + * This file implements the Unicast Manager object. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.14 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LINE_LENGTH 256 + +/********************************************************************** + **********************************************************************/ +/* + * This flag is used for stopping the relaxation algorithm if no + * change detected during the fabric scan + */ +static boolean_t __some_hop_count_set; + +/********************************************************************** + **********************************************************************/ +void +osm_ucast_mgr_construct( + IN osm_ucast_mgr_t* const p_mgr ) +{ + memset( p_mgr, 0, sizeof(*p_mgr) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_ucast_mgr_destroy( + IN osm_ucast_mgr_t* const p_mgr ) +{ + CL_ASSERT( p_mgr ); + + OSM_LOG_ENTER( p_mgr->p_log, osm_ucast_mgr_destroy ); + + if (p_mgr->lft_buf) + free(p_mgr->lft_buf); + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_ucast_mgr_init( + IN osm_ucast_mgr_t* const p_mgr, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_ucast_mgr_init ); + + CL_ASSERT( p_req ); + CL_ASSERT( p_subn ); + CL_ASSERT( p_lock ); + + osm_ucast_mgr_construct( p_mgr ); + + p_mgr->p_log = p_log; + p_mgr->p_subn = p_subn; + p_mgr->p_lock = p_lock; + p_mgr->p_req = p_req; + + p_mgr->lft_buf = malloc(IB_LID_UCAST_END_HO + 1); + if (!p_mgr->lft_buf) + return IB_INSUFFICIENT_MEMORY; + + OSM_LOG_EXIT( p_mgr->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +struct ucast_mgr_dump_context { + osm_ucast_mgr_t *p_mgr; + FILE *file; +}; + +static void +ucast_mgr_dump(osm_ucast_mgr_t *p_mgr, FILE *file, + void (*func)(cl_map_item_t *, void *)) +{ + struct ucast_mgr_dump_context dump_context; + + dump_context.p_mgr = p_mgr; + dump_context.file = file; + + cl_qmap_apply_func(&p_mgr->p_subn->sw_guid_tbl, func, &dump_context); +} + +void +ucast_mgr_dump_to_file(osm_ucast_mgr_t *p_mgr, const char *file_name, + void (*func)(cl_map_item_t *, void *)) +{ + char path[1024]; + FILE *file; + + snprintf(path, sizeof(path), "%s/%s", + p_mgr->p_subn->opt.dump_files_dir, file_name); + + file = fopen(path, "w"); + if (!file) { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "ucast_mgr_dump_to_file: ERR 3A12: " + "Failed to open fdb file (%s)\n", path ); + return; + } + + ucast_mgr_dump(p_mgr, file, func); + + fclose(file); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_ucast_mgr_dump_path_distribution( + IN cl_map_item_t *p_map_item, + IN void *cxt) +{ + osm_node_t *p_node; + osm_node_t *p_remote_node; + uint8_t i; + uint8_t num_ports; + uint32_t num_paths; + ib_net64_t remote_guid_ho; + osm_switch_t* p_sw = (osm_switch_t *)p_map_item; + osm_ucast_mgr_t* p_mgr = ((struct ucast_mgr_dump_context *)cxt)->p_mgr; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_dump_path_distribution ); + + p_node = osm_switch_get_node_ptr( p_sw ); + num_ports = osm_switch_get_num_ports( p_sw ); + + osm_log_printf( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_ucast_mgr_dump_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 ); + osm_log_printf( p_mgr->p_log, OSM_LOG_DEBUG,"\n %03u : %u", i, num_paths ); + if( i == 0 ) + { + osm_log_printf( p_mgr->p_log, OSM_LOG_DEBUG, " (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_remote_type( p_node, i ) ) + { + case IB_NODE_TYPE_SWITCH: + osm_log_printf( p_mgr->p_log, OSM_LOG_DEBUG, " (link to switch" ); + break; + case IB_NODE_TYPE_ROUTER: + osm_log_printf( p_mgr->p_log, OSM_LOG_DEBUG, " (link to router" ); + break; + case IB_NODE_TYPE_CA: + osm_log_printf( p_mgr->p_log, OSM_LOG_DEBUG, " (link to CA" ); + break; + default: + osm_log_printf( p_mgr->p_log, OSM_LOG_DEBUG, " (link to unknown node type" ); + break; + } + + osm_log_printf( p_mgr->p_log, OSM_LOG_DEBUG, " 0x%" PRIx64 ")", + remote_guid_ho ); + } + + osm_log_printf( p_mgr->p_log, OSM_LOG_DEBUG, "\n" ); + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_ucast_mgr_dump_ucast_routes( + IN cl_map_item_t *p_map_item, + IN void *cxt ) +{ + const osm_node_t* p_node; + 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; + osm_switch_t* p_sw = (osm_switch_t *)p_map_item; + osm_ucast_mgr_t* p_mgr = ((struct ucast_mgr_dump_context *)cxt)->p_mgr; + FILE *file = ((struct ucast_mgr_dump_context *)cxt)->file; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_dump_ucast_routes ); + + p_node = osm_switch_get_node_ptr( p_sw ); + + max_lid_ho = osm_switch_get_max_lid_ho( p_sw ); + + fprintf( file, "__osm_ucast_mgr_dump_ucast_routes: " + "Switch 0x%016" PRIx64 "\n" + "LID : Port : Hops : Optimal\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) ) ); + for( lid_ho = 1; lid_ho <= max_lid_ho; lid_ho++ ) + { + fprintf(file, "0x%04X : ", lid_ho); + + 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. + */ + num_hops = osm_switch_get_hop_count( p_sw, lid_ho, port_num ); + if( num_hops == OSM_NO_PATH ) + { + fprintf( file, "UNREACHABLE\n" ); + continue; + } + + best_hops = osm_switch_get_least_hops( p_sw, lid_ho ); + fprintf( file, "%03u : %02u : ", port_num, num_hops ); + + if( best_hops == num_hops ) + fprintf( file, "yes" ); + else + { + best_port = osm_switch_recommend_path( + p_sw, lid_ho, TRUE, + NULL, NULL, NULL, NULL ); /* No LMC Optimization */ + fprintf( file, "No %u hop path possible via port %u!", + best_hops, best_port ); + } + + fprintf( file, "\n" ); + } + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +ucast_mgr_dump_lid_matrix(cl_map_item_t *p_map_item, void *cxt) +{ + osm_switch_t* p_sw = (osm_switch_t *)p_map_item; + osm_ucast_mgr_t* p_mgr = ((struct ucast_mgr_dump_context *)cxt)->p_mgr; + FILE *file = ((struct ucast_mgr_dump_context *)cxt)->file; + osm_node_t *p_node = osm_switch_get_node_ptr(p_sw); + unsigned max_lid = osm_switch_get_max_lid_ho(p_sw); + unsigned max_port = osm_switch_get_num_ports(p_sw); + 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; + + fprintf(file, "0x%04x:", lid); + for (port = 0 ; port < max_port ; port++) + fprintf(file, " %02x", + osm_switch_get_hop_count(p_sw, lid, port)); + p_port = cl_ptr_vector_get(&p_mgr->p_subn->port_lid_tbl, lid); + if (p_port) + fprintf(file, " # portguid 0x%" PRIx64, + cl_ntoh64(osm_port_get_guid(p_port))); + fprintf(file, "\n"); + } +} + +/********************************************************************** + **********************************************************************/ +void +ucast_mgr_dump_lfts(cl_map_item_t *p_map_item, void *cxt) +{ + osm_switch_t* p_sw = (osm_switch_t *)p_map_item; + osm_ucast_mgr_t* p_mgr = ((struct ucast_mgr_dump_context *)cxt)->p_mgr; + FILE *file = ((struct ucast_mgr_dump_context *)cxt)->file; + osm_node_t *p_node = osm_switch_get_node_ptr(p_sw); + unsigned max_lid = osm_switch_get_max_lid_ho(p_sw); + unsigned max_port = osm_switch_get_num_ports(p_sw); + uint16_t lid; + uint8_t port; + char desc[IB_NODE_DESCRIPTION_SIZE + 1]; + + memcpy(desc, p_node->node_desc.description, IB_NODE_DESCRIPTION_SIZE); + desc[IB_NODE_DESCRIPTION_SIZE] = '\0'; + fprintf(file, "Unicast lids [0x0-0x%x] of switch Lid %u guid 0x%016" + PRIx64 " (\'%s\'):\n", + max_lid, osm_node_get_base_lid(p_node, 0), + cl_ntoh64(osm_node_get_node_guid(p_node)), desc); + for (lid = 0; lid <= max_lid; lid++) { + osm_port_t *p_port; + port = osm_switch_get_port_by_lid(p_sw, lid); + + if (port >= max_port) + continue; + + fprintf(file, "0x%04x %03u # ", lid, port); + + p_port = cl_ptr_vector_get(&p_mgr->p_subn->port_lid_tbl, lid); + if (p_port) { + p_node = osm_port_get_parent_node(p_port); + memcpy(desc, p_node->node_desc.description, + IB_NODE_DESCRIPTION_SIZE); + desc[IB_NODE_DESCRIPTION_SIZE] = '\0'; + fprintf(file, "%s portguid 0x016%" PRIx64 ": \'%s\'", + ib_get_node_type_str(osm_node_get_type(p_node)), + cl_ntoh64(osm_port_get_guid(p_port)), desc); + } + else + fprintf(file, "unknown node and type"); + fprintf(file, "\n"); + } + fprintf(file, "%u lids dumped\n", max_lid); +} + +/********************************************************************** + **********************************************************************/ +static void __osm_ucast_mgr_dump_tables(osm_ucast_mgr_t *p_mgr) +{ + ucast_mgr_dump_to_file(p_mgr, "opensm-lid-matrix.dump", + ucast_mgr_dump_lid_matrix); + ucast_mgr_dump_to_file(p_mgr, "opensm-lfts.dump", ucast_mgr_dump_lfts); + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + ucast_mgr_dump(p_mgr, NULL, __osm_ucast_mgr_dump_path_distribution); + ucast_mgr_dump_to_file(p_mgr, "osm.fdbs", __osm_ucast_mgr_dump_ucast_routes); +} + +/********************************************************************** + Starting a rebuild, so notify the switch so it can clear tables, etc... +**********************************************************************/ +static void +__osm_ucast_mgr_clean_switch( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + osm_switch_prepare_path_rebuild((osm_switch_t *)p_map_item); +} + +/********************************************************************** + Add each switch's own LID(s) to its LID matrix. +**********************************************************************/ +static void +__osm_ucast_mgr_process_hop_0( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + osm_switch_t* const p_sw = (osm_switch_t*)p_map_item; + osm_ucast_mgr_t* const p_mgr = (osm_ucast_mgr_t*)context; + osm_node_t *p_node; + uint16_t lid_ho, base_lid_ho, max_lid_ho; + cl_status_t status; + uint8_t lmc; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_hop_0 ); + + p_node = p_sw->p_node; + + CL_ASSERT( p_node ); + CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH ); + + base_lid_ho = cl_ntoh16( osm_node_get_base_lid( p_node, 0 ) ); + if (osm_switch_sp0_is_lmc_capable( p_sw, p_mgr->p_subn )) + lmc = osm_node_get_lmc( p_node, 0 ); + else + lmc = 0; + max_lid_ho = (uint16_t)( base_lid_ho + (1 << lmc) - 1 ); + + for (lid_ho = base_lid_ho; lid_ho <= max_lid_ho; lid_ho++) + { + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_ucast_mgr_process_hop_0: " + "Processing switch GUID 0x%" PRIx64 ", LID 0x%X\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + lid_ho ); + } + + status = osm_switch_set_hops( p_sw, lid_ho, 0, 0 ); + if( status != CL_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_ucast_mgr_process_hop_0: ERR 3A02: " + "Setting hop count failed (%s) for " + "switch GUID 0x%" PRIx64 ", LID 0x%X\n", + CL_STATUS_MSG( status ), + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + lid_ho ); + } + } + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_ucast_mgr_process_neighbor( + IN osm_ucast_mgr_t* const p_mgr, + IN osm_switch_t* const p_sw, + IN osm_switch_t* const p_remote_sw, + IN const uint8_t port_num, + IN const uint8_t remote_port_num ) +{ + uint16_t lid_ho; + uint16_t max_lid_ho; + osm_node_t* p_node; + const osm_node_t* p_remote_node; + uint8_t hops; + cl_status_t status; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_neighbor ); + + CL_ASSERT( p_sw ); + CL_ASSERT( p_remote_sw ); + CL_ASSERT( port_num ); + CL_ASSERT( remote_port_num ); + + p_node = osm_switch_get_node_ptr( p_sw ); + p_remote_node = osm_switch_get_node_ptr( p_remote_sw ); + + CL_ASSERT( p_node ); + CL_ASSERT( p_remote_node ); + + CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH ); + CL_ASSERT( osm_node_get_type( p_remote_node ) == IB_NODE_TYPE_SWITCH ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_ucast_mgr_process_neighbor: " + "Node 0x%" PRIx64 ", remote node 0x%" PRIx64 "\n" + "\t\t\t\tport 0x%X, remote port 0x%X\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + cl_ntoh64( osm_node_get_node_guid( p_remote_node ) ), + port_num, remote_port_num ); + } + + /* + Iterate through all the LIDs in the neighbor switch. + */ + max_lid_ho = osm_switch_get_max_lid_ho( p_remote_sw ); + + /* + Make sure the local lid matrix has enough room to hold + all the LID info coming from the remote LID matrix. + */ + osm_switch_set_min_lid_size( p_sw, max_lid_ho ); + + hops = OSM_NO_PATH; + for( lid_ho = 1; lid_ho <= max_lid_ho; lid_ho++ ) + { + /* + Find the lowest hop count value to this LID. + */ + hops = osm_switch_get_least_hops( p_remote_sw, lid_ho ); + + if( hops != OSM_NO_PATH ) + { + /* + Increment hop count of the neighbor by 1, since it + takes 1 hop to get to the neighbor. + */ + hops++; + + CL_ASSERT( hops <= osm_switch_get_hop_count( p_sw, lid_ho, + port_num ) ); + if( osm_switch_get_hop_count( p_sw, lid_ho, + port_num ) > hops ) + { + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_ucast_mgr_process_neighbor: " + "New best path is %u hops for LID 0x%X\n", + hops, lid_ho ); + } + + /* mark the fact we have got to change anything */ + __some_hop_count_set = TRUE; + + status = osm_switch_set_hops( p_sw, lid_ho, + port_num, hops ); + if( status != CL_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_ucast_mgr_process_neighbor: ERR 3A03: " + "Setting hop count failed (%s)\n", + CL_STATUS_MSG( status ) ); + } + } + } + } + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_ucast_mgr_process_leaf( + IN osm_ucast_mgr_t* const p_mgr, + IN osm_switch_t* const p_sw, + IN osm_node_t* const p_node, + IN const uint8_t port_num, + IN osm_node_t* const p_remote_node, + IN const uint8_t remote_port_num ) +{ + uint16_t i; + uint16_t base_lid_ho; + uint16_t max_lid_ho; + uint8_t lmc; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_leaf ); + + CL_ASSERT( p_node ); + CL_ASSERT( p_remote_node ); + CL_ASSERT( port_num ); + CL_ASSERT( remote_port_num ); + + switch( osm_node_get_type( p_remote_node ) ) + { + case IB_NODE_TYPE_CA: + case IB_NODE_TYPE_ROUTER: + base_lid_ho = cl_ntoh16( osm_node_get_base_lid( + p_remote_node, remote_port_num ) ); + lmc = osm_node_get_lmc( p_remote_node, remote_port_num ); + break; +#if 0 + case IB_NODE_TYPE_SWITCH: + base_lid_ho = cl_ntoh16( osm_node_get_base_lid( + p_remote_node, 0 ) ); + lmc = 0; + break; +#endif + + default: + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_ucast_mgr_process_leaf: ERR 3A01: " + "Bad node type %u, GUID 0x%" PRIx64 "\n", + osm_node_get_type( p_remote_node ), + cl_ntoh64( osm_node_get_node_guid( p_node ) )); + goto Exit; + } + + max_lid_ho = (uint16_t)(base_lid_ho + (1 << lmc) - 1 ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_ucast_mgr_process_leaf: " + "Discovered LIDs [0x%X,0x%X]\n" + "\t\t\t\tport number 0x%X, node 0x%" PRIx64 "\n", + base_lid_ho, max_lid_ho, + port_num, cl_ntoh64( osm_node_get_node_guid( p_node ) )); + } + + for( i = base_lid_ho; i <= max_lid_ho; i++ ) + osm_switch_set_hops( p_sw, i, port_num, 1 ); + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_ucast_mgr_process_leaves( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + osm_switch_t* const p_sw = (osm_switch_t*)p_map_item; + osm_ucast_mgr_t* const p_mgr = (osm_ucast_mgr_t*)context; + osm_node_t *p_node; + osm_node_t *p_remote_node; + uint32_t port_num; + uint8_t remote_port_num; + uint32_t num_ports; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_leaves ); + + p_node = p_sw->p_node; + + CL_ASSERT( p_node ); + CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_ucast_mgr_process_leaves: " + "Processing switch 0x%" PRIx64 "\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) )); + } + + /* + Add the LIDs of all leaves of this switch to the LID matrix. + Don't bother processing loopback paths from one port of + this switch to the another port. + Don't process neighbor switches yet. + Start with port 1 to skip the switch's management port. + */ + num_ports = osm_node_get_num_physp( p_node ); + + 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 != p_node ) + && (osm_node_get_type( p_remote_node ) != IB_NODE_TYPE_SWITCH ) ) + { + __osm_ucast_mgr_process_leaf( + p_mgr, + p_sw, + p_node, + (uint8_t)port_num, + p_remote_node, + remote_port_num ); + } + } + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_ucast_mgr_process_port( + IN osm_ucast_mgr_t* const p_mgr, + IN osm_switch_t* const p_sw, + IN const osm_port_t* const p_port ) +{ + 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; + /* + The following are temporary structures that will aid + in providing better routing in LMC > 0 situations + */ + uint16_t lids_per_port = 1 << p_mgr->p_subn->opt.lmc; + uint64_t *remote_sys_guids = NULL; + uint64_t *remote_node_guids = NULL; + uint16_t num_used_sys = 0; + uint16_t num_used_nodes = 0; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_port ); + + remote_sys_guids = malloc( sizeof(uint64_t) * lids_per_port ); + if( remote_sys_guids == NULL ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_ucast_mgr_process_port: ERR 3A09: " + "Cannot allocate array. Insufficient memory\n"); + goto Exit; + } + + memset( remote_sys_guids, 0, sizeof(uint64_t) * lids_per_port ); + + remote_node_guids = malloc( sizeof(uint64_t) * lids_per_port ); + if( remote_node_guids == NULL ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_ucast_mgr_process_port: ERR 3A0A: " + "Cannot allocate array. Insufficient memory\n"); + goto Exit; + } + + memset( remote_node_guids, 0, sizeof(uint64_t) * lids_per_port ); + + 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, + "__osm_ucast_mgr_process_port: 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; + } + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_ucast_mgr_process_port: " + "Processing port 0x%" PRIx64 + ", LIDs [0x%X,0x%X]\n", + cl_ntoh64( osm_port_get_guid( p_port ) ), + min_lid_ho, max_lid_ho ); + } + + /* + TO DO - This should be runtime error, not a CL_ASSERT() + */ + CL_ASSERT( max_lid_ho < osm_switch_get_fwd_tbl_size( p_sw ) ); + + node_guid = osm_node_get_node_guid(osm_switch_get_node_ptr( p_sw ) ); + + /* + 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. + */ + for( lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++ ) + { + /* Use the enhanced algorithm only for LMC > 0 */ + if (lids_per_port > 1) + port = osm_switch_recommend_path( p_sw, lid_ho, + p_mgr->p_subn->ignore_existing_lfts, + remote_sys_guids, &num_used_sys, + remote_node_guids, &num_used_nodes ); + else + port = osm_switch_recommend_path( p_sw, lid_ho, + p_mgr->p_subn->ignore_existing_lfts, + NULL, NULL, NULL, NULL ); + + /* + There might be no path to the target + */ + if (port == OSM_NO_PATH) + { + /* do not try to overwrite the ppro of non existing port ... */ + is_ignored_by_port_prof = TRUE; + + /* Up/Down routing can cause unreachable routes between some + switches so we do not report that as an error in that case */ + if (!p_mgr->p_subn->p_osm->routing_engine.build_lid_matrices) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_ucast_mgr_process_port: ERR 3A08: " + "No path to get to LID 0x%X from switch 0x%" PRIx64 "\n", + lid_ho, cl_ntoh64( node_guid ) ); + /* trigger a new sweep - try again ... */ + p_mgr->p_subn->subnet_initialization_error = TRUE; + } + else + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_ucast_mgr_process_port: " + "No path to get to LID 0x%X from switch 0x%" PRIx64 "\n", + lid_ho, cl_ntoh64( node_guid ) ); + } + else + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_ucast_mgr_process_port: " + "Routing LID 0x%X to port 0x%X" + "\n\t\t\t\tFor switch 0x%" PRIx64 "\n", + lid_ho, port, cl_ntoh64( node_guid ) ); + + /* + we would like to optionally ignore this port in equalization + like in the case of the Mellanox Anafa Internal PCI TCA port + */ + is_ignored_by_port_prof = + osm_port_prof_is_ignored_port(p_mgr->p_subn, cl_ntoh64(node_guid), port); + + /* + 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(osm_port_get_parent_node(p_port)) == + IB_NODE_TYPE_SWITCH); + } + } + + /* + We have selected the port for this LID. + Write it to the forwarding tables. + */ + p_mgr->lft_buf[lid_ho] = port; + if (!is_ignored_by_port_prof) + osm_switch_count_path(p_sw, port); + } + + Exit: + if (remote_sys_guids) + free(remote_sys_guids); + if (remote_node_guids) + free(remote_node_guids); + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_ucast_mgr_set_fwd_table( + IN osm_ucast_mgr_t* const p_mgr, + IN osm_switch_t* const p_sw ) +{ + osm_node_t *p_node; + osm_dr_path_t *p_path; + osm_madw_context_t context; + ib_api_status_t status; + ib_switch_info_t si; + uint32_t block_id_ho = 0; + uint8_t block[IB_SMP_DATA_SIZE]; + boolean_t set_swinfo_require = FALSE; + uint16_t lin_top; + uint8_t life_state; + + CL_ASSERT( p_mgr ); + + OSM_LOG_ENTER( p_mgr->p_log, osm_ucast_mgr_set_fwd_table ); + + CL_ASSERT( p_sw ); + + p_node = osm_switch_get_node_ptr( p_sw ); + + CL_ASSERT( p_node ); + + p_path = osm_node_get_any_dr_path_ptr( p_node ); + + CL_ASSERT( p_path ); + + /* + Set the top of the unicast forwarding table. + */ + si = *osm_switch_get_si_ptr( p_sw ); + lin_top = cl_hton16( osm_switch_get_max_lid_ho( p_sw ) ); + 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 ) + { + if ( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_ucast_mgr_set_fwd_table: " + "Setting switch FT top to LID 0x%X\n", + osm_switch_get_max_lid_ho( p_sw ) ); + } + + 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->p_req, + 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, + "osm_ucast_mgr_set_fwd_table: ERR 3A06: " + "Sending SwitchInfo attribute failed (%s)\n", + ib_get_err_str( status ) ); + } + else + p_mgr->any_change = TRUE; + } + + /* + Send linear forwarding table blocks to the switch + as long as the switch indicates it has blocks needing + configuration. + */ + + context.lft_context.node_guid = osm_node_get_node_guid( p_node ); + context.lft_context.set_method = TRUE; + + for (block_id_ho = 0; + osm_switch_get_fwd_tbl_block( p_sw, block_id_ho, block ) ; + block_id_ho++ ) + { + if (!memcmp(block, p_mgr->lft_buf + block_id_ho * 64, 64)) + continue; + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_ucast_mgr_set_fwd_table: " + "Writing FT block %u\n", block_id_ho ); + } + + status = osm_req_set( p_mgr->p_req, + p_path, + p_mgr->lft_buf + block_id_ho * 64, + sizeof(block), + IB_MAD_ATTR_LIN_FWD_TBL, + cl_hton32( block_id_ho ), + CL_DISP_MSGID_NONE, + &context ); + + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_ucast_mgr_set_fwd_table: ERR 3A05: " + "Sending linear fwd. tbl. block failed (%s)\n", + ib_get_err_str( status ) ); + } + else + { + p_mgr->any_change = TRUE; + /* + HACK: for now we will assume we succeeded to send + and set the local DB based on it. This should allow + us to immediatly dump out our routing. + */ + osm_switch_set_ft_block( + p_sw, p_mgr->lft_buf + block_id_ho * 64, block_id_ho ); + } + } + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_ucast_mgr_process_tbl( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + osm_switch_t* const p_sw = (osm_switch_t*)p_map_item; + osm_ucast_mgr_t* const p_mgr = (osm_ucast_mgr_t*)context; + osm_node_t *p_node; + const osm_port_t *p_port; + const cl_qmap_t* p_port_tbl; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_tbl ); + + p_node = p_sw->p_node; + + CL_ASSERT( p_node ); + CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_ucast_mgr_process_tbl: " + "Processing switch 0x%" PRIx64 "\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) )); + } + + /* Initialize LIDs in buffer to invalid port number. */ + memset(p_mgr->lft_buf, 0xff, IB_LID_UCAST_END_HO + 1); + + p_port_tbl = &p_mgr->p_subn->port_guid_tbl; + + /* + Iterate through every port setting LID routes for each + port based on base LID and LMC value. + */ + + 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 ) ) + { + __osm_ucast_mgr_process_port( p_mgr, p_sw, p_port ); + } + + osm_ucast_mgr_set_fwd_table( p_mgr, p_sw ); + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_ucast_mgr_process_neighbors( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + osm_switch_t* const p_sw = (osm_switch_t*)p_map_item; + osm_ucast_mgr_t* const p_mgr = (osm_ucast_mgr_t*)context; + osm_node_t *p_node; + osm_node_t *p_remote_node; + uint32_t port_num; + uint8_t remote_port_num; + uint32_t num_ports; + osm_physp_t* p_physp; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_neighbors ); + + p_node = p_sw->p_node; + + CL_ASSERT( p_node ); + CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_ucast_mgr_process_neighbors: " + "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 != p_node ) + && p_remote_node->sw ) + { + /* 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 (!osm_link_is_healthy( p_physp ) ) + continue; + + __osm_ucast_mgr_process_neighbor(p_mgr, p_sw, p_remote_node->sw, + (uint8_t)port_num, remote_port_num ); + + } + } + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_ucast_mgr_build_lid_matrices( + IN osm_ucast_mgr_t* const p_mgr ) +{ + uint32_t i; + uint32_t iteration_max; + cl_qmap_t *p_sw_guid_tbl; + + p_sw_guid_tbl = &p_mgr->p_subn->sw_guid_tbl; + + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "osm_ucast_mgr_build_lid_matrices: " + "Starting switches Min Hop Table Assignment\n" ); + + /* + Set the switch matrices for each switch's own port 0 LID(s) + then set the lid matrices for the each switch's leaf nodes. + */ + cl_qmap_apply_func( p_sw_guid_tbl, + __osm_ucast_mgr_process_hop_0, p_mgr ); + + cl_qmap_apply_func( p_sw_guid_tbl, + __osm_ucast_mgr_process_leaves, 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 + */ + __some_hop_count_set = TRUE; + for( i = 0; (i < iteration_max) && __some_hop_count_set; i++ ) + { + __some_hop_count_set = FALSE; + cl_qmap_apply_func( p_sw_guid_tbl, + __osm_ucast_mgr_process_neighbors, p_mgr ); + } + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_ucast_mgr_build_lid_matrices: " + "Min-hop propagated in %d steps\n", i ); + } +} + +/********************************************************************** + **********************************************************************/ +osm_signal_t +osm_ucast_mgr_process( + IN osm_ucast_mgr_t* const p_mgr ) +{ + struct osm_routing_engine *p_routing_eng; + osm_signal_t signal = OSM_SIGNAL_DONE; + cl_qmap_t *p_sw_guid_tbl; + boolean_t default_routing = TRUE; + + OSM_LOG_ENTER( p_mgr->p_log, osm_ucast_mgr_process ); + + p_sw_guid_tbl = &p_mgr->p_subn->sw_guid_tbl; + p_routing_eng = &p_mgr->p_subn->p_osm->routing_engine; + + 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) + goto Exit; + + p_mgr->any_change = FALSE; + cl_qmap_apply_func(p_sw_guid_tbl, __osm_ucast_mgr_clean_switch, NULL); + + if (!p_routing_eng->build_lid_matrices || + p_routing_eng->build_lid_matrices(p_routing_eng->context) != 0) + osm_ucast_mgr_build_lid_matrices(p_mgr); + + osm_log( p_mgr->p_log, OSM_LOG_INFO, + "osm_ucast_mgr_process: " + "Min Hop Tables configured on all switches\n" ); + + /* + Now that the lid matrices have been built, we can + build and download the switch forwarding tables. + */ + + if ( p_routing_eng->ucast_build_fwd_tables && + (p_routing_eng->ucast_build_fwd_tables(p_routing_eng->context) == 0) ) + default_routing = FALSE; + else + cl_qmap_apply_func( p_sw_guid_tbl, __osm_ucast_mgr_process_tbl, p_mgr ); + + /* dump fdb into file: */ + if ( osm_log_is_active( p_mgr->p_log, OSM_LOG_ROUTING ) ) + { + if ( !default_routing && p_routing_eng->ucast_dump_tables != 0 ) + p_routing_eng->ucast_dump_tables(p_routing_eng->context); + else + __osm_ucast_mgr_dump_tables( p_mgr ); + } + + if (p_mgr->any_change) + { + signal = OSM_SIGNAL_DONE_PENDING; + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "osm_ucast_mgr_process: " + "LFT Tables configured on all switches\n"); + } + else + { + signal = OSM_SIGNAL_DONE; + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "osm_ucast_mgr_process: " + "No need to set any LFT Tables on any switches\n"); + } + + Exit: + CL_PLOCK_RELEASE( p_mgr->p_lock ); + OSM_LOG_EXIT( p_mgr->p_log ); + return( signal ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_updn.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_updn.c new file mode 100644 index 00000000..d23b52c4 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_ucast_updn.c @@ -0,0 +1,1281 @@ +/* + * 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: + * Implementation of Up Down Algorithm using ranking & Min Hop + * Calculation functions + * + * Environment: + * Linux User Mode + * + * $Revision: 1.0 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +/* //////////////////////////// */ +/* Local types */ +/* //////////////////////////// */ + +/* direction */ +typedef enum _updn_switch_dir +{ + UP = 0, + DOWN +} updn_switch_dir_t; + +/* This enum respresent available states in the UPDN algorithm */ +typedef enum _updn_state +{ + UPDN_INIT = 0, + UPDN_RANK, + UPDN_MIN_HOP_CALC, +} updn_state_t; + +/* Rank value of this node */ +typedef struct _updn_rank +{ + cl_map_item_t map_item; + uint8_t rank; +} updn_rank_t; + +/* Histogram element - the number of occurences of the same hop value */ +typedef struct _updn_hist +{ + cl_map_item_t map_item; + uint32_t bar_value; +} updn_hist_t; + +typedef struct _updn_next_step +{ + updn_switch_dir_t state; + osm_switch_t *p_sw; +} updn_next_step_t; + +/* guids list */ +typedef struct _updn_input +{ + uint32_t num_guids; + uint64_t * guid_list; +} updn_input_t; + +/* updn structure */ +typedef struct _updn +{ + updn_state_t state; + boolean_t auto_detect_root_nodes; + cl_qmap_t guid_rank_tbl; + updn_input_t updn_ucast_reg_inputs; + cl_list_t * p_root_nodes; + osm_opensm_t *p_osm; +} updn_t; + +/* ///////////////////////////////// */ +/* Statics */ +/* ///////////////////////////////// */ +static int __osm_updn_find_root_nodes_by_min_hop(OUT updn_t *p_updn); + +/********************************************************************** + **********************************************************************/ +/* This function returns direction based on rank and guid info of current & + remote ports */ +static updn_switch_dir_t +__updn_get_dir( + IN updn_t *p_updn, + IN uint8_t cur_rank, + IN uint8_t rem_rank, + IN uint64_t cur_guid, + IN uint64_t rem_guid ) +{ + uint32_t i = 0, max_num_guids = p_updn->updn_ucast_reg_inputs.num_guids; + uint64_t *p_guid = p_updn->updn_ucast_reg_inputs.guid_list; + boolean_t cur_is_root = FALSE, rem_is_root = FALSE; + + /* 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 discover + the subnet correctly (and not from the point of view of the last root node). + */ + for ( i = 0; i < max_num_guids; i++ ) + { + if (cur_guid == p_guid[i]) + cur_is_root = TRUE; + if (rem_guid == p_guid[i]) + rem_is_root = TRUE; + } + if (cur_is_root && rem_is_root) + return UP; + + if (cur_rank < rem_rank) + return DOWN; + else if (cur_rank > rem_rank) + return UP; + else + { + /* Equal rank, decide by guid number, bigger == UP direction */ + if (cur_guid > rem_guid) + return UP; + else + return DOWN; + } +} + +/********************************************************************** + **********************************************************************/ +/* This function creates a new element of updn_next_step_t type then return its + pointer , Null if malloc has failed */ +static updn_next_step_t* +__updn_create_updn_next_step_t( + IN updn_switch_dir_t state, + IN osm_switch_t* const p_sw ) +{ + updn_next_step_t *p_next_step; + + p_next_step = (updn_next_step_t*) malloc(sizeof(*p_next_step)); + if (p_next_step) + { + memset(p_next_step, 0, sizeof(*p_next_step)); + p_next_step->state = state; + p_next_step->p_sw = p_sw; + } + + return p_next_step; +} + +/********************************************************************** + **********************************************************************/ +/* This function updates an element in the qmap list by guid index and rank value */ +/* Return 0 if no need to futher update 1 if brought a new value */ +static int +__updn_update_rank( + IN cl_qmap_t *p_guid_rank_tbl, + IN ib_net64_t guid, + IN uint8_t rank ) +{ + updn_rank_t *p_updn_rank; + + p_updn_rank = (updn_rank_t*) cl_qmap_get(p_guid_rank_tbl, guid); + if (p_updn_rank == (updn_rank_t*) cl_qmap_end(p_guid_rank_tbl)) + { + p_updn_rank = (updn_rank_t*) malloc(sizeof(updn_rank_t)); + + CL_ASSERT (p_updn_rank); + + p_updn_rank->rank = rank; + + cl_qmap_insert(p_guid_rank_tbl, guid, &p_updn_rank->map_item); + return 1; + } + else + { + if (p_updn_rank->rank > rank) + { + p_updn_rank->rank = rank; + return 1; + } + } + return 0; +} + +/********************************************************************** + * This function does the bfs of min hop table calculation by guid index + * as a starting point. + **********************************************************************/ +static int +__updn_bfs_by_node( + IN updn_t *p_updn, + IN osm_subn_t *p_subn, + IN osm_port_t *p_port, + IN cl_qmap_t *p_guid_rank_tbl ) +{ + /* Init local vars */ + osm_switch_t *p_self_node = NULL; + uint8_t pn, pn_rem; + osm_physp_t *p_physp, *p_remote_physp; + cl_list_t *p_currList, *p_nextList; + uint16_t root_lid, max_sw_lid; + updn_next_step_t *p_updn_switch, *p_tmp; + updn_switch_dir_t next_dir, current_dir; + osm_log_t *p_log = &p_updn->p_osm->log; + + OSM_LOG_ENTER( p_log, __updn_bfs_by_node ); + + /* Init the list pointers */ + p_nextList = (cl_list_t*)malloc(sizeof(cl_list_t)); + cl_list_construct( p_nextList ); + cl_list_init( p_nextList, 10 ); + p_currList = p_nextList; + + p_physp = osm_port_get_default_phys_ptr(p_port); + /* Check valid pointer */ + if (!p_physp || !osm_physp_is_valid(p_physp )) + { + OSM_LOG_EXIT( p_log ); + return 1; + } + /* The Root BFS - lid */ + root_lid = cl_ntoh16(osm_physp_get_base_lid( p_physp )); + /* printf ("-V- BFS through lid : 0x%x\n", root_lid); */ + osm_log( p_log, OSM_LOG_DEBUG, + "__updn_bfs_by_node:" + "Starting lid : 0x%x \n", root_lid ); + + if (p_port->p_node->sw) + { + p_self_node = p_port->p_node->sw; + /* Update its Min Hop Table */ + osm_log( p_log, OSM_LOG_DEBUG, + "__updn_bfs_by_node:" + "Update Min Hop Table of GUID 0x%" PRIx64 "\n", + cl_ntoh64(p_port->guid) ); + osm_switch_set_hops(p_self_node, root_lid, 0, 0); + } + else + { + /* This is a CA or router - need to take its remote port */ + p_remote_physp = p_physp->p_remote_physp; + /* + make sure that the following occur: + 1. The port isn't NULL + 2. The port is a valid port + */ + if ( p_remote_physp && osm_physp_is_valid ( p_remote_physp )) + { + /* Check if the remote port is a switch, if it is update root_lid, + Min Hop Table */ + if (!p_remote_physp->p_node->sw) + { + osm_log( p_log, OSM_LOG_ERROR, + "__updn_bfs_by_node: ERR AA07: " + "This is a non switched subnet OR non valid connection, cannot perform UPDN algorithm\n" ); + OSM_LOG_EXIT( p_log ); + return 1; + } + else + { + p_self_node = p_remote_physp->p_node->sw; + max_sw_lid = osm_switch_get_max_lid_ho(p_self_node); + if ((1 <= root_lid) && (root_lid <= max_sw_lid)) + /* Update its Min Hop Table */ + { + /* NOTE : Check if there is a function which prints the Min Hop Table */ + osm_log( p_log, OSM_LOG_DEBUG, + "__updn_bfs_by_node:" + "Update Min Hop Table of GUID 0x%" PRIx64 "\n", + cl_ntoh64(p_remote_physp->port_guid) ); + osm_switch_set_hops(p_self_node, root_lid, + p_remote_physp->port_num, 1); + + } + else + { + osm_log( p_log, OSM_LOG_ERROR, + "__updn_bfs_by_node: ERR AA09: " + " Invalid lid value 0x%x for switch 0x%" PRIx64 "\n", + root_lid, + cl_ntoh64(p_self_node->p_node->node_info.port_guid) ); + OSM_LOG_EXIT( p_log ); + return 1; + } + } + } + } + + CL_ASSERT(p_self_node); + + osm_log( p_log, OSM_LOG_DEBUG, + "__updn_bfs_by_node:" + "Starting from switch - port GUID 0x%" PRIx64 "\n", + cl_ntoh64(p_self_node->p_node->node_info.port_guid) ); + + /* Update list with the updn_next_step_t new element */ + /* NOTE : When inserting an item which is a pointer to a struct, does remove + action also free its memory */ + if (!(p_tmp=__updn_create_updn_next_step_t(UP, p_self_node))) + { + osm_log( p_log, OSM_LOG_ERROR, + "__updn_bfs_by_node: ERR AA08: " + "Could not create updn_next_step_t\n" ); + return 1; + } + + cl_list_insert_tail(p_currList, p_tmp); + + /* BFS the list till no next element */ + osm_log( p_log, OSM_LOG_VERBOSE, + "__updn_bfs_by_node:" + "BFS the subnet [\n" ); + + while (!cl_is_list_empty(p_currList)) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__updn_bfs_by_node:" + "Starting a new iteration with %zu elements in current list\n", + cl_list_count(p_currList) ); + /* Init the switch directed list */ + p_nextList = (cl_list_t*)malloc(sizeof(cl_list_t)); + cl_list_construct( p_nextList ); + cl_list_init( p_nextList, 10 ); + /* Go over all current list items till it's empty */ + /* printf ("-V- In inner while\n"); */ + p_updn_switch = (updn_next_step_t*)cl_list_remove_head( p_currList ); + /* While there is a pointer to updn struct we continue to BFS */ + while (p_updn_switch) + { + current_dir = p_updn_switch->state; + osm_log( p_log, OSM_LOG_DEBUG, + "__updn_bfs_by_node:" + "Visiting port GUID 0x%" PRIx64 "\n", + cl_ntoh64(p_updn_switch->p_sw->p_node->node_info.port_guid) ); + /* Go over all ports of the switch and find unvisited remote nodes */ + for ( pn = 0; pn < osm_switch_get_num_ports(p_updn_switch->p_sw); pn++ ) + { + /* printf("-V- Inner for in port num 0x%X\n", pn); */ + osm_node_t *p_remote_node; + cl_list_iterator_t updn_switch_iterator; + boolean_t HasVisited = FALSE; + ib_net64_t remote_guid,current_guid; + updn_rank_t *p_rem_rank, *p_cur_rank; + uint8_t current_min_hop, remote_min_hop, set_hop_return_value; + osm_switch_t *p_remote_sw; + + current_guid = osm_node_get_node_guid(p_updn_switch->p_sw->p_node); + p_remote_node = osm_node_get_remote_node( p_updn_switch->p_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 || + (osm_node_get_type(p_remote_node) != IB_NODE_TYPE_SWITCH) ) + continue; + /* Fetch remote guid only after validation of remote node */ + remote_guid = osm_node_get_node_guid(p_remote_node); + /* printf ("-V- Current guid : 0x%" PRIx64 " Remote guid : 0x%" PRIx64 "\n", */ + /* cl_ntoh64(current_guid), cl_ntoh64(remote_guid)); */ + p_remote_sw = p_remote_node->sw; + p_rem_rank = (updn_rank_t*)cl_qmap_get(p_guid_rank_tbl, remote_guid); + p_cur_rank = (updn_rank_t*)cl_qmap_get(p_guid_rank_tbl, current_guid); + /* Decide which direction to mark it (UP/DOWN) */ + next_dir = __updn_get_dir (p_updn, p_cur_rank->rank, p_rem_rank->rank, + current_guid, remote_guid); + + osm_log( p_log, OSM_LOG_DEBUG, + "__updn_bfs_by_node:" + "move from 0x%016" PRIx64 " rank: %u " + "to 0x%016" PRIx64" rank: %u\n", + cl_ntoh64(current_guid), p_cur_rank->rank, + cl_ntoh64(remote_guid), p_rem_rank->rank ); + /* 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, + "__updn_bfs_by_node:" + "Avoiding move from 0x%016" PRIx64 " to 0x%016" PRIx64"\n", + cl_ntoh64(current_guid), cl_ntoh64(remote_guid) ); + /* Illegal step */ + continue; + } + /* Set MinHop value for the current lid */ + current_min_hop = osm_switch_get_least_hops(p_updn_switch->p_sw,root_lid); + /* Check hop count if better insert into NextState list && update + the remote node Min Hop Table */ + remote_min_hop = osm_switch_get_hop_count(p_remote_sw, root_lid, pn_rem); + if (current_min_hop + 1 < remote_min_hop) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__updn_bfs_by_node (less):" + "Setting Min Hop Table of switch: 0x%" PRIx64 + "\n\t\tCurrent hop count is: %d, next hop count: %d" + "\n\tlid to set: 0x%x" + "\n\tport number: 0x%X" + " \n\thops number: %d\n", + cl_ntoh64(remote_guid), remote_min_hop,current_min_hop + 1, + root_lid, pn_rem, current_min_hop + 1 ); + set_hop_return_value = osm_switch_set_hops(p_remote_sw, root_lid, pn_rem, current_min_hop + 1); + if (set_hop_return_value) + { + osm_log( p_log, OSM_LOG_ERROR, + "__updn_bfs_by_node (less) ERR AA01: " + "Invalid value returned from set min hop is: %d\n", + set_hop_return_value ); + } + /* Check if remote port is allready has been visited */ + updn_switch_iterator = cl_list_head(p_nextList); + while( updn_switch_iterator != cl_list_end(p_nextList) ) + { + updn_next_step_t *p_updn; + p_updn = (updn_next_step_t*)cl_list_obj(updn_switch_iterator); + /* Mark HasVisited only if: + 1. Same node guid + 2. Same direction + */ + if ((p_updn->p_sw->p_node == p_remote_node) && (p_updn->state == next_dir)) + HasVisited = TRUE; + updn_switch_iterator = cl_list_next(updn_switch_iterator); + } + if (!HasVisited) + { + /* Insert updn_switch item into the next list */ + if(!(p_tmp=__updn_create_updn_next_step_t(next_dir, p_remote_sw))) + { + osm_log( p_log, OSM_LOG_ERROR, + "__updn_bfs_by_node: ERR AA11: " + "Could not create updn_next_step_t\n" ); + return 1; + } + osm_log( p_log, OSM_LOG_DEBUG, + "__updn_bfs_by_node: " + "Inserting new element to the next list: guid=0x%" PRIx64 " %s\n", + cl_ntoh64(p_tmp->p_sw->p_node->node_info.port_guid), + (p_tmp->state == UP ? "UP" : "DOWN") + ); + cl_list_insert_tail(p_nextList, p_tmp); + } + /* If the same value only update entry - at the min hop table */ + } else if (current_min_hop + 1 == osm_switch_get_hop_count(p_remote_sw, + root_lid, + pn_rem)) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__updn_bfs_by_node (equal):" + "Setting Min Hop Table of switch: 0x%" PRIx64 + "\n\t\tCurrent hop count is: %d, next hop count: %d" + "\n\tlid to set: 0x%x" + "\n\tport number: 0x%X" + "\n\thops number: %d\n", + cl_ntoh64(remote_guid), + osm_switch_get_hop_count(p_remote_sw, root_lid, pn_rem), + current_min_hop + 1, root_lid, pn_rem, current_min_hop + 1 ); + set_hop_return_value = osm_switch_set_hops(p_remote_sw, root_lid, pn_rem, current_min_hop + 1); + + if (set_hop_return_value) + { + osm_log( p_log, OSM_LOG_ERROR, + "__updn_bfs_by_node (less) ERR AA12: " + "Invalid value returned from set min hop is: %d\n", + set_hop_return_value ); + } + } + } + free (p_updn_switch); + p_updn_switch = (updn_next_step_t*)cl_list_remove_head( p_currList ); + } + /* Cleanup p_currList */ + cl_list_destroy( p_currList ); + free (p_currList); + + /* Reassign p_currList to p_nextList */ + p_currList = p_nextList; + } + /* Cleanup p_currList - Had the pointer to cl_list_t */ + cl_list_destroy( p_currList ); + free (p_currList); + osm_log( p_log, OSM_LOG_VERBOSE, + "__updn_bfs_by_node:" + "BFS the subnet ]\n" ); + OSM_LOG_EXIT( p_log ); + return 0; +} + +/********************************************************************** + **********************************************************************/ +static void +updn_destroy( + IN updn_t* const p_updn ) +{ + cl_map_item_t *p_map_item; + uint64_t *p_guid_list_item; + + /* Destroy the updn struct */ + p_map_item = cl_qmap_head( &p_updn->guid_rank_tbl); + while( p_map_item != cl_qmap_end( &p_updn->guid_rank_tbl)) + { + osm_log ( &p_updn->p_osm->log, OSM_LOG_DEBUG, + "osm_subn_calc_up_down_min_hop_table: " + "guid = 0x%" PRIx64 " rank = %u\n", + cl_ntoh64(cl_qmap_key(p_map_item)), + ((updn_rank_t *)p_map_item)->rank ); + cl_qmap_remove_item( &p_updn->guid_rank_tbl, p_map_item); + free( (updn_rank_t *)p_map_item); + p_map_item = cl_qmap_head( &p_updn->guid_rank_tbl); + } + + /* free the array of guids */ + if (p_updn->updn_ucast_reg_inputs.guid_list) + free(p_updn->updn_ucast_reg_inputs.guid_list); + + /* destroy the list of root nodes */ + while ((p_guid_list_item = cl_list_remove_head( p_updn->p_root_nodes ))) + free( p_guid_list_item ); + + cl_list_remove_all( p_updn->p_root_nodes ); + cl_list_destroy( p_updn->p_root_nodes ); + free ( p_updn->p_root_nodes ); + free (p_updn); +} + +/********************************************************************** + **********************************************************************/ +static updn_t* +updn_construct(osm_log_t *p_log) +{ + updn_t* p_updn; + + OSM_LOG_ENTER( p_log, updn_construct ); + p_updn = malloc(sizeof(updn_t)); + if (p_updn) + memset(p_updn, 0, sizeof(updn_t)); + OSM_LOG_EXIT( p_log ); + return(p_updn); +} + +/********************************************************************** + **********************************************************************/ +static cl_status_t +updn_init( + IN updn_t* const p_updn, + IN osm_opensm_t *p_osm ) +{ + cl_list_t * p_list; + FILE* p_updn_guid_file; + char line[MAX_UPDN_GUID_FILE_LINE_LENGTH]; + uint64_t * p_tmp; + cl_list_iterator_t guid_iterator; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( &p_osm->log, updn_init ); + + p_updn->p_osm = p_osm; + p_updn->state = UPDN_INIT; + cl_qmap_init( &p_updn->guid_rank_tbl ); + p_list = (cl_list_t*)malloc(sizeof(cl_list_t)); + if (!p_list) + { + status = IB_ERROR; + goto Exit; + } + + cl_list_construct( p_list ); + cl_list_init( p_list, 10 ); + p_updn->p_root_nodes = p_list; + p_updn->updn_ucast_reg_inputs.num_guids = 0; + p_updn->updn_ucast_reg_inputs.guid_list = NULL; + p_updn->auto_detect_root_nodes = FALSE; + + /* + Check the source for root node list, if file parse it, otherwise + wait for a callback to activate auto detection + */ + if (p_osm->subn.opt.updn_guid_file) + { + /* Now parse guid from file */ + p_updn_guid_file = fopen(p_osm->subn.opt.updn_guid_file, "r"); + if (p_updn_guid_file == NULL) + { + osm_log( &p_osm->log, OSM_LOG_ERROR, + "osm_opensm_init : ERR AA02: " + "Failed to open guid list file (%s)\n", + p_osm->subn.opt.updn_guid_file ); + status = IB_NOT_FOUND; + goto Exit; + } + + while ( fgets(line, MAX_UPDN_GUID_FILE_LINE_LENGTH, p_updn_guid_file) ) + { + if (strcspn(line, " ,;.") == strlen(line)) + { + /* Skip empty lines anywhere in the file - only one char means the Null termination */ + if (strlen(line) > 1) + { + p_tmp = malloc(sizeof(uint64_t)); + *p_tmp = strtoull(line, NULL, 16); + cl_list_insert_tail(p_updn->p_root_nodes, p_tmp); + } + } + else + { + osm_log( &p_osm->log, OSM_LOG_ERROR, + "osm_opensm_init: ERR AA03: " + "Bad formatted guid in file (%s): %s\n", + p_osm->subn.opt.updn_guid_file, line ); + status = IB_NOT_FOUND; + break; + } + } + + /* For Debug Purposes ... */ + osm_log( &p_osm->log, OSM_LOG_DEBUG, + "osm_opensm_init: " + "UPDN - Root nodes fetching by file %s\n", + p_osm->subn.opt.updn_guid_file ); + guid_iterator = cl_list_head(p_updn->p_root_nodes); + while( guid_iterator != cl_list_end(p_updn->p_root_nodes) ) + { + osm_log( &p_osm->log, OSM_LOG_DEBUG, + "osm_opensm_init: " + "Inserting GUID 0x%" PRIx64 " as root node\n", + *((uint64_t*)cl_list_obj(guid_iterator)) ); + guid_iterator = cl_list_next(guid_iterator); + } + } + else + { + p_updn->auto_detect_root_nodes = TRUE; + } + /* If auto mode detection required - will be executed in main b4 the assignment of UI Ucast */ + +Exit : + OSM_LOG_EXIT( &p_osm->log ); + return (status); +} + +/********************************************************************** + **********************************************************************/ +/* NOTE : PLS check if we need to decide that the first */ +/* rank is a SWITCH for BFS purpose */ +static int +updn_subn_rank( + IN uint64_t root_guid, + IN uint8_t base_rank, + IN updn_t* p_updn ) +{ + /* Init local vars */ + osm_port_t *p_root_port = NULL; + uint16_t tbl_size; + uint8_t rank = base_rank; + osm_physp_t *p_physp, *p_remote_physp, *p_physp_temp; + cl_list_t *p_currList,*p_nextList; + cl_status_t did_cause_update; + uint8_t num_ports, port_num; + osm_log_t *p_log = &p_updn->p_osm->log; + + OSM_LOG_ENTER( p_log, updn_subn_rank ); + + osm_log( p_log, OSM_LOG_VERBOSE, + "updn_subn_rank: " + "Ranking starts from GUID 0x%" PRIx64 "\n", root_guid ); + + /* Init the list pointers */ + p_nextList = (cl_list_t*)malloc(sizeof(cl_list_t)); + cl_list_construct( p_nextList ); + cl_list_init( p_nextList, 10 ); + p_currList = p_nextList; + + /* Check valid subnet & guid */ + tbl_size = (uint16_t)(cl_qmap_count(&p_updn->p_osm->subn.port_guid_tbl)); + if (tbl_size == 0) + { + osm_log( p_log, OSM_LOG_ERROR, + "updn_subn_rank: ERR AA04: " + "Port guid table is empty, cannot perform ranking\n" ); + OSM_LOG_EXIT( p_log ); + return 1; + } + + p_root_port = (osm_port_t*) cl_qmap_get(&p_updn->p_osm->subn.port_guid_tbl, + cl_ntoh64(root_guid)); + if( p_root_port == (osm_port_t*)cl_qmap_end( &p_updn->p_osm->subn.port_guid_tbl ) ) + { + osm_log( p_log, OSM_LOG_ERROR, + "updn_subn_rank: ERR AA05: " + "Wrong guid value: 0x%" PRIx64 "\n", root_guid ); + OSM_LOG_EXIT( p_log ); + return 1; + } + + /* Rank the first chosen guid anyway since its the base rank */ + osm_log( p_log, OSM_LOG_DEBUG, + "updn_subn_rank: " + "Ranking port GUID 0x%" PRIx64 "\n", root_guid ); + + __updn_update_rank(&p_updn->guid_rank_tbl, cl_ntoh64(root_guid), rank); + /* + 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 = osm_port_get_default_phys_ptr( p_root_port ); + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + /* We can safely add the node to the list */ + cl_list_insert_tail(p_nextList, p_physp); + /* Assign pointer to the list for BFS */ + p_currList = p_nextList; + + /* BFS the list till its empty */ + osm_log( p_log, OSM_LOG_VERBOSE, + "updn_subn_rank: " + "BFS the subnet [\n" ); + + while (!cl_is_list_empty(p_currList)) + { + rank++; + p_nextList = (cl_list_t*)malloc(sizeof(cl_list_t)); + cl_list_construct( p_nextList ); + cl_list_init( p_nextList, 10 ); + p_physp = (osm_physp_t*)cl_list_remove_head( p_currList ); + /* Go over all remote nodes and rank them (if not allready visited) till + no elemtent in the list p_currList */ + while ( p_physp != NULL ) + { + num_ports = osm_node_get_num_physp( p_physp->p_node ); + osm_log( p_log, OSM_LOG_DEBUG, + "updn_subn_rank: " + "Handling port GUID 0x%" PRIx64 "\n", + cl_ntoh64(p_physp->port_guid) ); + 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_temp = osm_node_get_physp_ptr( p_physp->p_node, port_num ); + p_remote_physp = p_physp_temp->p_remote_physp; + + /* + make sure that all the following occur on p_remote_physp: + 1. The port isn't NULL + 2. The port is a valid port + */ + if ( p_remote_physp && + osm_physp_is_valid ( p_remote_physp )) + { + port_guid = p_remote_physp->port_guid; + osm_log( p_log, OSM_LOG_DEBUG, + "updn_subn_rank: " + "Visiting remote port GUID 0x%" PRIx64 "\n", + cl_ntoh64(port_guid) ); + /* Was it visited ? + Only if the pointer equal to cl_qmap_end its not + found in the list */ + osm_log( p_log, OSM_LOG_DEBUG, + "updn_subn_rank: " + "Ranking port GUID 0x%" PRIx64 "\n", cl_ntoh64(port_guid) ); + did_cause_update = __updn_update_rank(&p_updn->guid_rank_tbl, port_guid, rank); + + osm_log( p_log, OSM_LOG_VERBOSE, + "updn_subn_rank: " + "Rank of port GUID 0x%" PRIx64 " = %u\n", cl_ntoh64(port_guid), + ((updn_rank_t*)cl_qmap_get(&p_updn->guid_rank_tbl, port_guid))->rank + ); + + if (did_cause_update) + { + cl_list_insert_tail(p_nextList, p_remote_physp); + } + } + } + /* Propagte through the next item in the p_currList */ + p_physp = (osm_physp_t*)cl_list_remove_head( p_currList ); + } + /* First free the allocation of cl_list pointer then reallocate */ + cl_list_destroy( p_currList ); + free(p_currList); + /* p_currList is empty - need to assign it to p_nextList */ + p_currList = p_nextList; + } + + osm_log( p_log, OSM_LOG_VERBOSE, + "updn_subn_rank: " + "BFS the subnet ]\n" ); + + cl_list_destroy( p_currList ); + free(p_currList); + + /* Print Summary of ranking */ + osm_log( p_log, OSM_LOG_VERBOSE, + "updn_subn_rank: " + "Rank Info :\n\t Root Guid = 0x%" PRIx64 "\n\t Max Node Rank = %d\n", + cl_ntoh64(p_root_port->guid), rank ); + p_updn->state = UPDN_RANK; + OSM_LOG_EXIT( p_log ); + return 0; +} + +/********************************************************************** + **********************************************************************/ +static int +__osm_subn_set_up_down_min_hop_table( + IN updn_t* p_updn ) +{ + /* Init local vars */ + osm_subn_t *p_subn = &p_updn->p_osm->subn; + osm_log_t *p_log = &p_updn->p_osm->log; + osm_switch_t *p_next_sw,*p_sw; + osm_port_t *p_next_port,*p_port; + ib_net64_t port_guid; + + OSM_LOG_ENTER( p_log, __osm_subn_set_up_down_min_hop_table ); + if (p_updn->state == UPDN_INIT) + { + osm_log( p_log, OSM_LOG_ERROR, + "__osm_subn_set_up_down_min_hop_table: ERR AA06: " + "Calculating Min Hop only allowed after ranking\n" ); + OSM_LOG_EXIT( p_log ); + return 1; + } + + /* Check if its a non switched subnet .. */ + if ( cl_is_qmap_empty( &p_subn->sw_guid_tbl ) ) + { + osm_log( p_log, OSM_LOG_ERROR, + "__osm_subn_set_up_down_min_hop_table: ERR AA10: " + "This is a non switched subnet, cannot perform UPDN algorithm\n" ); + OSM_LOG_EXIT( p_log ); + return 1; + } + /* Go over all the switches in the subnet - for each init their Min Hop + Table */ + osm_log( p_log, OSM_LOG_VERBOSE, + "__osm_subn_set_up_down_min_hop_table: " + "Init Min Hop Table of all switches [\n" ); + + 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 ); + /* Clear Min Hop Table */ + osm_lid_matrix_clear(&(p_sw->lmx)); + } + + osm_log( p_log, OSM_LOG_VERBOSE, + "__osm_subn_set_up_down_min_hop_table: " + "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, + "__osm_subn_set_up_down_min_hop_table: " + "BFS through all port guids in the subnet [\n" ); + 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 ); + port_guid = cl_qmap_key(&(p_port->map_item)); + osm_log( p_log, OSM_LOG_DEBUG, + "__osm_subn_set_up_down_min_hop_table: " + "BFS through port GUID 0x%" PRIx64 "\n", + cl_ntoh64(port_guid) ); + if(__updn_bfs_by_node(p_updn, p_subn, p_port, + &p_updn->guid_rank_tbl)) + { + OSM_LOG_EXIT( p_log ); + return 1; + } + } + + osm_log( p_log, OSM_LOG_VERBOSE, + "__osm_subn_set_up_down_min_hop_table: " + "BFS through all port guids in the subnet ]\n" ); + /* Cleanup */ + OSM_LOG_EXIT( p_log ); + return 0; +} + +/********************************************************************** + **********************************************************************/ +static int +__osm_subn_calc_up_down_min_hop_table( + IN uint32_t num_guids, + IN uint64_t * guid_list, + IN updn_t* p_updn ) +{ + uint8_t idx = 0; + cl_map_item_t *p_map_item; + int status; + + OSM_LOG_ENTER( &p_updn->p_osm->log, osm_subn_calc_up_down_min_hop_table ); + osm_log( &p_updn->p_osm->log, OSM_LOG_VERBOSE, + "__osm_subn_calc_up_down_min_hop_table: " + "Ranking all port guids in the list\n" ); + if (num_guids == 0) + { + osm_log( &p_updn->p_osm->log, OSM_LOG_ERROR, + "__osm_subn_calc_up_down_min_hop_table: ERR AA0A: " + "No guids were given or number of guids is 0\n" ); + return 1; + } + + for (idx = 0; idx < num_guids; idx++) + { + /* Apply the ranking for each guid given by user - bypass illegal ones */ + updn_subn_rank(guid_list[idx], 0, p_updn); + } + /* After multiple ranking need to set Min Hop Table by UpDn algorithm */ + osm_log( &p_updn->p_osm->log, OSM_LOG_VERBOSE, + "__osm_subn_calc_up_down_min_hop_table: " + "Setting all switches' Min Hop Table\n" ); + + status = __osm_subn_set_up_down_min_hop_table (p_updn); + + /* Cleanup updn rank tbl */ + p_map_item = cl_qmap_head( &p_updn->guid_rank_tbl); + while( p_map_item != cl_qmap_end( &p_updn->guid_rank_tbl)) + { + osm_log( &p_updn->p_osm->log, OSM_LOG_DEBUG, + "__osm_subn_calc_up_down_min_hop_table: " + "guid = 0x%" PRIx64 " rank = %u\n", + cl_ntoh64(cl_qmap_key(p_map_item)), + ((updn_rank_t *)p_map_item)->rank ); + cl_qmap_remove_item( &p_updn->guid_rank_tbl, p_map_item); + free( (updn_rank_t *)p_map_item); + p_map_item = cl_qmap_head( &p_updn->guid_rank_tbl); + } + + OSM_LOG_EXIT( &p_updn->p_osm->log ); + return status; +} + +/********************************************************************** + **********************************************************************/ +/* UPDN callback function */ +static int +__osm_updn_call( + void *ctx ) +{ + updn_t *p_updn = ctx; + + OSM_LOG_ENTER( &p_updn->p_osm->log, __osm_updn_call ); + + /* First auto detect root nodes - if required */ + if ( p_updn->auto_detect_root_nodes ) + { + osm_ucast_mgr_build_lid_matrices( &p_updn->p_osm->sm.ucast_mgr ); + /* printf ("-V- b4 osm_updn_find_root_nodes_by_min_hop\n"); */ + __osm_updn_find_root_nodes_by_min_hop( p_updn ); + } + /* printf ("-V- after osm_updn_find_root_nodes_by_min_hop\n"); */ + /* Only if there are assigned root nodes do the algorithm , otherwise perform do nothing */ + if ( p_updn->updn_ucast_reg_inputs.num_guids > 0) + { + osm_log( &(p_updn->p_osm->log), OSM_LOG_DEBUG, + "__osm_updn_call: " + "activating UPDN algorithm\n" ); + __osm_subn_calc_up_down_min_hop_table( p_updn->updn_ucast_reg_inputs.num_guids, + p_updn->updn_ucast_reg_inputs.guid_list, + p_updn ); + } + else + osm_log( &p_updn->p_osm->log, OSM_LOG_INFO, + "__osm_updn_call: " + "disable UPDN algorithm, no root nodes were found\n" ); + + OSM_LOG_EXIT( &p_updn->p_osm->log ); + return 0; +} + +/********************************************************************** + **********************************************************************/ +/* UPDN convert cl_list to guid array in updn struct */ +static void +__osm_updn_convert_list2array( + IN updn_t * p_updn ) +{ + uint32_t i = 0, max_num = 0; + uint64_t *p_guid; + + OSM_LOG_ENTER( &p_updn->p_osm->log, __osm_updn_convert_list2array ); + + p_updn->updn_ucast_reg_inputs.num_guids = cl_list_count( + p_updn->p_root_nodes); + if (p_updn->updn_ucast_reg_inputs.guid_list) + free(p_updn->updn_ucast_reg_inputs.guid_list); + p_updn->updn_ucast_reg_inputs.guid_list = (uint64_t *)malloc( + p_updn->updn_ucast_reg_inputs.num_guids*sizeof(uint64_t)); + if (p_updn->updn_ucast_reg_inputs.guid_list) + memset(p_updn->updn_ucast_reg_inputs.guid_list, 0, + p_updn->updn_ucast_reg_inputs.num_guids*sizeof(uint64_t)); + if (!cl_is_list_empty(p_updn->p_root_nodes)) + { + while( (p_guid = (uint64_t*)cl_list_remove_head(p_updn->p_root_nodes)) ) + { + p_updn->updn_ucast_reg_inputs.guid_list[i] = *p_guid; + free(p_guid); + i++; + } + max_num = i; + for (i = 0; i < max_num; i++ ) + osm_log( &p_updn->p_osm->log, OSM_LOG_DEBUG, + "__osm_updn_convert_list2array: " + "Map GUID 0x%" PRIx64 " into UPDN array\n", + p_updn->updn_ucast_reg_inputs.guid_list[i] ); + } + /* Since we need the template list for other sweeps, we wont destroy & free it */ + OSM_LOG_EXIT( &p_updn->p_osm->log ); +} + +/********************************************************************** + **********************************************************************/ +/* Find Root nodes automatically by Min Hop Table info */ +static int +__osm_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_next_sw, *p_sw; + osm_port_t *p_next_port, *p_port; + osm_physp_t *p_physp; + uint32_t numCas = 0; + uint32_t numSws = cl_qmap_count(&p_osm->subn.sw_guid_tbl); + cl_qmap_t min_hop_hist; /* Histogram container */ + updn_hist_t *p_updn_hist, *p_up_ht; + uint8_t maxHops = 0; /* contain the max histogram index */ + uint64_t *p_guid; + cl_list_t *p_root_nodes_list = p_updn->p_root_nodes; + cl_map_t ca_by_lid_map; /* map holding all CA lids */ + uint16_t self_lid_ho; + + OSM_LOG_ENTER( &p_osm->log, osm_updn_find_root_nodes_by_min_hop ); + + osm_log( &p_osm->log, OSM_LOG_DEBUG, + "__osm_updn_find_root_nodes_by_min_hop: " + "current number of ports in the subnet is %d\n", + cl_qmap_count(&p_osm->subn.port_guid_tbl) ); + /* Init the required vars */ + cl_qmap_init( &min_hop_hist ); + cl_map_construct( &ca_by_lid_map ); + cl_map_init( &ca_by_lid_map, 10 ); + + /* EZ: + p_ca_list = (cl_list_t*)malloc(sizeof(cl_list_t)); + cl_list_construct( p_ca_list ); + cl_list_init( p_ca_list, 10 ); + */ + + /* Find the Maximum number of CAs (and routers) for histogram normalization */ + osm_log( &p_osm->log, OSM_LOG_VERBOSE, + "__osm_updn_find_root_nodes_by_min_hop: " + "Find the number of CAs and store them in cl_list\n" ); + p_next_port = (osm_port_t*)cl_qmap_head( &p_osm->subn.port_guid_tbl ); + while( p_next_port != (osm_port_t*)cl_qmap_end( &p_osm->subn.port_guid_tbl ) ) { + p_port = p_next_port; + p_next_port = (osm_port_t*)cl_qmap_next( &p_next_port->map_item ); + if ( osm_node_get_type(p_port->p_node) != IB_NODE_TYPE_SWITCH ) + { + p_physp = osm_port_get_default_phys_ptr(p_port); + self_lid_ho = cl_ntoh16( osm_physp_get_base_lid(p_physp) ); + numCas++; + /* EZ: + self = malloc(sizeof(uint16_t)); + *self = self_lid_ho; + cl_list_insert_tail(p_ca_list, self); + */ + cl_map_insert( &ca_by_lid_map, self_lid_ho, (void *)0x1); + osm_log( &p_osm->log, OSM_LOG_DEBUG, + "__osm_updn_find_root_nodes_by_min_hop: " + "Inserting into array GUID 0x%" PRIx64 ", Lid: 0x%X\n", + cl_ntoh64(osm_port_get_guid(p_port)), self_lid_ho ); + } + } + osm_log( &p_osm->log, OSM_LOG_DEBUG, + "__osm_updn_find_root_nodes_by_min_hop: " + "Found %u CA, %u SW in the subnet\n", numCas, numSws ); + p_next_sw = (osm_switch_t*)cl_qmap_head( &p_osm->subn.sw_guid_tbl ); + osm_log( &p_osm->log, OSM_LOG_VERBOSE, + "__osm_updn_find_root_nodes_by_min_hop: " + "Passing through all switches to collect Min Hop info\n" ); + while( p_next_sw != (osm_switch_t*)cl_qmap_end( &p_osm->subn.sw_guid_tbl ) ) + { + uint16_t max_lid_ho, lid_ho; + uint8_t hop_val; + uint16_t numHopBarsOverThd1 = 0; + uint16_t numHopBarsOverThd2 = 0; + double thd1, thd2; + + p_sw = p_next_sw; + /* Roll to the next switch */ + p_next_sw = (osm_switch_t*)cl_qmap_next( &p_sw->map_item ); + + /* Clear Min Hop Table && FWD Tbls - This should caused opensm to + rebuild its FWD tables , post setting Min Hop Tables */ + max_lid_ho = osm_switch_get_max_lid_ho(p_sw); + /* Get base lid of switch by retrieving port 0 lid of node pointer */ + self_lid_ho = cl_ntoh16( osm_node_get_base_lid( p_sw->p_node, 0 ) ); + osm_log( &p_osm->log, OSM_LOG_DEBUG, + "__osm_updn_find_root_nodes_by_min_hop: " + "Passing through switch lid 0x%X\n", self_lid_ho ); + for (lid_ho = 1; lid_ho <= max_lid_ho; lid_ho++) + { + /* Skip lids which are not CAs - + for the histogram purposes we care only about CAs */ + + /* EZ: + boolean_t LidFound = FALSE; + cl_list_iterator_t ca_lid_iterator= cl_list_head(p_ca_list); + while( (ca_lid_iterator != cl_list_end(p_ca_list)) && !LidFound ) + { + uint16_t *p_lid; + + p_lid = (uint16_t*)cl_list_obj(ca_lid_iterator); + if ( *p_lid == lid_ho ) + LidFound = TRUE; + ca_lid_iterator = cl_list_next(ca_lid_iterator); + + } + if ( LidFound ) + */ + if (cl_map_get( &ca_by_lid_map, lid_ho )) + { + hop_val = osm_switch_get_least_hops( p_sw, lid_ho ); + if (hop_val > maxHops) + maxHops = hop_val; + p_updn_hist = + (updn_hist_t*)cl_qmap_get( &min_hop_hist , (uint64_t)hop_val ); + if ( p_updn_hist == (updn_hist_t*)cl_qmap_end( &min_hop_hist)) + { + /* New entry in the histogram , first create it */ + p_updn_hist = (updn_hist_t*) malloc(sizeof(updn_hist_t)); + CL_ASSERT (p_updn_hist); + p_updn_hist->bar_value = 1; + cl_qmap_insert(&min_hop_hist, (uint64_t)hop_val, &p_updn_hist->map_item); + osm_log( &p_osm->log, OSM_LOG_DEBUG, + "__osm_updn_find_root_nodes_by_min_hop: " + "Creating new entry in histogram %u with bar value 1\n", + hop_val ); + } + else + { + /* Entry exist in the table , just increment the value */ + p_updn_hist->bar_value++; + osm_log( &p_osm->log, OSM_LOG_DEBUG, + "__osm_updn_find_root_nodes_by_min_hop: " + "Updating entry in histogram %u with bar value %d\n", + hop_val, p_updn_hist->bar_value ); + } + } + } + + /* Now recognize the spines by requiring one bar to be above 90% of the + number of CAs */ + thd1 = numCas * 0.9; + thd2 = numCas * 0.05; + osm_log( &p_osm->log, OSM_LOG_DEBUG, + "__osm_updn_find_root_nodes_by_min_hop: " + "Pass over the histogram value and find only one root node above " + "thd1 = %f && thd2 = %f\n", thd1, thd2 ); + + p_updn_hist = (updn_hist_t*) cl_qmap_head( &min_hop_hist ); + while( p_updn_hist != (updn_hist_t*)cl_qmap_end( &min_hop_hist ) ) + { + p_up_ht = p_updn_hist; + p_updn_hist = (updn_hist_t*)cl_qmap_next( &p_updn_hist->map_item ) ; + if ( p_up_ht->bar_value > thd1 ) + numHopBarsOverThd1++; + if ( p_up_ht->bar_value > thd2 ) + numHopBarsOverThd2++; + osm_log( &p_osm->log, OSM_LOG_DEBUG, + "__osm_updn_find_root_nodes_by_min_hop: " + "Passing through histogram - Hop Index %u: " + "numHopBarsOverThd1 = %u, numHopBarsOverThd2 = %u\n", + (uint16_t)cl_qmap_key((cl_map_item_t*)p_up_ht), + numHopBarsOverThd1, numHopBarsOverThd2 ); + } + + /* destroy the qmap table and all its content - no longer needed */ + osm_log( &p_osm->log, OSM_LOG_DEBUG, + "__osm_updn_find_root_nodes_by_min_hop: " + "Cleanup: delete histogram " + "UPDN - Root nodes fetching by auto detect\n" ); + p_updn_hist = (updn_hist_t*) cl_qmap_head( &min_hop_hist ); + while ( p_updn_hist != (updn_hist_t*)cl_qmap_end( &min_hop_hist ) ) + { + cl_qmap_remove_item( &min_hop_hist, (cl_map_item_t*)p_updn_hist ); + free( p_updn_hist ); + p_updn_hist = (updn_hist_t*) cl_qmap_head( &min_hop_hist ); + } + + /* If thd conditions are valid insert the root node to the list */ + if ( (numHopBarsOverThd1 == 1) && (numHopBarsOverThd2 == 1) ) + { + p_guid = malloc(sizeof(uint64_t)); + *p_guid = cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)); + osm_log( &p_osm->log, OSM_LOG_DEBUG, + "__osm_updn_find_root_nodes_by_min_hop: " + "Inserting GUID 0x%" PRIx64 " as root node\n", + *p_guid ); + cl_list_insert_tail(p_root_nodes_list, p_guid); + } + } + + /* destroy the map of CA lids */ + cl_map_remove_all( &ca_by_lid_map ); + cl_map_destroy( &ca_by_lid_map ); + + /* Now convert the cl_list to array */ + __osm_updn_convert_list2array(p_updn); + + OSM_LOG_EXIT( &p_osm->log ); + return 0; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_updn_delete( + void *context ) +{ + updn_t *p_updn = context; + + updn_destroy(p_updn); +} + +int +osm_ucast_updn_setup( + osm_opensm_t *p_osm ) +{ + updn_t *p_updn; + + p_updn = updn_construct(&p_osm->log); + if (!p_updn) + return -1; + p_osm->routing_engine.context = p_updn; + p_osm->routing_engine.delete = __osm_updn_delete; + p_osm->routing_engine.build_lid_matrices = __osm_updn_call; + + if (updn_init(p_updn, p_osm) != IB_SUCCESS) + return -1; + if (!p_updn->auto_detect_root_nodes) + __osm_updn_convert_list2array(p_updn); + + return 0; +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_vl15intf.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_vl15intf.c new file mode 100644 index 00000000..7548789a --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_vl15intf.c @@ -0,0 +1,544 @@ +/* + * 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: + * Implementation of osm_vl15_t. + * This object represents the VL15 Interface object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/********************************************************************** + **********************************************************************/ +void +__osm_vl15_poller( + IN void *p_ptr ) +{ + ib_api_status_t status; + osm_madw_t *p_madw; + uint32_t mads_sent; + uint32_t unicasts_sent; + uint32_t mads_on_wire; + osm_vl15_t* const p_vl = (osm_vl15_t*)p_ptr; + cl_qlist_t* p_fifo; + + OSM_LOG_ENTER( p_vl->p_log, __osm_vl15_poller ); + + 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 ) ) + { + if( osm_log_is_active( p_vl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_vl->p_log, OSM_LOG_DEBUG, + "__osm_vl15_poller: " + "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 ); + } + + /* + 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. + */ + mads_on_wire = cl_atomic_inc( + &p_vl->p_stats->qp0_mads_outstanding_on_wire ); + CL_ASSERT( mads_on_wire <= p_vl->max_wire_smps ); + } + else + { + unicasts_sent = cl_atomic_inc( + &p_vl->p_stats->qp0_unicasts_sent ); + } + + mads_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 ) + { + uint32_t outstanding; + cl_status_t cl_status; + + osm_log( p_vl->p_log, OSM_LOG_ERROR, + "__osm_vl15_poller: 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 and qp0_mads_outstanding_on_wire + that was incremented in the code above. */ + mads_sent = cl_atomic_dec( &p_vl->p_stats->qp0_mads_sent ); + if( p_madw->resp_expected == TRUE ) + cl_atomic_dec( &p_vl->p_stats->qp0_mads_outstanding_on_wire ); + + /* + The following code is similar to the code in + __osm_sm_mad_ctrl_retire_trans_mad. We need to decrement the + qp0_mads_outstanding counter, and if we reached 0 - need to call + the cl_disp_post with OSM_SIGNAL_NO_PENDING_TRANSACTION (in order + to wake up the state mgr). + There is one difference from the code in __osm_sm_mad_ctrl_retire_trans_mad. + This code is called on all mads, if osm_vendor_send() failed, unlike + __osm_sm_mad_ctrl_retire_trans_mad which is called only on mads where + resp_expected == TRUE. As a result, the qp0_mads_outstanding counter + should be decremented and handled accordingly only if this is a mad + with resp_expected == TRUE. + */ + if ( p_madw->resp_expected == TRUE ) + { + outstanding = cl_atomic_dec( &p_vl->p_stats->qp0_mads_outstanding ); + + osm_log( p_vl->p_log, OSM_LOG_DEBUG, + "__osm_vl15_poller: " + "%u QP0 MADs outstanding\n", + p_vl->p_stats->qp0_mads_outstanding ); + + if( outstanding == 0 ) + { + /* + The wire is clean. + Signal the state manager. + */ + if( osm_log_is_active( p_vl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_vl->p_log, OSM_LOG_DEBUG, + "__osm_vl15_poller: " + "Posting Dispatcher message %s\n", + osm_get_disp_msg_str( OSM_MSG_NO_SMPS_OUTSTANDING ) ); + } + + cl_status = cl_disp_post( p_vl->h_disp, + OSM_MSG_NO_SMPS_OUTSTANDING, + (void *)OSM_SIGNAL_NO_PENDING_TRANSACTIONS, + NULL, + NULL ); + + if( cl_status != CL_SUCCESS ) + { + osm_log( p_vl->p_log, OSM_LOG_ERROR, + "__osm_vl15_poller: ERR 3E06: " + "Dispatcher post message failed (%s)\n", + CL_STATUS_MSG( cl_status ) ); + } + } + } + } + else + { + if( osm_log_is_active( p_vl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_vl->p_log, OSM_LOG_DEBUG, + "__osm_vl15_poller: " + "%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 ); + } + } + } + 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, + "__osm_vl15_poller: ERR 3E02: " + "Event wait failed (%s)\n", + CL_STATUS_MSG( status ) ); + } + } + + /* + 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 back these mads... + */ + + OSM_LOG_EXIT( p_vl->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_vl15_construct( + IN osm_vl15_t* const p_vl ) +{ + memset( p_vl, 0, sizeof(*p_vl) ); + p_vl->state = OSM_VL15_STATE_INIT; + p_vl->thread_state = OSM_THREAD_STATE_NONE; + cl_event_construct( &p_vl->signal ); + cl_spinlock_construct( &p_vl->lock ); + cl_qlist_init( &p_vl->rfifo ); + cl_qlist_init( &p_vl->ufifo ); + cl_thread_construct( &p_vl->poller ); + p_vl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_vl15_destroy( + IN osm_vl15_t* const p_vl, + IN struct _osm_mad_pool *p_pool) +{ + osm_madw_t* p_madw; + + OSM_LOG_ENTER( p_vl->p_log, osm_vl15_destroy ); + + /* + Signal our threads that we're leaving. + */ + p_vl->thread_state = OSM_THREAD_STATE_EXIT; + + /* + Don't trigger unless event has been initialized. + Destroy the thread before we tear down the other objects. + */ + if( p_vl->state != OSM_VL15_STATE_INIT ) + cl_event_signal( &p_vl->signal ); + + cl_thread_destroy( &p_vl->poller ); + + /* + Return the outstanding messages to the pool + */ + + cl_spinlock_acquire( &p_vl->lock ); + + while (!cl_is_qlist_empty( &p_vl->rfifo)) + { + p_madw = (osm_madw_t*)cl_qlist_remove_head( &p_vl->rfifo); + osm_mad_pool_put( p_pool, p_madw ); + } + while (!cl_is_qlist_empty( &p_vl->ufifo)) + { + p_madw = (osm_madw_t*)cl_qlist_remove_head( &p_vl->ufifo); + osm_mad_pool_put( p_pool, p_madw ); + } + + cl_spinlock_release( &p_vl->lock ); + + cl_event_destroy( &p_vl->signal ); + p_vl->state = OSM_VL15_STATE_INIT; + cl_spinlock_destroy( &p_vl->lock ); + + OSM_LOG_EXIT( p_vl->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vl15_init( + IN osm_vl15_t* const p_vl, + IN osm_vendor_t* const p_vend, + IN osm_log_t* const p_log, + IN osm_stats_t* const p_stats, + IN const int32_t max_wire_smps, + IN osm_subn_t* const p_subn, + IN cl_dispatcher_t* const p_disp, + IN cl_plock_t* const p_lock + ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_vl15_init ); + + 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; + p_vl->p_subn = p_subn; + p_vl->p_lock = p_lock; + + status = cl_event_init( &p_vl->signal, FALSE ); + if( status != IB_SUCCESS ) + goto Exit; + + p_vl->state = OSM_VL15_STATE_READY; + + status = cl_spinlock_init( &p_vl->lock ); + if( status != IB_SUCCESS ) + goto Exit; + + /* + Initialize the thread after all other dependent objects + have been initialized. + */ + status = cl_thread_init( &p_vl->poller, __osm_vl15_poller, p_vl, + "opensm poller" ); + if( status != IB_SUCCESS ) + goto Exit; + + p_vl->h_disp = cl_disp_register( + p_disp, + CL_DISP_MSGID_NONE, + NULL, + NULL ); + + if( p_vl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_vl15_init: ERR 3E01: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_vl15_poll( + IN osm_vl15_t* const p_vl ) +{ + OSM_LOG_ENTER( p_vl->p_log, osm_vl15_poll ); + + 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 ) + { + if( osm_log_is_active( p_vl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_vl->p_log, OSM_LOG_DEBUG, + "osm_vl15_poll: " + "Signalling poller thread\n" ); + } + + cl_event_signal( &p_vl->signal ); + } + + OSM_LOG_EXIT( p_vl->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_vl15_post( + IN osm_vl15_t* const p_vl, + IN osm_madw_t* const p_madw ) +{ + OSM_LOG_ENTER( p_vl->p_log, osm_vl15_post ); + + CL_ASSERT( p_vl->state == OSM_VL15_STATE_READY ); + + if( osm_log_is_active( p_vl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_vl->p_log, OSM_LOG_DEBUG, + "osm_vl15_post: " + "Posting p_madw = 0x%p\n", p_madw ); + } + + /* + Determine in which fifo to place the pending madw. + */ + cl_spinlock_acquire( &p_vl->lock ); + if( p_madw->resp_expected == TRUE ) + { + cl_qlist_insert_tail( &p_vl->rfifo, (cl_list_item_t*)p_madw ); + cl_atomic_inc( &p_vl->p_stats->qp0_mads_outstanding ); + } + else + { + cl_qlist_insert_tail( &p_vl->ufifo, (cl_list_item_t*)p_madw ); + } + cl_spinlock_release( &p_vl->lock ); + + if( osm_log_is_active( p_vl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_vl->p_log, OSM_LOG_DEBUG, + "osm_vl15_post: " + "%u QP0 MADs on wire, %u QP0 MADs outstanding\n", + p_vl->p_stats->qp0_mads_outstanding_on_wire, + p_vl->p_stats->qp0_mads_outstanding ); + } + + osm_vl15_poll( p_vl ); + + OSM_LOG_EXIT( p_vl->p_log ); +} + +void +osm_vl15_shutdown( + IN osm_vl15_t* const p_vl, + IN osm_mad_pool_t* const p_mad_pool) +{ + osm_madw_t* p_madw; + + OSM_LOG_ENTER( p_vl->p_log, osm_vl15_shutdown ); + + /* 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 ); + + cl_disp_unregister( p_vl->h_disp ); + + /* 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 ) ) + { + if( osm_log_is_active( p_vl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_vl->p_log, OSM_LOG_DEBUG, + "osm_vl15_shutdown: " + "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 ) ) + { + if( osm_log_is_active( p_vl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_vl->p_log, OSM_LOG_DEBUG, + "osm_vl15_shutdown: " + "Releasing Request p_madw = %p\n", p_madw ); + } + + osm_mad_pool_put( p_mad_pool, p_madw ); + cl_atomic_dec( &p_vl->p_stats->qp0_mads_outstanding ); + + 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-1/ulp/opensm/user/opensm/osm_vl_arb_rcv.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_vl_arb_rcv.c new file mode 100644 index 00000000..2bb9690f --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_vl_arb_rcv.c @@ -0,0 +1,240 @@ +/* + * 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: + * Implementation of osm_vla_rcv_t. + * This object represents the Vl Arbitration Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +#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_vla_rcv_construct( + IN osm_vla_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_vla_rcv_destroy( + IN osm_vla_rcv_t* const p_rcv ) +{ + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_vla_rcv_destroy ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vla_rcv_init( + IN osm_vla_rcv_t* const p_rcv, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_vla_rcv_init ); + + osm_vla_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_req = p_req; + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +/* + * WE MIGHT ONLY RECEIVE GET or SET responses + */ +void +osm_vla_rcv_process( + IN const osm_vla_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ) +{ + cl_qmap_t *p_guid_tbl; + 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( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_vla_rcv_process ); + + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + + p_context = osm_madw_get_vla_context_ptr( p_madw ); + p_vla_tbl = (ib_vl_arb_table_t*)ib_smp_get_payload_ptr( p_smp ); + + port_guid = p_context->port_guid; + node_guid = p_context->node_guid; + + CL_ASSERT( p_smp->attr_id == IB_MAD_ATTR_VL_ARBITRATION ); + + p_guid_tbl = &p_rcv->p_subn->port_guid_tbl; + cl_plock_excl_acquire( p_rcv->p_lock ); + p_port = (osm_port_t*)cl_qmap_get( p_guid_tbl, port_guid ); + + if( p_port == (osm_port_t*)cl_qmap_end( p_guid_tbl ) ) + { + cl_plock_release( p_rcv->p_lock ); + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_vla_rcv_process: 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 = osm_port_get_parent_node( p_port ); + 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 = osm_port_get_default_phys_ptr(p_port); + port_num = p_port->default_port_num; + } + + CL_ASSERT( p_physp ); + + /* + We do not mind if this is a result of a set or get - all we want is to update + the subnet. + */ + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_vla_rcv_process: " + "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( !osm_physp_is_valid( p_physp ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_vla_rcv_process: " + "Got invalid port number 0x%X\n", + port_num ); + goto Exit; + } + + osm_dump_vl_arb_table( p_rcv->p_log, + port_guid, block_num, + port_num, p_vla_tbl, + OSM_LOG_DEBUG ); + + if ( (block_num < 1) || (block_num > 4) ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_vla_rcv_process: " + "Got invalid block number 0x%X\n", + block_num ); + goto Exit; + } + osm_physp_set_vla_tbl( p_physp, p_vla_tbl, block_num); + + Exit: + cl_plock_release( p_rcv->p_lock ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_vl_arb_rcv_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_vl_arb_rcv_ctrl.c new file mode 100644 index 00000000..8dde5a87 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_vl_arb_rcv_ctrl.c @@ -0,0 +1,127 @@ +/* + * 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: + * Implementation of osm_vla_rcv_ctrl_t. + * This object represents the Vl Arbitration request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_vla_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_vla_rcv_process( ((osm_vla_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_vla_rcv_ctrl_construct( + IN osm_vla_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_vla_rcv_ctrl_destroy( + IN osm_vla_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vla_rcv_ctrl_init( + IN osm_vla_rcv_ctrl_t* const p_ctrl, + IN osm_vla_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_vla_rcv_ctrl_init ); + + osm_vla_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_VL_ARB, + __osm_vla_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_vla_rcv_ctrl_init: ERR 4001: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/st.c b/branches/WOF2-1/ulp/opensm/user/opensm/st.c new file mode 100644 index 00000000..c6d1d998 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/st.c @@ -0,0 +1,625 @@ +/* + * 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$ + */ + + + +/* static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + +typedef struct st_table_entry st_table_entry; + +struct st_table_entry { + unsigned int hash; + st_data_t key; + st_data_t record; + st_table_entry *next; +}; + +#define ST_DEFAULT_MAX_DENSITY 5 +#define ST_DEFAULT_INIT_TABLE_SIZE 11 + +/* + * DEFAULT_MAX_DENSITY is the default for the largest we allow the + * average number of items per bin before increasing the number of + * bins + * + * DEFAULT_INIT_TABLE_SIZE is the default for the number of bins + * allocated initially + * + */ +static int numcmp(void *, void *); +static st_ptr_t numhash(void *); +static struct st_hash_type type_numhash = { + numcmp, + numhash, +}; + + +/* extern int strcmp(const char *, const char *); */ +static int strhash(const char *); + +static inline st_ptr_t st_strhash(void *key) +{ + return strhash((const char *)key); +} + +static inline int st_strcmp(void *key1, void *key2) +{ + return strcmp((const char *)key1, (const char *)key2); +} + +static struct st_hash_type type_strhash = { + st_strcmp, + st_strhash +}; + + +#define xmalloc malloc +#define xcalloc calloc +#define xrealloc realloc +#define xfree free + +static void rehash(st_table *); + +#define alloc(type) (type*)xmalloc(sizeof(type)) +#define Calloc(n,s) (char*)xcalloc((n), (s)) + +#define EQUAL(table,x,y) ((x)==(y) || (*table->type->compare)(((void*)x),((void *)y)) == 0) + +#define do_hash(key,table) (unsigned int)(*(table)->type->hash)(((void*)key)) +#define do_hash_bin(key,table) (do_hash(key, table)%(table)->num_bins) + +/* + * MINSIZE is the minimum size of a dictionary. + */ + +#define MINSIZE 8 + +/* + Table of prime numbers 2^n+a, 2<=n<=30. +*/ +static long primes[] = { + 8 + 3, + 16 + 3, + 32 + 5, + 64 + 3, + 128 + 3, + 256 + 27, + 512 + 9, + 1024 + 9, + 2048 + 5, + 4096 + 3, + 8192 + 27, + 16384 + 43, + 32768 + 3, + 65536 + 45, + 131072 + 29, + 262144 + 3, + 524288 + 21, + 1048576 + 7, + 2097152 + 17, + 4194304 + 15, + 8388608 + 9, + 16777216 + 43, + 33554432 + 35, + 67108864 + 15, + 134217728 + 29, + 268435456 + 3, + 536870912 + 11, + 1073741824 + 85, + 0 +}; + +static int +new_size(int size) +{ + int i; + +#if 0 + for (i=3; i<31; i++) { + if ((1< size) return 1< size) return primes[i]; + } + /* Ran out of polynomials */ + return -1; /* should raise exception */ +#endif +} + +#ifdef HASH_LOG +static int collision = 0; +static int init_st = 0; + +static void +stat_col() +{ + FILE *f = fopen("/var/log/osm_st_col", "w"); + fprintf(f, "collision: %d\n", collision); + fclose(f); +} +#endif + +st_table* +st_init_table_with_size(type, size) + struct st_hash_type *type; + size_t size; +{ + st_table *tbl; + +#ifdef HASH_LOG + if (init_st == 0) + { + init_st = 1; + atexit(stat_col); + } +#endif + + size = new_size(size); /* round up to prime number */ + + tbl = alloc(st_table); + tbl->type = type; + tbl->num_entries = 0; + tbl->num_bins = size; + tbl->bins = (st_table_entry **)Calloc(size, sizeof(st_table_entry*)); + + return tbl; +} + +st_table* +st_init_table(type) + struct st_hash_type *type; +{ + return st_init_table_with_size(type, 0); +} + +st_table* +st_init_numtable(void) +{ + return st_init_table(&type_numhash); +} + +st_table* +st_init_numtable_with_size(size) + size_t size; +{ + return st_init_table_with_size(&type_numhash, size); +} + +st_table* +st_init_strtable(void) +{ + return st_init_table(&type_strhash); +} + +st_table* +st_init_strtable_with_size(size) + size_t size; +{ + return st_init_table_with_size(&type_strhash, size); +} + +void +st_free_table(table) + st_table *table; +{ + register st_table_entry *ptr, *next; + int i; + + for (i = 0; i < table->num_bins; i++) { + ptr = table->bins[i]; + while (ptr != 0) { + next = ptr->next; + free(ptr); + ptr = next; + } + } + free(table->bins); + free(table); +} + +#define PTR_NOT_EQUAL(table, ptr, hash_val, key) \ +((ptr) != 0 && (ptr->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key))) + +#ifdef HASH_LOG +#define COLLISION collision++ +#else +#define COLLISION +#endif + +#define FIND_ENTRY(table, ptr, hash_val, bin_pos) do {\ + bin_pos = hash_val%(table)->num_bins;\ + ptr = (table)->bins[bin_pos];\ + if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) \ + {\ + COLLISION;\ + while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {\ + ptr = ptr->next;\ + }\ + ptr = ptr->next;\ + }\ +} while (0) + +int +st_lookup(table, key, value) + st_table *table; + register st_data_t key; + st_data_t *value; +{ + unsigned int hash_val, bin_pos; + register st_table_entry *ptr; + + hash_val = do_hash(key, table); + FIND_ENTRY(table, ptr, hash_val, bin_pos); + + if (ptr == 0) + { + return 0; + } + else + { + if (value != 0) + *value = ptr->record; + return 1; + } +} + +#define ADD_DIRECT(table, key, value, hash_val, bin_pos)\ +do {\ + st_table_entry *entry;\ + if (table->num_entries/(table->num_bins) > ST_DEFAULT_MAX_DENSITY) \ + {\ + rehash(table);\ + bin_pos = hash_val % table->num_bins;\ + }\ + \ + entry = alloc(st_table_entry);\ + \ + entry->hash = hash_val;\ + entry->key = key;\ + entry->record = value;\ + entry->next = table->bins[bin_pos];\ + table->bins[bin_pos] = entry;\ + table->num_entries++;\ +} while (0); + + +int +st_insert(table, key, value) + register st_table *table; + register st_data_t key; + st_data_t value; +{ + unsigned int hash_val, bin_pos; + register st_table_entry *ptr; + + hash_val = do_hash(key, table); + FIND_ENTRY(table, ptr, hash_val, bin_pos); + + if (ptr == 0) + { + ADD_DIRECT(table, key, value, hash_val, bin_pos); + return 0; + } + else + { + ptr->record = value; + return 1; + } +} + +void +st_add_direct(table, key, value) + st_table *table; + st_data_t key; + st_data_t value; +{ + unsigned int hash_val, bin_pos; + + hash_val = do_hash(key, table); + bin_pos = hash_val % table->num_bins; + ADD_DIRECT(table, key, value, hash_val, bin_pos); +} + +static void +rehash(table) + register st_table *table; +{ + register st_table_entry *ptr, *next, **new_bins; + int i, old_num_bins = table->num_bins, new_num_bins; + unsigned int hash_val; + + new_num_bins = new_size(old_num_bins+1); + new_bins = (st_table_entry**)Calloc(new_num_bins, sizeof(st_table_entry*)); + + for (i = 0; i < old_num_bins; i++) { + ptr = table->bins[i]; + while (ptr != 0) { + next = ptr->next; + hash_val = ptr->hash % new_num_bins; + ptr->next = new_bins[hash_val]; + new_bins[hash_val] = ptr; + ptr = next; + } + } + free(table->bins); + table->num_bins = new_num_bins; + table->bins = new_bins; +} + +st_table* +st_copy(old_table) + st_table *old_table; +{ + st_table *new_table; + st_table_entry *ptr, *entry; + size_t i, num_bins = old_table->num_bins; + + new_table = alloc(st_table); + if (new_table == 0) + { + return 0; + } + + *new_table = *old_table; + new_table->bins = (st_table_entry**) + Calloc(num_bins, sizeof(st_table_entry*)); + + if (new_table->bins == 0) + { + free(new_table); + return 0; + } + + for (i = 0; i < num_bins; i++) { + new_table->bins[i] = 0; + ptr = old_table->bins[i]; + while (ptr != 0) { + entry = alloc(st_table_entry); + if (entry == 0) + { + free(new_table->bins); + free(new_table); + return 0; + } + *entry = *ptr; + entry->next = new_table->bins[i]; + new_table->bins[i] = entry; + ptr = ptr->next; + } + } + return new_table; +} + +int +st_delete(table, key, value) + register st_table *table; + register st_data_t *key; + st_data_t *value; +{ + unsigned int hash_val; + st_table_entry *tmp; + register st_table_entry *ptr; + + hash_val = do_hash_bin(*key, table); + ptr = table->bins[hash_val]; + + if (ptr == 0) + { + if (value != 0) *value = 0; + return 0; + } + + if (EQUAL(table, *key, ptr->key)) + { + table->bins[hash_val] = ptr->next; + table->num_entries--; + if (value != 0) *value = ptr->record; + *key = ptr->key; + free(ptr); + return 1; + } + + for (; ptr->next != 0; ptr = ptr->next) { + if (EQUAL(table, ptr->next->key, *key)) + { + tmp = ptr->next; + ptr->next = ptr->next->next; + table->num_entries--; + if (value != 0) *value = tmp->record; + *key = tmp->key; + free(tmp); + return 1; + } + } + + return 0; +} + +int +st_delete_safe(table, key, value, never) + register st_table *table; + register st_data_t *key; + st_data_t *value; + st_data_t never; +{ + unsigned int hash_val; + register st_table_entry *ptr; + + hash_val = do_hash_bin(*key, table); + ptr = table->bins[hash_val]; + + if (ptr == 0) + { + if (value != 0) *value = 0; + return 0; + } + + for (; ptr != 0; ptr = ptr->next) { + if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) + { + table->num_entries--; + *key = ptr->key; + if (value != 0) *value = ptr->record; + ptr->key = ptr->record = never; + return 1; + } + } + + return 0; +} + +static int +delete_never(st_data_t key, st_data_t value, st_data_t never) +{ + if (value == never) return ST_DELETE; + return ST_CONTINUE; +} + +void +st_cleanup_safe(table, never) + st_table *table; + st_data_t never; +{ + int num_entries = table->num_entries; + + st_foreach(table, delete_never, never); + table->num_entries = num_entries; +} + +void +st_foreach(table, func, arg) + st_table *table; + int (*func)(st_data_t key, st_data_t val, st_data_t arg); + st_data_t arg; +{ + st_table_entry *ptr, *last, *tmp; + enum st_retval retval; + int i; + + for (i = 0; i < table->num_bins; i++) { + last = 0; + for (ptr = table->bins[i]; ptr != 0;) { + retval = (*func)(ptr->key, ptr->record, arg); + switch (retval) { + case ST_CONTINUE: + last = ptr; + ptr = ptr->next; + break; + case ST_STOP: + return; + case ST_DELETE: + tmp = ptr; + if (last == 0) + { + table->bins[i] = ptr->next; + } + else + { + last->next = ptr->next; + } + ptr = ptr->next; + free(tmp); + table->num_entries--; + } + } + } +} + +static int +strhash(string) + register const char *string; +{ + register int c; + +#ifdef HASH_ELFHASH + register unsigned int h = 0, g; + + while ((c = *string++) != '\0') { + h = ( h << 4 ) + c; + if ( g = h & 0xF0000000 ) + h ^= g >> 24; + h &= ~g; + } + return h; +#elif HASH_PERL + register int val = 0; + + while ((c = *string++) != '\0') { + val = val*33 + c; + } + + return val + (val>>5); +#else + register int val = 0; + + while ((c = *string++) != '\0') { + val = val*997 + c; + } + + return val + (val>>5); +#endif +} + +static int +numcmp(x, y) + void *x, *y; +{ + return (st_ptr_t)x != (st_ptr_t)y; +} + +static st_ptr_t +numhash(n) + void *n; +{ + return (st_ptr_t)n; +} + diff --git a/branches/WOF2-1/ulp/opensm/user/osmtest/Makefile b/branches/WOF2-1/ulp/opensm/user/osmtest/Makefile new file mode 100644 index 00000000..9c985f57 --- /dev/null +++ b/branches/WOF2-1/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 $(NTMAKEENV)\makefile.def diff --git a/branches/WOF2-1/ulp/opensm/user/osmtest/SOURCES b/branches/WOF2-1/ulp/opensm/user/osmtest/SOURCES new file mode 100644 index 00000000..8ee31d94 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/SOURCES @@ -0,0 +1,71 @@ +!if $(FREEBUILD) +TARGETNAME=osmtest +!else +TARGETNAME=osmtestd +!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 + +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 +OVR_DIR=..\addon + + +SOURCES=\ + osmt_slvl_vl_arb.c \ + osmt_service.c \ + osmt_multicast.c \ + osmt_inform.c \ + osmtest.c \ + main.c \ + + + +OSM_HOME=.. + +TARGETLIBS=\ +!if $(FREEBUILD) + $(LIBPATH)\*\ibal.lib \ + $(LIBPATH)\*\complib.lib \ + $(TARGETPATH)\*\osmv_ibal.lib \ + $(TARGETPATH)\*\opensm_ibal.lib + +!else + $(LIBPATH)\*\ibald.lib \ + $(LIBPATH)\*\complibd.lib \ + $(TARGETPATH)\*\osmv_ibald.lib \ + $(TARGETPATH)\*\opensm_ibald.lib +!endif + +#DO NOT TOUCH the order of search path , until ib_types.h merging process will be done +INCLUDES= \ + $(OSM_HOME)\osmtest\include; \ + $(OSM_HOME)\include; \ + $(OSM_HOME); \ + $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; + +# Could be any special flag needed for this project +USER_C_FLAGS=$(USER_C_FLAGS) /MD +#Add preproccessor definitions +C_DEFINES=$(C_DEFINES) -DWIN32 -D__WIN__ -D__i386__ -Dinline=__inline -DMT_LITTLE_ENDIAN -DOSM_VENDOR_INTF_AL +C_DEFINES=$(C_DEFINES) -I.. -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 + diff --git a/branches/WOF2-1/ulp/opensm/user/osmtest/include/error.h b/branches/WOF2-1/ulp/opensm/user/osmtest/include/error.h new file mode 100644 index 00000000..ef80b337 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/include/error.h @@ -0,0 +1,57 @@ +/* + * 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: + * Declaration of error code ranges for the various osmtest modules. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.2 $ + */ + + +/* + osmtest object + 0x0100 - 0x01FF + + parser object + 0x0200 - 0x02FF + + osmtest object + 0x0300 - 0x03FF + +*/ + diff --git a/branches/WOF2-1/ulp/opensm/user/osmtest/include/osmt_inform.h b/branches/WOF2-1/ulp/opensm/user/osmtest/include/osmt_inform.h new file mode 100644 index 00000000..f0262541 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/include/osmt_inform.h @@ -0,0 +1,88 @@ +/* + * 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$ + */ + + +#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-1/ulp/opensm/user/osmtest/include/osmt_mtl_regular_qp.h b/branches/WOF2-1/ulp/opensm/user/osmtest/include/osmt_mtl_regular_qp.h new file mode 100644 index 00000000..0466b76c --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/include/osmt_mtl_regular_qp.h @@ -0,0 +1,187 @@ +/* + * 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$ + */ + + +/* + * 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-1/ulp/opensm/user/osmtest/include/osmtest.h b/branches/WOF2-1/ulp/opensm/user/osmtest/include/osmtest.h new file mode 100644 index 00000000..58feec98 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/include/osmtest.h @@ -0,0 +1,517 @@ +/* + * 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: + * Declaration of osmtest_t. + * This object represents the OSMTest Test object. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +#ifndef _OSMTEST_H_ +#define _OSMTEST_H_ + +#include +#include +#include +#include +#include +#include +#include "osmtest_base.h" +#include "osmtest_subnet.h" + +/****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-1/ulp/opensm/user/osmtest/include/osmtest_base.h b/branches/WOF2-1/ulp/opensm/user/osmtest/include/osmtest_base.h new file mode 100644 index 00000000..f3716d3d --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/include/osmtest_base.h @@ -0,0 +1,72 @@ +/* + * 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: + * Declaration of osmtest_t. + * This object represents the OSMTest Test object. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.2 $ + */ +#ifndef _OSMTEST_BASE_H_ +#define _OSMTEST_BASE_H_ + +#ifndef __WIN__ +#include +#else +#include +#endif + +#define OSMTEST_MAX_LINE_LEN 120 +#ifdef WIN32 +#define OSMTEST_FILE_PATH_MAX 4096 +#else +#define OSMTEST_FILE_PATH_MAX PATH_MAX +#endif + +#define STRESS_SMALL_RMPP_THR 100000 +/* + Take long times when quering big clusters (over 40 nodes) , an average of : 0.25 sec for query + each query receives 1000 records +*/ +#define STRESS_LARGE_RMPP_THR 4000 +#define STRESS_LARGE_PR_RMPP_THR 20000 + +extern const char *const p_file; + +#endif /* _OSMTEST_BASE_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/osmtest/include/osmtest_subnet.h b/branches/WOF2-1/ulp/opensm/user/osmtest/include/osmtest_subnet.h new file mode 100644 index 00000000..418dd366 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/include/osmtest_subnet.h @@ -0,0 +1,349 @@ +/* + * 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: + * Declaration of osmtest_t. + * This object represents the OSMTest Test object. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.2 $ + */ + +#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-1/ulp/opensm/user/osmtest/main.c b/branches/WOF2-1/ulp/opensm/user/osmtest/main.c new file mode 100644 index 00000000..339d0e0e --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/main.c @@ -0,0 +1,678 @@ +/* + * 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 the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF 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 osmtest. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#include +#include +#include +#include "osmtest.h" + +/******************************************************************** + D E F I N E G L O B A L V A R I A B L E S +*********************************************************************/ + +/* + This is the global osmtest object. + One osmtest object is required per subnet. + Future versions could support multiple subents by + instantiating more than one osmtest object. +*/ +#define GUID_ARRAY_SIZE 64 +#define OSMT_DEFAULT_RETRY_COUNT 3 +#define OSMT_DEFAULT_TRANS_TIMEOUT_MILLISEC 1000 +#define OSMT_DEFAULT_TRAP_WAIT_TIMEOUT_SEC 10 + +/********************************************************************** + **********************************************************************/ +boolean_t +osmt_is_debug(void) +{ +#if defined( _DEBUG_ ) + return TRUE; +#else + return FALSE; +#endif /* defined( _DEBUG_ ) */ +} + +/********************************************************************** + **********************************************************************/ +ib_net64_t +get_port_guid( + IN osmtest_t *p_osm, uint64_t port_guid, + IN boolean_t is_service) +{ + uint32_t i; + uint32_t choice = 0; + char junk[128]; + boolean_t done_flag = FALSE; + ib_api_status_t status; + uint32_t num_ports = GUID_ARRAY_SIZE; + ib_port_attr_t attr_array[GUID_ARRAY_SIZE]; + + /* + 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 defined ( OSM_VENDOR_INTF_OPENIB ) + /* If port_guid is 0, and this is gen2 - use the default port whose info is in attr_array[0] */ + if ( port_guid == 0 ) + { + printf("Using default GUID 0x%" PRIx64 "\n", cl_hton64(attr_array[0].port_guid)); + return( attr_array[0].port_guid ); + } +#endif /* OSM_VENDOR_INTF_OPENIB */ + + /* If port_guid is 0, and we are in windows - find the first port with link_state != DOWN and + use it as default port. */ + if ( port_guid == 0 ) + { + for ( i = 0; i < num_ports; i++ ) + { + if (attr_array[i].link_state > IB_LINK_DOWN) + { + /* Use this port */ + printf("Using default guid 0x%" PRIx64 "\n", cl_hton64(attr_array[i].port_guid)); + return( attr_array[i].port_guid ); + } + } + /* If we are running as a service, and all ports are down we return the + first port (we can't open a window, as a service)*/ + if (is_service) { + return( attr_array[0].port_guid ); + } + } + + /* More than one possible port - list all ports and let the user to choose. */ + while( done_flag == FALSE ) + { + printf( "\nChoose a local port number with which to bind:\n\n" ); + /* If this is gen2 code - then port 0 has details of the default port used. + no need to print it. + If this is not gen2 code - need to print details of all ports. */ +#if defined ( OSM_VENDOR_INTF_OPENIB ) + for( i = 1; i < num_ports; i++ ) + { + printf("\t%u: GUID = 0x%8" PRIx64 ", lid = 0x%04X, state = %s\n", + i, cl_ntoh64( attr_array[i].port_guid ), + attr_array[i].lid, + ib_get_port_state_str( attr_array[i].link_state ) ); + } + printf( "\nEnter choice (1-%u): ", i-1 ); +# else + for( i = 0; i < num_ports; i++ ) + { + /* + Print the index + 1 since by convention, port numbers + start with 1 on host channel adapters. + */ + + printf("\t%u: GUID = 0x%8" PRIx64 ", lid = 0x%04X, state = %s\n", + i+1, cl_ntoh64( attr_array[i].port_guid ), + attr_array[i].lid, + ib_get_port_state_str( attr_array[i].link_state ) ); + } + printf( "\nEnter choice (1-%u): ", i ); +#endif /* OSM_VENDOR_INTF_OPENIB */ + + fflush( stdout ); + if (scanf( "%u", &choice )) + { + /* If gen2 code - choice can be between 1 to num_ports-1 + if not gen2 code - choice can be between 1 to num_ports */ +#if defined ( OSM_VENDOR_INTF_OPENIB ) + if( choice >= num_ports ) +# else + if( choice > num_ports || choice < 1 ) +#endif /* OSM_VENDOR_INTF_OPENIB */ + { + printf("\nError: Lame choice!\n"); + fflush( stdin ); + } + else + { + done_flag = TRUE; + } + } + else + { + /* get rid of the junk in the selection line */ + scanf( "%s", junk ); + printf("\nError: Lame choice!\n"); + fflush( stdin ); + } + } +#if defined ( OSM_VENDOR_INTF_OPENIB ) + printf("Choice guid=0x%8" PRIx64 "\n", cl_ntoh64( attr_array[choice].port_guid )); + return( attr_array[choice].port_guid ); +# else + return( attr_array[choice - 1].port_guid ); +#endif /* OSM_VENDOR_INTF_OPENIB */ +} +/********************************************************************** + **********************************************************************/ +void show_usage(void); + +void +show_usage( ) +{ + printf + ( "\n------- osmtest - Usage and options ----------------------\n" ); + printf( "Usage: osmtest [options]\n" ); + printf( "Options:\n" ); + printf( "-f \n" + "--flow \n" + " This option directs osmtest to run a specific flow:\n" + " FLOW DESCRIPTION\n" + " c = create an inventory file with all nodes, ports and paths.\n" + " a = run all validation tests (expecting an input inventory)\n" + " v = only validate the given inventory file.\n" + " s = run service registration, un-registration and lease.\n" + " e = run event forwarding test.\n" + " f = flood the SA with queries accoring to the stress mode.\n" + " m = multicast flow.\n" + " q = QoS info - VLArb and SLtoVL tables.\n" + " t = run trap 64/65 flow. This flow requires running of external tool.\n" + " (default is all but 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" ); + 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" + " -d3 - Use mem tracking.\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"); + 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" + " Without -g, osmtest displays a menu of possible\n" + " port GUIDs and waits for user input.\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 the -c option for related information.\n\n" ); + printf( "-s\n" + "--stress\n" + " This option runs the specified stress test instead\n" + " of the normal test suite.\n" + " Stress test options are as follows:\n" + " OPT Description\n" + " --- -----------------\n" + " -s1 - Single-MAD response SA queries .\n" + " -s2 - Multi-MAD (RMPP) response SA queries.\n" + " -s3 - Multi-MAD (RMPP) Path Record SA queries.\n" + " Without -s, stress testing is not performed.\n\n" ); + printf( "-M\n" + "--Multicast_Mode\n" + " This option specify length of Multicast test :\n" + " OPT Description\n" + " --- -----------------\n" + " -M1 - Short Multicast Flow (default) - single mode.\n" + " -M2 - Short Multicast Flow - multiple mode.\n" + " -M3 - Long Multicast Flow - single mode.\n" + " -M4 - Long Multicast Flow - multiple mode.\n" + " Single mode - Osmtest is tested alone , with no other \n" + " apps that interact vs. OpenSM MC.\n" + " Multiple mode - Could be run with other apps using MC vs.\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" ); +} + +/********************************************************************** + **********************************************************************/ +void show_menu(void); + +void +show_menu( ) +{ + printf( "\n------- Interactive Menu -------\n" ); + printf( "X - Exit.\n\n" ); +} +void OsmReportState(IN const char *p_str) +{ +} + +/********************************************************************** + **********************************************************************/ +int OSM_CDECL +main( int argc, + char *argv[] ) +{ + static osmtest_t osm_test; + osmtest_opt_t opt = { 0 }; + ib_net64_t guid = 0; + int max_lid = 100; + ib_api_status_t status; + uint32_t log_flags = OSM_LOG_ERROR | OSM_LOG_INFO; + char flow_name[64]; + boolean_t mem_track = FALSE; + uint32_t next_option; + const char *const short_option = "f:l:m:M:d:g:s:t:i:cvVh"; + + /* + * 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", 1, NULL, 'g'}, + {"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 */ + }; + + 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 = 0; /* 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 = 1; + } else if (!strcmp("v",optarg)) { + strcpy(flow_name, "Validate Inventory"); + opt.flow = 2; + } else if (!strcmp("s",optarg)) { + strcpy(flow_name, "Services Registration"); + opt.flow = 3; + } else if (!strcmp("e",optarg)) { + strcpy(flow_name, "Event Forwarding"); + opt.flow = 4; + } else if (!strcmp("f",optarg)) { + strcpy(flow_name, "Stress SA"); + opt.flow = 5; + } else if (!strcmp("m",optarg)) { + strcpy(flow_name, "Multicast"); + opt.flow = 6; + } else if (!strcmp("q",optarg)) { + strcpy(flow_name, "QoS: VLArb and SLtoVL"); + opt.flow = 7; + } else if (!strcmp("t", optarg)) { + strcpy(flow_name, "Trap 64/65"); + opt.flow = 8; + } else if (!strcmp("a",optarg)) { + strcpy(flow_name, "All Validations"); + opt.flow = 0; + } else { + printf( "\nError: un-known flow %s.\n",flow_name); + exit(2); + } + break; + + case 'w': + /* + * Specifies trap 64/65 wait time + */ + CL_ASSERT( strtol( optarg, NULL, 0 ) < 0x100 ); + opt.wait_time = (uint8_t)strtol( optarg, NULL, 0 ); + printf( "\tTrap 64/65 wait time = %d\n", opt.wait_time ); + break; + + case 'm': + /* + * Specifies the max LID to search for during exploration. + */ + max_lid = atoi( optarg ); + printf( "\tMAX-LID %u\n", max_lid ); + break; + + case 'g': + /* + * Specifies port guid with which to bind. + */ + guid = cl_hton64( strtoull( optarg, NULL, 16 )); + printf( "\tGUID 0x%016" PRIx64 "\n", guid ); + break; + case 't': + /* + * Specifies transaction timeout. + */ + opt.transaction_timeout = strtol( optarg, NULL, 0 ); + printf( "\tTransaction timeout = %d\n", opt.transaction_timeout ); + break; + + case 'l': + opt.log_file = optarg; + printf("\tLog File:%s\n", opt.log_file ); + break; + + case 'v': + /* + * Increases log verbosity. + */ + log_flags = ( log_flags << 1 ) | 1; + printf( "\tVerbose option -v (log flags = 0x%X)\n", log_flags ); + break; + + case 'V': + /* + * Specifies maximum log verbosity. + */ + log_flags = 0xFFFFFFFF; + opt.force_log_flush = TRUE; + printf( "\tEnabling maximum log verbosity\n" ); + break; + + case 's': + /* + * Perform stress test. + */ + opt.stress = strtol( optarg, NULL, 0 ); + printf( "\tStress test enabled: " ); + switch ( opt.stress ) + { + case 1: + printf( "Small SA queries\n" ); + break; + case 2: + printf( "Large SA queries\n" ); + break; + case 3: + printf( "Large Path Record SA queries\n" ); + break; + default: + printf( "Unknown value %u (ignored)\n", opt.stress ); + opt.stress = 0; + break; + } + break; + + case 'M': + /* + * Perform stress 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: + printf( "Use Mem Tracking.\n" ); + mem_track = TRUE; + break; + default: + printf( "Unknown value %ld (ignored)\n", strtol( optarg, NULL, 0 ) ); + break; + } + break; + + case 'h': + show_usage( ); + return 0; + + case 'x': + log_flags = strtol( optarg, NULL, 0 ); + printf( "\t\t\t\tVerbose option -vf (log flags = 0x%X)\n", + log_flags ); + break; + + case -1: + printf( "Done with args\n" ); + break; + + default: /* something wrong */ + abort( ); + } + + } + while( next_option != -1 ); + + printf( "\tFlow = %s\n", flow_name ); + + if (mem_track) __cl_mem_track(TRUE); + + + 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 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,1))) { + 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, (uint16_t)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 ); + + if (mem_track) cl_mem_display(); + + Exit: + return ( status ); +} diff --git a/branches/WOF2-1/ulp/opensm/user/osmtest/osmt_inform.c b/branches/WOF2-1/ulp/opensm/user/osmtest/osmt_inform.c new file mode 100644 index 00000000..94c74df4 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/osmt_inform.c @@ -0,0 +1,961 @@ +/* + * 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$ + */ + + +#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 + * + * Environment: + * Linux User Mode + * + * $Revision: 1.2 $ + */ + +#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, osmt_bind_inform_qp ); + + port_guid = p_osmt->local_port.port_guid; + + osm_log( p_log, OSM_LOG_DEBUG, + "osmt_bind_inform_qp: " + "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, + "osmt_bind_inform_qp: " + "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, + "osmt_bind_inform_qp: 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, + "osmt_bind_inform_qp: 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, + "osmt_bind_inform_qp: " + "Initialized QP:0x%X in VAPI Mode\n", + p_qp_ctx->qp_bind_hndl.qp_id + ); + + osm_log( p_log, OSM_LOG_DEBUG, + "osmt_bind_inform_qp: " "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, + "osmt_bind_inform_qp: 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_unbind_inform_qp ); + + 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, + "osmt_unbind_inform_qp: " + "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, osmt_reg_unreg_inform_info ); + + /* 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, + "osmt_reg_unreg_inform_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, + "osmt_reg_unreg_inform_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, + "osmt_reg_unreg_inform_info: ERR 0120: " + "Error posting recv bufs\n"); + status = IB_ERROR; + goto Exit; + } + osm_log( p_log, OSM_LOG_DEBUG, + "osmt_reg_unreg_inform_info: " + "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, + "osmt_reg_unreg_inform_info: ERR 0121: " + "Error Preparing AVH (%s)\n", + VAPI_strerror_sym(vapi_ret) ); + status = IB_ERROR; + goto Exit; + } + osm_log( p_log, OSM_LOG_DEBUG, + "osmt_reg_unreg_inform_info: " + "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, + "osmt_reg_unreg_inform_info: 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, + "osmt_reg_unreg_inform_info: 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, + "osmt_reg_unreg_inform_info: 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, + "osmt_reg_unreg_inform_info: " + "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, + "osmt_reg_unreg_inform_info: 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, + "osmt_reg_unreg_inform_info: " + "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, + "osmt_reg_unreg_inform_info: " + "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, + "osmt_reg_unreg_inform_info: " + "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, + "osmt_reg_unreg_inform_info: 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, osmt_send_trap_wait_for_forward ); + + osm_log( p_log, OSM_LOG_INFO, + "osmt_send_trap_wait_for_forward: " + "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, + "osmt_send_trap_wait_for_forward: ERR 0127: " + "Error posting recv bufs\n"); + status = IB_ERROR; + goto Exit; + } + osm_log( p_log, OSM_LOG_DEBUG, + "osmt_send_trap_wait_for_forward: " + "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; */ + + if( osm_log_is_active( p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_log, OSM_LOG_DEBUG, + "osmt_send_trap_wait_for_forward: " + "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, + "osmt_send_trap_wait_for_forward: 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, + "osmt_send_trap_wait_for_forward: ERR 0129: " + "Error Preparing AVH (%s)\n", + VAPI_strerror_sym(vapi_ret) ); + status = IB_ERROR; + goto Exit; + } + osm_log( p_log, OSM_LOG_DEBUG, + "osmt_send_trap_wait_for_forward: " + "Prepared AVH\n"); + + osm_log( p_log, OSM_LOG_DEBUG, + "osmt_send_trap_wait_for_forward: " + "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, + "osmt_send_trap_wait_for_forward: ERR 0130: " + "Timeout receiving mad (%s)\n", + VAPI_strerror_sym(vapi_ret) ); + status = IB_TIMEOUT; + } + else + { + osm_log( p_log, OSM_LOG_ERROR, + "osmt_send_trap_wait_for_forward: 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, + "osmt_send_trap_wait_for_forward: " + "Received the Report!\n"); + status = IB_SUCCESS; + } + else + { + osm_log( p_log, OSM_LOG_ERROR, + "osmt_send_trap_wait_for_forward: 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, + "osmt_send_trap_wait_for_forward: 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, osmt_trap_wait ); + + osm_log( p_log, OSM_LOG_INFO, + "osmt_trap_wait: " + "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, + "osmt_trap_wait: ERR 0130: " + "Timeout receiving mad (%s)\n", + VAPI_strerror_sym(vapi_ret) ); + status = IB_TIMEOUT; + } + else + { + osm_log( p_log, OSM_LOG_ERROR, + "osmt_trap_wait: 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, + "osmt_trap_wait: " + "Received the Report!\n"); + status = IB_SUCCESS; + } + else + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_trap_wait: 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, + "osmt_trap_wait: 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, osmt_run_inform_info_flow); + + /* 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, + "osmt_run_inform_info_flow:" + "Error during UnSubscribe: (%s)\n", + ib_get_err_str( status )); + goto Exit; + } + else + { + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_inform_info_flow:" + "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, + "osmt_run_inform_info_flow:" + "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, + "osmt_run_inform_info_flow:" + "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, + "osmt_run_inform_info_flow:" + "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, osmt_run_trap64_65_flow); + + /* 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, + "osmt_run_trap64_65_flow: ERR 0127: " + "Error posting recv bufs for trap 64\n"); + status = IB_ERROR; + goto Exit; + } + + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmt_run_trap64_65_flow: " + "Posted recv bufs for trap 64\n"); + + /* init the inform info */ + osmt_init_inform_info_by_trap(p_osmt, + cl_hton16(65), + &inform_info); + + /* send the inform info registration */ + status = osmt_reg_unreg_inform_info(p_osmt, + &qp_ctx, + &inform_info, + 1); + if (status != IB_SUCCESS) + { + goto Exit; + } + + /*--------------------- PREP -------------------------*/ + if (osmt_mtl_mad_post_recv_bufs( + &qp_ctx.qp_bind_hndl, + qp_ctx.p_recv_buf, + 1, /* we need to reveive the report */ + GRH_LEN + MAD_BLOCK_SIZE, + 1) != 1) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_trap64_65_flow: ERR 0127: " + "Error posting recv bufs for trap 65\n"); + status = IB_ERROR; + goto Exit; + } + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmt_run_trap64_65_flow: " + "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, + "osmt_run_trap64_65_flow:" + "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, + "osmt_run_trap64_65_flow:" + "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-1/ulp/opensm/user/osmtest/osmt_mtl_regular_qp.c b/branches/WOF2-1/ulp/opensm/user/osmtest/osmt_mtl_regular_qp.c new file mode 100644 index 00000000..e1f8c3cc --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/osmt_mtl_regular_qp.c @@ -0,0 +1,447 @@ +/* + * 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$ + */ + + +#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-1/ulp/opensm/user/osmtest/osmt_multicast.c b/branches/WOF2-1/ulp/opensm/user/osmtest/osmt_multicast.c new file mode 100644 index 00000000..7082e7d4 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/osmt_multicast.c @@ -0,0 +1,3500 @@ +/* + * 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: + * Implementation of Multicast Member testing flow.. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.2 $ + */ + +#ifndef __WIN__ +#include +#endif +#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, + "__osmt_print_all_multicast_records: 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, + "__osmt_print_all_multicast_records: 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, osmt_query_mcast ); + + /* + * 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, + "osmt_query_mcast: 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, + "osmt_query_mcast: 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, + "osmt_query_mcast: " + "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, + "osmt_query_mcast: " + "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 ) ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_query_mcast: ERR 0265: " + "MCG MGIDs are the same - invalid MGID : 0x%016" PRIx64 " 0x%016" + PRIx64 "\n", + cl_ntoh64(p_rec->mgid.unicast.prefix), + cl_ntoh64(p_rec->mgid.unicast.interface_id)); + 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, + "osmt_query_mcast: 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, + "osmt_query_mcast: 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, osmt_send_mcast_request ); + + /* + * 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, + "osmt_send_mcast_request: 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, + "osmt_send_mcast_request: 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, + "osmt_send_mcast_request: 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, + "osmt_send_mcast_request: 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, + "osmt_send_mcast_request: " + "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 ) { + ib_api_status_t status; + ib_member_rec_t mc_req_rec; + ib_member_rec_t *p_mc_res; + ib_sa_mad_t res_sa_mad; + uint64_t comp_mask = 0; + ib_net64_t remote_port_guid = 0x0; + cl_qmap_t *p_mgrp_mlid_tbl; + osmtest_mgrp_t *p_mgrp; + ib_gid_t special_mgid, tmp_mgid, proxy_mgid; + ib_net16_t invalid_mlid = 0x0; + ib_net16_t max_mlid = cl_hton16(0xFFFE), tmp_mlid; + boolean_t ReachedMlidLimit = FALSE; + int start_cnt = 0, cnt, middle_cnt = 0, end_cnt = 0; + int start_ipoib_cnt = 0, end_ipoib_cnt = 0; + int mcg_outside_test_cnt = 0, fail_to_delete_mcg = 0; + osmtest_req_context_t context; + ib_node_record_t *p_rec; + uint32_t num_recs = 0, i; + uint8_t mtu_phys = 0, rate_phys = 0; + cl_map_t test_created_mlids; /* List of all mlids created in this test */ + ib_member_rec_t* p_recvd_rec; + boolean_t got_error = FALSE; + + static ib_gid_t good_mgid = { + { + 0xFF, 0x12, 0xA0, 0x1C, + 0xFE, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x12, 0x34, 0x56, 0x78 + } + }; + static ib_gid_t osm_ipoib_mgid = { + { + 0xff, /* multicast field */ + 0x12, /* scope */ + 0x40, 0x1b, /* IPv4 signature */ + 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ + 0xff, 0xff, 0xff, 0xee, /* 32 bit IPv4 broadcast address */ + }, + }; + static ib_gid_t osm_ts_ipoib_good_mgid = { + { + 0xff, /* multicast field */ + 0x12, /* non-permanent bit,scope */ + 0x40, 0x1b, /* IPv4 signature */ + 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ + 0x00, 0x00, 0x00, 0x01, /* 32 bit IPv4 broadcast address */ + }, + }; + static ib_gid_t osm_ipoib_good_mgid = { + { + 0xff, /* multicast field */ + 0x12, /* non-permanent bit,scope */ + 0x40, 0x1b, /* IPv4 signature */ + 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ + 0xff, 0xff, 0xff, 0xff, /* 32 bit IPv4 broadcast address */ + }, + }; + static ib_gid_t osm_link_local_mgid = { + { + 0xFF, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01 + }, + }; + + OSM_LOG_ENTER( &p_osmt->log, osmt_run_mcast_flow ); + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "GetTable of all current MCGs...\n" + ); + status = osmt_query_mcast( p_osmt ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 2FF " + "GetTable of all records has failed!\n" ); + goto Exit; + } + + /* Initialize the test_created_mgrps map */ + cl_map_construct(&test_created_mlids); + cl_map_init(&test_created_mlids, 1000); + + p_mgrp_mlid_tbl = &p_osmt->exp_subn.mgrp_mlid_tbl; + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + /* Only when we are on single mode check flow - do the count comparison, otherwise skip */ + if (p_osmt->opt.mmode == 1 || p_osmt->opt.mmode == 3) + { + start_cnt = cl_qmap_count(p_mgrp_mlid_tbl); + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow (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, + "osmt_run_mcast_flow: " + "Non-IPoIB MC Groups exist: mgid=0x%016" PRIx64 ":0x%016" PRIx64 "\n", + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix), + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id) ); + mcg_outside_test_cnt++; + } + + p_mgrp = (osmtest_mgrp_t*)cl_qmap_next( &p_mgrp->map_item ); + } + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " + "Found IPoIB MC Group, so we run SilverStorm Bug Flow...\n" ); + /* Try to join first like IPoIB of SilverStorm */ + memcpy(&mc_req_rec.mgid,&osm_ipoib_good_mgid,sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_JOIN_STATE; + + status = osmt_send_mcast_request( + p_osmt, 0xff, /* User Defined query Set */ + &mc_req_rec, + comp_mask, + &res_sa_mad ); + + osm_log(&p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Joining an existing IPoIB multicast group\n"); + osm_log(&p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Sent Join request with :\n\t\tport_gid=0x%016"PRIx64 + ":0x%016" PRIx64 ", mgid=0x%016" PRIx64 ":0x%016" PRIx64 + "\n\t\tjoin state= 0x%x, response is : %s\n", + cl_ntoh64(mc_req_rec.port_gid.unicast.prefix), + cl_ntoh64(mc_req_rec.port_gid.unicast.interface_id), + cl_ntoh64(mc_req_rec.mgid.unicast.prefix), + cl_ntoh64(mc_req_rec.mgid.unicast.interface_id), + (mc_req_rec.scope_state & 0x0F), + ib_get_err_str(status)); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02B3: " + "Failed joining existing IPoIB MCGroup - got %s\n", + ib_get_err_str(status)); + goto Exit; + } + /* Check MTU & Rate Value and resend with SA suggested values */ + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + /* Prepare the mc_req_rec for the rest of the flow */ + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + /* + We simulate the same situation as in SilverStorm - a response with the + exact RATE & MTU as the SA responded with. Actually the query + has included some more fields but we know that problem was + genereated by the RATE + */ + osm_log(&p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " + "Sending attributes of MCG : \n\t\tMTU=0x%02X, RATE=0x%02X\n" + , mc_req_rec.mtu, mc_req_rec.rate); + status = osmt_send_mcast_request( p_osmt, 0xff, /* User Defined query */ + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log(&p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: ERR 02EF: " + "Query as Full Member of already existing ipoib group 0x%016" + PRIx64 ":0x%016" PRIx64 " has failed\n", + cl_ntoh64(mc_req_rec.mgid.unicast.prefix), + cl_ntoh64(mc_req_rec.mgid.unicast.interface_id)); + + 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, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 0xee, /* User Defined query Get */ + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status == IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow : 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, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 0xee, /* User Defined query Get */ + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status == IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow : 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, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + (( ib_net16_t ) (res_sa_mad.status & IB_SMP_STATUS_MASK )) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02EE: " + "Expectedd REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + (( ib_net16_t ) (res_sa_mad.status & IB_SMP_STATUS_MASK )) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02ED: " + "Expectedd REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + /* no MGID */ + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + + mc_req_rec.mgid.raw[15] = 0x01; + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + (( ib_net16_t ) (res_sa_mad.status & IB_SMP_STATUS_MASK )) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02EC: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + (( ib_net16_t ) (res_sa_mad.status & IB_SMP_STATUS_MASK )) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02EA: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + (( ib_net16_t ) (res_sa_mad.status & IB_SMP_STATUS_MASK )) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02E9: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* o15.0.1.8: */ + /* - Request join with irrelevant RATE : get a ERR_INSUFFICIENT_COMPONENTS */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0207: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Check Valid value which is unreasonable now */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0208: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Check Valid value which is unreasonable now */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02AB: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Checking above max value of MTU which is impossible */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02AC: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Checking below min value of MTU which is impossible */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02AD: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02AE: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + +#if 0 + /* Currently PacketLifeTime isn't checked in opensm */ + /* Check PacketLifeTime as 0 */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02AF: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } +#endif + + /* o15.0.1.4: */ + /* - Create an MGID by asking for a join with MGID = 0 */ + /* providing P_Key, Q_Key, SL, FlowLabel, Tclass. */ + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking Create given MGID=0 skip service level (o15.0.1.4)...\n" + ); + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + /* no MGID */ + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + /* IB_MCR_COMPMASK_SL | Intentionally missed */ + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | + IB_MCR_COMPMASK_RATE; + + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + (( ib_net16_t ) (res_sa_mad.status & IB_SMP_STATUS_MASK )) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02A8: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Check that no same MCG in the SMDB */ + status = osmt_query_mcast( p_osmt); + + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02AA: " + "Could not get all MC Records in subnet, got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + /* Only when we are on single mode check flow - do the count comparison, otherwise skip */ + if (p_osmt->opt.mmode == 1 || p_osmt->opt.mmode == 3) + { + middle_cnt = cl_qmap_count(&p_osmt->exp_subn.mgrp_mlid_tbl); + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow (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, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " + "Checking Create given MGID=0 skip Qkey and Pkey (o15.0.1.4)...\n" + ); + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + /* no MGID */ + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + /* IB_MCR_COMPMASK_QKEY | */ + /* IB_MCR_COMPMASK_PKEY | Intentionally missed */ + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | + IB_MCR_COMPMASK_RATE; + + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + (( ib_net16_t ) (res_sa_mad.status & IB_SMP_STATUS_MASK )) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02A7: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Bad Query o15.0.1.4 */ + + status = osmt_query_mcast( p_osmt); + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking Create given MGID=0 skip TClass (o15.0.1.4)...\n" + ); + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + /* no MGID */ + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + /* IB_MCR_COMPMASK_TCLASS | Intentionally missed */ + /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | + IB_MCR_COMPMASK_RATE; + + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR || + (( ib_net16_t ) (res_sa_mad.status & IB_SMP_STATUS_MASK )) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02A6: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking Create given MGID=0 valid Set several options :\n\t\t" + "First above min RATE, Second less than max RATE\n\t\t" + "Third above min MTU, Second less than max MTU\n\t\t" + "Fifth exact MTU & RATE feasible, Sixth exact RATE feasible\n\t\t" + "Seventh exact MTU feasible (o15.0.1.4)...\n" + ); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_1X | + IB_PATH_SELECTOR_GREATER_THAN << 6; + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | + IB_MCR_COMPMASK_RATE; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02A5: " + "Failed to create MCG for MGID=0 with higher than minimum RATE - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid )); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_12X | + IB_PATH_SELECTOR_LESS_THAN << 6; + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | + IB_MCR_COMPMASK_RATE; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0211: " + "Failed to create MCG for MGID=0 with less than highest RATE - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid )); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + + mc_req_rec.mtu = IB_MTU_LEN_4096 | + IB_PATH_SELECTOR_LESS_THAN << 6; + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | + IB_MCR_COMPMASK_MTU; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0238: " + "Failed to create MCG for MGID=0 with less than highest MTU - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid )); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + mc_req_rec.mtu = IB_MTU_LEN_256 | + IB_PATH_SELECTOR_GREATER_THAN << 6; + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | + IB_MCR_COMPMASK_MTU; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0239: " + "Failed to create MCG for MGID=0 with higher than lowest MTU - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid )); + cl_map_insert( &test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + /* Using Exact feasible MTU & RATE */ + + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Using Exact feasible MTU & RATE: " + "MTU = 0x%02X, RATE = 0x%02X\n", + mtu_phys, rate_phys ); + + mc_req_rec.mtu = mtu_phys; + mc_req_rec.rate = rate_phys; + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | + IB_MCR_COMPMASK_MTU | + IB_MCR_COMPMASK_RATE_SEL | + IB_MCR_COMPMASK_RATE; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0240: " + "Failed to create MCG for MGID=0 with exact MTU & RATE - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid )); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + /* Using Exact feasible RATE */ + + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Using Exact feasible RATE: 0x%02X\n", + rate_phys ); + + mc_req_rec.rate = rate_phys; + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | + IB_MCR_COMPMASK_RATE; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0241: " + "Failed to create MCG for MGID=0 with exact RATE - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid )); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + /* Using Exact feasible MTU */ + + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Using Exact feasible MTU: 0x%02X\n", + mtu_phys ); + + mc_req_rec.mtu = mtu_phys; + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | + IB_MCR_COMPMASK_MTU; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0242: " + "Failed to create MCG for MGID=0 with exact MTU - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid )); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + + /* o15.0.1.5: */ + /* - Check the returned MGID is valid. (p 804) */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: ERR 0209: " + "Validating MGID failed. MGID:0x%016" PRIx64 ":%016" PRIx64 "\n", + cl_ntoh64( p_mc_res->mgid.unicast.prefix ), + cl_ntoh64( p_mc_res->mgid.unicast.interface_id ) + ); + 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, + "osmt_run_mcast_flow: " + "Checking Create given MGID=0 (o15.0.1.4)...\n" + ); + + status = osmt_query_mcast(p_osmt); + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + /* no MGID */ + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + mc_req_rec.pkt_life = 0 | IB_PATH_SELECTOR_GREATER_THAN << 6; + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_LIFE | + IB_MCR_COMPMASK_LIFE_SEL; + + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0210: " + "Failed to create MCG for MGID=0 - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid )); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + + /* o15.0.1.6: */ + /* - Create a new MCG with valid requested MGID. */ + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + mc_req_rec.mgid = good_mgid; + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking Create given valid MGID=0x%016" PRIx64 " : " + "0x%016" PRIx64 " (o15.0.1.6)...\n", + cl_ntoh64(mc_req_rec.mgid.unicast.prefix), + cl_ntoh64(mc_req_rec.mgid.unicast.interface_id)); + + /* Before creation, need to check that this group doesn't exist */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, /* join */ + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0301: " + "Tried joining group that shouldn't have existed - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Set State to full member to allow group creation */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Now creating group with given valid MGID=0x%016" PRIx64 " : " + "0x%016" PRIx64 " (o15.0.1.6)...\n", + cl_ntoh64(mc_req_rec.mgid.unicast.prefix), + cl_ntoh64(mc_req_rec.mgid.unicast.interface_id)); + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0211: " + "Failed to create MCG for MGID=0x%016" PRIx64 " : " + "0x%016" PRIx64 " (o15.0.1.6) - got %s/%s\n", + cl_ntoh64(good_mgid.unicast.prefix), + cl_ntoh64(good_mgid.unicast.interface_id), + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad)) ); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid )); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: ERR 0212: " + "Validating MGID failed. MGID:0x%016" PRIx64 ":%016" PRIx64 "\n", + cl_ntoh64( p_mc_res->mgid.unicast.prefix ), + cl_ntoh64( p_mc_res->mgid.unicast.interface_id ) + ); + 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, + "osmt_run_mcast_flow: " + "Checking BAD MGID=0xFA..... (o15.0.1.6)...\n" + ); + + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + + mc_req_rec.mgid.raw[0] = 0xFA; + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0213: " + "Failed to recognize MGID error for MGID=0xFA - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* - Try again with MGID prefix = 0xA01B (maybe 0x1BA0 little or big ?) */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0214: " + "Failed to recognize MGID error for A01B with link-local bit (status %s) (rem status %s)\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Change the mgid prefix - get back ERR_REQ_INVALID */ + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0215: " + "Failed to recognize MGID PREFIX error for MGID=0xEF - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Change the scope to reserved - get back VALID REQ */ + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking local scope with full member \n\t\tand valid mgid 0x%016" + PRIx64 ":0x%016" PRIx64 " ... (o15.0.1.6)...\n", + cl_ntoh64(mc_req_rec.mgid.unicast.prefix), + cl_ntoh64(mc_req_rec.mgid.unicast.interface_id)); + + mc_req_rec.mgid = good_mgid; + + mc_req_rec.mgid.raw[1] = 0x1F; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0216: " + "Failed to create MCG for MGID=0x%016" PRIx64 " : " + "0x%016" PRIx64 " - got %s/%s\n", + cl_ntoh64(good_mgid.unicast.prefix), + cl_ntoh64(good_mgid.unicast.interface_id), + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) ); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid )); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + + /* Change the flags to invalid value 0x2 - get back INVALID REQ */ + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking invalid flags=0xFF 22 ... (o15.0.1.6)...\n" + ); + + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + + mc_req_rec.mgid = good_mgid; + + mc_req_rec.mgid.raw[1] = 0x22; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0217: " + "Failed to recognize create with invalid flags value 0x2 - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Change the MGID to link local MGID - get back VALID REQ */ + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking link local MGID 0xFF02:0:0:0:0:0:0:1 (o15.0.1.6)...\n" + ); + + mc_req_rec.mgid = osm_link_local_mgid; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0218: " + "Failed to create MCG for MGID=0xFF02:0:0:0:0:0:0:1 - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid )); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + + /* o15.0.1.7 - implicitlly checked during the prev steps. */ + /* o15.0.1.8 - implicitlly checked during the prev steps. */ + + /* o15.0.1.9 */ + /* - Create MCG with Invalid JoinState.FullMember != 1 : get ERR_REQ_INVALID */ + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking new MGID with invalid join state (o15.0.1.9)...\n" + ); + + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + + mc_req_rec.mgid = good_mgid; + mc_req_rec.mgid.raw[12] = 0xFF; + mc_req_rec.scope_state = 0x22; /* link-local scope, non-member state */ + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0219: " + "Failed to recognize create with JoinState != FullMember - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Lets try a valid join scope state */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking new MGID with valid join state (o15.0.1.9)...\n" + ); + + mc_req_rec.mgid = good_mgid; + mc_req_rec.scope_state = 0x23; /* link-local scope, non member and full member */ + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0220: " + "Failed to create MCG with valid join state 0x3 - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid ) ); + cl_map_insert( &test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + + /* Lets try another invalid join scope state */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking new MGID with invalid join state (o15.0.1.9)...\n" + ); + + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + + /* We have created a new MCG so now we need different mgid when cresting group otherwise it will be counted as join request .*/ + mc_req_rec.mgid = good_mgid; + mc_req_rec.mgid.raw[12] = 0xFC; + + mc_req_rec.scope_state = 0x24; /* link-local scope, send only member */ + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0221: " + "Failed to recognize create with JoinState != FullMember - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Lets try another valid join scope state */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking new MGID creation with valid join state (o15.0.1.9)...\n" + ); + + mc_req_rec.mgid = good_mgid; + mc_req_rec.mgid.raw[12] = 0xFB; + memcpy(&special_mgid, &mc_req_rec.mgid, sizeof(ib_gid_t)); + mc_req_rec.scope_state = 0x2F; /* link-local scope, Full member with all other bits turned on */ + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0222: " + "Failed to create MCG with valid join state 0xF - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow: " + "Created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid )); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + + /* o15.0.1.10 - can't check on a single client .-- obsolete - + checked by SilverStorm bug o15-0.2.4, never the less recheck */ + /* o15-0.2.4 - Check a join request to already created MCG */ + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, /* User Defined query */ + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02CC: " + "Failed to join MCG with valid req, returned status = %s\n", + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) )); + goto Exit; + } + + /* 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, + "osmt_run_mcast_flow: " + "Checking Retry of existing MGID - See JoinState update (o15.0.1.11)...\n" + ); + + mc_req_rec.mgid = good_mgid; + mc_req_rec.scope_state = 0x22; /* link-local scope, send only member */ + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02CD: " + "Failed to update existing MGID - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: 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, + "osmt_run_mcast_flow: " + "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; + /* link-local scope, non member (so we should not be able to delete) */ + /* but the FullMember bit should be gone */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking Partially delete JoinState (o15.0.1.14)...\n" + ); + mc_req_rec.scope_state = 0x22; + status = osmt_send_mcast_request( p_osmt, 0, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if ((status != IB_SUCCESS) || (p_mc_res->scope_state != 0x21)) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02CF: " + "Failed to partially update JoinState : %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* So far successfully delete state - Now change it */ + mc_req_rec.mgid = good_mgid; + mc_req_rec.scope_state = 0x24; /* link-local scope, send only member */ + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02C0: " + "Failed to update existing MCG - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: ERR 02C1: " + "Validating JoinState update failed. Expected 0x25 got: 0x%02X\n", + p_mc_res->scope_state + ); + status = IB_ERROR; + goto Exit; + } + /* Now try to update value of join state */ + mc_req_rec.scope_state = 0x21; /* link-local scope, full member */ + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02C2: " + "Failed to update existing MGID - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: ERR 02C3: " + "Validating JoinState update failed. Expected 0x25 got: 0x%02X\n", + p_mc_res->scope_state + ); + status = IB_ERROR; + goto Exit; + } + + /* Now try to update value of join state */ + mc_req_rec.scope_state = 0x22; /* link-local scope,non member */ + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02C4: " + "Failed to update existing MGID - got %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + goto Exit; + } + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: 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, + "osmt_run_mcast_flow: " + "Checking BAD RATE when connecting to existing MGID (o15.0.1.13)...\n" + ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + + mc_req_rec.mgid = good_mgid; + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_1X | + IB_PATH_SELECTOR_LESS_THAN << 6; + comp_mask = + IB_MCR_COMPMASK_GID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | + IB_MCR_COMPMASK_RATE; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02C6: " + "Failed to catch BAD RATE joining an exiting MGID: %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Try MTU that does not exist in any MCG */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking BAD MTU (higher them max) when connecting to " + "existing MGID (o15.0.1.13)...\n" + ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + + mc_req_rec.mgid = osm_ipoib_mgid; + mc_req_rec.mtu = + IB_MTU_LEN_4096 | + IB_PATH_SELECTOR_GREATER_THAN << 6; + comp_mask = + IB_MCR_COMPMASK_GID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | + IB_MCR_COMPMASK_MTU; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02C7: " + "Failed to catch BAD RATE (higher them max) joining an exiting MGID: %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Try another MTU that does not exist in any MCG */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking BAD MTU (less than min) when connecting " + "to existing MGID (o15.0.1.13)...\n" + ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + + mc_req_rec.mgid = osm_ipoib_mgid; + mc_req_rec.mtu = + IB_MTU_LEN_256 | + IB_PATH_SELECTOR_LESS_THAN << 6; + comp_mask = + IB_MCR_COMPMASK_GID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | + IB_MCR_COMPMASK_MTU; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02C8: " + "Failed to catch BAD RATE (less them min) joining an exiting MGID: %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* o15.0.1.14: */ + /* - Try partial delete - actually updating the join state. check it. */ + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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 FullMember bit should be gone */ + mc_req_rec.scope_state = 0x22; + + status = osmt_send_mcast_request( p_osmt, 0, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02C9: " + "Fail to partially update JoinState during delete: %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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 non member & send only member have left */ + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02CA: " + "Validating JoinState update failed. Expected 0x25 got: 0x%02X\n", + p_mc_res->scope_state + ); + status = IB_ERROR; + goto Exit; + } + + /* Now use the same scope_state and delete all JoinState - leave multicast group since state is 0x0 */ + + mc_req_rec.scope_state = 0x25; + status = osmt_send_mcast_request( p_osmt, 0, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02CB: " + "Failed to update JoinState during delete: %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: 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, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, /* join */ + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status != IB_REMOTE_ERROR) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02BC: " + "Succeeded Joining Deleted Group: %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* - Try deletion of the IPoIB MCG and get: ERR_REQ_INVALID */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking BAD Delete of Mgid membership (no prev join) (o15.0.1.15)...\n" + ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + + mc_req_rec.mgid = osm_ipoib_mgid; + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_1X | + IB_PATH_SELECTOR_GREATER_THAN << 6; + mc_req_rec.scope_state = 0x21; /* delete full member */ + + status = osmt_send_mcast_request( p_osmt, 0, /* delete flag */ + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02BD: " + "Failed to catch BAD delete from IPoIB: %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* Prepare another MCG for the following tests : */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking Create given MGID=0x%016" PRIx64 " : " + "0x%016" PRIx64 "\n\t\t(o15.0.1.4)...\n", + cl_ntoh64(osm_ipoib_mgid.unicast.prefix), + cl_ntoh64(osm_ipoib_mgid.unicast.interface_id) ); + + mc_req_rec.mgid = good_mgid; + mc_req_rec.mgid.raw[12] = 0xAA; + mc_req_rec.pkt_life = 0 | IB_PATH_SELECTOR_GREATER_THAN << 6; + mc_req_rec.scope_state = 0x21; /* Full memeber */ + comp_mask = + IB_MCR_COMPMASK_GID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_LIFE | + IB_MCR_COMPMASK_LIFE_SEL; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02BE: " + "Failed to create MCG for 0x%016" PRIx64 " : " + "0x%016" PRIx64 " - got %s/%s\n", + cl_ntoh64(good_mgid.unicast.prefix), + cl_ntoh64(good_mgid.unicast.interface_id), + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) ); + goto Exit; + } + + /* - Try delete with valid join state */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking Full Delete of a group (o15.0.1.14)...\n" + ); + mc_req_rec.scope_state = 0x21; /* the FullMember is the current JoinState */ + status = osmt_send_mcast_request( p_osmt, 0, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + + if (status != IB_SUCCESS) + { + goto Exit; + } + + /* o15.0.1.15: */ + /* - Try deletion of the IPoIB MCG and get: ERR_REQ_INVALID */ + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking BAD Delete of IPoIB membership (no prev join) (o15.0.1.15)...\n" + ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + + mc_req_rec.mgid = osm_ipoib_mgid; + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_1X | + IB_PATH_SELECTOR_GREATER_THAN << 6; + mc_req_rec.scope_state = 0x21; /* delete full member */ + + status = osmt_send_mcast_request( p_osmt, 0, /* delete flag */ + &mc_req_rec, + comp_mask, + &res_sa_mad ); + + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 0223: " + "Failed to catch BAD delete from IPoIB: %s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /**************************************************************************/ + /* Checking join with invalid MTU */ + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Checking Join with unrealistic mtu : \n" + "\t\tFirst create new MCG than try to join it \n" + "\t\twith unrealistic MTU greater than 4096 (o15.0.1.8)...\n" + ); + + /* First create new mgrp */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + mc_req_rec.mtu = IB_MTU_LEN_1024 | IB_PATH_SELECTOR_EXACTLY << 6; + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | + IB_MCR_COMPMASK_MTU; + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: 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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status == IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02E4: " + "Expected REMOTE ERROR got:%s/%s\n", + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) + ); + status = IB_ERROR; + goto Exit; + } + + /* - Try GetTable with PortGUID wildcarded and get back some groups. */ + status = osmt_query_mcast( p_osmt); + cnt = cl_qmap_count(&p_osmt->exp_subn.mgrp_mlid_tbl); + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow (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, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: 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, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " + "remote port_guid = 0x%" PRIx64 "\n", + cl_ntoh64(p_rec->node_info.port_guid) ); + + remote_port_guid = p_rec->node_info.port_guid; + i = num_recs; + break; + } + } + + if (remote_port_guid != 0x0) + { + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + mc_req_rec.port_gid.unicast.interface_id = remote_port_guid; + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS; /* all above are required */ + + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + + + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02B4: " + "Could not join on behalf of remote port 0x%016" PRIx64 + " remote status: %s\n", + cl_ntoh64(remote_port_guid), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) ); + status = IB_ERROR; + goto Exit; + } + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + memcpy(&proxy_mgid,&p_mc_res->mgid,sizeof(ib_gid_t)); + + /* First try a bad deletion then good one */ + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_START "\n" ); + + status = osmt_send_mcast_request( p_osmt, 0, /* delete flag */ + &mc_req_rec, + comp_mask, + &res_sa_mad ); + + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: " EXPECTING_ERRORS_END "\n" ); + + if (status == IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02A9: " + "Successful deletion of remote port guid with local one MGID : " + "0x%016" PRIx64 " : 0x%016" PRIx64 ", Got : %s/%s\n", + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix), + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id), + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) ); + status = IB_ERROR; + goto Exit; + } + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Trying deletion of remote port with the right port guid\n" ); + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + mc_req_rec.mgid = proxy_mgid; + mc_req_rec.port_gid.unicast.interface_id = remote_port_guid; + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_JOIN_STATE; + status = osmt_send_mcast_request( p_osmt, 0, /* delete flag */ + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02B0: " + "Failed to delete mgid with remote port guid MGID : " + "0x%016" PRIx64 " : 0x%016" PRIx64 ", Got : %s/%s\n", + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix), + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id), + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) ); + goto Exit; + } + } + else + { + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " + "Checking Creation of Maximum avaliable Groups (MulticastFDBCap)...\n" + ); + tmp_mlid = cl_ntoh16(max_mlid) - cnt; + + while (tmp_mlid > 0 && !ReachedMlidLimit) { + uint16_t cur_mlid = 0; + + /* Request Set */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + /* Good Flow - mgid is 0 while giving all required fields for + join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_1X | + IB_PATH_SELECTOR_GREATER_THAN << 6; + mc_req_rec.mlid = max_mlid; + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MLID; + status = osmt_send_mcast_request( p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad ); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + if (status != IB_SUCCESS) + { + + if (cur_mlid > cl_ntoh16(max_mlid)) + { + + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow : ERR 2E1 " + "Successful Join with greater mlid than switches support (MulticastFDBCap) 0x%04X\n", + cur_mlid ); + status = IB_ERROR; + osm_dump_mc_record( &p_osmt->log, p_mc_res, OSM_LOG_VERBOSE ); + goto Exit; + } else if (( res_sa_mad.status & IB_SMP_STATUS_MASK ) == IB_SA_MAD_STATUS_NO_RESOURCES) { + /* You can quitly exit the loop since no available mlid in SA DB + i.e. reached the maximum valiad avalable mlid */ + ReachedMlidLimit = TRUE; + } + } + else + { + cur_mlid = cl_ntoh16(p_mc_res->mlid); + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = (ib_member_rec_t*)ib_sa_mad_get_payload_ptr( &res_sa_mad ); + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_run_mcast_flow : " + "Created MGID:0x%016" PRIx64 " : " + "0x%016" PRIx64 " MLID:0x%04X\n", + cl_ntoh64( p_recvd_rec->mgid.unicast.prefix ), + cl_ntoh64( p_recvd_rec->mgid.unicast.interface_id ), + cl_ntoh16( p_recvd_rec->mlid )); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), p_recvd_rec ); + } + tmp_mlid--; + } + } + + /* Prepare the mc_req_rec for the rest of the flow */ + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + /**************************************************************************/ + /* o15.0.1.16: */ + /* - Try GetTable with PortGUID wildcarded and get back some groups. */ + + status = osmt_query_mcast( p_osmt); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: 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, + "osmt_run_mcast_flow (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, + "osmt_run_mcast_flow : " + "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, + "osmt_run_mcast_flow : " + "Sending request to delete MGID : 0x%016" PRIx64 + " : 0x%016" PRIx64 ", scope_state : 0x%02X\n", + cl_ntoh64(mc_req_rec.mgid.unicast.prefix), + cl_ntoh64(mc_req_rec.mgid.unicast.interface_id), + mc_req_rec.scope_state ); + status = osmt_send_mcast_request( p_osmt, 0, /* delete flag */ + &mc_req_rec, + comp_mask, + &res_sa_mad ); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: ERR 02FF: " + "Failed to delete MGID : 0x%016" PRIx64 " : 0x%016" PRIx64 + " ,\n\t\t it is not our MCG, Status : %s/%s\n", + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix), + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id), + ib_get_err_str( status ), + ib_get_mad_status_str( (ib_mad_t*)(&res_sa_mad) ) ); + fail_to_delete_mcg++; + } + } + else + { + end_ipoib_cnt++; + } + p_mgrp = (osmtest_mgrp_t*)cl_qmap_next( &p_mgrp->map_item ); + } + + status = osmt_query_mcast( p_osmt); + + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_mcast_flow: 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, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: " + "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, + "osmt_run_mcast_flow: ERR 02FE: " + "Wasn't able to erase mgrp with MGID:0x%016" PRIx64 " : 0x%016" + PRIx64 " MLID:0x%04X\n", + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix), + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id), + mlid ); + got_error = TRUE; + } + else + { + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_run_mcast_flow: " + "Still exists %s MGID:0x%016" PRIx64 " : 0x%016" PRIx64 "\n", + (IS_IPOIB_MGID(&p_mgrp->mcmember_rec.mgid)) ? "IPoIB" : "non-IPoIB", + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix), + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id) ); + } + 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-1/ulp/opensm/user/osmtest/osmt_service.c b/branches/WOF2-1/ulp/opensm/user/osmtest/osmt_service.c new file mode 100644 index 00000000..4325ed5d --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/osmt_service.c @@ -0,0 +1,1833 @@ +/* + * 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: + * 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 + * + * Environment: + * Linux User Mode + * + * $Revision: 1.1 $ + */ + +#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, osmt_register_service ); + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_register_service: " + "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, + "osmt_register_service: 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, + "osmt_register_service: 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, + "osmt_register_service: " + "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, osmt_register_service_with_full_key ); + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_register_service_with_full_key: " + "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, + "osmt_register_service_with_full_key: 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, + "osmt_register_service_with_full_key: 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, + "osmt_register_service_with_full_key: " + "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, + "osmt_register_service_with_full_key: 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, osmt_register_service_with_data ); + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_register_service_with_data: " + "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, + "osmt_register_service_with_data:" + "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, + "osmt_register_service_with_data: 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, + "osmt_register_service_with_data: 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, + "osmt_register_service_with_data: " + "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, + "osmt_register_service_with_data: " + "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, osmt_get_service_by_id ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_get_service_by_id_and_name: " + "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, + "osmt_get_service_by_id_and_name: 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, + "osmt_get_service_by_id_and_name: " + "IS EXPECTED ERROR ^^^^\n"); + status = IB_SUCCESS; + } + else + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_get_service_by_id_and_name: 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, + "osmt_get_service_by_id_and_name: " + "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, + "osmt_get_service_by_id_and_name: " + "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, + "osmt_get_service_by_id_and_name: " + "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, osmt_get_service_by_id ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_get_service_by_id: " + "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, + "osmt_get_service_by_id: 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, + "osmt_get_service_by_id: " + "IS EXPECTED ERROR ^^^^\n"); + status = IB_SUCCESS; + } + else + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_get_service_by_id: 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, + "osmt_get_service_by_id: 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, + "osmt_get_service_by_id: " + "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, + "osmt_get_service_by_id: " + "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, osmt_get_service_by_name_and_key ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + char buf_service_key[33]; + + sprintf(buf_service_key, + "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + 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]); + + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_get_service_by_name_and_key: " + "Getting service record: name: %s and key: %s\n", + sr_name, buf_service_key ); + } + + /* + * 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, + "osmt_get_service_by_name_and_key: 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, + "osmt_get_service_by_name_and_key: " + "IS EXPECTED ERROR ^^^^\n"); + status = IB_SUCCESS; + } + else + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_get_service_by_name_and_key: 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, + "osmt_get_service_by_name_and_key: " + "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, + "osmt_get_service_by_name_and_key: " + "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, + "osmt_get_service_by_name_and_key: " + "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, osmt_get_service_by_name ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_get_service_by_name: " + "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, + "osmt_get_service_by_name: 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, + "osmt_get_service_by_name: " + "IS EXPECTED ERROR ^^^^\n"); + status = IB_SUCCESS; + } + else + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_get_service_by_name: 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, + "osmt_get_service_by_name: 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, + "osmt_get_service_by_name: " + "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, + "osmt_get_service_by_name: " + "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, osmt_get_all_services_and_check_names ); + + /* 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; + } + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_get_all_services_and_check_names: " + "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, + "osmt_get_all_services_and_check_names: 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, + "osmt_get_all_services_and_check_names: 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, + "osmt_get_all_services_and_check_names: " + "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, + "osmt_get_all_services_and_check_names: " + "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, + "osmt_get_all_services_and_check_names: " + "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, + "osmt_get_all_services_and_check_names: " + "-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, + "osmt_get_all_services_and_check_names: " + "-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, + "osmt_get_all_services_and_check_names: 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, osmt_delete_service_by_name); + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_delete_service_by_name: " + "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, + "osmt_delete_service_by_name: 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, + "osmt_delete_service_by_name: 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, + "osmt_delete_service_by_name: 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, + "osmt_delete_service_by_name: 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, + "osmt_delete_service_by_name: 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, + "osmt_run_service_records_flow: " + "IS EXPECTED ERROR ^^^^\n"); + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmt_delete_service_by_name: " + "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, osmt_run_service_records_flow); + + /* Init Service names */ + for (i = 0; i <= 6; 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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[7] */ + status = osmt_get_service_by_id(p_osmt, 0, cl_ntoh64(id[7]), &srv_rec); + if (status != IB_SUCCESS) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmt_run_service_records_flow: ERR 4A20: " + "Found service: id: 0x%016" PRIx64 " " + "that is invalid\n", + id[7] ); + 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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, + "osmt_run_service_records_flow: 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-1/ulp/opensm/user/osmtest/osmt_slvl_vl_arb.c b/branches/WOF2-1/ulp/opensm/user/osmtest/osmt_slvl_vl_arb.c new file mode 100644 index 00000000..45fe4916 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/osmt_slvl_vl_arb.c @@ -0,0 +1,570 @@ +/* + * 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: + * 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 + * + * Environment: + * Linux User Mode + * + * $Revision: 1.2 $ + */ + +#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, osmtest_write_vl_arb_table ); + + 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, osmt_query_vl_arb ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmt_query_vl_arb: " + "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, + "osmt_query_vl_arb: 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, + "osmt_query_vl_arb: 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, + "osmt_query_vl_arb: " + "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, osmt_query_all_ports_vl_arb ); + + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_query_all_ports_vl_arb: " + "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, + "osmt_query_all_ports_vl_arb: 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, + "osmt_query_all_ports_vl_arb: 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, osmtest_write_slvl_map_table ); + + 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, osmt_query_slvl_map ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmt_query_slvl_map: " + "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, + "osmt_query_slvl_map: 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, + "osmt_query_slvl_map: 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, + "osmt_query_slvl_map: " + "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, osmt_query_all_ports_slvl_map ); + + /* + * Go over all ports that exist in the subnet + * get the relevant SLtoVLs + */ + + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmt_query_all_ports_slvl_map: " + "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, + "osmt_query_all_ports_slvl_map: 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, + "osmt_query_all_ports_slvl_map: 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, + "osmt_query_all_ports_slvl_map: 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, osmt_run_slvl_and_vlarb_records_flow ); + + 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-1/ulp/opensm/user/osmtest/osmtest.c b/branches/WOF2-1/ulp/opensm/user/osmtest/osmtest.c new file mode 100644 index 00000000..f889dc58 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/osmtest/osmtest.c @@ -0,0 +1,7489 @@ +/* + * 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$ + */ + + +/* 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.10 $ + */ + +#ifdef __WIN__ +#pragma warning(disable : 4996) +#endif + +#include +#include +#include +#ifdef __WIN__ +#include +#else +#include +#include +#endif +#include +#include "osmtest.h" + +#ifndef __WIN__ +#define strnicmp strncasecmp +#endif + +#define POOL_MIN_ITEMS 64 +#define GUID_ARRAY_SIZE 64 + +typedef 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 we bypass the vendor deletion + Since it's already 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, + "osmtest_init: [\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, + "osmtest_init: 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, &p_osmt->log ); + if( status != IB_SUCCESS ) + goto Exit; + + Exit: + osm_log( &p_osmt->log, OSM_LOG_FUNCS, + "osmtest_init: ]\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, osmtest_query_res_cb ); + + p_ctxt->result = *p_rec; + + if( p_rec->status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_query_res_cb: 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, osmtest_get_all_recs ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_get_all_recs: " + "Getting all %s records\n", ib_get_sa_attr_str( attr_id ) ); + } + + /* + * Do a blocking query for all records in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset( &req, 0, sizeof( req ) ); + memset( &user, 0, sizeof( user ) ); + + p_context->p_osmt = p_osmt; + user.attr_id = attr_id; + user.attr_offset = cl_ntoh16( ( uint16_t ) ( attr_size >> 3 ) ); + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa( p_osmt->h_bind, &req ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_all_recs: 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, + "osmtest_get_all_recs: 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, + "osmtest_get_all_recs: " + "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, osmtest_validate_sa_class_port_info ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_validate_sa_class_port_info: " + "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, + "osmtest_validate_sa_class_port_info: 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, + "osmtest_validate_sa_class_port_info: 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, + "osmtest_validate_sa_class_port_info: " + "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, + "osmtest_validate_sa_class_port_info:\n-----------------------------\nSA Class Port Info:\n" + " base_ver:%u\n class_ver:%u\n cap_mask:0x%X\n resp_time_val:0x%X\n-----------------------------\n", + p_cpi->base_ver, p_cpi->class_ver, cl_ntoh16(p_cpi->cap_mask), p_cpi->cap_mask2_resp_time + ); + + 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, osmtest_get_node_rec ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_get_node_rec: " + "Getting node record for 0x%016" PRIx64 "\n", + cl_ntoh64( node_guid ) ); + } + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset( &req, 0, sizeof( req ) ); + memset( &user, 0, sizeof( user ) ); + memset( &record, 0, sizeof( record ) ); + + record.node_info.node_guid = node_guid; + + p_context->p_osmt = p_osmt; + user.comp_mask = IB_NR_COMPMASK_NODEGUID; + user.attr_id = IB_MAD_ATTR_NODE_RECORD; + user.attr_offset = cl_ntoh16( ( uint16_t ) ( sizeof( record ) >> 3 ) ); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa( p_osmt->h_bind, &req ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_node_rec: 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, + "osmtest_get_node_rec: 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, + "osmtest_get_node_rec: " + "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, osmtest_get_node_rec_by_lid ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_get_node_rec_by_lid: " + "Getting node record for LID 0x%02X\n", + cl_ntoh16( lid ) ); + } + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset( &req, 0, sizeof( req ) ); + memset( &user, 0, sizeof( user ) ); + memset( &record, 0, sizeof( record ) ); + + record.lid = lid; + + p_context->p_osmt = p_osmt; + user.comp_mask = IB_NR_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_NODE_RECORD; + user.attr_offset = cl_ntoh16( ( uint16_t ) ( sizeof( record ) >> 3 ) ); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa( p_osmt->h_bind, &req ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_node_rec_by_lid: 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, + "osmtest_get_node_rec_by_lid: 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, + "osmtest_get_node_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 ); +} + +/********************************************************************** + **********************************************************************/ +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, osmtest_get_path_rec_by_guid_pair); + + 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, + "osmtest_get_path_rec_by_guid_pair: " + "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, + "osmtest_get_path_rec_by_guid_pair: 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, + "osmtest_get_path_rec_by_guid_pair: 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, + "osmtest_get_path_rec_by_guid_pair: " + "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, osmtest_get_path_rec_by_gid_pair); + + 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, + "osmtest_get_path_rec_by_gid_pair: " + "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, + "osmtest_get_path_rec_by_gid_pair: 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, + "osmtest_get_path_rec_by_gid_pair: 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, + "osmtest_get_path_rec_by_gid_pair: " + "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, osmtest_get_multipath_rec ); + + /* + * 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, + "osmtest_get_multipath_rec: 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, + "osmtest_get_multipath_rec: 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, + "osmtest_get_multipath_rec: " + "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, osmtest_get_port_rec ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_get_port_rec: " + "Getting PortInfoRecord for port with LID 0x%X\n", + cl_ntoh16( lid ) ); + } + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset( &req, 0, sizeof( req ) ); + memset( &user, 0, sizeof( user ) ); + memset( &record, 0, sizeof( record ) ); + + record.lid = lid; + + p_context->p_osmt = p_osmt; + user.comp_mask = IB_PIR_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_PORTINFO_RECORD; + user.attr_offset = cl_ntoh16( ( uint16_t ) ( sizeof( record ) >> 3 ) ); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa( p_osmt->h_bind, &req ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_port_rec: 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, + "osmtest_get_port_rec: 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, + "osmtest_get_port_rec: " + "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, osmtest_get_port_rec_by_num ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_get_port_rec_by_num: " + "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, + "osmtest_get_port_rec_by_num: 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, + "osmtest_get_port_rec_by_num: 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, + "osmtest_get_port_rec_by_num: " + "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, osmtest_stress_port_recs_large ); + + 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, + "osmtest_stress_port_recs_large: 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, + "osmtest_stress_port_recs_large: " + "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, osmtest_stress_node_recs_large ); + + 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, + "osmtest_stress_node_recs_large: 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, + "osmtest_stress_node_recs_large: " + "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, osmtest_stress_path_recs_large ); + + 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, + "osmtest_stress_path_recs_large: 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, + "osmtest_stress_path_recs_large: " + "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, osmtest_stress_path_recs_by_guid ); + + 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, + "osmtest_stress_path_recs_by_guid:" + "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, + "osmtest_stress_path_recs_by_guid: 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; + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_stress_path_recs_by_guid: " + "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, osmtest_stress_port_recs_small ); + + 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, + "osmtest_stress_port_recs_small: 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, + "osmtest_stress_port_recs_small: " + "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, osmtest_get_local_port_lmc ); + + 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, + "osmtest_get_local_port_lmc: ERR 001A: " + "osmtest_get_port_rec failed (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + + num_recs = context.result.result_cnt; + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_get_local_port_lmc: " + "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, + "osmtest_get_local_port_lmc: " + "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, osmtest_wrong_sm_key_ignored ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_INFO ) ) + { + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmtest_wrong_sm_key_ignored: " + "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, + "osmtest_wrong_sm_key_ignored: " EXPECTING_ERRORS_START "\n" ); + status = osmv_query_sa( p_osmt->h_bind, &req ); + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_wrong_sm_key_ignored: " 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, + "osmtest_wrong_sm_key_ignored: 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, osmtest_write_port_info ); + + 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, + "osmtest_write_port_info: 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, osmtest_write_path_info ); + + 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" + "# 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 ), + p_rec->qos_class_sl, + p_rec->mtu, p_rec->rate, p_rec->pkt_life, + p_rec->preference ); + + if( result < 0 ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_write_path_info: 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, osmtest_write_node_info ); + + 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, + "osmtest_write_node_info: 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, osmtest_write_link ); + + 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, + "osmtest_write_link: 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, osmtest_write_all_link_recs ); + + 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, + "osmtest_write_all_link_recs: 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; + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_write_all_link_recs: " + "Received %zu records\n", num_recs ); + } + + result = fprintf( fh, "#\n" "# Link Records\n" "#\n" ); + if( result < 0 ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_write_all_link_recs: 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, osmtest_get_path_rec_by_lid_pair ); + + 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, + "osmtest_get_path_rec_by_lid_pair: " + "Query for path from 0x%X to 0x%X\n", + slid,dlid ); + status = osmv_query_sa( p_osmt->h_bind, &req ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_path_rec_by_lid_pair: 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, + "osmtest_get_path_rec_by_lid_pair: 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, + "osmtest_get_path_rec_by_lid_pair: " + "Remote error = %s\n", + ib_get_mad_status_str( osm_madw_get_mad_ptr + ( (*p_context).result.p_result_madw ) ) ); + } + goto Exit; + } + + Exit: + OSM_LOG_EXIT( &p_osmt->log ); + return ( status ); +} + +#ifdef VENDOR_RMPP_SUPPORT +/********************************************************************** + * ASSUMES RMPP + **********************************************************************/ +static ib_api_status_t +osmtest_write_all_node_recs( IN osmtest_t * const p_osmt, + IN FILE * fh ) +{ + osmtest_req_context_t context; + const ib_node_record_t *p_rec; + uint32_t i; + cl_status_t status; + size_t num_recs; + int result; + + OSM_LOG_ENTER( &p_osmt->log, osmtest_write_all_node_recs ); + + 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, + "osmtest_write_all_node_recs: 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; + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_write_all_node_recs: " + "Received %zu records\n", num_recs ); + } + + result = fprintf( fh, "#\n" "# Node Records\n" "#\n" ); + if( result < 0 ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_write_all_node_recs: 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, osmtest_write_all_port_recs ); + + 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, + "osmtest_write_all_port_recs: 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; + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_write_all_port_recs: " + "Received %zu records\n", num_recs ); + } + + result = fprintf( fh, "#\n" "# PortInfo Records\n" "#\n" ); + if( result < 0 ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_write_all_port_recs: 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, osmtest_write_all_path_recs ); + + 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, + "osmtest_write_all_path_recs: 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; + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_write_all_path_recs: " + "Received %zu records\n", num_recs ); + } + + result = fprintf( fh, "#\n" "# Path Records\n" "#\n" ); + if( result < 0 ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_write_all_path_recs: ERR 0026: " + "Write failed\n" ); + status = IB_ERROR; + goto Exit; + } + + for( i = 0; i < num_recs; i++ ) + { + p_rec = osmv_get_query_path_rec( context.result.p_result_madw, i ); + osmtest_write_path_info( p_osmt, fh, p_rec ); + } + + Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if( context.result.p_result_madw != NULL ) + { + osm_mad_pool_put( &p_osmt->mad_pool, context.result.p_result_madw ); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT( &p_osmt->log ); + return ( status ); +} + +#else +/* + * NON RMPP BASED QUERY FOR ALL NODES: BASED ON THE MAX LID GIVEN BY THE USER + */ +static ib_api_status_t +osmtest_write_all_node_recs( + IN osmtest_t * const p_osmt, + IN FILE * fh ) +{ + osmtest_req_context_t context; + node_t *p_node; + node_t *p_guid_node; + const ib_node_record_t *p_rec; + cl_status_t status = CL_SUCCESS; + int result; + uint16_t lid; + + OSM_LOG_ENTER( &p_osmt->log, osmtest_write_all_node_recs ); + + result = fprintf( fh, "#\n" "# Node Records\n" "#\n" ); + if( result < 0 ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_write_all_node_recs: 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, + "osmtest_write_all_node_recs: 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, + "osmtest_write_all_node_recs: 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, osmtest_write_all_port_recs ); + + 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, + "osmtest_write_all_port_recs: 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, + "osmtest_write_all_port_recs: 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, + "osmtest_write_all_port_recs: 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, osmtest_write_all_path_recs ); + + 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, + "osmtest_write_all_path_recs: 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, osmtest_create_inventory_file ); + + fh = fopen( p_osmt->opt.file_name, "w" ); + if( fh == NULL ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_create_inventory_file: 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, osmtest_stress_large_rmpp_pr ); + 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, osmtest_stress_large_rmpp ); + 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, osmtest_stress_small_rmpp ); + gettimeofday( &start_tv, NULL ); + printf("-I- Start time is : %09ld:%06ld [sec:usec]\n", + start_tv.tv_sec, (long)start_tv.tv_usec); + + while( (num_queries < STRESS_SMALL_RMPP_THR) && (num_timeouts < 100) ) + { + delta_recs = 0; + delta_queries = 0; + + status = osmtest_stress_port_recs_small( p_osmt, &delta_recs, + &delta_queries ); + if( status != IB_SUCCESS ) + goto Exit; + + num_recs += delta_recs; + num_queries += delta_queries; + + print_freq += delta_recs; + if( print_freq > 5000 ) + { + gettimeofday( &end_tv, NULL ); + printf( "%" PRIu64 " records, %" PRIu64 " queries\n", + num_recs, num_queries ); + if (end_tv.tv_usec > start_tv.tv_usec) + { + sec_diff = end_tv.tv_sec-start_tv.tv_sec; + usec_diff = end_tv.tv_usec-start_tv.tv_usec; + } + else + { + sec_diff = end_tv.tv_sec-start_tv.tv_sec - 1; + usec_diff = 1000000 - (start_tv.tv_usec - end_tv.tv_usec); + } + printf("-I- End time is : %09ld:%06ld [sec:usec]\n", + end_tv.tv_sec, (long)end_tv.tv_usec); + printf("-I- Querying %" PRId64 " port_info queries (single mad) took %04ld:%06ld [sec:usec]\n", + num_queries, sec_diff, usec_diff); + print_freq = 0; + } + } + + Exit: + gettimeofday( &end_tv, NULL ); + printf("-I- End time is : %09ld:%06ld [sec:usec]\n", + end_tv.tv_sec, (long)end_tv.tv_usec); + if (end_tv.tv_usec > start_tv.tv_usec) + { + sec_diff = end_tv.tv_sec-start_tv.tv_sec; + usec_diff = end_tv.tv_usec-start_tv.tv_usec; + } + else + { + sec_diff = end_tv.tv_sec-start_tv.tv_sec - 1; + usec_diff = 1000000 - (start_tv.tv_usec - end_tv.tv_usec); + } + + printf("-I- Querying %" PRId64 " port_info queries (single mad) took %04ld:%06ld [sec:usec]\n", + num_queries, sec_diff, usec_diff); + if (num_timeouts > 50) + { + status = IB_TIMEOUT; + } + /* Exit: */ + OSM_LOG_EXIT( &p_osmt->log ); + return ( status ); +} + +/********************************************************************** + **********************************************************************/ +static void +osmtest_prepare_db_generic( IN osmtest_t * const p_osmt, + IN cl_qmap_t * const p_tbl ) +{ + generic_t *p_generic; + + OSM_LOG_ENTER( &p_osmt->log, osmtest_prepare_db_generic ); + + 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 ); + + 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, osmtest_check_missing_nodes ); + + 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, + "osmtest_check_missing_nodes: 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, osmtest_check_missing_ports ); + + 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, + "osmtest_check_missing_ports: 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, osmtest_check_missing_paths ); + + 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, + "osmtest_check_missing_paths: 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, + "osmtest_path_rec_kay_is_valid: 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, osmtest_validate_path_data ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_validate_path_data: " + "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, + "osmtest_validate_path_data: 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, + "osmtest_validate_path_data: 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, + "osmtest_validate_path_data: 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, + "osmtest_validate_path_data: 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, + "osmtest_validate_path_data: 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, osmtest_validate_node_data ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_validate_node_data: " + "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, + "osmtest_validate_node_data: 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, + "osmtest_validate_node_data: 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, + "osmtest_validate_node_data: 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, + "osmtest_validate_node_data: 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, + "osmtest_validate_node_data: 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, + "osmtest_validate_node_data: 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, + "osmtest_validate_node_data: 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, + "osmtest_validate_node_data: 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, + "osmtest_validate_node_data: 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, + "osmtest_validate_node_data: 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, + "osmtest_validate_node_data: 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, osmtest_validate_node_rec ); + + /* + * 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, + "osmtest_validate_node_rec: 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, osmtest_validate_port_data ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_validate_port_data: " + "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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + p_port->rec.port_info.capability_mask, 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, + "osmtest_validate_port_data: 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, osmtest_validate_port_rec ); + + /* + * 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, + "osmtest_validate_port_rec: 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, osmtest_validate_path_rec ); + + /* + * 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, + "osmtest_validate_path_rec: 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, osmtest_validate_all_node_recs ); + + 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, + "osmtest_validate_all_node_recs: ERR 0096: " + "osmtest_get_all_recs failed (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + + num_recs = context.result.result_cnt; + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_validate_all_node_recs: " + "Received %zu records\n", num_recs ); + } + + /* + * Compare the received records to the database. + */ + osmtest_prepare_db( p_osmt ); + + for( i = 0; i < num_recs; i++ ) + { + p_rec = osmv_get_query_node_rec( context.result.p_result_madw, i ); + + status = osmtest_validate_node_rec( p_osmt, p_rec ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_validate_all_node_recs: 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, + "osmtest_validate_all_node_recs: 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, osmtest_validate_all_guidinfo_recs ); + + 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, + "osmtest_validate_all_guidinfo_recs: ERR 0099: " + "osmtest_get_all_recs failed (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + + num_recs = context.result.result_cnt; + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_validate_all_guidinfo_recs: " + "Received %zu records\n", num_recs ); + } + + /* No validation as yet */ + + Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if( context.result.p_result_madw != NULL ) + { + osm_mad_pool_put( &p_osmt->mad_pool, context.result.p_result_madw ); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT( &p_osmt->log ); + return ( status ); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_all_path_recs( IN osmtest_t * const p_osmt ) +{ + osmtest_req_context_t context; + const ib_path_rec_t *p_rec; + uint32_t i; + cl_status_t status; + size_t num_recs; + + OSM_LOG_ENTER( &p_osmt->log, osmtest_validate_all_path_recs ); + + 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, + "osmtest_validate_all_path_recs: ERR 009A: " + "osmtest_get_all_recs failed (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + + num_recs = context.result.result_cnt; + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_validate_all_path_recs: " + "Received %zu records\n", num_recs ); + } + + /* + * Compare the received records to the database. + */ + osmtest_prepare_db( p_osmt ); + + for( i = 0; i < num_recs; i++ ) + { + p_rec = osmv_get_query_path_rec( context.result.p_result_madw, i ); + + status = osmtest_validate_path_rec( p_osmt, p_rec ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_validate_all_path_recs: 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, + "osmtest_validate_all_path_recs: 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, osmtest_get_link_rec_by_lid ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_get_link_rec_by_lid: " + "Getting link record from LID 0x%02X to LID 0x%02X\n", + cl_ntoh16( from_lid ), cl_ntoh16( to_lid ) ); + } + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset( &req, 0, sizeof( req ) ); + memset( &user, 0, sizeof( user ) ); + memset( &record, 0, sizeof( record ) ); + + record.from_lid = from_lid; + record.to_lid = to_lid; + p_context->p_osmt = p_osmt; + if (from_lid) + user.comp_mask |= IB_LR_COMPMASK_FROM_LID; + if (to_lid) + user.comp_mask |= IB_LR_COMPMASK_TO_LID; + user.attr_id = IB_MAD_ATTR_LINK_RECORD; + user.attr_offset = cl_ntoh16( ( uint16_t ) ( sizeof( record ) >> 3 ) ); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa( p_osmt->h_bind, &req ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_link_rec_by_lid: 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, + "osmtest_get_link_rec_by_lid: 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, osmtest_get_guidinfo_rec_by_lid ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_get_guidinfo_rec_by_lid: " + "Getting GUIDInfo record for LID 0x%02X\n", + cl_ntoh16( lid ) ); + } + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset( &req, 0, sizeof( req ) ); + memset( &user, 0, sizeof( user ) ); + memset( &record, 0, sizeof( record ) ); + + record.lid = lid; + p_context->p_osmt = p_osmt; + user.comp_mask = IB_GIR_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_GUIDINFO_RECORD; + user.attr_offset = cl_ntoh16( ( uint16_t ) ( sizeof( record ) >> 3 ) ); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa( p_osmt->h_bind, &req ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_guidinfo_rec_by_lid: 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, + "osmtest_get_guidinfo_rec_by_lid: 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, + "osmtest_get_guidinfo_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 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, osmtest_get_pkeytbl_rec_by_lid ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_get_pkeytbl_rec_by_lid: " + "Getting PKeyTable record for LID 0x%02X\n", + cl_ntoh16( lid ) ); + } + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset( &req, 0, sizeof( req ) ); + memset( &user, 0, sizeof( user ) ); + memset( &record, 0, sizeof( record ) ); + + record.lid = lid; + p_context->p_osmt = p_osmt; + user.comp_mask = IB_PKEY_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_PKEY_TBL_RECORD; + user.attr_offset = cl_ntoh16( ( uint16_t ) ( sizeof( record ) >> 3 ) ); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = sm_key; + + status = osmv_query_sa( p_osmt->h_bind, &req ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_pkeytbl_rec_by_lid: 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, + "osmtest_get_pkeytbl_rec_by_lid: 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, + "osmtest_get_pkeytbl_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 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, osmtest_get_lft_rec_by_lid ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_get_lft_rec_by_lid: " + "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; + user.comp_mask = IB_LFTR_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_LFT_RECORD; + user.attr_offset = cl_ntoh16( ( uint16_t ) ( sizeof( record ) >> 3 ) ); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa( p_osmt->h_bind, &req ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_lft_rec_by_lid: 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, + "osmtest_get_lft_rec_by_lid: 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, + "osmtest_get_lft_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 ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_sminfo_record_request( + IN osmtest_t * const p_osmt, + 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; + + OSM_LOG_ENTER( &p_osmt->log, osmtest_sminfo_record_request ); + + /* + * Do a blocking query for these records in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset( &req, 0, sizeof( req ) ); + memset( &user, 0, sizeof( user ) ); + memset( &record, 0, sizeof( record ) ); + + p_context->p_osmt = p_osmt; + user.attr_id = IB_MAD_ATTR_SMINFO_RECORD; + user.attr_offset = cl_ntoh16( ( uint16_t ) ( sizeof( record ) >> 3 ) ); + 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, + "osmtest_sminfo_record_request: ERR 008C: " + "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, + "osmtest_sminfo_record_request: 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, + "osmtest_sminfo_record_request: " + "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, osmtest_validate_single_path_rec_lid_pair ); + + 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, + "osmtest_validate_single_path_rec_lid_pair: 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, + "osmtest_validate_single_path_rec_lid_pair: ERR 0103: " + "Too many records. Expected 1, received %zu\n", num_recs ); + + status = IB_ERROR; + } + else + { + p_rec = osmv_get_query_path_rec( context.result.p_result_madw, 0 ); + + status = osmtest_validate_path_data( p_osmt, p_path, p_rec ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_validate_single_path_rec_lid_pair: 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, osmtest_validate_single_node_rec_lid ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_validate_single_node_rec_lid: " + "Getting NodeRecord for node with LID 0x%X\n", + cl_ntoh16( lid ) ); + } + + memset( &context, 0, sizeof( context ) ); + memset( &req, 0, sizeof( req ) ); + memset( &user, 0, sizeof( user ) ); + memset( &record, 0, sizeof( record ) ); + + record.lid = lid; + + context.p_osmt = p_osmt; + user.comp_mask = IB_NR_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_NODE_RECORD; + user.attr_offset = cl_ntoh16( (uint16_t) ( sizeof( record ) >> 3 ) ); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa( p_osmt->h_bind, &req ); + + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_validate_single_node_rec_lid: 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, + "osmtest_validate_single_node_rec_lid: 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, + "osmtest_validate_single_node_rec_lid: " + "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, + "osmtest_validate_single_node_rec_lid: " + "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, + "osmtest_validate_single_node_rec_lid: 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, osmtest_validate_single_port_rec_lid ); + + 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, + "osmtest_validate_single_port_rec_lid: 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, + "osmtest_validate_single_port_rec_lid: 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, osmtest_validate_single_path_rec_guid_pair ); + + memset( &req, 0, sizeof( req ) ); + memset( &context, 0, sizeof( context ) ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_validate_single_path_rec_guid_pair: " + "\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, + "osmtest_validate_single_path_rec_guid_pair: 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, + "osmtest_validate_single_path_rec_guid_pair: 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, + "osmtest_validate_single_path_rec_guid_pair: " + "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, + "osmtest_validate_single_path_rec_guid_pair: %zu records\n", + num_recs); + + for( i = 0; i < num_recs; i++ ) + { + p_rec = osmv_get_query_path_rec( context.result.p_result_madw, i ); + + /* + * Make sure the GUID values are correct + */ + if( p_rec->dgid.unicast.interface_id != p_pair->dest_guid ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_validate_single_path_rec_guid_pair: 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, + "osmtest_validate_single_path_rec_guid_pair: 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, + "osmtest_validate_single_path_rec_guid_pair: 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, osmtest_validate_single_path_recs ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_validate_single_path_recs: " + "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 ); + } + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_validate_single_path_recs: " + "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, + "osmtest_validate_single_path_recs: 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 ); + } + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_validate_single_path_recs: " + "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, + "osmtest_validate_single_path_recs: 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, osmtest_validate_single_node_recs ); + + p_node_lid_tbl = &p_osmt->exp_subn.node_lid_tbl; + + osmtest_prepare_db( p_osmt ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_validate_single_node_recs: " + "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, + "osmtest_validate_single_node_recs: 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 ); + } + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_validate_single_node_recs: " + "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, + "osmtest_validate_single_node_recs: 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, osmtest_validate_single_port_recs ); + + p_port_key_tbl = &p_osmt->exp_subn.port_key_tbl; + + osmtest_prepare_db( p_osmt ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_validate_single_port_recs: " + "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, + "osmtest_validate_single_port_recs: 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 ); + } + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_VERBOSE ) ) + { + osm_log( &p_osmt->log, OSM_LOG_VERBOSE, + "osmtest_validate_single_port_recs: " + "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, + "osmtest_validate_single_port_recs: 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; +#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 +#endif + + OSM_LOG_ENTER( &p_osmt->log, osmtest_validate_against_db ); + +#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); + +#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, + "osmtest_get_multipath_rec: " 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, + "osmtest_get_multipath_rec: " + "Got error %s\n", ib_get_err_str(status) ); + } + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_multipath_rec: " 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, + "osmtest_get_multipath_rec: " 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, + "osmtest_get_multipath_rec: " + "Got error %s\n", ib_get_err_str(status) ); + } + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_multipath_rec: " 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 */ + 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, + "osmtest_get_multipath_rec: " 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, + "osmtest_get_multipath_rec: " + "Got error %s\n", ib_get_err_str(status) ); + } + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_multipath_rec: " 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 */ + 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, + "osmtest_get_multipath_rec: " 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, + "osmtest_get_multipath_rec: " + "Got error %s\n", ib_get_err_str(status) ); + } + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_multipath_rec: " 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, + "osmtest_get_multipath_rec: " 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, + "osmtest_get_multipath_rec: " + "Got error %s\n", ib_get_err_str(status) ); + } + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_multipath_rec: " 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; + + /* 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; + + /* 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 test */ + memset( &context, 0, sizeof( context ) ); + status = osmtest_sminfo_record_request( p_osmt, &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 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; + + /* 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, + "osmtest_get_path_rec_by_lid_pair: " 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, + "osmtest_get_path_rec_by_lid_pair: " + "Got error %s\n", ib_get_err_str(status) ); + } + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_path_rec_by_lid_pair: " EXPECTING_ERRORS_END "\n" ); + + if( status == IB_SUCCESS ) + { + status = IB_ERROR; + goto Exit; + } + + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_path_rec_by_lid_pair: " 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, + "osmtest_get_path_rec_by_lid_pair: " + "Got error %s\n", ib_get_err_str(status) ); + } + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_path_rec_by_lid_pair: " EXPECTING_ERRORS_END "\n" ); + + if( status == IB_SUCCESS ) + { + status = IB_ERROR; + goto Exit; + } + } + } +#endif + + status = osmtest_validate_single_port_recs( p_osmt ); + if( status != IB_SUCCESS ) + goto Exit; + + if (! p_osmt->opt.ignore_path_records) + { + status = osmtest_validate_single_path_recs( p_osmt ); + if( status != IB_SUCCESS ) + goto Exit; + } + + Exit: + OSM_LOG_EXIT( &p_osmt->log ); + return ( status ); +} + +/********************************************************************** + **********************************************************************/ +static const osmtest_token_t * +str_get_token( IN char *const p_str ) +{ + const osmtest_token_t *p_tok; + uint32_t index = 0; + + p_tok = &token_array[index]; + + while( p_tok->val != OSMTEST_TOKEN_UNKNOWN ) + { + if( strnicmp( p_str, p_tok->str, p_tok->str_size ) == 0 ) + return ( p_tok ); + + p_tok = &token_array[++index]; + } + + return ( NULL ); +} + +/********************************************************************** + Returns true if not whitespace character encountered before EOL. +**********************************************************************/ +static boolean_t +str_skip_white( IN char line[], + IN OUT uint32_t * const p_offset ) +{ + while( ( ( line[*p_offset] == '\t' ) || + ( line[*p_offset] == ' ' ) ) && + ( line[*p_offset] != '\n' ) && ( line[*p_offset] != '\0' ) ) + { + ++*p_offset; + } + + if( ( line[*p_offset] == '\n' ) || ( line[*p_offset] == '\0' ) ) + return ( FALSE ); + else + return ( TRUE ); +} + +/********************************************************************** + Returns true if not whitespace character encountered before EOL. +**********************************************************************/ +static void +str_skip_token( IN char line[], + IN OUT uint32_t * const p_offset ) +{ + while( ( line[*p_offset] != '\t' ) && + ( line[*p_offset] != ' ' ) && ( line[*p_offset] != '\0' ) ) + { + ++*p_offset; + } +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_parse_node( IN osmtest_t * const p_osmt, + IN FILE * const fh, + IN OUT uint32_t * const p_line_num ) +{ + ib_api_status_t status = IB_SUCCESS; + uint32_t offset; + char line[OSMTEST_MAX_LINE_LEN]; + boolean_t done = FALSE; + node_t *p_node; + node_t *p_guid_node; + const osmtest_token_t *p_tok; + + OSM_LOG_ENTER( &p_osmt->log, osmtest_parse_node ); + + 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, + "osmtest_parse_node: 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, + "osmtest_parse_node: ERR 0120: " + "Ignoring line %u with unknown token: %s\n", + *p_line_num, &line[offset] ); + continue; + } + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_node: " + "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, + "osmtest_parse_node: 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, + "osmtest_parse_node: 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, osmtest_parse_port ); + + 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, + "osmtest_parse_port: 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, + "osmtest_parse_port: ERR 0124: " + "Ignoring line %u with unknown token: %s\n", + *p_line_num, &line[offset] ); + continue; + } + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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])); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ) ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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 ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_port: " + "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, + "osmtest_parse_port: 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, + "osmtest_parse_port: 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, osmtest_parse_path ); + + 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, + "osmtest_parse_path: 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, + "osmtest_parse_path: ERR 0128: " + "Ignoring line %u with unknown token: %s\n", + *p_line_num, &line[offset] ); + got_error = TRUE; + continue; + } + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_path: " + "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 ) ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_path: " + "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 ) ); + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_path: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_path: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_path: " + "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 ) ); + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_path: " + "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, + "osmtest_parse_path: 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, osmtest_parse_link); + + /* + * 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, + "osmtest_parse_link: 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, + "osmtest_parse_link: ERR 012B: " + "Ignoring line %u with unknown token: %s\n", + *p_line_num, &line[offset] ); + got_error = TRUE; + continue; + } + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_parse_link: " + "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, + "osmtest_parse_link: 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, osmtest_create_db ); + + fh = fopen( p_osmt->opt.file_name, "r" ); + if( fh == NULL ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_create_db: 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, + "osmtest_create_db: ERR 0131: " + "Ignoring line %u: %s\n", line_num, &line[offset] ); + got_error = TRUE; + continue; + } + + if( osm_log_is_active( &p_osmt->log, OSM_LOG_DEBUG ) ) + { + osm_log( &p_osmt->log, OSM_LOG_DEBUG, + "osmtest_create_db: " + "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, + "osmtest_create_db: 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, + "osmtest_create_db: ERR 0133: " + "Bad status received during parsing (%s)\n", + ib_get_err_str( status ) ); + fclose( fh ); + goto Exit; + } + } + + fclose( fh ); + + Exit: + OSM_LOG_EXIT( &p_osmt->log ); + return ( status ); +} + +/********************************************************************** + Returns the index in the local port attribute array for the + user's selection. +**********************************************************************/ +static uint32_t +osmtest_get_user_port( IN osmtest_t * const p_osmt, + IN const ib_port_attr_t p_attr_array[], + IN uint32_t const num_ports ) +{ + uint32_t i; + uint32_t choice = 0; + boolean_t done_flag = FALSE; + + OSM_LOG_ENTER( &p_osmt->log, osmtest_get_user_port ); + + /* + * User needs prompting for the local port GUID with which + * to bind. + */ + + while( done_flag == FALSE ) + { + printf( "\nChoose a local port number with which to bind:\n\n" ); + for( i = 0; i < num_ports; i++ ) + { + /* + * Print the index + 1 since by convention, port numbers + * start with 1 on host channel adapters. + */ + + printf( "\t%u: GUID = 0x%8" PRIx64 ", lid = 0x%04X, state = %s\n", + i + 1, cl_ntoh64( p_attr_array[i].port_guid ), + p_attr_array[i].lid, + ib_get_port_state_str( p_attr_array[i].link_state ) ); + } + + printf( "\nEnter choice (1-%u): ", i ); + scanf( "%u", &choice ); + if( choice > num_ports ) + printf( "\nError: Lame choice!\n" ); + else + done_flag = TRUE; + + } + printf("\n"); + OSM_LOG_EXIT( &p_osmt->log ); + return ( choice - 1 ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_bind( IN osmtest_t * p_osmt, + IN uint16_t max_lid, + IN ib_net64_t guid OPTIONAL ) +{ + uint32_t port_index; + ib_api_status_t status; + uint32_t num_ports = GUID_ARRAY_SIZE; + ib_port_attr_t attr_array[GUID_ARRAY_SIZE]; + + OSM_LOG_ENTER( &p_osmt->log, osmtest_bind ); + + /* + * 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, + "osmtest_bind: 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, + "osmtest_bind: 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, + "osmtest_bind: 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, + "osmtest_bind: " + "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, + "osmtest_bind: 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, osmtest_run ); + + status = osmtest_validate_sa_class_port_info(p_osmt); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_run: ERR 0138: " + "Could not obtain SA ClassPortInfo (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + + if( p_osmt->opt.flow == 1 ) + { + /* + * 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, + "osmtest_run: ERR 0139: " + "Inventory file create failed (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + } + else + { + if( p_osmt->opt.flow == 5 ) + { + /* + * Stress SA - flood the it 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, + "osmtest_run: 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, + "osmtest_run: 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, + "osmtest_run: 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, + "osmtest_run: ERR 0143: " + "Large RMPP stress test failed (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + break; + default: + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_run: ERR 0144: " + "Unknown stress test value %u\n", + p_osmt->opt.stress ); + break; + } + } + else + { + + /* + * Run normal validition tests. + */ + if (p_osmt->opt.flow == 0 || p_osmt->opt.flow == 2) + { + /* + * Only validate the given inventory file + */ + status = osmtest_create_db( p_osmt ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_run: 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, + "osmtest_run: ERR 0146: " + "SA validation database failure (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + } + + if (p_osmt->opt.flow == 0) + { + status = osmtest_wrong_sm_key_ignored( p_osmt ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_run: ERR 0147: " + "Try wrong SM_Key failed (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + } + + if (p_osmt->opt.flow == 0 || p_osmt->opt.flow == 3) + { + /* + * 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, + "osmtest_run: ERR 0148: " + "Service Flow failed (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + } + + if (p_osmt->opt.flow == 0 || p_osmt->opt.flow == 4) + { + /* + * 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, + "osmtest_run: ERR 0149: " + "Inform Info Flow failed: (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } +#else + osm_log (&p_osmt->log, OSM_LOG_INFO, + "osmtest_run: The event forwarding flow " + "is not implemented yet!\n"); + status = IB_SUCCESS; + goto Exit; +#endif + } + + if (p_osmt->opt.flow == 7) + { + /* + * 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, + "osmtest_run: 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, + "osmtest_run: ERR 0150: " + "Failed to get SLtoVL and VL Arbitration Tables (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + } + + if (p_osmt->opt.flow == 8) + { + /* + * 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, + "osmtest_run: 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, + "osmtest_run: The event forwarding flow " + "is not implemented yet!\n"); + status = IB_SUCCESS; + goto Exit; +#endif + } + + if (p_osmt->opt.flow == 0 || p_osmt->opt.flow == 6) + { + /* + * Multicast flow + */ + status = osmt_run_mcast_flow( p_osmt ); + if( status != IB_SUCCESS ) + { + osm_log( &p_osmt->log, OSM_LOG_ERROR, + "osmtest_run: ERR 0152: " + "Multicast Flow failed: (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + } + + osm_log( &p_osmt->log, OSM_LOG_INFO, + "osmtest_run: " + "\n\n***************** ALL TESTS PASS *****************\n\n" ); + + } + } + + Exit: + OSM_LOG_EXIT( &p_osmt->log ); + return ( status ); +} + diff --git a/branches/WOF2-1/ulp/qlgcvnic/dirs b/branches/WOF2-1/ulp/qlgcvnic/dirs new file mode 100644 index 00000000..ed41dcf4 --- /dev/null +++ b/branches/WOF2-1/ulp/qlgcvnic/dirs @@ -0,0 +1,2 @@ +DIRS=\ + kernel diff --git a/branches/WOF2-1/ulp/qlgcvnic/kernel/SOURCES b/branches/WOF2-1/ulp/qlgcvnic/kernel/SOURCES new file mode 100644 index 00000000..0f0ed04b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/inic.rc b/branches/WOF2-1/ulp/qlgcvnic/kernel/inic.rc new file mode 100644 index 00000000..84699441 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/makefile b/branches/WOF2-1/ulp/qlgcvnic/kernel/makefile new file mode 100644 index 00000000..128ed372 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/makefile.inc b/branches/WOF2-1/ulp/qlgcvnic/kernel/makefile.inc new file mode 100644 index 00000000..4f29f500 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/netvnic.cdf b/branches/WOF2-1/ulp/qlgcvnic/kernel/netvnic.cdf new file mode 100644 index 00000000..7f1a2767 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/netvnic.inx b/branches/WOF2-1/ulp/qlgcvnic/kernel/netvnic.inx new file mode 100644 index 00000000..c20210ac --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_adapter.c b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_adapter.c new file mode 100644 index 00000000..dfec0429 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_adapter.h b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_adapter.h new file mode 100644 index 00000000..cbed2237 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_config.h b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_config.h new file mode 100644 index 00000000..7d49064c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_control.c b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_control.c new file mode 100644 index 00000000..5d7bce80 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_control.h b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_control.h new file mode 100644 index 00000000..b18372bf --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_controlpkt.h b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_controlpkt.h new file mode 100644 index 00000000..12427267 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_data.c b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_data.c new file mode 100644 index 00000000..09f1ca55 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_data.h b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_data.h new file mode 100644 index 00000000..14bc0c1b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_debug.h b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_debug.h new file mode 100644 index 00000000..a5df64f3 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_driver.c b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_driver.c new file mode 100644 index 00000000..08947e9b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_driver.h b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_driver.h new file mode 100644 index 00000000..fe1ab950 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_ib.c b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_ib.c new file mode 100644 index 00000000..b902e784 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_ib.h b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_ib.h new file mode 100644 index 00000000..b230c3ba --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_netpath.c b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_netpath.c new file mode 100644 index 00000000..98ddb374 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_trailer.h b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_trailer.h new file mode 100644 index 00000000..c047a9b6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_util.h b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_util.h new file mode 100644 index 00000000..4704404a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_viport.c b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_viport.c new file mode 100644 index 00000000..fe3adac2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/qlgcvnic/kernel/vnic_viport.h b/branches/WOF2-1/ulp/qlgcvnic/kernel/vnic_viport.h new file mode 100644 index 00000000..b881e69f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/dirs b/branches/WOF2-1/ulp/srp/dirs new file mode 100644 index 00000000..ed41dcf4 --- /dev/null +++ b/branches/WOF2-1/ulp/srp/dirs @@ -0,0 +1,2 @@ +DIRS=\ + kernel diff --git a/branches/WOF2-1/ulp/srp/kernel/SOURCES b/branches/WOF2-1/ulp/srp/kernel/SOURCES new file mode 100644 index 00000000..237c439a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/ib_srp.cdf b/branches/WOF2-1/ulp/srp/kernel/ib_srp.cdf new file mode 100644 index 00000000..59269844 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/ib_srp.inx b/branches/WOF2-1/ulp/srp/kernel/ib_srp.inx new file mode 100644 index 00000000..5b57db83 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/ibsrp.rc b/branches/WOF2-1/ulp/srp/kernel/ibsrp.rc new file mode 100644 index 00000000..5de864e8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/makefile b/branches/WOF2-1/ulp/srp/kernel/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/makefile.inc b/branches/WOF2-1/ulp/srp/kernel/makefile.inc new file mode 100644 index 00000000..4f29f500 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp.h b/branches/WOF2-1/ulp/srp/kernel/srp.h new file mode 100644 index 00000000..626af3ec --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_aer_req.h b/branches/WOF2-1/ulp/srp/kernel/srp_aer_req.h new file mode 100644 index 00000000..540c41ce --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_aer_rsp.h b/branches/WOF2-1/ulp/srp/kernel/srp_aer_rsp.h new file mode 100644 index 00000000..78d9deeb --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_cmd.h b/branches/WOF2-1/ulp/srp/kernel/srp_cmd.h new file mode 100644 index 00000000..3c1e76e3 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_connection.c b/branches/WOF2-1/ulp/srp/kernel/srp_connection.c new file mode 100644 index 00000000..5b7780ff --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_connection.h b/branches/WOF2-1/ulp/srp/kernel/srp_connection.h new file mode 100644 index 00000000..982a7b81 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_cred_req.h b/branches/WOF2-1/ulp/srp/kernel/srp_cred_req.h new file mode 100644 index 00000000..6f47638a --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_cred_rsp.h b/branches/WOF2-1/ulp/srp/kernel/srp_cred_rsp.h new file mode 100644 index 00000000..70b3ca9f --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_data.h b/branches/WOF2-1/ulp/srp/kernel/srp_data.h new file mode 100644 index 00000000..87c5d1bc --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_data_path.c b/branches/WOF2-1/ulp/srp/kernel/srp_data_path.c new file mode 100644 index 00000000..f879d7f2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_data_path.h b/branches/WOF2-1/ulp/srp/kernel/srp_data_path.h new file mode 100644 index 00000000..63db7be2 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_debug.h b/branches/WOF2-1/ulp/srp/kernel/srp_debug.h new file mode 100644 index 00000000..9a5ff7a1 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_descriptors.c b/branches/WOF2-1/ulp/srp/kernel/srp_descriptors.c new file mode 100644 index 00000000..bf07ec79 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_descriptors.h b/branches/WOF2-1/ulp/srp/kernel/srp_descriptors.h new file mode 100644 index 00000000..00cbe1a6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_driver.c b/branches/WOF2-1/ulp/srp/kernel/srp_driver.c new file mode 100644 index 00000000..14f5167e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_event.c b/branches/WOF2-1/ulp/srp/kernel/srp_event.c new file mode 100644 index 00000000..be1c2ad6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_event.h b/branches/WOF2-1/ulp/srp/kernel/srp_event.h new file mode 100644 index 00000000..2aad4eaf --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_hba.c b/branches/WOF2-1/ulp/srp/kernel/srp_hba.c new file mode 100644 index 00000000..03271b4e --- /dev/null +++ b/branches/WOF2-1/ulp/srp/kernel/srp_hba.c @@ -0,0 +1,1044 @@ +/* + * 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 ( p_path_rec_1->resv1 != p_path_rec_2->resv1 ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("resv1 does not match.\n") ); + } + + if ( p_path_rec_1->resv2 != p_path_rec_2->resv2 ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("resv2 does not match.\n") ); + } + + 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-1/ulp/srp/kernel/srp_hba.h b/branches/WOF2-1/ulp/srp/kernel/srp_hba.h new file mode 100644 index 00000000..86d3238b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_hca.c b/branches/WOF2-1/ulp/srp/kernel/srp_hca.c new file mode 100644 index 00000000..14f0cf5d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_hca.h b/branches/WOF2-1/ulp/srp/kernel/srp_hca.h new file mode 100644 index 00000000..897a3e9d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_i_logout.h b/branches/WOF2-1/ulp/srp/kernel/srp_i_logout.h new file mode 100644 index 00000000..55c0188c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_information_unit.h b/branches/WOF2-1/ulp/srp/kernel/srp_information_unit.h new file mode 100644 index 00000000..6a6e5d67 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_iu_buffer.h b/branches/WOF2-1/ulp/srp/kernel/srp_iu_buffer.h new file mode 100644 index 00000000..5939e4b7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_login_rej.h b/branches/WOF2-1/ulp/srp/kernel/srp_login_rej.h new file mode 100644 index 00000000..99b66653 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_login_req.h b/branches/WOF2-1/ulp/srp/kernel/srp_login_req.h new file mode 100644 index 00000000..24487ba9 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_login_rsp.h b/branches/WOF2-1/ulp/srp/kernel/srp_login_rsp.h new file mode 100644 index 00000000..38561c14 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_rsp.h b/branches/WOF2-1/ulp/srp/kernel/srp_rsp.h new file mode 100644 index 00000000..5e3e526b --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_session.c b/branches/WOF2-1/ulp/srp/kernel/srp_session.c new file mode 100644 index 00000000..c9dfdd20 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_session.h b/branches/WOF2-1/ulp/srp/kernel/srp_session.h new file mode 100644 index 00000000..a0ee0365 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_t_logout.h b/branches/WOF2-1/ulp/srp/kernel/srp_t_logout.h new file mode 100644 index 00000000..e284fbea --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/srp/kernel/srp_tsk_mgmt.h b/branches/WOF2-1/ulp/srp/kernel/srp_tsk_mgmt.h new file mode 100644 index 00000000..3eacd1c8 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/dirs b/branches/WOF2-1/ulp/wsd/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-1/ulp/wsd/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-1/ulp/wsd/user/README b/branches/WOF2-1/ulp/wsd/user/README new file mode 100644 index 00000000..dd75d261 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/user/SOURCES b/branches/WOF2-1/ulp/wsd/user/SOURCES new file mode 100644 index 00000000..8672f54c --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/user/extensions.c b/branches/WOF2-1/ulp/wsd/user/extensions.c new file mode 100644 index 00000000..cebf3bc6 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/user/ib_cm.c b/branches/WOF2-1/ulp/wsd/user/ib_cm.c new file mode 100644 index 00000000..d883e841 --- /dev/null +++ b/branches/WOF2-1/ulp/wsd/user/ib_cm.c @@ -0,0 +1,960 @@ +/* + * 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); +static 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. + */ +static void AL_API +cm_apr_callback( + IN ib_cm_apr_rec_t *p_cm_apr_rec ) +{ + /* TODO */ + IBSP_ENTER( IBSP_DBG_CM ); + + UNUSED_PARAM( p_cm_apr_rec ); + + IBSP_ERROR( ("not implemented") ); + + CL_ASSERT( 0 ); + + 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 ) +{ + /* TODO */ + IBSP_ENTER( IBSP_DBG_CM ); + + UNUSED_PARAM( p_cm_lap_rec ); + + IBSP_ERROR( ("not implemented") ); + + CL_ASSERT( 0 ); + + 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 ) +{ + 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.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.p_alt_path = NULL; + 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 = 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-1/ulp/wsd/user/ibsp_duplicate.c b/branches/WOF2-1/ulp/wsd/user/ibsp_duplicate.c new file mode 100644 index 00000000..6a1e1424 --- /dev/null +++ b/branches/WOF2-1/ulp/wsd/user/ibsp_duplicate.c @@ -0,0 +1,327 @@ +/* + * 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; + + 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, dest_port_guid, &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; + } + + 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 ); + 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-1/ulp/wsd/user/ibsp_iblow.c b/branches/WOF2-1/ulp/wsd/user/ibsp_iblow.c new file mode 100644 index 00000000..c6625327 --- /dev/null +++ b/branches/WOF2-1/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 */ + NULL, /* 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-1/ulp/wsd/user/ibsp_ip.c b/branches/WOF2-1/ulp/wsd/user/ibsp_ip.c new file mode 100644 index 00000000..0b47c286 --- /dev/null +++ b/branches/WOF2-1/ulp/wsd/user/ibsp_ip.c @@ -0,0 +1,566 @@ +/* + * 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; +}; + + +intn_t 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 ); + + for(;;) + { + hr = IbatResolve( + p_src_addr, + p_dest_addr, + (IBAT_PATH_BLOB*)&path + ); + + if( hr != E_PENDING ) + break; + + Sleep( 100 ); + } + 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 struct ibsp_port *port, + IN ib_net64_t dest_port_guid, + 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 = port->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, port->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", + port->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( (port->hca->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_ip_address 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-1/ulp/wsd/user/ibsp_mem.c b/branches/WOF2-1/ulp/wsd/user/ibsp_mem.c new file mode 100644 index 00000000..70710441 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/user/ibsp_mem.h b/branches/WOF2-1/ulp/wsd/user/ibsp_mem.h new file mode 100644 index 00000000..39861287 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/user/ibsp_mngt.c b/branches/WOF2-1/ulp/wsd/user/ibsp_mngt.c new file mode 100644 index 00000000..4e221ce1 --- /dev/null +++ b/branches/WOF2-1/ulp/wsd/user/ibsp_mngt.c @@ -0,0 +1,289 @@ +/* + * FileName: ibsp_mngt.c + * + * Copyright (c) + * + * Abstract: Hardware ressource management (HCA and ports). + * + * Author: + * + * Revision History: + * + */ + +#include "ibspdll.h" + +/* Build a list of IP addresses associated with a port */ +int +build_port_ip_list(IN struct ibsp_port *port) +{ + struct ibsp_ip_addr *ip_addr; + cl_list_item_t *item; + int ret; + + CL_ENTER(IBSP_DBG_HW, gdbg_lvl); + CL_TRACE(IBSP_DBG_HW, gdbg_lvl, + ("build_port_ip_list for port %UI64x\n", cl_ntoh64(port->guid))); + + cl_qlist_init(&port->ip_list); + + ret = query_ip_address(port, &port->ip_list); + if (ret) { + CL_ERROR(IBSP_DBG_HW, gdbg_lvl, ("query_ip_address failed (%d)\n", ret)); + goto error; + } + + CL_EXIT(IBSP_DBG_HW, gdbg_lvl); + return 0; + + error: + /* Free the list */ + while((item = cl_qlist_remove_head(&port->ip_list)) != cl_qlist_end(&port->ip_list)) { + + ip_addr = PARENT_STRUCT(item, struct ibsp_ip_addr, item); + + HeapFree(g_ibsp.heap, 0, ip_addr); + } + + CL_EXIT_ERROR(IBSP_DBG_HW, gdbg_lvl, + ("Failed to build list of IP addr for port %016UI64x\n", + CL_HTON64(port->guid))); + + return 1; +} + +/* Get the info from a port. Link it to the parent HCA. */ +int +build_port_info(IN struct ibsp_hca *hca, + IN ib_net64_t port_guid, + IN uint8_t port_num, OUT struct ibsp_port **port_out) +{ + int ret; + struct ibsp_port *port; + cl_list_item_t *item_ip; + + CL_ENTER(IBSP_DBG_HW, gdbg_lvl); + + port = HeapAlloc(g_ibsp.heap, HEAP_ZERO_MEMORY, sizeof(struct ibsp_port)); + + if (port == NULL) { + CL_ERROR(IBSP_DBG_HW, gdbg_lvl, + ("HeapAlloc failed (%d)\n", sizeof(struct ibsp_port))); + ret = WSAEPROVIDERFAILEDINIT; + goto done; + } + + port->guid = port_guid; + port->port_num = port_num; + port->hca = hca; + + ret = build_port_ip_list(port); + + if (ret) { + CL_ERROR(IBSP_DBG_HW, gdbg_lvl, ("build_port_ip_list failed (%d)\n", ret)); + ret = WSAEPROVIDERFAILEDINIT; + goto done; + } + + /* Insert the new list of IP into the global list of IP addresses. */ + 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); + + cl_qlist_insert_tail(&g_ibsp.ip_list, &ip->item_global); + } + + *port_out = port; + + CL_EXIT(IBSP_DBG_HW, gdbg_lvl); + + ret = 0; + + done: + if (ret) { + HeapFree(g_ibsp.heap, 0, port); + } + + CL_EXIT(IBSP_DBG_HW, gdbg_lvl); + + return ret; +} + +/* Open and query the HCA for its ports */ +int +build_hca_info(IN ib_net64_t hca_guid, OUT struct ibsp_hca **hca_out) +{ + struct ibsp_hca *hca = NULL; + ib_ca_attr_t *ca_attr = NULL; + size_t ca_attr_size = 0; + uint8_t port_num; + int ret; + ib_api_status_t status; + + CL_ENTER(IBSP_DBG_HW, gdbg_lvl); + + hca = HeapAlloc(g_ibsp.heap, HEAP_ZERO_MEMORY, sizeof(struct ibsp_hca)); + if (hca == NULL) { + CL_ERROR(IBSP_DBG_HW, gdbg_lvl, + ("can't get enough memory (%d)\n", sizeof(struct ibsp_hca))); + ret = WSAEPROVIDERFAILEDINIT; + goto done; + } + + hca->guid = hca_guid; + cl_qlist_init(&hca->ports_list); + + status = ib_open_ca(g_ibsp.al_handle, hca->guid, NULL, /* event handler */ + NULL, /* context */ + &hca->hca_handle); + + if (status != IB_SUCCESS) { + CL_ERROR(IBSP_DBG_HW, gdbg_lvl, ("ib_open_ca failed (%d)\n", status)); + ret = WSAEPROVIDERFAILEDINIT; + goto done; + } + + /* Build the list of ports of each HCAs */ + query_ca_again: + status = ib_query_ca(hca->hca_handle, ca_attr, &ca_attr_size); + + if (status == IB_INSUFFICIENT_MEMORY) { + + CL_TRACE(IBSP_DBG_HW, gdbg_lvl, ("ib_query_ca needs %d bytes\n", ca_attr_size)); + + /* Allocate more memory */ + if (ca_attr) { + HeapFree(g_ibsp.heap, 0, ca_attr); + } + + ca_attr = HeapAlloc(g_ibsp.heap, 0, ca_attr_size); + + if (ca_attr) + goto query_ca_again; + else { + CL_ERROR(IBSP_DBG_HW, gdbg_lvl, ("HeapAlloc failed\n")); + ret = WSAEPROVIDERFAILEDINIT; + goto done; + } + } else if (status != IB_SUCCESS) { + CL_ERROR(IBSP_DBG_HW, gdbg_lvl, ("ib_query_ca failed (%d)\n", status)); + ret = WSAEPROVIDERFAILEDINIT; + goto done; + } + + CL_TRACE(IBSP_DBG_HW, gdbg_lvl, ("found %d port on that HCA\n", ca_attr->num_ports)); + + for(port_num = 0; port_num < ca_attr->num_ports; port_num++) { + struct ibsp_port *port; + + ret = build_port_info(hca, ca_attr->p_port_attr[port_num].port_guid, port_num + 1, /* TODO: correct or should query port info? */ + &port); + if (ret) { + CL_ERROR(IBSP_DBG_HW, gdbg_lvl, ("build_port_info failed (%d)\n", ret)); + goto done; + } + + cl_qlist_insert_tail(&hca->ports_list, &port->item); + } + + *hca_out = hca; + + ret = 0; + + done: + if (ca_attr) { + HeapFree(g_ibsp.heap, 0, ca_attr); + } + + if (ret) { + if (hca) { + + if (hca->hca_handle) { + status = ib_close_ca(hca->hca_handle, NULL); + + if (status != IB_SUCCESS) { + CL_ERROR(IBSP_DBG_HW, gdbg_lvl, + ("ib_close_ca failed (%d)\n", status)); + } + } + + HeapFree(g_ibsp.heap, 0, hca); + } + } + + CL_TRACE_EXIT(IBSP_DBG_HW, gdbg_lvl, ("return code is %d\n", ret)); + + return ret; +} + +/* Build the HCA tree. This allows for hotplug. Each HCA is + * discovered, as well as each ports. */ +int +build_hca_tree(void) +{ + ib_net64_t *guid_list = NULL; + ib_api_status_t status; + int ret; + unsigned int hca_num; + size_t adapter_count; + + CL_ENTER(IBSP_DBG_HW, gdbg_lvl); + + /* Get the GUIDS of the adapters, so we can open them */ + status = ib_get_ca_guids(g_ibsp.al_handle, NULL, &adapter_count); + if (status != IB_INSUFFICIENT_MEMORY) { + CL_ERROR(IBSP_DBG_HW, gdbg_lvl, ("first ib_get_ca_guids failed\n")); + ret = WSAEPROVIDERFAILEDINIT; + goto done; + } + + /* Make sure we have a reasonable number of HCAs */ + CL_ASSERT(adapter_count < 10); + + guid_list = HeapAlloc(g_ibsp.heap, 0, sizeof(ib_net64_t) * adapter_count); + if (guid_list == NULL) { + CL_ERROR(IBSP_DBG_HW, gdbg_lvl, + ("can't get enough memory (%d, %d)\n", sizeof(ib_net64_t), + adapter_count)); + ret = WSAEPROVIDERFAILEDINIT; + goto done; + } + + status = ib_get_ca_guids(g_ibsp.al_handle, guid_list, &adapter_count); + if (status != IB_SUCCESS) { + CL_ERROR(IBSP_DBG_HW, gdbg_lvl, ("second ib_get_ca_guids failed (%d)\n", status)); + ret = WSAEPROVIDERFAILEDINIT; + goto done; + } + + CL_TRACE(IBSP_DBG_HW, gdbg_lvl, ("got %d adapter guid(s)\n", adapter_count)); + + for(hca_num = 0; hca_num < adapter_count; hca_num++) { + + struct ibsp_hca *hca; + + ret = build_hca_info(guid_list[hca_num], &hca); + if (ret) { + CL_ERROR(IBSP_DBG_HW, gdbg_lvl, ("build_hca_info failed (%d)\n", ret)); + goto done; + } + + cl_qlist_insert_tail(&g_ibsp.hca_list, &hca->item); + } + + CL_ASSERT(adapter_count == cl_qlist_count(&g_ibsp.hca_list)); + + CL_EXIT(IBSP_DBG_HW, gdbg_lvl); + + ret = 0; + + done: + if (guid_list) { + HeapFree(g_ibsp.heap, 0, guid_list); + } + + CL_EXIT(IBSP_DBG_HW, gdbg_lvl); + + return ret; +} diff --git a/branches/WOF2-1/ulp/wsd/user/ibsp_perfmon.c b/branches/WOF2-1/ulp/wsd/user/ibsp_perfmon.c new file mode 100644 index 00000000..e4d947a7 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/user/ibsp_perfmon.h b/branches/WOF2-1/ulp/wsd/user/ibsp_perfmon.h new file mode 100644 index 00000000..1d94cb78 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/user/ibsp_pnp.c b/branches/WOF2-1/ulp/wsd/user/ibsp_pnp.c new file mode 100644 index 00000000..efd1ef90 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/user/ibspdebug.c b/branches/WOF2-1/ulp/wsd/user/ibspdebug.c new file mode 100644 index 00000000..c67a84d3 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/user/ibspdebug.h b/branches/WOF2-1/ulp/wsd/user/ibspdebug.h new file mode 100644 index 00000000..98d95a1a --- /dev/null +++ b/branches/WOF2-1/ulp/wsd/user/ibspdebug.h @@ -0,0 +1,267 @@ +/* + * 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)) + + + +#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_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-1/ulp/wsd/user/ibspdefines.h b/branches/WOF2-1/ulp/wsd/user/ibspdefines.h new file mode 100644 index 00000000..3af02c3e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/user/ibspdll.c b/branches/WOF2-1/ulp/wsd/user/ibspdll.c new file mode 100644 index 00000000..190249a3 --- /dev/null +++ b/branches/WOF2-1/ulp/wsd/user/ibspdll.c @@ -0,0 +1,2329 @@ +/* + * 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; +uint8_t g_pkt_life_modifier = 0; +uint8_t g_qp_retries = QP_ATTRIB_RETRY_COUNT; +DWORD_PTR g_dwPollThreadAffinityMask = 0; + +uint32_t g_ibsp_dbg_level = TRACE_LEVEL_ERROR; +uint32_t g_ibsp_dbg_flags = 0x1; + +/* + * 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 = (uint8_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; + } + + if( init_globals() ) + return FALSE; + +#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; + + 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) ); + + /* 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; + } + + 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, dest_port_guid, &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; + } + + 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 ); + 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; +} + + +/* 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") ); + 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; +} + + + diff --git a/branches/WOF2-1/ulp/wsd/user/ibspdll.def b/branches/WOF2-1/ulp/wsd/user/ibspdll.def new file mode 100644 index 00000000..8932928b --- /dev/null +++ b/branches/WOF2-1/ulp/wsd/user/ibspdll.def @@ -0,0 +1,6 @@ +LIBRARY ibwsd +EXPORTS +WSPStartupEx +IBSPPmOpen +IBSPPmCollectData +IBSPPmClose diff --git a/branches/WOF2-1/ulp/wsd/user/ibspdll.h b/branches/WOF2-1/ulp/wsd/user/ibspdll.h new file mode 100644 index 00000000..570a64ae --- /dev/null +++ b/branches/WOF2-1/ulp/wsd/user/ibspdll.h @@ -0,0 +1,72 @@ +/* + * 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 uint8_t g_pkt_life_modifier; +extern uint8_t g_qp_retries; + +#endif /* IBSPDLL_H */ diff --git a/branches/WOF2-1/ulp/wsd/user/ibspdll.rc b/branches/WOF2-1/ulp/wsd/user/ibspdll.rc new file mode 100644 index 00000000..3cbc9d8e --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/user/ibspproto.h b/branches/WOF2-1/ulp/wsd/user/ibspproto.h new file mode 100644 index 00000000..4df6d7b3 --- /dev/null +++ b/branches/WOF2-1/ulp/wsd/user/ibspproto.h @@ -0,0 +1,298 @@ +/* + * 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 */ +intn_t 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 struct ibsp_port *port, + IN ib_net64_t dest_port_guid, + 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 ); + +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 ); diff --git a/branches/WOF2-1/ulp/wsd/user/ibspstruct.h b/branches/WOF2-1/ulp/wsd/user/ibspstruct.h new file mode 100644 index 00000000..3b1fc533 --- /dev/null +++ b/branches/WOF2-1/ulp/wsd/user/ibspstruct.h @@ -0,0 +1,469 @@ +/* + * 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. */ +}; + +/* 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; + +#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; +}; + +/* 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; + +#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-1/ulp/wsd/user/makefile b/branches/WOF2-1/ulp/wsd/user/makefile new file mode 100644 index 00000000..a28a5610 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/user/misc.c b/branches/WOF2-1/ulp/wsd/user/misc.c new file mode 100644 index 00000000..5d81bb52 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/wsd/user/sockinfo.c b/branches/WOF2-1/ulp/wsd/user/sockinfo.c new file mode 100644 index 00000000..e837e429 --- /dev/null +++ b/branches/WOF2-1/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->recv_wr, 0x38, sizeof(socket_info->send_wr) ); + memset( socket_info->recv_wr, 0x38, sizeof(socket_info->recv_wr) ); + memset( socket_info->recv_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.41.0

jtcLU)E zdpO{%=O>gvV$$J}#R9f(oQPLRK5)>XI`_8+_(v*A3D@{y!;`)lya4H1-X6}uR{zkM z#F3-@Zb)azyc&z)gpJ&-ho(6;Ijo=LszzLxO-izb-Ty>WWakY#?|C7CpyqsxI#iDS zu(eWx(5yc|>LiNlw2{tWr^ir&Xr&#Z!|LZ*ambg9^#;gC*Aw!YiFlI5(*!4Ifo1!v z%g!p|Z8&?(iy>CCv-Ehx)a^?TN6C8-$Bzv`7tLgs8j0%xVBpv%>IybmCQ!yZsCo37 zaz4KNl^{j~8EPH|o@DuWmBTUd!<~XJKr-|^#hjDE2hEUNpY){Cir+wNXykdHlUzhs z=<`q7R7q@px@pcibmn>)nz!vbT zjS}oCb?>32kyzlv{@2cdWhpX0^uSMZ`D-Nz#>y8_6hu@e2NMnCo>lpCGIKAr@*Q@7 zfxZ|497E#L$C=!VG9W~$`-7d%QH1%5Qb*|4KktMX$TV3!@u1|NXiybBQzUGjYQSN^ z6Vi^T%y9Zq&t~uytTz_7n2j&OSE8G+o^xbU`2p*)!{8JFvAqlT3qVRijWH5g^vR%_ zq-YQVwCIQ==E?vABFr7}1IskkzuBTPDg|L7ILgatluUZXAf=?~*+`d@K}y(DWn%VzJjbm!FOyv_Sc?Ji?8f zbt{VN_i!e%Ms^nxrf)LM`#KSGyk-VI9eX}`W50In4^=tI4 z@NrvIsuZ^iRaas$<+1!#b)WrIuVmcd(&cUiw%|#eFOn9iZ_~z;GJiajNt(52FYifV z5oXVSzZTGR%SN%fAdHsUm9#}83H?FY5N$PLx-IYXy#`+fnQMIGz%>tn4s5LbD;PeC zzFAu9u+|!p+%rIraON>=hvCo>qgSqR3H8CtfT;A(xVeq7HTMl#&8`NO9=V}Wq?nef z^T1tEm)?TZeG=0SvGjs8O}F^(oO*GYEu?32Yb8iY?s4N%l2t{-o!K#-RQWl)=K_Hf z9U4A?3wpROXaYM=H$v2h=$5*ljy!+&ima}XiwgK(D^L%&aDE2 zKj&J%2G^d_FKhTC0u^K^K{ zYIs`KK5-$*7dlULq9$@-@8w7+WCn$Oyc7R+Ygt9!R-a)LV-CtEwuwZqt!Ouyaxo6t zBoQfB@fph_T#p_iz&nPjaUqCUC~p%9>RheYyrB`?EA|E?jnN)_c<-z#97;n1Uam@}uBVDiiEFI48qp217Y{RB-i#HsZW?yC8CJRgP z8fZYIpQ5Y*_n5h3m|QS2`F<8vgOS+)l%Z_`VG{^^LjbqIBHH@=vjpi-k10UFu90K{ zI4f$^mJF#AByF(sM)JW|E#g2Fi#GE%Ft826D8-M4u}>R!7ZEQ>!uK9n#zBcDF%FC> z2*|Pb@up`9HUvZiHr|LiCOKc0@aa%kEF?>xBkEca(a1sIT3U+vZX3)`RaTeNqx+S) zI4g3ywqXZa)1gOE_e>w-nV~bJH@?Vi8xBhY8l?Lsm2Q&$%7DGuING;@9Do?$8S4*9;p+O)5?6r*oVZX|pYy!5`8>#g?Fo)i)L6R4>j@p{@qu@Ql0K}~BYGM>jy2zfUxK=C z6r(Sb2j6X;$5@H(HI$I_{LEJ{?GSMKx%3W83|Trvc$knmVXb8h(uz>TAEYeCd(G&m z*tr)^fH?s1a2Z?ey~El?^ut4%3kYf z7d{=Ok3MF?o;@E`ubZ`nUk8u@1g_Y?mHe2}h++@`^HD-FVO(TWlf2>sP!v;;HpD5z zaX3=wBbhYqQ0H-AaXbAtI^YFCNGX08RCrO5xI5~JjW9^CMh?7JhCE%F>j}F#XoT~m zh^R0!zaK=iuvlt59=vr8TEP7HDg{d`d^)c=DFS7L=fmF&jd#X)Ccbtmm{hNqZ7kOG3eud!E%hAG8SSD_R))=T zr;HlSc-&{jA?31B3L?p}efs0$R}$QDt6Bh|`;cBwz=?-B{I zS2&MMfzg?_6CO_aWndwW=o-)>>NLi}G{2GO8}Xn&tPnDn`N5EeuIBDSpJT?>HDIrq z$j|0V%G)Z3DaKd>{lJ{Xab82XN#pK zx2^W`LlzB8F88vexD6yu5S=x^h=4cO;0&rom|*Y7RU8KbF-OTWmTd@^p^dz@KhWSZ+HfGi!ST+sp;);$_EFl7{K zzkd~Wm*;YL+A~JNf}7rS-cym)6kYswo{*BncD#BRxC!gp%%D+G8H_5~DRd41{5bjT z=T^6T$CRxh3nr&o>x!dIxjd?+rL{8DfM1JRAr<9&hNR7@fgp0d&ThK8k3C^0(LJHQ z$S1ft2yJyV0QTF+z*pM$d*IZaknj4=u98Xj5pE@0bhZ*Iv0-ugE~BjHO(CMUg~@;v zX{?=FfQTa0Ws|GI4frOJv2UU+y(h-)I<<4nRSS@)QFjHqc79=K%UOUWAQoz}sEtNi zC`4KPOGntj(U{>Gm7kCzzIa#BLnSJf2Gg?nuw{Kozm`3~doCPvcQRZKpg8_Gs;S`t*1tV5z^c^e_UwaOK!WIHZNwLh^NK%Xf`hU#d>Kknxvk8# z-7L=WolYx+rCv{;*yLr)tUrR2DzwAgH>>Y6=v@(@$99&cur$wo9B}LN!HI_YeqFsS zvgFkZ4-MD;#*XBX~A@5T5VbiJ+al%8W;vw^;Yd*MthoW%*?&1EGWF z-G+N^V}XNGH*}xZ1gKkjmWNeq*^ek@Z*P>Yd${l~!AGUmB@aNzF4mXp*bUa|o5k<0seU8TyFjI#775450kxJA}s z7VNJQR7zeNK_v`#ACQv-?KJFmH||A67t$Xl1I}TV4fcj9q9Bp?`J9#Bv_t#K87;u| zP7%=+nvWw|tdz_%B(dHFrhIb#%IM~F@L{if=xb&{8DVkw)oT`&4;HCk5b=Pi)MXSl zK7~;h+ePjVaYL`l;iHjDq_Wb_LmsW`K86HM7xuLm!qO3jha&j;{cLKUl^C zggl(X0kmfr-3zvo&1*`D~bX2fs8 z;r|Yc`YY-``ONS`tw{ysNxN8mnJN+IGEDsBDgA@qv3Vu*2=$2OOHZG|e;+XRsLVrUl1v;>VD)I4tI zF)kO^ba&B}cn3sMT*sD3sO!V;_P4KFw3I4$HOR)JAzi)m=bOi*C_x-5q=keZT;2Dbo0?ifQri@{hl0xQC4iTbcvUkM^1SBbV8 z0{eHjR_3IM>acem^80%A@Cj~aDPQJf;W@`^C8z0VBD7k6Zny}Tnx`63%$t`mP9yFW zDP4D=D?l1cfpM*zqE7f4N=7l%#Fx+IXXtKfAQ#24P^41#stQ4x{kRBndabtDP2rfe zLvjPPPu;h7C{L`KC|9qi*E_G=i~OPe=8I6;_9=jQWQ~^EdGb6YjYo{pk{mzNNIdtX%&X>%5WBex;;THA&#Pom=|W+qVcd z;pu>RPKkVdWh=@orulV@p$yNckr%pi0AS$`>f5r-(*dQ36?WQm&FGHwW_#FY*P-+j z*_!5y*`0K{5Y1jcWl7#3N7xd&I~}vSZ9ilFTPOp& z4O$}NG%D)M7l83yXIGlaYo&YQ2$7PgFju!t;o7a}m@Vc|n&^3W5(ggmb6Xpw@Tys8 zXnx=oC}?+xQhHx+07vfOmi&Iz#^Rr4Z%ZzjCv0H4&LfOHl zrxt&{;>$u~-@vuFS6d#Bz%hjGvE^E9m%8Hf?QJMK zsU$;`66=m@@`}L=*ExJcHD5kUBE^q_s(?aykoN}$)Pq&XKwd!rh#)Om=WGf8POg1< zi07sAyvG8XnR1O4HX$PdG~&suOsgp}`rT~lAr*eE;H3Ig>>v>ox1@>C97_8JDNNv@ zCjxmgn0#60Hdr4ps8DRiU7>)6JdbSm`W^%b9Q@ldp82eT-bDnB>(BZz5W*o5u6*8$ zCy`7R>kj=TZoc4&px*So{*zVpYcMXs-a*_w*CX<`r5muWo2Dp#knizPjcMT$B!okt zp#uK*kk0)oZX^I3hxAIU7ZQ1N=8IU zNEV5fTexn{FZMY6p%|g@=@{m0S&TIRg*fUHx-WZiZ6t1g2L&RCR+?406 zz+G9{N+wuLKJx$s;^m?eQLkhTjcdv`Ll+zJ%lE z5~0ef&?)A;ehp-ha4-FNyqbk!&uqqox5%tHpR(NG{bYp9y>6^kJ{;@yLPH;d@_Vn^^lF^9zqNan zdAu5BgBpxfErpMss=H*%7o1Vm<*KIhhUq>OQ;vAcR=3J z)T~?2GQ?!8ASNL;5yC~61+h zkfh)Hmt2s$-%%i>PeeTFpDe&qqm!Y?XlDBxlix9rQl19~K^jxhIX9TG4M;@aAz;P5 zVZiXelhbvsXgIr{5=YMguMEeY&e}CJD{lwK!NEx!kv~Kc6Yc`c#J_MTNG>eNq%T!q zsWqAiIN^g{hzaw;Kt*NbqQVWR_#qOUJ+(yOP1docDf?Lse8#V(tIqMozg*N#DKD3L zau6xesPbs$B-EnG90LiQs^-I%?=zEw$xV;TCxdw!AV|fQ(M!qs(icukN2(1I1AkaY zSNA?&ImTC>lVVRoMqhvK?@j>XKgu8#yX`Yy{G+fH`P-6Q%19WXrMQ`gJ>c**ZB0TN zS`V=B;mQ@Oe+sU*CFvP*+`iBC6tV}fu-c`2!b}NNI59L2d9xSy&(1)8+<~*2O)>#T zOQTcRHWP7KfV?BwDrX~m7F(R`+al4`?m=b3W-}W>YGgLIS0_$yXXlwrOb-jKkT6f_ zu;OWyrBc{)C1IREn!(;v`B6)O);Ov$XQeS+cAriqDYI&qS0Ttjrxj6x5^2U8QZ4RT zBrNK%8k|J>O_fDO0sIqCC5XA zjk~si`hMgwvUT6{RrR|>^b6Po*XsC=4FN7dfizvYWo4McPGoc-OY8(aDm2#1bzxmL zvZ5T4eY4?l1mZ+4<5EXoK1pTBM;)*&d?g#cF|A(S$}pZbII67tMB*HaDb^3U<5PBi zfJCm#*%BS=(9h>B&nRC~DHU_W0QK&(c0W|}l#-re?-fyw_>y&-H)_b>ObvR({Rui; zKq?TAjilJ}c%QG?p)BbWEh?^o-2BbyHC?QtO~A7{gy%)An2x;JTkUK>uwley{^Lwh z<=05c6@?zA)Z^k#a_FoG%~<@4x~ZRT1E^w+7f3pj0kaRv%vR#E?_+}rS}9m zNTpVLk(}wG>Yy+^1-<=iTB|WJeM!?V33+k4d2xx#g{`2ZRhXNKT!NF*aZ_uABL z5Pf_X>(v+ZV$_i6`}QZtzDf{E_B)8o@+gfU$OHv%B3&(iHoeJKg^}lnxTZ_G$Rnm= z{Cd~*_{F$@`U-a{4nOzo>sy)UdKKrkC9|YQNvm+w0PzenCTG&~z%z9b37VFdQ-2s7 z%B?BCFD+Tb8?c*hA<@1tFF+I6AcBEB(g>Kj#b@vNz{_~L1*@I_8|M;CMxJgQJoSzP zHUFPH53U?xjm#Lw2oSD3ZDjZQ1)`HqB_KnzAl;KqFi+REfCSDv?e-a2+lE(sVp+X8 z$nQ$0TUf9=$7QloR7ob5Y%bF>L>&@HiFOA_e+UGUb}F9F6Xti@dh|nn(qELMc(fO zQh!}c^Km-O|E4%&`As16e;Q%?hvMwF5B|4`ynhk?{J&7-{Z8BSA4MJ$+sDw>y=$n0ke!gcrRp-kkx0e z#uz*6qP)eY{Ia`g(<*NaMarHPnD5PVF%jn~1cNJ_N!w?qvJsOnV!B=FbfE^04Dx0+ z`8rbG%+8j@?a|#wK2-qx$~VcF|N1*el65i`>xRx zEcxV5;wD>UFnN*cpsm#7FSHpTDY5DYDCbQ!nC<+wDF|i#s)1Lfg~01=Duzui{J1noxht$G6k6o4(u`t}w3w4;di-*xLhD z?on#fK;O0hLQRkjYtS_z;()oC97f(?g&wx4jUFHy7pCDOxTvmRZXWR6lYst(V5mJ% z`O9ku%KGT{Pd7|m1whF^_}pnSY{++z=p;gQw`mC_?N=YdRHcjhIOP!&*VAT6A+_)+ zPmcJrC3n~rQ0oZJ$UX~3$PvLT0_bny4xlY@u&|!esYokEwN){%sUTj=w^z^Om4P+k z8zVS|BaDhm@WklLNJMn%SRphgU`Uz{C;)zz+~OlhS#KcML6bFG?z%=|SoE9Cy{Xj9 zhR*hIwSpco*AN!FTwHk^jdbw2fSOo^nyXzK65WnKA}eZ-TDmMli6*4wP^Zh6N9P`y zOH-OWMsZsJMvB9D<8S(LaLZfod#;{`g?H7?kd5-R2cuiL4D-&T+#xoNv#Z4(Ar#|0 zF&Z@qU02SU;q8c$s0#HNxZYvw{P#De_VAv0S8K#E0Ly5UV7pSLveCb4^XtEyR z^E%V*fK&S#0kFhGWDGObL5UNu0`HEvsO!mfNEGSqr`oF*jNs8DHS7Gx!bA1U*dye}7wtE=u**9IVDh=} zj?)U)AdN{ArDrl-PJtEgjoc8S7KOq!2kX}tPRZcB^W70Z)up_MZoOHER&)zrSGV5p zQr!KK-(Wx2=I?7es7Br=U-B5V>+T7;2B1?jIeX?qj1b3n*{t&!f9u*brrl{P4m_d#Mc#3(Mhu_a_%W^Wc>@lpdRQ@RwnZ*gsxp`(UBx;9_Q{W zzJtv{XF)o-qmUh>EGRz`Qk0O^AOL$s?g?^5qSHg9Gy?asX%MW2NH?GE$LVraABf9d zEH)!KskI!5^jJb9ip z_SY^B8&MtJ(XA&K8lb{9xbNHb^TLeCru?_@S@%k`_ihz-s-!BW?yDVjHqlp~1wL;X zcVPKuQoTF@XUDPkqxvDsP#bf$z>pnB3fWGM z`;lRvf32TJT;>?V7T~01R||HTi`BA*q`xhCaukQh*wIib%8MpZB3zx$jCbA-_mr=t z!E5U3zQ?=$4MXo!IQbKjT#;O#l=$WOYofw3v{n{b zy#7upy#Rc#32DS0zEh7N`I&iW8h~1^JO38BvZroMGDxExu>CXtW6V1ccZm=#h>fpA zt^4D_;>hj|$4_6w-FIH0Et75(2|9sc#4$CkdpD4#$#M|PPYcVN(Qd*@VG)z@DO)s? zg5!@M!)d>F8|>J!qZ{?CIa91T7p*n!#^KM$@#Sl9+=FDcp`XM(RbpGLE}W$;Igy$a zAAhoo#0^y?=qp+$yKGtr;1)nw-v`50P84UDDk8qw$KUP5Z=LRcIm%rkVS3_SS1pAD z0c7NSJxZ@aBVp_rtF+*5HYhKizceu$~)QpB6 z9SZgHBaxc~J+^tj9T-zU87~T>{ZX_S%D9j^H73q7Y%J0z71B@U3|V5O&8fnGoPx`5 zIM6dp8Nl|#%mD-^Sb05ZGUuZ8xM@3#j#>ao(Wg+fUa4$y>We*3(q#-7*$vLMx>SyC zF)ypv`b5f#j3|w|x4vBgu2oE&z}Dyc9}7}dU>ah1gjU4bCtuVOrV>0BmkP=i*Lw~I zlRfqF9ZSL)#7W>J&CpWqX(r@zw-mP<7<7F?LnqaYSJgIy?pYmJ=~&C&@Z+`234`tC zvm9-;t1n9BYo_pmth|CI^?6XFGhrL%NwM|7dx(qiAq#GALZL*1?TH;5v*Tanz56Gx zye9J}t}8rDG|~eMIX$<k1Vd5C$3~m;hh} zqa)gL=4MN9PnFZEv)@QkLlJ8bb&td>SV<4#QD#W$eP{Ms{_>=ro8f3#J4WfF`=m zhB$JLuCpdKBlyO7?M`$x9%>Di$+$7iZZS_IqS1FrcI{KoWfbk>X!6@25m9Oa`f&%( z+f~A=M-SL1ndm9!-K)E?NG(|E9CL8y6BX4=mo>%4$|CrK9`i|npBrM$!Q*bkpy0o<8Hptj*iAnycpgGGYTbOsJ`668c(I;q9Z4>t)rIr*vBeJWigkk{2h62QT% zF4>IdJzzn&?zxO6#2Aa;&q8}lM0F%09DPKFi8DjLUa@6C&vAc}tW&m%I@CuyBXpj? z{FqpE;+0))3jh8x8uapM2Xu>lW{|&1&Y1|=PcHYx^0bV|hB9gc>xCO+2PCnqfZh7z7{HIk8R>0ewVKrYb{sf{pk!V$%8{?#FSm`5R*qZ3hifg7smuJUw)c!Z< zsIw89n63tf9rODOg+orC4wpsKGpj9bmU65{9d1^@$IdopZD*#Ny8nAxL>xmgrD>2C z#-)aHY8Gf=ULTQ6PclwU6HS0AzAgQL3f?HFA_sC&Qjiu`xYnEXMCA1F<|Z>1G99U* zOQ(QjUeiN;VBZ0dSj7@wh!5n4e%sEi)Ap@{&Nc!8iBQN84vz|@2-Jw*mihd5n0S_P z>`dqA^`e`(>7E(yC{DyU5gv!>o-d$HC9? zDM|MtT6lduzMzR3>h9&!Y9Y-ERJD#LbW19XPajPzngDdWbtlJNXOBgxEp_8}IQWD; zK@fbt+vyNQ;SY$}wWcBHYo zZ4(PDmxXf4(twq)wae<^1+zZKGhT)05bn+ZVxnwEUeFu%#B!uY?CC%i2>dIKM_fVC zqqQc?N3{e^^DFLZXg&kJYul@-!{ze73AE6f?80eYaFgF_E(7~p+HiCsAAs1BwQvFZ zf5gdrViOFk?RKGdA8sm_dE+k23LD0uk5UYy{?>6>Uo*Qz62Q9WDc5?mvy>-`Ri2d7 zZPu%0)P)7TB%3$6vgygq$=}<55XgPQe6VDsQUr7;+{j_5#w{$>5h7rvk`mA0Ke5n3 zL_b!-m8{^z9EPZ*GL(kP%hCfXMv_0YbxBbLQwh3>4I*esDCt4WSwuFaC6A@shhQ zTqL%~o2pzKm&E?E%&6B;b1*iVzG@}ik^$_RpQR027~ylQA8dfY)|~hMKzsamg;W3K zfXTnYcmEtP`3Ktfp9M_*72o@BX^;O7UHhM)J^mB*_HWuFBlF+7`2T|TXssq~x5CW zZk;r~?+*+-CZm+m@f*gcf9PWI05!2Ed#u|ck90Evtc<6niK^t&`1Cp6bCprDs&WCP zQE#9zc#HE^J^d*Hf5LMC7e*aw1dz5haffYgM#WqNY?*7R7^%_)(uOIz* z2QV`L>iuPFkj=3ssKj+hJqDe4S|=}Ld)Of@1yA}A$P&&6$rQ_77$pv2v70|pzFm1X+N+f)H+e>r3DC|s7#hpAu zV|ob{a_ZXJS|gxO38$jy0bf;@nJyUq_F>%*x-i+{X)>ZCo zVI=~)uJOIcxl5q0Vyjwpo>ee_5>xEI!1RmaHPJD46<$$3(mCvdi3{yyi*V2t;F8HDlE5AYJS2ql4 zB8D!|EqTv?6k|rPV1jo^z^!c;R%1tk2YHB(1J@0$oW-!q1u5U@n*GIr{dxkj$Og&x`iU4P3;j- zy3Ns;B{d?Z^96Gtx+cICmEC=$X;083W@oJ1VN?4R#X318F4)pJFI-O+< z_qY3p1MB)rQOPuq`V^Ib~std)RBErIkA3`$ndga(Mi&6m zfZUPMB^PTon8f+b!Ht=Yu)}Z>`e4PzegF(i300jnm{~vqpKRamu zdJF$M2kn19^?y=g@_+v*{~s!vjrH%A+JE7oRjE(L9FCxFUs792f)TSt+L@kWj{3tk zflE+RZ$h)FCYUQE5hyL@c!%_Iobp8!EU|S-%n4NDwcb2#f%Ds{$?uYmWK7$tintgU ze%=?z$fR#l$WEQKdA_rtmEgXyu^Dk!<$S*xPWx&PE8>v5?>tnDO`q62E9(nsiAn17 z-5?r%Kp(`VwV{j7!I z8>KQibXe_3yS`;=gXdt2{bJjf2#572?eo@I= zbFeg!oQFk5{g z0UofDW@)3GKGB*7nixFgsYjjl!a>fh zKxq6HZJX3z;EG(>gI z^GO4nzT!$SS}cRpOoNB=1fX}eRdFZ}3#>1q2874NGz${_MF1ypI#zUbiSo7#>m@uR z&~XMew7Vx9=2y*_MV>1N@C3on+(=O-qS{x8r4DJGTtp_pSTe%)BO zBBWO&$r35exxK>oC~bUE_|cJ40%^WfustUZ9Y12q7|FT;*_0N_)F3UyKS%7M1MrD z)^y8FTfu*WYKsXT7%}5&yD_To^i>d<{}IC9E+r_o7=TMe^`JRPIAA8}ZI|KJ$6B}7 ziRX|@x7SfxN~--zCk{tLNfopeM zW`rLKP#qY1`l;z2ETtN_mm8yJ-Ed**C3P+M0!UiU6#J$T`3r7vJXunJjWndiv~x!g zrywa*J`lr)kNG%3JG)IF4?*)PWL{PQCUAyil(x!sBPY>Tj^u~>fxwN-*q=$4xNZ+< z$>Nws+?wK{IOsAz$%=2Mh((tJ=9wiX0)Y5Tt^BR=%UVY&vn5V|2GiGxUI>09^)#E{ znJ1aDqlx*fATd%I=!8TZN@O}*jk`4646UqR9x1!YYu<7%T85%4-j}Y^&AEFZkCH&n z1rkU7_hDF1<(Rl!290hn;rD#|2~x;0g@$&D^+eai3~}L!dlsXvVW}Q}1UtacG0hF= zKW^y;na3op1h0QG7DSsR&b2Njn_!3_c)DQ#s8-ouE zsGpjNy^xy@TW1~>$<%vtqkjLW?yzgk#{BLm?_4ZF^zB}~r{Nb-ty9<;c%pjsORz8f zb}gTeL27#XtPujnh_cOC3Xl`I;hl|Q+MC{7eW9R+4k^jLrY?d8m>nQw!mb6GBRP)> z$RT?(V(Yz?T+lBYQw0Q8)tb%hHu<>`$F>YNe zWltM{QWoM>w@kwON^zXJ;*tXRlT_4vM3d~e_{WpAJ(6Zka;d%~u&yKL7~PZARD7(~ z+!XX^_iVHJfD8$zhRDOqK`S3$Bq2?bG(ib$rt6`;;zbau`5bI*qa5tO*zPVc_0TcI z`=VPL00u{rdQPEC!(U8ljzemilkr+D=6O6c)LQg|GXC`^)wRKTFf=p) zr~jzua3-=cu}Uj%{E@4kZK5RKP)q2g_T7Bc^Slw-1XaU&L}h}>bm~uEknPhAjRrf{Atg9|uu1?D z9xS(SM`CUY7N_80p*L_wBTr`-fD;mGlr{Xs;8Pds0va(Lbdqrh(}3sQ5K>IF>zV;M z5VuE@8Qy9nGHvwTQY+C(r8S-lfvey6ag0u+Gc6FkR8ndM`Wj5bvn zseNFwbO@kMFGN&MvDkoyi7x%S5m#k`snf)B)G=0!@tN}$iPSkiX)1)}>7@*mNDYx9 z{J9Y8E+SLaQaX=&_HNvw)&;&Xs1?|9Y4XBA!# zB?wwKF@wCpu!r3bo z2T##;70?-JR3j$1ShAewq9<0rxJ#Qs*tNoY7R?~vZ=a3?x&GQkH&_i)mLL<(9>aK{U zu=#V+EECw}*7_r-LE5<9)Cy+fO$W678KvOBJf8J7Ds4t>j>39As9z<3QuxElgoRBy>ew++6;Cmdll|4{*k( zTel0Bf2^DhupO&-FI7qjk;YoCU3nrwS8)ZU%92WsfAUGgsB?wKO{C)-!nK&|%Z{FX zkYJ=MPEnbFhuMmqWK#4JPlp1Xs`ftnDFai02l*>KApW4(IX}i3)d)=XKW>M??^KJ> zXF3&%QPTX-ZY&bxl|s2tSMIYt#@4>z4_)N)?GO^*JZtLp(fq(%d?lwMPq3YU?r^Rb zrz&o7QiHbCerc*W^}eUc@Z4$z5<%R%%Jj)KH@60+$WX2@!_8j~j3lenB@nK?2k6S` z%Phs@anGLJDn-i-OC-kmI|$@5K`t!NaO%Zu?8->0g!MZYn;?CPbc5m7@10Q%V0Y@p z4vpP-IX)Cat4Vu$t;F(s1FgrQc@Ip+yK?)hbAr z(@&zj4AQ^wRu7#I=e&hN1HTv?LA1-?Fb6M?nYSTL1MV}xD|1irYSWV0}WMk;N3O1sWGEs%#|uL zN#Nu(aHz~;sp+)FV#oFCD10+i zB!ql=#HIrLVhgR|ng@*`^y@4SE|1t(bHi%y5x6I5_+u{w6TqBBM)^wA*Y@Sp*#%lP ztrK{vcNFB41|oXxi3u$sxsjlDeP^lhlqgAbdco9zqxuoL?gwH-R0jdAu?n}VS9?r2 z=O@|{;19j=5t?~4ZZJ?NEZla?#Ifvp9*VJ=ecv5eo zICX4M1zcV@R~U9n6}zlbx`6p8hOKr301Xre5s}1UMs_px zE*Sfp)0W))G3*;$IFM@n;U};!s30+ZwwD8!iO_qC8>&n{(a#W`gXjCaK(>{bmW1+^ z7G#>oI=re0>b!Z- zW6x-F47LPsrMwfi_ddOHC|Fr+D23RKG=1w>U$nf`A(%{I0+R;Rd*X7@x>)*L52^sK z>u=hV4*^#^l~~vf#NX5f1?@rfVt;U)KPC${KZv=uw{PC{4^2fGxoMgjL1GY(=sS1$ zZM82B{~Ur9^EKIDsnC2te0u{Wyn^T37V9~(DBAn-j*nE=)Sae{-G8%uk_jt*BMi5t zl<7VRMp@W8o)ag0X+AStnn_#V+6bzor6V?nHNj7!OWS2}VnpB`?fzO(4E|tclqIMz zSSxmq9^422Ce0~jqUF`W^!-vaTI3x~q|-9zC=bykQV7nu@OQy=o@ee5WXopMQ=GYj zG?XGH++F-Y_BzcvU9Zks7OYcs;f{L0Rqvc4wCAFB6}y1dIVpozY21$DPpfhHWBKeB zA_+%*7piDnyoO?1nFIoLojtRejkkR1#JjI0mr!t9^dNU-qX6&O^|x1_>HBoR+7X~w z=7sOfcu*__8&|XcXC1i>b|wUn6!ui!tUG}%SRCe_q7arCEO0tPh%!ZJKw08Nl>$<$ zZO{mp4pNd*pos8l0v$4~A;JZ7X2H*sjKM6MV%0 zST|nYiKaPX++)qcW^-qrm1-}>!}Wt&AO$ZlyUQY^+l8L#kOM2ALe-SKgh$O%uJu|? zdzFeeYe~D9r4ICLzNr$AET)D0ue>A#&4>15n~t5b3a2Cm{2^#HvVdxDPVF@BNVtj& zk)x_jVTx2P;2ki_69R5+-Isn&s(o?m4c9qm?XCeYA7O!T>Q#Qt)vc<&+;E;Wg;Qr1 z2Ou;=xjvYXb8j%N*+=7v;w{b5*aDMk+?6m@?q?U!HDDHA{piyy$SHCvgY_!mDi|nl z!_S06M9$iHs3do1Hb*eGZb+x>j`(mf_}go>nX4hP(|A+}S+S9x-@#6Nr!UaPuETmY z@qve1qv6G)6O@=lV#jxTSW`(^+S_NjBNl0j$DH-KV?4jLZ})<7=i@b`hSI@Pjm5;N z@`S;hDM-7Wiw~g2a2W7?d3p(Yk&%@w3~a{4c!gWD zUsOoP=qdOk0`*p$%>SV(QmICko{^LMebI&bC)NB-$}UcR?u2p_&)#o|8OLOyY_1IG zbdMf2FsiTzjf9~_(NM;)4KZIl3c?7vRj>J+tR@virPvvV6CFo4nvp|F`O#-XpT|g( zbH`pFc4&(&8EFt!8K7diTPg4yQ3yx+D<9h>l;+yGsAu)r#I)AhBKNO&sfLudR{1cmQCggElh>{N~)&G4-x2*Nm;nlY4Jo@ zDgqfuG;csqqCxjOzig64>4D(q{PqD9A?DWEz0tSD-kLj zU#oDT#aGFi@`tK@{G>@6pdq+?;4Ix_8yT{N(Gq(oH269JaC|{ZOHMEIZhc(jLYGJ# zyx!>N!yT;QA(pa0r7q-xfGoP89Ll0CAH)0zI5=W$DUW_64m*Z>zf=q5QP)r7up=<2O^LcbSUJ zSgq$<(TndzP&||%uYW}IKx9Hu2srBR@_%GljVI4AnF!c*4YH`4OFPMG=dcJUH@FM8 zLc&kxd|nxv3d{hqip~N0D1e09t@&iK)C6k6_YYi0;CwBoC&7tE^<+ckQMoaf(lOt&YWmc)l3#fZ%;+FjC!UB9WrLIGbnD7v50`9*;>T%QHtFi?GeimshkGV;Jc>{cE(zD3rpG>Wo0;R3aGB+V{sz2xN(JJsS0^sBeYw_?(Vm2 zkbN=Du$n$0w~5wa4^rTDIV>8gd>uEo1CZ+rwr6xh9muL*h5$D~^CdTzBe}{xGUpv7 z76iSjgL&r8XJa0RmI3I2vnQ84l|pOKNR(O_g`GJ9goVrJ#Y|Kg{3K`v@9$FdNh^r% z?}Rz0ur4^RW18l7s4B3?14xX>lk_9jCVJS7K$p?C;y+{A?p)<`S1Bzw)zaf?>mC~U z@#Oe|uzl*mkZeY&6{#&im+~>?c;0n$(Rn6#qJmdBb}XbpkW=D#x~}TLMZ0vRdfC%n zE!XhL7Xj?R!-+iV;j5fAfp}ayputJ9%a1C`$%|y9y%XgLf%a})v|H$ym5m^HU}3%%H5t|KdX&j&VK4YUG9Cy z33vD;!{l4>(c|AybG}s+%c9>)oQv?5Q~8OSbG z(;#+IgCX{K@B6BjXcF2W8c|j_OKkY76M=%{Bi$w|KT90KHn^r}P1y^c3{H4#K96(l zX)|g`<%E=v(j9yIpF`vl8RU}ZCCii>P)%DDPJiFG+}RR9?u~d=Wq|qkJqi`VNia2c z{f(U=nJA`-Y*g&Ygsoa{u?9xfv|smB7VDX}wME?Y2WgldSQUO+Qny&s4td#dlJ0i4 z{Ph4UFd=44FQll+t2+#Z(-~6<6P))xyERwrO-2TUi#RW9QpP269=N|wz$MN1eVnhl z1;$Mjj1eGKtS*M1QrPinGTB8jih~yn5=u>>m~%P^O%r4F!JPX{^}9m;VPr(GpgWjQsUd)mYKfV>F0fxZTCLLs!P9D;)qt*ON)+_N<>!*yolLR`~uz_p_v zFf2fB?HsYES!I7tkopWnP|qm`h!(^garJwK<(*jWB0(gmxPU+83YOS+qHWixcFo6g zxShK^q}X(aH9b_bbMRm3PhycSQ|XC_>?d6pk4v$<@4Q`zE=Zd5W>D4XZ!}wnhcwpY zj9!!U8;kO9#iqv{My@{E4DIA!V%{M_*k}U)q&*sCG)9K6ylnx`J?)H;LtjMmEWw7T zxG$?~m!=U)-_8cBck@P412UwxMT`rwY>IRH>-jB%O}6#Pkmy@OdzHT=f7?pv8Xao} zC9y*=VDo7`mV-TtEk|K_SD8qY-nQ3iE9#Amutv+L548+UOyws4xb;g91RIwM4OsFn zv@9_!&2J=sk1V?c!^+26k5RUnW@!#)n~xPKL;s#SLciUX+=`5ErlCITmZc;YXPhR~ z1$9_S*qq58kwCTp=3d>NZqMeWhcgxJnpbWfkdsS`4DYct%9xRLY~y z(hYZj3S6Q9oa|Ky9;v4$Kt}bJ2JS;8q>sTcXU_n;L@HMRoCa|TSSKvQ)1c@8-^pP^ z{8-|61>jw44^a6r5LPG!bAZ04JVlbPdUGG;C*DMX{{d}qfi)+SxibT5G6ZT0+C3Fs ztwgS8x4T-7@W44b3(g0=OE-YLsYG3$2%pI#Fs;t@*wOI=SMx&yM4;MRox4Cv%KtVz5`>wMWNPfoBmUzG_(DO7v&``~q~2en z(~js2>tSXjB%g~{oBN$STYm>0UBaS&iH;w^n_oFoUL{FUVLS4h98;O?F!&;Oj9!n+6l$ zsi@wss}S|~g4~Y->mn;&c5p*AfnZ?xV+MsUA=zd$eYTSY)?Y28{fy7DzOGSR;QIq}tAyj4nhLjhloz;mbc6>t zsOi+hYkl?BTH%68_#9ha?u%QUM)EWF)GfoBgZb>W%$?>^Qe=|lnr{TZTC=?l{Ndw+ z_rT^}&i7o^V&aT!tPzHy+!9PWlm8BQ_vK=tAHoe+%Xd|%e68tP8zgH6pa3|tM$O7; z zKsd3UR}H8$UPPsd11Y-k!DAI<_Z#v}5@UU6#(A+rC_*Qf@46#Cs`yUK zJ=JQQYPf{gmM!Z}rDv-y_$=qB=!|c&;eZSSy!0=QU-*b*;IQ6&&zPyo5so|u?2E>!#xiz0Tsct;b;JXU4eISy&pL)c*;Fgmu znk=~7p;o%>w{bBpNfMLEL8rg!$4GI~ypav_h)sTd(&zep?<4-P{VfEJ5JrL?p6+A- z!N7vVG1eF>>P$_iE435qSqxKuBjPo~2F~SHL>te~UC4UfQWX~Dr%{XXfxo-la7C6N z^70*_DHK$!2zao6=RSXP6Bcu}nS;?;h<*r*BtaA<0Orh_v77d`H*N;labQbQ!9-16 zN%eR%4#(e;a|Kdl(=u*4d=ONM-}P`2BTi-%zpJ2D-D00}s(pcTpi0mOCclsgZ)$WR z6v05VieU@UmLAh z<%7d=7LF+bp{YkhGBi^!bOld+%F*-gKE1s(n_asV1OFPSD0oO-x3!m&ODN>CaphRz z@R!n*aSaS)sYSXMFkAm1;*7Y8I0z771L!w#dq2ucp9sB64`Vx4JEkr*Rke(j?qr?G zWH#2-sR#^|PlIgsY<`NI6=~ql5F7M5+h>2^VRZ47ybxqr7#0>*#?Qp-fKkK@0)5&6 zH;H?Tee)WZf!1ceF587_HAKcwc(EjN@_-N{&s5cXcL{Tiu#$u4LX@crM%9ZBn)bT( zvGFhx&@XW+ruKCHyB+2S8J>nDq@n#fFRppyB5$rFK&4=u`?diDAIUPnWqME>4T6?o zybu`xsa>hJIW)--P%Hk$mNGogXzy8A9F6-K8R`xRW%6eOL)q=WM3))nV||P#gqv=T zdgrtjjj6wxu39YU#t6$;%f_KCKvsGDsbYKWDm?X;>mhKokO@ZQ%+F20$_Gij#$(^$gJy0B28sH$CJ7Eik`#f04ZQO73TKo5XSLoQ$9DA5}0Gicw(2kaw_Z1 z_+#|dbo3TFg|KNrB={2}j%AVZijuv!2V_`qE`sVg*$`Z9-r z=fY^0i_5Xzu>fX-D@cB&)Hw%o?m*-Kl*@@32PXXyz6G8UkAX<~A#+%cWWO0|h^Pv` z3XLtUKv9PMFn`BS9`paTSn%DW1ASvp=fXj5Z7G_Ef)wHpe~Y;#bo)_}aL0LoTLg2e zy`XGkDQxG`wZKD9@5w4IU~AHWCVd>5D#34%M#7`1kK7IuH>Y z<(XS{541))5E2z%f>4QBPq=i$S4f*_-K74~gImV=6Bc+l`2D zXr17go1$;&LBlhInGhG=j=7HHpC55EuxtyB#`xe7+Ix2QWEM&;+;2rfQz|#4dk?v; zTj{;Xw$E$*yKs3V3lsK{q1W|RBYRPh6RdRH;ZO@~O!+j@irkZUDy8!_CA(6^komS; z>h1J7(l-3IlQGTGfSM|kVc7s3YU>inM?WOP=QZom)=8EaA12k0s~z@Si!>zz!iDRAgs~$TNgh7|=f3&St8C>)9qGr)bVD>1b!gXlE2c{z^YlE`5$sNM;0> zK(_~=h=+($Lsl9FiH_S&_=tdE{~amtsg^>euw}xmULZG-_!iC<+uh5ut_O}HF7{-F zsC&{^5dMmwSJEX~-(c0A1Lt(bnW62&IT7NW*SVNuQufj|1~xK4-)FVs$%tjBSBE8T z4~xUV$Ow24p)FZ2kKygH5Az1%Oo@IF59tSk42Oi{EvJo@L~<@mnBg5~Zf)qwWGs4P zE=1H6|5Byp;u{p+t=l&0ezf0z#KM?O_D6e)bt}lGogCW04(X79SQC!Xg#dN$w5Nr3 z%tW&Ls~dh{%-8ae#C#S@>tSpXkXHA$Y<*zq!yheLx zZoNi;Ol;bd73UsGVtKX-fKX~x1H1GJNEs96FuOxqVn&F`!&)suF~}&OF>yw-9YhKy zG?EY8_oMl8n%u0paNZ~bU_hvKTe99YuI+7UiZaJgGi5jQx7;4N4$OtL_o>Jzs%RZj zo5jEy&^dipzCN0%2x-+8Kq4D`}Zf`@HyzU01{|Mx&_eRU{6TYJK<2{)ElI{{mucT%MI6rzLxx7kMzeskwWAQCyD-{mAQPjpTFbr@7DI!_p- z3glD#HG@wf{E)F-d%&7U)US8>;D{QC@$=#LB~S5tzB4@|Yz|AKkIPd$qI zdx`h&Eeg=m4i6O5S7J)WvL55&<8cnv2xat1ZV9fiuxBXsSwvX!f|nd`p6@em1$`G7 z)(?^g*zei(o9U05ga${6%qyX;g96qQ^YPBWK*M^UYps^G#@W=H05}WBql*f<5H@RS4mpEvj4~^%q4VGlmmd z49A+a44vIQYWe`bno#gQBd z@FLhHW-KUvy!&AMyo{ImjB-V-uk@H{TH-+1< zjx^0oC}H_b`~ZKr-y`~Ae#fB|*Fij<6JY^Mi{z808loTedi!Te5Vci|+x6P*>=g?h znF)yb`-qiL@8axyK7r04JYf0}4SDy!8nEBhkj?l_47o32BjpovXCz(h(Ja9WW6<>N`cdJs2qL?1eKf#289Lmh?%0A2m&2Y~C?+58Vg@qcO-`@ayy|CN9I zCv=kiA28*AB8vYlE&CTF<-aA0|2xd{e}X9fPps#^iQ+7O*~$NkC|>n1`+FmZJ&)>B zh+(ocV0N#j(uxyw)z#+b+9ddO1QJ4kfFS^>8`=-}37>o3UjPtQ1vpAI)tZJSUL9WV z_b#*WnakUmeZLyltC8sCqhk5LC4du0R-l0!IcsiopTjA=O5RK8H;q;T1>E8%s(rs=dq^`9c6)@(uS1Gp_!Gb*J^kA0+isA!291pT7fXbk zd|04hfBZoqjez_FVx93>W+?)maFXW9D>8l5tnzCVeC%Fpjn|kBdwmFG?8a|P)U`L6QdK9SfDI@Pm$@GP z{ll7UBwZ@ww-w<{orC|Fc4Qo`eaU;Q6GUB2Oz)hdACl=2j{JanyCXv6g)4@q(n!Y2 z@V}@#ryyOzHB0ZZZQHhO+qP}nwr$(qW!tvxs$EsHPoJ5N?wOA0o{pG{iTLyC{~|LZ zFEVniZ$0b9!$~eBJjdn0OU#FVz;v@AB6d6sm1XFNeOjBF%t2fQ1H(1&nj@$+- zyIg-83P6{-zo{TMLScUAx`ReMMs4X?g5VUY_2x9hqurWvo?0U)E&R z;F*|2gqFu3V#TRWN3|rji*CbE4+lcNObc>cD7J)PCNAyBzJ^754bppWFTK|lQnehSnaB?G z7f5+bcH_z(+p|1$io!+61c_TFXl%l)@7WO$Z$u8}Ou0+Z@h19MfU<^lh~WfC)I{xT zqsRVq6R;bt?2PLp(;Z79?+Q~K)QqH$?OLOuGaJK&VV}NntK|%9`^x*uQc&mbr5=tb zU6aqvt%G?ZGgv>C9haxLb=v0Z^s3O%l8zH%sSeX3#)vv#+4OzZNRw5TZi*i+0v#Q}#>}=29upYj$$h}` z)gP5sPbK*V0?`x>m5&Y}#$j2v6K+w*AiqzX&10ofLZc!G)xdc{F4GIXEf>tfcP={u zQWsxhf{w>bMu2ZBbX3ByN_vye>Lxo4Bu%u)q&x;; ze!>(Jji(?FIm+?vB|%z2T+8Fl*{^5=!4fd1^P>SbS{ZKpg-lhU8i+h`ZHYV-^l%Mw z7*$aY*E1DysqqM4*c-Zs=P_%~QcV9r!k)BroN=K$879kRVi|Q*oSG@U9p4|Ol-g+X z043TQ$|@u#SiEhKtpf&I0nXRLM}Mu~UxWNA2Uh1{iUAeKE@L9s>0p^iM5hwsE)*PZ ztqU=dh4W7b-lV8CbFGxIFQ6*U@x9tj@)deq5CGlLh7@v40r2KH={~}FOBQB{DkCDT znU$}iXuyltO=(~6JPQf_VC9bGGe>5YE9R`5mSQP@SHkxB<+iVmWP?bKC)w#ul$Sa> zhH1sJEgLc6AV(o7M6C`?CB5dtG3=NvOr(`gqe<%X_U@tZOP8&Ufmr;tNivV z$zVJ5WCYAdcfr%qIS=bHjP9>m9S|hDC1z^^Piy!~!lFW_#`5eK#T5YDF6V)z=IX2j zC?QXhU!6u|+OxsE!im)6GjZTB1d+Gghg-U`)g`MTsUz2EJ+Y#qIVM8S!Z1Y;II%s= zF7w0cSnPt8lR@i*7LJvnj`?X&562l6rM6)g+Q~s3f{6+SDHfenf}6^6Duakt9LtOz za}61~fCkKulQzjpz`VDR#6A*ggX&D#$3V1#ha#?bkwxu6F6JP#ELWpWI-V!{gfn2p z#@vFHiT13!`-WHT*B#Ro-FHsRj-7l#!UqHTnmgL{)0hJvPitHfsd^Qx)# z5lT3WceW%M<8(%K%Aidi&#CZ~I9e*Ks_BeqJ?C(OT^|gy$ZUv>CqXf z3ig#Nf`0SD02+VJ&og2m>qLDBjb}&GP?v)qa67VNblc;h_@Wfhz74!1Z3Q<&fFPg4 zzN5?YD&&;)jXo5BL~C)yYqhyvQZ;z7ep{fXL71_t5mp+0xO7UsA^}X;~9r7_)u1aOF;^GxY$O4 z>We}p2QVR@tc@eCfxfzQHK5H^1j$bge!(>KfWOF4@CbRD>K+gTuYHk?#dP8$q1X^@C?`#p+FHc3|P2Y z8<0(w&c|8Rpx&A>?io!G?P=9m6Uw~ybxlVq5f&8K@lNMf=EAXiWjOx$wQkd!SZ9}h za4Tno7VLolX#>~i}hgH#^`vmp2vhc%x7AU94sxM@Y9EQ zDAOkrUeBlE-5iGq|1v&?5yf7e_dCdxaNx}{CW1WB2=cJ-IQjiW-c4chq3d=xwG2M) zna&7wrabqP_zmMJ+mUB}1{YkFP;*)bXT1^jJ45R%R52FPl0oi^;LwXSuH0U?U^B2P z-eR-z-EqqlqD$g zJ6WL3pVV!LKjT_svVC5qnQquY;*j7*;QAWgDHU~sVE_@a&5lRJRk3Q*V3ZfF2Ql_b?;1bkaqbjTuIybQujm7M-sIn zl$n`i&$ZWS*O*OOzfT^(Ft80;;l@sOt31Gz^8aYdaNV<8P+Vp6Y({cYCmOl!`(O?` zT_4XZg&B!;(5Im-9TSPYXQBy#qojop^)d!$gZGpZD&@Mkr+01JIAqK$3FN5HURE>M@92 z#;X?1&NoEe5STYn?6sBwhF(Qu6|^30C?fvEZsT=(6F=`0ztBRfFHFS`VkE}JRkmG;_VYyR5SC(4aKo}Q^%NOVJ^D!Z^!m@Q5-hk5RbV^p}{Tq}* zhqviiLeWO;hVK=8h)IeGL?4n%qQPMtCYksX$PMW0Xs_tklA!fK%D5^ogYMP#$Z}eg zHBEwL3q+jaL1%UDP9Eb1ZlAyE`kg-+v2^v+Vvy^0*E!o`@sXk0tn7pLJE(>F^zhGn z3iS*U=kn1{ePx|}Fa5|nHBJ)!F=yeTsOfFpikhD{PC<1ad=xOVf&f}PxcLE?iZ{tS zamXz>twEMiB0#G+nRrH$Uh{Y-aB8`Z2&|WGI*Ymzvie6V2i;{H=Vg&z+5(+350x<4 z0;0OflyZ6&L&!-awa@3x+S-r|?JbsI!2DSmA4nnE zGJZfKxsx*-`?YFgE&85zgGJZdaYbhrGvEL?1-Q{kQd^$+8Ub=wP<@D(VGTMv;rf;M z>IrybFd&=o!HmzR(M!pC8(TkUFMG8v8}%m<`X;I6)|JOaIky888*vjz(tw^I^13dT zQD++)85Ls7hI6+%3OwxIBz4?F@bV*ExnQ41K2nabXqFerfkb{z+rWeW_w&tavIagjW%sL)P=-rV|Tp0&Oe<89cCN&aS0FmkC?}d zSsnDrDTj}LpthxQkpMMpH9e-lu3CXkb=s<3l&uRYZ(Q;qE#Q+txb2L45ws|POFKCg zMhXTF#dKItn|qH1A97KqK<;_7-~8Qf& z%s7Drhw9O$dCEZs8n$Kq@(f2nT$^gsJyUAWmW$(DI3<-~_^CFU$;rm9M0zc2g8Pm3+h(0^)Z{ztHb}+rW!2Das$8K1UIIlBWUKS&#aa02pJI>iEM33`9u@alHsB9F(=^EB+0ki54Gx&0m zE$V>?Ay|v;FF_8?uRu|tWnA`{_YYKB%yh*+#uvsm!%dM_;ldX7u;R{a7# zDGOK1R{#k{^X~AZ?+O)rt%-MobTD297D+_-#}8AYYFjWjZp>5o+y%9aJQ@%OL@*4^ zT}bgk6Jph{J)+}qjK70^#B@1F7QoOs&jmhm(?o3uMr6F#+G8{F2MeQyWnb_7i&o<; z!=1%NIER``JQZGLPi~QkYvR}GnuKuJJau4yi92Hu5FQB5@DIC`?Xd z9c5j46b`P4%$L-&KA>L>M63$`ftT}dnwtLWUJm;|4Vi!A<*@&2kH~-K<@|Huf5*%D zm#hB2Yz?6kWx;3opJo#;FFp*Nh`Y0xlCy!c2|hPBKAo5n13m*i(?1iM|MI_(owc2# zlD&b^KNko&vHoMhKhvN8Sn!X-#Mby9_xvvp=znVvVP<3bFZnv&YFc)Otf;=Pb$diD z<;;X4+o)?Gr50uBgiTu3+;Rd0?5s9cqN&}9IZ%;bDA#a1PDKaCwBYbjNBbS#rxSQ- zQEa!>jFufb$Pzl`$lqs!99hLFluk*;sx)v>Y-&mcD@Y2(mYT0oY<*kkEm^1*iKP~` zsa7AA{_BGWs(#sp?MpU&QHDyyC8`Q1iP~^tyNl!dVdS-lMa%wDZ|q~Yyo@9ZbssU9 zM-Rvu%ncvEq|%T-kTu?JOw-1$zuUlv$xgO>N3tqVb5AApu*{C6gPosdZO51yoBp~hPgSt# zcgX#tpVZjAZdGc%k;%aY_R)Ky9e?G+=R62IPECF)`5akESh>Pfw6Kvzxo|%8=EG7w zV6rkGW{Lg`KRHxPxmNlk?2yY|KWhAeD_9$h4mB0yk{oos~ zl~xpS_(QUi#kNFKBrTn%$CcNrZhzKAlu>n0`4fs=_Se`W!wCDvu&p!HZz{|dM$^vq zw?sI(+sv}0v=dA@41f`aDASC!U@K(I7U3?a^$^e_Q5Pa}T6+3fR&#*GKzVvXOFa>= zcf+r2-TTk|4fT1j=dMFJx!v&!V`0B(O^>ZrF)s8dj%Sh2Cm-0PDw=*R3rN}ljpGU2 zk8Z_Mq%CXmhWbJsFmB(>5V2J>v6J3`g!USCsoO;lw5- z2I7C<8*@PO(0R+Ir&KFP6FQj!5UPDOYYMdtGz#|&`;%doTEGb&g)!Yur6bB;)3-W4 zM=-t%q$btOuG>T`&-;}Nhm}DoFdSZ024HA>g+mSnkg)0K;ApymCp(R&3QT3i0J2s<$Xx#-Zm6eldyp;tf5G4Pa*g zS2yJ!^JEzh-D@Lx40E8ldj~zq3w7&yY(|sM6=ElrDaq>p;7|CiO+qU&uv(!#>p+o? zLlop<(DE&P#Uve>>`8)J5Q?VLb^I-EzGRSPF-8w|Ej#SR-;FVM+4+9Eo;Q$ckF+c# zqOt{Zsj`awDi=+RyukVSfiEvHVEcz1mS|JYY8=s?E(M_nkJJ9qe)fK7BKoi+Oe+z< zy(1xdz{<;43xz<5)tiE!4AX~Y54;oJZnWT%IQgw6tW#kxU&uUYHBvkyaW9a!$x76r z+^q0k;&;ROY#0}wtdOG}2RnfsafDLRW)v+(qy9BkB!>9-XPGHtE*v#V9RO7xlQU@ay1Ic-UNHU#;mKWIu>}u* zLY0B8wdVtBIxJBRarpYhP8+tdq^5qltE?>E~ zU&N8~rupVwvfDlSZzx|LsskN>qHlA{H0>6?W$PV?#fa?Mhfa~uwCd%9uzAq&&f71+ zztSP&QqzAxcu{fUy`!lGvnyYSqUeBw08Az_R08 zX$sKsdX@USMXKp*h}aD#bPO7E-@y`sY_(mJL!W$1g*9d*N6HNDVCoJS@R5PRpynE+gR{J~i zMnUU^KAM{i9j@d1SGmSl7U#nIn2EKzmnl{{QeUpPD>{Ozz4~{IjjPj5)GUPvWbR&p zwbIxeQTdYD&ZX>iCKHq{yEOii*f&Q@;|O~21E8KV`hz_BMF%}QB{V35QvvmoGOG5O zx;iR0T8Kt`CJW_R2eJ}xk}mp5F=if)o;mAWt~iH?GV#sZS%lNYNlmAqw}twUgEOLQ zp9p#fp&xOH9ATOa{9f@;L-A1*braK`!JPkl#N-#{Z~LAoN=AwzVXkZw47GuNa<-5edOp>j6d>_w_%e+j>%(-c1CQu4@DBl4 z$$}EKP?;KwQ^>tec29dM2}RaZ9ktNw$7)SoTzq=P(lv=me6m1a(bIUcWs~-Bd=ya6 z{Vfo$H9ghEbcf7`^S+wn_omLK4)vbckW|{uNcs73AFz3;aL6~hpM(K7-jpg!-l2w3 zBjxrdz`iWXd~+cJ5GPRr2Ay&3BbXojKS9-u%~J!Clm|q8a~XXArq)Ljg7h#5py}D$ zn|;YZJo%=it5aoS+(^zEfN~w0Hd?UNG-sW(?y$RRlE?%$p%2VF zvAfEhCt=$(23!{lw(FIkZrD;xI$3C7Dx||P6Toxc7r>o;cDVGd6zt=+z->OMOW4^y znV{?6h~!!O7zM7q0$W^``KrJ5w&CTpKBr7q=L>0u)WAT_8$43b%B)$J@hr;#gV>9% zmA>;!v-Hr;mD7c~ABWC_NKvA$oiFLFQ)QI!B8aH;mx?3PoeLHr(VRXmG!?24)IkKj zk(qYY{Sy66zPZ}P7d^mj{<|%6S18j48LzcP13dG1SvH`DfZ3vpW=-6EDk-6LoB_0%wV7AqtTJ3QH>DbcSZgT9l?zg+-FMTm{^ zGOjPK-ucaoa3*A6LilX!HlE^)4_tCUw_QKCIAOGpAB^OjzmCUGgyqxYUQ~;)!KGI? z-Tm{09TU}bQP*Tt4+IE4W%bk|yGrP&ZKiv9B%2Q&itBVf4KcU+zQ6I%;66$!o9Jw0 z`jXAxb zcDR9ZFof$Q^8Rk}%31I^^D|7vA6hb8%zh$bo%JsKrkX8d_EPbIa0%O}4BcSN?^5gU zSj?L)-M&~vsw^hNKZY&-t!n$Moat-!`qDVLiLJ+G@NfY6G>R1R{@-* zl_T81Taj9d-v_aop;#;$>EJ0At95>koa?DEW+A+j!?VamMw_I4ijJrquyfP-o_BS$6g6?9{ zBSwPra-5BLlM~^=yIKYk_T%N?61>O}3k+1I=GtCOEM6eFR#oOX*EQSiCrfGp-#H6e z?KDrb*W>LN04qUGy#Q7LVVy7UJ_iYT0aP-ZFf&{)l5EjIQ}0Iqvj%J-uPn2O^5$f2?4^k~zJ-&{BM>seUVf;vr4gewlGjy9{N*X?ppHdj{e(wC&OT=C!#UxGGu z?Y&gcM)OS8vHY&qDSLf%z`WpN?)}kL>lwRMIy@tCHG; z?u~Iea1S8Df~fUfBFvO@=j4724=E4jNq{Cs|`F?)d z9CBmiQ1)u;#-43j+qke!RKEtB`aYD7wM%WZRshat5Iq4*S#89Zk4sV}2lbEcfDaI`{ku!r! zx@x{Ro;JWEF<%t}N|@!viH$m%+^P>LfqqVt*83An%#{v0NZ5f* zngC5Sb(vVgD)78ys7)}SZ9gZV$-ymh4gI`B%t5mcJw$&qnc}{cfNdEzi*@o9HA>2P}81ATq>GNO(w8Eq8ZYG>Y^Cg67P4icT{wPv!$RN z%N&RF)nGIC>-}IZ8Ttxo61P!5TC|&J=!R*f9;>vMaF1GdlyFnoQOZqdO)x<>VNEny z@qX?8YN&5`_&+^F_J0u2|LV*A$5s0OCnU}O542kGugNB4_dlD5+5Z)r{?9zbf1d5X z$lfn$bga z+qOXxK{#z+2{oXxwGQV+i7-;RbMeQdo+3W+#5G)5pHa^Y{Ts&e{>+BOsYR_X;#Jcd zI&eKooQH(+eT>zNF(t86p}sbi)p^mW@+h>Nsa;>4@7BhwJu&5&+w6Zt_Wn(3gspQ? zB#$Fe4bN^?_Neko9AmM}CQ3*8y-cJR$1lrHPZFp7sB&1p228B}UN6biQg8V*De~3% z!~E$x;Mv^^>#5!6%e8nw_VyujHl*$VFB-*muwAEFZ6>;8n3_fWO86W>H}pj<<&ubM zus+48M#v)P#QcT}cgakP#cAVE2>+9yB`9roKKf+k9PX!rd+^j_njyPi}knoL(BH`VY1uPB%SpwA!u zz0?vj8Q`~6kePpC)UaDM2s@TJ=XkTku(x0^osE%ufatzWmso>*i9~cYIkUc|?KX!J ztIcrsBJvZ@>6OHb&fjUCpm7@Vw9~`u6@jwLC`=PIJSqw0JfF92N*qk?QtD$h%2+Sn zQ$|Nh?yQ%1>24J1%yLL%c>FLb#JZe}_vdgFkGWmU0Q1BYWX#G$w%U})z$&8tbBbC8g*}V933f3nK(&SzRj#OMK zhF{l}0wwSyWQXBBqjr?&R;xdHb*jTILR^tYW*8Tm6B7>NcLcF6z?Fw$!Qi*jS>9$T>rAn&80wd_CPX{IL-}#K~t$$}_9_gAg zV%@GgPMy0we2T%F6Bti^+8|Nu{7Df?#Dn2z09q51g4QssKd$)=rop(ua0{o>(o>-o z9yhvng)4|=?8SJdB|v8v+wyWyGEWwAr}E;C=JjD=vAOrCMk87mZxv!VOtS(wg1JZ* zpPDYM%Q{WQ3sj1%&Dzcb?ZVz>@W4ndB6dkr7utCk$KR7qjVZ~%BZC@g>dByn?7?g* zy}IKVX#LV9nSBIBJizcxkm={y8r?IPM;e7E<3OOXwS=tQNWq#eNFj8tB>C6tqutY) z!kfyq2QdtjHBYCk{wCru5t8MIjoBYVkA#9AX2@7DqJva$fRMI#0Ab=CE{Ljn zu^K}h0>J_)0!S3rrup<+_NFNeLuZX?v&{Ud1BICu&u849uihHPc?QnczBfx?rn9QakzHa^O69{yE^`^Q1FQM6dUGTa(2%@l`Ir zNy$9zm$Q!8V6X|RP>uJ=@Fx5)kl^Zo?x7$7iqANMD_}0zUf4lO_Q$)#4+9cM^MznBNH%6>#8x*2b1XMZKwQ$li#^A4RGkg|nfW}!}hYI&8$ z>=833=b%x?>7wuxuqh77o7p)WYizJ5$l;eD-yPxy08$NGP?`HXirvqtl#S5xkhFj= z&Koiz&az8lZt)O@tyL38s|HxrkI(AEdzR2ZEMmU#Nb=MGU%i5RqCZU@%Eg^vnVr1KcGzG!=Hk-un94a@xPW zbNhbRqaH)C0Fty}cf}2QvdYroCclMsy*rj7r zgPR!SEurHRFng?yjr0RRS}0rQONht-Y`p9h=$*23P z=Sni7LlB_cM=`x&=YWN=-o+7tj7g6nFY>C=neVQJz%G2YCkYl7Zi^_xFH$jY-XT!&-3-k#}_bP{+gv~2*;K5OrQ z2+R;kIJZryE(M5K*MacF-EEX>n!nChH~HRPF~kF0H9tiH2KnOz2dkPdB?dR+ES^p- z%kwD*o|mgp;$5hK*rm|exPaNaiRBgBVE7e2+lcX9;?%D*ocBl?>NTgo9ztD#k4I0A zdKZ-{Lu8)XJeLb51rCLB{JMtC6I(__40ZJc6!Xrs04~M`z}6=07l1YU1y-L+MasTY zcKWLFyA(0x$oFOx8_32{lg}s6Kg1U+@)*(FfbXgVNr-J6pPi z`c+BXeSzv(sn_^Gvm0E`$K2G*Iz+ZsRb}g3MG_@=4(rJ;ARPO*_O+|L@lTK2I$$pI zxAlZHP3vNV_;jNmhQrH2`M43Xpfe9aK|C=MK_tj5Fq4K?a3qjdrJl3fB(0%<_x_J~Cc!Xq&Rh}cDT9mCjp#ta;T z&V7~O&z#n(bFlgs$5&RK-*c+?UjCn>F6@i1F5<1MxcOo!#bTjm=&=TmYxf>>*`0$t z0#^$O+kTLBso1~<_?@rFv{Hqlyd=lJa`|6@fhZ#a=UIj2ZoSO`stg9nXiQ3TUNM4< z)VBRV&4Xi0>-**a?mr^}t##-l>Mg~Z+;w!%!_lIv8;g=EkjbYTD7sh+XUkiaE)O*O z8j_@jO>ewOlq)f3UejjN+`Gve;&Vy?XU9PVb$B1jI9RW;Q_jGqx7nVYhVSs|4a!Rq zU?0#-fQ*TX!ThbexAdYxgAZ2x^KZuYwwd~O5=NwDBfwTBj~Js&u#zC zLKHhnl@zifc6 zQ`ejKOQ;83f`}Io_Oanw+Kz@MX@CGT9UILxE#!^729d6ofUhypT+C2Lt5cJQ_g?b9kjx@o7aU0{X8pmY_!t3hFx z%<{s-N1J|Tm}nJj*j;1lDJ4C|4c%tQ#nB-Fy@L5OW+<)nGi&{w-uM;k-`F;T2b&Sf zZf;cMsU4pT;WJqGS4rWVx=WdKF>htmq&N+!=(1&E#@xw7Nr96kkAyby?KE){r4t6= zz$0TkNIeqYnw=%7gm$n7O7J_$pHme2wC)7W} z7Y>LUgtN(hvUsxT%n*ml8cD&VBpL=MkS=d=JA%8v!0n^I)mdP20m9HgU;8CXP5YWq zJBM1xr3nw0p7as6t$VTzVz#zicbBQjq1kH*`PS$st^dgX^^ncRX99ZRNXndFDz7td zK-)CrXG|^zYO`IJQJ^NOc~lcr!A5Q+G=nCqgVM(6FLEb|iRIQye?S(Ao%Q1)o@wN1 zff54<$5xd`jgKdlMh|QdL@f%W(~l}}mZL|_!!?e?;DNmOPnOP0DL`7ur#viS%|aOL z@!oaK1q(m}A2k^AK&94eyMbM}{1ou^X+iHs&f;2b%evb{?7r z;UyXB=~3AL$TKcVH$XW6=vnUM@BAO1vJ%ua0LCArUmo_CqK!tKoRGSMFSC8R|f0^J6=`U*2 zV9Aq45jgxQm0WHb+HSR_YC*Z5?9{p2bX6HB2ix@LP?A@$Q{mWMX_GdKPd5Rbg5TY6 zUeXfGS1dP&jFdC#FW9a01Xq-{!Agb%?Ar7c(3%U^rW0h*x>u*+^0Y|ThCz=v&+UYQ zMwfpSlu}|VI%-r|cFUw%%_>#=GmeN8TA@VqzK2t_#2gu&;c2Cx6{CG)6X`UI8A;D< zxeg2~?6P-`t=!<>y0L(4k6d0XgAzRTCWnl5`if{BoK`QI;sUB1VIyz;cgyfZ7OjwWN3-h z5B;%7AIKI%1Aho)a>%U#{MZO5(4^^DP@i~(_yyL5^$W~SWNG@PmHwyo)z?0}?DX}9 z%3)XNKJI-aHXpXvK;EM74BoOW|B#`;cB+|avu@H1%thBg-(Q{xz3nfY^c?$<7l5_L zE=oQG*bXYdSL*yd@_tA>hCXng1Sdbfn8avtlxT`9DXVCIpxc#rg&&?(IMO5=6wSJu z4@*4n3v{!=AezlEb5aWji2%{SboW4Fgtzb;R{|E**p^d4bXm5$t!u;a+C6@u0*JeG z9of-&WTg|$ACK6QCLj_Y$;aioQ@XO}2NGT5pYdSKvq%KXR2V@?3-VYFJmdDsqcL0N zpDFJyM=^a{s{vIFJcW2a1hCzjIXK7qIPprRA&D?}y)zdj&hwCZ9_5bGfGkCH1m z-33w?XToU`|KcV}U{T94S&0Cx&+joDW0tEBvkM$Jqh5khe&&zDV)Y z(#zM9U)P!}5upc)#N}Rd4DjZ^!6{7=&e$2)4m{B$hV5=_Oq@h-CW?vi=2R#(TXc?l zbCwpl%lEP}yjT@DUBFB~BH5>&Pv!dODr21{?#~U9yWyYQXz#L>x7-g?ZUTn!wc3$k zT%WxArBwk$fG6pAB6h#QrW5IbbCAfx8tbBH93uUAy>3iw!usp1Qeu5z)xC}D_KHg} zz{cRz&=9;tVDi5`5;M+uTu>`M<*i$z62S+T%P{S(d2;n0f2OETw=&T_E~3fG-)Y)2 zBRVqDp{n9#pz;T=c@rj1|D=rh57JtA%NxNWxDBU!sGoX{yJ>*KKb=60)9BhMelAnF z1iI`NxHWY2z~P=UpQG19*vp+XPs6fIKj+Jq-j-e@Kk}Kt;RHZWLKDbiuTJn5`guPvgO-a}O&O&P&p7@QMC={4-bNN7XMRdNt1rNq zF1Fi~6hZf0{K}*$`Q!k11KWHN%EF=_ibZc;d0T0D7{m=*gdWG+t%C4&(yrv&bW7?u z5f++=&0VQ`-+n0KqPD^HusOT{-GrxGH;^n7!S%Vz{y+`{yU4i@m&^fskL%%Y~T4v#-u|XTD=B z3lA)afUG4}#DCLh3!U7}9eu)?*>>grIwLG4`MsGYL)3$JB1>~DOPWxLZ+8)KG(NiLJKh;$sWl*BF1ST0|O z^Glt^BL0mLT=K?vtby{Ifcy|A*YJf3Rj=fLQ&r~-V#93P)mzlUYJay{ErW zUv#D5zW5fu{mVE4t1RG3U5}i^hQqSE4{RZaqc_ zUVJQu^geO+_6=MZSdOI2FKsLSpg7Gngj`61eR-|JT24~Rpn3*r`jl5B7}VJmlyQux zI0K_DSJycu6&yOcM-;;Qc8W0P3@}Sdz~#!Vio{AhZafZqgV~6>{q4P@D{Ea})(uQ@ zqc>S9X7W6d(?`?VqkxDEcY;yx^a>59pF_$uBw(C*6-2*46M7dVNvY(&&QWftF=j7u zQzRBI21z$|TGhUI^T11ca%7oRPkVrxC%%Dot9l!8JYib7&WaITey?i5Dk|Y4K&hasv*&mXXI1dPrkqXddF?FD$ha-SZsGP){L3KGXT&cjv;s& zau>mcx%2ppkCX<-h2$1M(Kk)GdlFog7ZK)^tB$#g|Fl;rsb9+~X}`cO3);a?QEZkI zyuk@)o+(U+5+i!vS^mVEy3f21z8aezP@+F3vd8~YmHjJbj8Rq1izz&#@{G+Xd%2mR z9B~>4Db7-YChvlL7F!O@O_7e`A%7xy(>ns9kMLzwxSg!m2-;$asVOCvr<4s<=|yn9 ztsNR?PVep;6V774;vd3(rT;uVSfHRCEY7oLSSmP#+h`^*C>>6@&bRp>ND6|{ptAak&ni!=U zbqH@5Mv0oAjmQ^!czk`GOnv8M5}){u>?I4hD(D{(6R#_EtCAoMS(uRy#1KxqG)N`?Omq5aRC|G(Lv z#5%)V+1U-yE8kzZX8fd-Uf;p=`+YXd&UdF; z_Xm-phILZ~6S)F%KaRIi+#~|_K->nlYSnI3S%oMk)UvvB`Lb`PEfwyKLI7>J@9{@H*zq;qgVUO8yH}FHZ&iOq_=Tr_##hlS27fvP!gu5y!ZK(IWoj zqFz!OJzYEXnlb{4ds;da6fd5g*>)Y#CHNA)4X&&u8^|MhkP+^8w%s8k#on3e^W(|y zyod-ucIrLAHM_Ygg1;M-C+AbU-l6j5up-&O3JGQtU$t~>&Y8dtm4rFKoFuverjRXv z;uLxfhcH3ft@$zm>Kc!O3hG=@3{GF-o{e{9!r~X2>_4>fjRPaho*p8t!1wTi67yc>%Nh;TG>nm-haOGT6CX1IEuJjtC5Kl22tQ zvl@Fx#~ALfdtTk(Cv5Y*N@=>3kBtrbUDfZM-w(AHG7?KDD@~D25u$8@NUE4Z%;nTL z@I(BmmYnISHMi}4fngKbgNr=TO+>c@R3l#pe_35rlIh98yMSqlh`8NUx&J6JCSY?7 zLr(lSVQGo`o~i=&l!c(sa`l^J46()3ll*SXDtP|LYEFrzXoJZ?2#c$ePOIju4wP|J zwXkR`5iemON1~Rl8j$JCD0^ZhL-vDx@WpvR(0u_g6@|$ra5P5)E^5B_c#F;69v?U+Q4b6YQH0~t+2(S<*2<)q`ET$o%Bbu5r0Q)Fy_#d z9cH+?X4g?lxS#uUf*(-J;vWugQ0Hci*Q~~Y*vauq$xWZ z{E3wF>UFP=Y->Z`!j3et)0ynQj)f&y?rc)!aDsV<)a!@Q%-?tc!c#;Hz+rOmlOxVkAUY#mF3!xP zb5Uxtx%#E)9^e_2Dij&Arm@dz)e;Lmb#v9Yqu1$uuFh!bWqhi96=!;W6x&0Utg>F= zwb3SA73-~Ub(MmgoI7h)N2oFQM?=mZCt~LLx7P``lpT-##u*tm|3%VuI}(3XNN;-@ zE4fA>89KW&p$lx|SiDFflsSMv%sBO+X$kJGa*0xPc$9a6IxiI}gnNaYg*i90xhz0Q z+`hal;$$$8-27zP{Gfp%tSTX@P>^(^HwI&E^Ey$;P<88;LBo}K_nu+?ev&~b(Mb;) zrul08#9WF=pOY0^J!8FhTufLgp00wH!SbUkl`@UfS)RT1FtZPnEM)Np$H*ddXTo}q z^`r>`!qg%7JXxWD!vnOSAOOK_-&^|k@qWQ^=1hC3k|%(E^khy?AZ5En_)$@w0w?MY zkXq{gukrA2vqg<_NeDNR^!_b|bD()0#b1?Z?qHci#YiEA`Z>6VZW_22tI zr~iYxcMKBsOSe4Jwr$(CZQHhe(zfl)leTT0v~AnYJag(+*MF*~YvNYlp6Q7G{zmK_ z@0Tam+P}4)jVacv!|f^l8WP|g*4T=3{3`>-CI zx*CyXQG^9V`o0&DMRHyE)8r3Pdq|i76Nn$5zghKM_V!D4cV|H@I16jMLDbeiU}91- zMMs(`b`T64IAS%6hetpan$>!D^2@Pch7WLYYc#WB@(ia`MApCWU=?dxO}KO(Q#EEP z!~*FK39%8lpGLZ^8IKSxs)>O z`aXj6v`>!2y(~QaVFv8vOU$urNXu#XxarRSY>CSVBw;exGmO6zkmkAf=6VT4_Jh(t?#$(A8pib8Du>WM$(hK-vm?S{HbGNYwbmKl%;w({+ zki`~2sFtRIavs2tD3r!cjQ#mB$Ck6u7NK?$CgnOeSN~Z$Ht?G_cywDG%-$JGlJT#61hA z5`Z3uMk zZL( z7a{jeFS*A@vjKR-Tu_m5?xkmQeuGL`6WPV9SJ-HWAzGy$hHkVTmz&Mn`s-VK3Th$D zrYqw3d)WM9nvx52LS$ib0OWt*%|6&Y)84+EL(X)R8=?SDU<$wyLYo!fPpF#OSxrtN zt#1sjL!82T8~!x5ZZRM_P<_P|6L0mGkv^8JpUr?Y=OW!{^_geWwe2nIWjcqNapj3A zCu&zk?exr_XY2wZVm7v z0IdA}IS9!RsA!ov^&0I{EYGYlLjlWuwr9uj9z5UCxjZTtN1K^{jC+&zc#oBV6X)&& zem3op!>gWTgxf^dl123;_3%Bgl_#nW40q%_`M99BY<8o=W{d?4-`Kl!bc<#k7 z1n&wQGm#=f2?4_*2#uod3eEP<^zXZ+jqR*AeVw=Y_B+YOoJd=}?pY-|8Q6>GaTZH2 zHMzHDNO(je5n*(sX$m9l6t0*oue%N;uuy7u6%>Fod4HC1tGd>Asz)WsyP3cC_7!T6|mIxrnqPUS> zB6w7G&uS|g6#Tigb~?3!H%jHXOwB9xhfh4%aDC>S^FtpK`(pgl%c7iW9_EJ*x>C$t zQH=>|pMYd1cu$t^K;LZ!gTjwPXyk<}gS&j#0T9gzU$DO3B%k^fBoo}q;UqTb!RmTJ zdi9&EWLKU>`O*f}oHviM?bZa9iIY7qA;w%n0YOR0)-rFyn1pJ8w?(X!FH;Lksb9{_ z2kj>C9J2WkZ=!RUr#R&Sw(ps`3goyxG2`?H{ zuyDVG5h;Rk)CUD0pDVfEP;6W7gBM3tHu6u!#f=lWoCNYhJMvv1j@93>r1-4C9~EP+ zHA($kTwV4`B*?Lul5tHaj6<`{#w@Xzrs5MzrI?dJ=N!6nemBfiqkIo=D{IlD92jO8m;IqLi+w)x9nhEZc#F8 z+E=Drx_;@f^nl}YaiM~HrD9wV=dwvtn~oo|8yO}oqR$41!rq@em=TcO?<#PBubb7k zk($P*3mT5fHmkg@M-2`TH+fVVm`=xnZtGcfnE~BkB9R9Yo`g4E1nP6B7>%5;|M9JF z>{B_y$2Q-E1$kLYF)PThFZo#vo{{*TFIVCM%oPAs!2uX@Pa(&vI`!tC-`rvv*00eq zFZ-C^$la(PYso(@mbl)cbZ<=c*=)i`0fZuDnI#?wGhra6b3+{b}&T!eKBN}2F@b>N9&Mwtzh()(3i zPu{|+$+i$^#3ReLjOm6~w<_E}UKIaQz-9>imX=2#WUDjr3OccCh}i%UEr^+3&WB_1 zy~%XwII|n!G|L^Af5i zMSWOm9UsTQOnAXuML%D$gK5C@UB=>;S|&T^#}_%bBez|^`lCd zn}A;0&r?~Mn^3COj|h*J1^PsI!yK;j-ikTUfcKke^k-mGbJ!*d{{+z^YP`}TMHaC7lSQ9IGI%*Wo(M@2r*b!xMxit$h zDe1TQs+-HExG6ilOptZxo(C_+`*E+*z9$wyWg9)c7CL98d`pLNwH6=pIKQ7{{IsEM z!_B&Zx0?!&05P4-RYaegE5xs0e@HF{Z~e$Z3^PYbc~irvat(8wP#J2Mwla%;$P$&7 z{P z%aZb`rl`4e0===lH^+kvE5`ugn4 zOj7plTm8cFD7pOr^vrvvxZgCn7h+8q4|5MxNMK%4(iMMu|JmT{Apful=^Ep&v{cYk z)iy$EnUO!yI)6FloIzf8npO;?p4cTlf0%hv*m2xWQR_)}Z=EX$e7LRIkk}-vrbWVG zqW-b1m)+cs_Sj7UJm`=n3vKw;Ffp7WY*05H0@lq1dh!G^GZ8#PpiITRR*52VcvdBo ztC*RSX8OdL_Zt>qH1><{f3&GM|JIE0KaJ6I{)4Rl3!~@!3#|XoY^uKjDF3xu)&Ds4 zue<)AW>fuB2H+n&2oonK$G>A!CI6}7*bqbWTdBnW@x!1a3LX3vPm>5>J5Q%Y09!Z5 z*B(l!OdO#X!6GsdtN5yJ^W!#mBfjZ!NEaL7#OZjl-S1>lK58vX-^g^)h_}(u^3Ucm z7KsIpXs8r(G8v=h)tPOd)2a%t!f+LJ)<*Wh@_37*Ft9t5Ts3>+BOTta@RP6|Vds z2-PRA^mV9zwS9gF6#cvv75Tj1d(kZR3z}<=6hf}#HYIwJ%+VLIVr8ySYupTWEKtHO zEnlB$U`f2QOC6>9gVcl6{t{smkmq4Qx-!#L3T+SZ3^3b(f2azcqHoMYBY$p|3|}Op zQEIXiITrq9sSFZj?GRpgGQz{Oa>i8s%My+YV{uV2MO^<+{OAD zzjE^c*U`f&4#?4=}eb9QaJaJ>$jI830ES&3W`SY|aEeb3=XLv-b4(`!D6rGxg9Asj|~Ym|wR zlIG&E)*v^8^3)i~7n(3lI6i;?qgIW)_$W(X$qYZu&_vpFpsMbUz>LX6cz}i<@NbPA z4=Oiq(u~?DXk9A(x`sgYad&!F4MMPh)9$1`=px>jNn<<%ugvj~Ar`q9@DB1dY@E?lqRDzwp++^E9u4n_+tBc0HxKnV`ouF(B=C*5Lk^B z^}%;3IjGn#&wq3D5w&qHy;NMa65y_mot8roph6i6hCfG2)G}&8vFuu_zMLP=&fn8Y z8M$^lQD~N{&bVl=yXKPHKLd_{>=M}0odpg`eYLK)ebb9}OfmxQzEjZV9#a@#TY}7M z$2)`=>RNE@%y;d*VeP}$RI&5$&Tj{xZ|Pgb6(JQZ65QKacA9GKtp;QRtPYgnV&?B0 zre25k8X)vG5ehX`GZd9?uE?QZ0Nj~Q(cE~R1WRwZTS(q+G~9^3zehgD%B&(IlbaA` z&?`AhL_q|ujs`uAM3MOViLPij)L8Wa501-$fz0?iU10r?Neu4xly({bp1raAl|l z>rlja=!=*?Hc~!_J?5|tB)QMIKnhS_Z8~{1I~UVn8M;JNz*L`Knyj8~>RvGk>F0Jq z-5}nf(OX=>8vy#Dk3)gTs&hwUt@@CY_nejM_tfA54+Q#jPFGB3T4`k&)GP!5gX&@* z0j^wFB~(W|r+2wu=Ez)?_ODkJqr^jyI{Q+}u9C(M59J4TA|IDB@Prc^<#jn)u~MM~esO?|B{H*zt))(@j6l?dZ?Wm%ha2uvdJD8Xl9%r}${uR-rw z2$4#_P7#$4q22@2N0|f*tCJaBRYK|WqUVb=6f^?sx4=Ugp<7!0o}voWDF);c%!g3v zs!khXgN{LC5F2qkP<_1Af%gg>&=f&*544^bEeyh5d9`zm$b5+i?l2xH*gO=COY{;J z0oC?9AT4#E;C|kmyj9%+&6JLk&oo(@bic1U|eM_VXEl3!q6n3xJ0c zWp^7CDa*a&8NwmaAl+T0AkLy|kR83Qwi0S6Uocvp`4faUGF*lrMUbpaaH59`>EnUk z?3kz@@f2o0U{K)_mTLFioX?B4F41THkheeioO|6v)MORF`ayyUH18lm$qJ+(WzwhB zzuIYtE7g@P=RH_t+^o`Bt;9fq^OV3_Ns9a>Q+aRly-qD-arj*2tUEh2+W||bM}QqC zcxi7H=Rj*CS44_wek{`rwmJ{Upb@yg$sM1Y3cZj<7lGl|hnY4yp4*In3@B$yY~e7z!+7sS3P5B!k2Wbok3XPU!XwB;^z4rB zGT6nHqPnB(8&bKmpb2_QN$i0#O=KHY75BwcP(Hek4w^(42@*&I4zrr+BZ)x*t&d8| zl3DIc!Yx=s2tXT(;JJh^V=SU&oe=i>vMJSzAWf+JULE^XR-Uf)cnF};eWmaO!zh&< zu)wE}+4Pxiw4$665_Pxbm7)PguiN)Zm9$&Qc}#{t4xl zD1+jmVk(I-vl7qUU1Nb{oTTe9p5wR}-S9$uA&o0H%|*!dX4xZ)_y~%mUb3)(_I7{; zF~jsuND+BZP>^^TNe8i6lObeby)nK~w$}J><~WBBY`~m%k7*JgkR&O5+f_*Yf=4OD0`0vRI?6 z+WFIjk}#%Z$yW(3qqvUamLk8!OgxdcxYd3mtM?ako-Y2o+e6JW>TQD>A)oiy&VZLs z%nR+2C)!dzKq)Q0RF*+fT0Tn4P`MxajH%YYwE8+{$^fX!1$u=-25dvagBSMwosJFr0@2`@#< zS|FdMg_6v5DXxK-lj=j zmsH(dIyqOVQ@v9~&5h^jkZel0rpCwKSua?FCg7XD-L9MXq`N^H*Zr=&YB;e)02{d7 z*6)`{gEIcPTcFKs_RCID02XNgVv*{s_QrRuIZMVt3gF}VvuCEfX^BxZm31?<3IG11 zu0aZl#_R5t^76a%l1D^bXG2irF>2*Oo*4<^XEc%v0Ogpx(=)J|HY(h& z9sy*9!GWt?cJyCH0`Mx;Wi+sIhBuJppsJv79RB=ESmC^<=5z)x3i40jfF?!khPC#? zXVGSs9Pq=I*(Y{)D?s4-#qkLb8~Psgxd4FiPf7a`#Ba)>doMCfGTt}6!%^aHk5|V) zUa$0lDP?$6$e^gm1mbqxn{JqdYNN(|qnFQT=F#?bm<=UvB0B=&y?2RKm4x%0snF8|2ImDg@BRq?@+`4pCM(= ze~JqHLtQa4{wYQLHz0suwGFF7F$CWg^+#bmEx_iF3Oms3uqQKM=^u-+`@&F%^Gl{OGs=XmVr79iZD5%_B`=pVB zS2+u&%utgnORNiSMdkjE(;UbKpf?EBciW&{2RKL(!fd;%`o`!6XxNj3B2O_Lo+GU) z&Ru|ZPu@24F>=+TEbtI7518#@`0*~40kFqLmjW7;XBKvkUYRiWM0jK?0-r=aP~EJ%GSf*RCk31A z_B>E0QeRgrXWD#Q$%~THh$Xl~Ci`I9S*AAxp+k#zDDx@kHz=GYqP+b_#8;q_iDH8g zw`f%{vu5w;-mMK5`jV~iKJbg=lh#G#lAS-sVIO8YZLK@&YEuU z79Mi|SsBWnICTcN{7peh+@j}tR%`zoKHxLXy=lniKmimR|2f5X=?2%!h(XJj=bV=Z~zht)aH-LOpo9c6wv znQoE@(Wa>arsai29;7s^O3^@b@I?8se6xhiy!v0s6tKmb)0hp{OM?!Fg!2fm%$oN; zJB+f&h+(S)E`#`PQ+_-mdyp`D0I_a^(2&y`WoV*ARvB(nQ^LK5_msF3N%~C5vlNe~ zgyo6~!#JoadCy*FUY#f_DPtZ^O(PNHR6apT5;N-jTKN z31;+xQ18iRPQ%l#Vo8Og$)I?cGFgrm>rc6u-5@b>vM=ckb49ejHkv}5){BXn#WFY* z-w2X#p*$+D@l_ftI1VFhn z^(tc*Hhf!kEI)c~ok6x7*ezUc{Pfz8`QqOSRKO*cXzaqN-It-B&*t9h>doa3{l*5s zSYd$s7gOP%VnY8DQ{k^AM)v=$#)9)NaO^*u3V#o7{gxcXB8V$r>ST&^ZM&9a+f#SU+C0F zuYU*a=_%u2Qp-t+Sn__ld(o&y7i+dsOdm_7nkr&Z{SZwZx! z0%Dct1WD=KvtTcnE=svMO7f1WRO3$qEX<(q zoHI+i^O@Y>p)KmDM~Q4|YG=-z)Q*LO_J%hE06zw!yye>5MjI=&Z6%X*Zf?~1fWp&TbzfG?2TqyEIvvcWf2?*=uSa_*<}8>6Ge z6LD|<=fp=j68{k@N5BJRYypJ;q}RAv#)}eU%Go)c|7XyjBvA+n2RNh}XH}p2sQ+`i zaW&hMl-oMN3UCC0=p!1j z#GECtPHl&gFI-w2x6m5Rm}9_8m$eaPCj_8hL0XM0E^%gx`r&+aL%Hp!Nph9BYg>;K zwdtaliUxb-Cxh5(G7UKt_i8@#GCJL5zpyWbokUN40k7*FwWclkf_hT2Ir{2h>~I2| zp}&NvmtZvHGp;Sy9tK#Isq?hI6%Byeg5q-L{K6@vG1^tf%(z*(5d#6GA73dU20$j` zBu0Sg*T1mFaYb$}VVSP)0@}+0HQ}{ex|;wau|5h;4Z*$9W8EK?ME!-!NrS)qVkK9a z_1;yJk1Gv7(|)uA{;$$<)*llyiCwg> zL8AoFlDT;MNm|bP#{jS&9R<9Rdi50`b>KuSn6_Qnvf_(4mTV^Sl;h6k88cgo@GVLU zrfFz3^gI{na($4mHw1EDAxf+*8scWH{3Ze#B1rVK)fuY{RR@MVqi@o>3*5}>rXvy= zUxZV)`xtSee)3=W-1Xh?sFhd0YYB;Sr}1dTgusbCd2d5Y_jgWbZd)}P5o(ctid@D; zCj1z~&3hyclq>u(z)8O%9ZFHAD`W(Nj(-Y3X;IJGu&l z88bhB;A}&}pC*_PPYoMj_{C#@PC+2h#hCkAv_=_dTBUKyGBx|~9r`E1@~5-Ay4<@& z&!*PxQ*m(Zq@aCJO;74<(ilg^ToXyZDT$}sVuJx#cq0VS!+k5cfOnn8n>V>fF9BW& zd9p4>Gsaf|zpfvH!AXc-d&)&sm<{W(I4CvhEjFVadlqr`41FSrxubXBjXRW@NLYB1 zJA{2Wd7#SjJQof(md->LLIISJJa_GxZpRq4E3#}xEQif6_gj-+X?2z#yq zZyQX8^jK}0<#i(L;we(BFfUVy$HD)VJTn+2e{0F zMx1sxD?FWc!JA9;N!QDjH;HUtxpC+h(o8;>xgX&!Jn(L%>ViXamH1QbD7abgXd$5c zGLgPR!|nMCpx3IW@n;CwcR_hv&-av=j`zWh4?X*g)6=h)OD-KR?V2EhqKp_jGCrg# zIz8U4*dIi$qLrB?P_3uwB^*!PZNX^-W)pA2MkSU3?of4*_z4X3uw8*rn5IH7)MMRV zR@fm^cSdn@E=7Ldw+=JG_yumSuT6uMdkWsr$pmV@Pm(|~*`Zzdey0L{?U8cp9bT!shcvI*v6r#S<`S zcqGa@qp+T6YW2Tbzb##)af3slX~_#WJ+dE%c{Ru}u^29wlS%Pz^Do4_KbO}Lbr|&6 z8y$ z-7rfG?8Ocv<8_Q5xQ)V1bn3as%X*IuEQaS3127_Dg?Whj^qigB9{xpse9iWWH)xri z1o#+xKGsR}8=i}tTuZ*l0Zl`LvztcaOjluQu)ngC0DGR~>qpx!73M{+Do_Pn0z#_n zglNJsFz8r2=`4tH(gSNjiD=fjXORsd(VSE1Qw3U7SdnPo_(HN;J7lJ2W-#*Q88!z` z>9?eN11QStWri?V8OzOgkw$$|T%1IOJrEgVoyY@@#efg5TN##?J^$dsP`y2mQc(?YD=ejSZ<(HJ#fQpFUea)BT&wNneH*zSm{9 zU1>u=%eOHDWG2EIaM@ZIDe${Aq&G`f@XRKJ&z>ch*~3OCd9)7gme_JIn)U!W0^;mE zFT`eRdu-SJz&O8j3EChves}l@n`W=T$i-i#?Y%m=Tf1$qTx`7uh#FLLlYOdWXF`>r z01EKE*=hyTPPxscGPrI3Dlu$9YRe&>Nmf34Y^)j zKR;?(NNa|x4kDkA%~aA?0kb{$Pw|5n`p4uD8|=ABizMHZt7}7zdB~*`u?3inoYib( z0*1F?_}fR84(<9O?X6ZGGwRr8fjNJf{IKW7x>}^LXghaxWkZSw_B_{$_Bz)}?zhOZ zVZ~UPz65Z?aoyv+?-Flj7T3ExrgB>t4q20m*D;yWA%4h1AVU|ju#o>LC>}E0>ViAI z1M^`C!?{CE|H{*|EMVf40#Zh6oy1q02mgayv|i+Ylz)s2e~b70<+T0l8pD5}6-uVg z_O4FGrp|x%ef+igM{U<3Ce?e;1Gc6$SYBbN{;T|B?j!-(w8^{kQzL8~>B; zWBqrW!7BANyA27nKhEGHi5~?VLFk8(3y@5rC2@=g7Y4O_ECB-&ZKH4!mZFmp$a}=w ze!DiR zf7-v-R}DTB1Q{NCVdjk(W)IE}A3j||%y2;IXiV+_tl|?^;Pr=wpY^$${qU#uaTCSp z6wED|_>_wy|0Ho66an?Se1{x&TA)xL{C!IL2)PTia{ACva|hSP^Wq3!Rc!T~+6+)< zIOS|S6SwG62cfTLunBE_xLx{HY9@Ex*+VzZYM_M`JSw!-L@FIiH2b3AB;>BoZo5_E zs0}b7TF$keGFMY!B4~*aty;Vkd*{uNY>Y2o4q!xm?<2N7#5ggI#CEZR;f|Qj60@nW z6Nn{uOvXimtpABse`$%)?!dZ50(A_Q&tfWhg782H1tq9=CG!OV)b1vvt8sdZ$M53Y z4f0?Jjt78J(U5du)B_htOJI8j+=vuh0{F4{Ak>ky>u=ie+5Qf2&w~I9wkO)ly&%%N zccV-`Iur~jl1Rrj#xpjm5CjE~s8^xiGbZEtV#UEAZWraHU(s>yM)8D7c|jSE`{8JS z0I95vSfvDqtFPWl!nABktQ_(Vv>#j7bhK96&_BM~&27G8G|a z-xvGU!k9&GS$Leki3Tfs;-y=GjO^SR575wQqvo;^P)x<_OHln&%oa{aN?M5%&K9-f z5}s0l>b4Hl5PagvZl+gz@>_(Rhp96!;kVN(D_xP3bG{ac>)MkLeUpPIS`7^@88MdR zc)BuEp!N3cDGHU06@5}OG}cgWU_tfJTz)#GTGQd zR$M>Y%a&~Gt0QMz%iCoAT_Mt9YAKpJq+ojpfeF>wvnn*HB|dR@dn{YIzqM{Emu7Q= zk%564j%mbIpU#t4OinQ4`1a?yzx|?iqB4+0bO;^o?zU+L22c*}SV1>G}dzniDAS?AwuyL^i@U+flvsjUAz=kR@*v08!UO%ELU6E|Ei|43YMuX z)s=Jx#?(>XH!i8=5YdKHRKCcc-`g|13ZKG*>&FI9atSca1ED!>;DnDAkfya5ZQc3s zsA*#mj24bhvY{D*h}BAwrgDqt&BsDf^B>EubQ?@CQ7f!wuZhyOmM!2S4s*|-UU7-T zp?y>06qcN|JHr7Pj`6vC1JTv9J->G`ai3ke_io$yIE6_J?ux+z=`q|Ltx-xVGIS>v z&Bm$UrD`N73<@-;*dLf5n?(I+ddcU))ZxKrmD#9I0wwP_{hoSy>*5om|nQVoRs-t(R$xJ z*m2~1Ykbgq*gfFTQNxO3=-|~aiUJoBOrIc^=K%QSYV0urY!HXh2meq)bOFc_+JoS) z^3q(Ganw8&sYDC90Q4RznA0iOd_Kt+s(;%QoPP?Mpm}&gZuZ9E-pj3VKh}vro*wR= zn78}h>j>#FF0YJ=6HmKI{i}uLm>+KTAW;&_#O$NYU!>PeUUt3Giw$TAHA9yJ{= z5ogYYfHi8Pu%aE>c^I&Q_AN(SO1E0fF3y`Q>5J08=sgF(i*_NzHjc7I2Bu5HStm#< zODvanf`9hiqqQU@OYCbtNhbUR{wpiQZVfPE!sRENjNHg*rJ3atfTY_@eJ{t*p!lj4 z|KyGHgR63NEo@hwZ2@{3>%OT+$Jpe=tM9J92~Xm{<+!3tSO#stcae}x2D}eM8<1L6 zxzDSY=H+3~Sg5DI&(Bx+@gEtlGl>G@J$^zaiUVe)h{f|+j-~--c5OY>x7XP$oMWVB z!B!D&R%>idsR+`pjiVFR(jWZ>4<0xj#?BHo6!MZFP|BU%#rDRjx3}0(mQ7;_4^sn~ zYncx|X0nAZJP5*S(7Cjp`jvds&6rP znIdC#%;n5jK8K^fxcPpkic7F(*qDj1ITAa{vb?f(%LX_?=SM@_fb!>qQP1rr2?KJH z1A;3x$zSG?a`BIy;KvhDq@5o|gX8bq-DvyC2HR*^=^>Y|ilq))V5XCFnNbgg>!Zsb zL&en#I`QP=gpKCE(;e2MUe7Lo$}EHwU|!{MlWCJM04?8G_Sepe8}D6@J|OPS6=_WRu~LyomnIPJ2O5-u8vcU<|mRHejAu0A$4iw!|aH z>Ae!;QYm3Iq;-|0>N$+`E=TCyrjUJKLFuVrgK(()&O%9a9li?qTfQmGln737Q9ktK zwd`t$&+IZzh11{qCuX`5u{p`L+*LBUZ6z+3r-017I0?eTSolr|pS$cN8X;-@6wNM~ zY7mb}N$$7OB|nuXl9VLm6R9eD1qVkjiIJHncS~yax@i8CaNNaS_!>O9M!u&pQc7om zxXy1o9So$9>TJEz!LZ`{C~5!9~?7L`SQbWMFjaT`YJ}=nft@yk9p#ZSr+! z2mY@F-;2c}fpM@>FO^bcEgS*O23Q6^x5{Dh;}06Tl+Avp0NZE8miVM_HnuR!`lr?2 zI7>ah=k;d1!wZKIP}(+u8ph`-#SK8W^wJeBz+Q!1K_ zq2P@zJyGU{M4g0X5aq+-FoPLYPZN`#K3L0S#@ruY#u!2T{;bsju#iD03{1p)GRH_t z95uMTe^?t2v}XkA%s41G?Qu<Qiya!f>`{&Gf0`PhbK!aC3bzogD9ye)`8NZA!{!5LN&iK`#F z`N};A8X?P=kqAqgB#t8Kn2S)KNF&IUf;=EZ8zBW%B-Dvq`1t#xOUn&8G+?(|AF&*r zt{O?3RMtM_6fr{B4u=SY&Q}3FM9D8NXHAwNMyq_&$eh`2xs%zLg%y}RV*Y3JN1PL2 zi8@7(!*tC^6q~nFAxU$M@?#ebo%|Iqie94jnQwkFq0~4k9r0v z-Z$B>B`3xH-F7|8CYg=hR;Bt)TrjTp{JiI3J-6J86BnaayAI#+`fbH~va~!X0B54N zP2jT``UMYdPd@*_dP8C)-Cn}gonx?Rl4r5CYsD2eshJ5t8g>52C|J*qKmc^mj1h}J z1M96rP@tIo?<2Jh{ME47y-e5`EB;(q}QlKB&q6rEWsaJNGBuM@e79&^5vU z8d#0@XdQ=Usn*4LrBJdrTYE}2LFG1_4`+<@2{@<|6BF_ z#fSW7s_*X)g#R_w_uru_|4XWm`40~Acl}8(_PZe6Q?+hNN*F2FIdu_WGZ@7P=i;GtfC0W>LU%{NU~4 zk$mUW8BX`cVSQ#eaOH^U9nDsDYnPVRzMNlv9iQZsy&fl3yq-fO{_W(DIZg6p9rxcai;YfdwcZ21bdg6yX*k)cLfoKno&y8v>Dq zcM}-u>0uq!eUsWJ*v~>xjJ#QFq?+X4@(^HcN*cbXH90`7KXk9c6Rp;;jZc|5GGEtc zee7{xZt@6>YCZ?u%`XP8$Q)UfIK&byzGONNG{Aq&!m%b`s?bU8MN%18j6fAFrc0xG zx+8sjAuOLVA@B9U51m7&W=N)v<@mX`)}!zF2F`kljFmtzsRZ93vVQouMT|pwLG2LA?wf` zm!2@QqTG5mG;lRo1w7!RGYiLxZ70q|@F%X^HfB{}Py<)KS5n^(qqcVtjn7R3X$Gr# zflX95a<^fQbb}t{_ak^%qJfPG!s0Sp+2KwSwim}|GmnL6umnl&p9o*#Fl9z8sxT;# zN#eFgWf|XFUI?ON-*cO0AlSR~$xaG|*7)hmc${HCTKuG8C`-Q=fw^ooCgfXEEqHHD zVP?RmX_Eb&Vv%Ch=cw4<-H9=6a6PqeJ_Q`1uf)p&RrMCp1al`c9bdAujXH+LW4-0S zXbado?Gw*S2(o3Z^Mmsd71x|%M=Uug#go|Nmtnf8pMjR?Qahyceon5t%X~W^sn-%% z@^~K!{6zhstS0w;?KyMQ`rz;Q$(HrZRq2OSfPwi}#TE{3D72)4w?z}X=n0IjmD5ZF z;&>^Pf)uvhL2q_4KR1_2JyZC#a|8>RG0#`t}9UXh4hFLuZA>; z%34`7rqkvJHozyKV_=at7R6ogh3K_A+H4|X=~1r|)rD=IFt(wRZ3ml!Oi)sb+RPYjMW9J@($9#Fi8H`^;fBhpATn0;tJ<(0sK zH=KNkq=)$_AOxG}Al^8|Y0iP)5DOk|{Yxiv470Z&p5j$8Y^Q$V2p7~qg$%d-w5R7o z;$pc|44<7qrB@UHoz{z}rZJL^H~Kv!7=fAf(&vYcJ6i}uxJN>cnCYVs3@>e(Xkv&D zz2``y!g;KHcig=NKd^Fs7L=XZ=*4Q-%g6gXf%2#gjUBN?3q&s)bV2jEqkxz7)`xHb z@MNGec#?Z37N4^xys%*u?B4OF5{&zA;#zh?@YnE6OZ!kTB;Wf*EfW?Ku9XF`{y*?52gNO@>?lfV6H{YWqL()OYm-yaw z#8**k^%u4&0jp6L@e@oej`@D3{Br{>dNd?GHIktoG^EtWtz9cf(RpvfbG0#jGN$Nv zL``=544LH#7~&(t#I7Q0na!|s9O$cmc({)h^Ag{i^9{-Kn`=7dNt?-?QE0b|EJZm^ z2e_W?m3x^S&t+5%Wx-)jMEoSa2iK~iz$lmUKBtXo zAqZfWA&$~&HQOI@`Be|9!LM_HJVlW&HaP+Fq&*(vBRqwdxl))#XDrTzQ#iKp$){O9 zag#;)RHBel6xEN-{f(nQ!yH z_aImOxb$viK5mApwY8H>Sx4bI@AwzLVh;;GeL9EvRtptGM{})08wsX8r1Bq6rF)jD z?h)!~dO8S<>Aue4>`556+YSwKJ|B}b^v{xk&Aj&A6E%C?La-_g$=gTAR_K0~&UjvQWpkod=9;q>#O2kkHmUOzD%HnmCIlOS$uA34U8GkA z$3q2Po!pTqr*Pa8lcuFcnea!7MYrefaH2@r8!E6#Z1ZU4gwKkOwKY4aTMTLnpqU)y7}05{a%9f|Yb#qi1m=g6;=_M`Ib; z=l1Q;{p)u0o6eB`!TP5%e3gpZ_RR&{94XLmTj=p7JGQ4GDCO z6N>4&ImBciis4~3mI*k+=_K-t?m#!M1@R!KQ%!`Mefe>Mp<)o8WU2z^VPL-}8%*_1 zQO>7XsutI!#buV7_mMQ^L0DX+(D%|O7(w`%e!0@N*^wl?=SH0cnSZPfvnt9KGc|;D zt#2R{=Aw^BCeZQn*;KqGkYp4%=(lg>xk@Vuxuctb-eqcss_K@m>vTC?(f}@cyEUN^ zI)__*PsL!h&Aem(&fbmWW?7kalY#R_H@ugKq8Xo;2Ukj2aDYJBwuS!_sysUIh zBoZumblSq3o1x#JxU+5&p)Dkj*q~V0QGvm(3+sJiW|mL`-QkE?Qqnt>M)LHPk-moG zA$8bdk@ous_glu}N6cri6|bPV#H43WUm13x0+U+16x5tw&^GE_ z-Y<`GC&QRg;BlzNw1O5a-Z9=EBn6{1qxpqJVcA=x5(-$*eu|D%_48dOi$?46tAyq( zPZ*>SsU__4@frk}6s-a<=p&B6JY6%n@5$349SCa=2;QXtbdqk9FKbl|7HApt${>kS zd4aXtQzIN!^8vkJQvuN3tK47)sb7<0SxVPCIBc3D8nPiRqll&W-qFLX=V9A==kf}% z2Dam&N6z`LwE>mtUCk62%9wMQv}USl$sT#T>F0Us`W-yx5>UwF_dNv2Sir$r)mLiG z{-MrNh<-^y&t$&~8Gzv8OlvzLF{?y*v|k1qhyE|>-aH=5u5BAukujO2WQxqgIhtoO z4;ey2nMr2K&_I-VjtVLBtU@S4B!$ROq>zNn5=zv2obLCz@3Zqbj??u#-}Cln||}dX;$yY&NE|Ph#5=EV?(uqHQpa`Nj=C)_0j9M zRL4yFfhqppaYJWg$&F4YnTAOow!LO{PF8MfpRdJK?5l}8Qrw+$`SH@TSfQ_0A58%~+>!h_k*fX4?ZlI^ppj;ipC>Z}ZXMlqV5?v=KCnq@x7W=1^9SaZ zYX(w_`A-C0lWDZ>l-x>{kVRZRbE58LmT2U-$khqguM(D2w5OL(F%Q3g9g-8Ka<%rJ zq|LV(vpmIWC7!r@qgM{q?V~Jxn4jc)hSsF1(y3%HXLLpDBl?nl?Y`XU!So zuj?$|>U1<8CmW!%Infl}`Zysi*hN%O>&Q%|<*BKD@f-WXl*9K=rmWagzDHb0sDAD7 zgw8hp?Nzgi_CGdNO4=^sEOYE68GB=vzBHGvrK@*nOkAYt{xw#vGV}5$kB;x&BU+~( zQ!TdvZ=kLlJDGR-3!jyl@SV=>a9>_R9ul`=_3qvOHf`C~GvsK;{cm$VM_^l%dV%bK%XOjO8h<3J^S<1WvLf#oh{(I!5ln`oVt>$(&ljI@$*-a zrv&LROmcj7VTFPuH*7}855EriwXjD)I_j4h>Ze;#CR@El_$Xfo@|BX6ke*9%eXF`A zS8$5DyZRJM+fhlXCw(uSjusv;NtN)YQ9f}-;^}_h8w<-}*)x_=mru)LhNc^5MS15q zuHGVXv!U>P+!}F^s!aa9F8O`d#8V4PYqAEm(Y^I!XLGxH+S2dkTU#~Iu6X>BJw5WK zp)KsB;Sa$hRMzuf&i}eRxY{{3SV*cKR%ydwd4n;tT=CJj*Rvm$H)a;H)-o_*Bab;dydPv*J9>oAE~>fr_tcItD|L#{xWx;T;AG6G5`DfQ5JU2%en{hT;nc#z3-pX z9?0X_&&V84DOA4Lnv-tomH2l2fr5d&qGqn*;-#M+Bv(eadZ3gSyo)0L9p&X;RnvIa za1avzuEE|xc|rZ_1<(JP^72=C`2X*e7rcV;|2lg|W3d0|&4Vg4%lP3oX55O$dhmGYKG)i4Y6!7R$umP^kJK^J@iuNL6fWF>(08% zQ|y;&GUR_X-)a7M#&4Cj}S)lTv2#SQC~T+7x!SJ0aBE8WfU*{465HYkdRe)v_9_4$Hf zv0UGiJjI&9>K6}}M@28+-trR+tgkhbU$EJfqwX>=zbJ8r&SJ$myQd!MF%s^Giq<{n z7{D}fOY0$*<;^V-y=Pn&(~oZDc`5hHy?i+)Z$-;kbMD8Zyo;JIeyv!4t#xM|6btp_ zu5d|b;riJ9)NQZZz90D6GT-+7NhyBH?+srv9?apsAGpV=(opPWS63O?XtD5_ z6w9D89%J(5QC4H=*y$S&+RJ!jT35v4BfEJRD}O5oq&4LRFtmOXhR9?Sm71-O@mZd?-P`7MXk#S1HJ6lSi9@F_^Um%Hi|G?dG zTl(uuiRC}I)ppBtlP4j6A3qCSMWG zV%KVXCY&A^jQsfagV|P*buuGW?CeC(GwG_H_X*6N%!0_qx2?bnrUs|3%#tZR<-fxs z>-{1wC5mG9t!(>a{&@b4NnWSbW0y*r+XIAuO=^v<7qYVrDakgRYH1^Dbuc+I*1uAj zD43@m__#;ePwpX|spe(1`%md<9fOL5lMQR$Dj0Q+Cu9}1m(k6VKMkx$R=<^1K{X29 zQ1!ZJdA?aNF(>FIvv%sS(p>?~Ki#azCf&LG1<6^?8$N5OKvO1#soJ^cOyRQ{KqvA-}M`lnsHpC@ODOY%GBr-StOL0*GnJ-P*8?!d6 z{qaGj4%pSVH7DXqp1S_*)#MgcD=*Kw=}Gd~C~Dkt@psCZw@ z`PUp9E(ZK~TYrqfa*?m9W8!<RN$o%D43u?w1#F1{RxZ-Zk!$zj&4E*a&-P`>(@88G(VWYok2 zPPU!H<{D!Q`e28Bm%d$a!v^kWa8)-ZZ?W%Z}~lV%5n(zSfqm&IwGIiAcf zhkB`+kAWZ#cW>ZXec1)YegxT?@`@DIykM(De-@e;BO1&BooO5iF$11^b<)O=C zKdno9lZ>z1e;jajE?Z++qcYT9GcsPG+!y=xgzg{1GL75o*@Bxr)Q?AxDQ2M~)sr#z zI6kp=JXZfa9$Pe~dL&HrQ|LvFBBc=Dx9@9)6nW->Po|X*${CVTvK}9wVls>w%#_7$n zx|Cx1n>K0$J!bRMv`@>YH=h`LFbgsncUPX1GDN+ei5y$2E&0T0&-l1jnyP3f^Yih^ zzTo9wwU%jRSBl*!Pmo7R{Ak+G_+c$m#C2hIxPa388oFRWprN|=@IJQJ3qPpBJ~0K9 zBwoKz%fx-8G!gS=(b8O{DpI*8ecU-g_)uw9GQSAs&UBfFg7;JV zi34g&$swL&ROUhbn%_d6sF|`xc~Fo%592C4OJ6#yq(30i?>cEz#Y-A^gggD1N-1Uf zTUBQDW@G#Hfv2C1pX$=}KCm-BF8rJN`_y_W&%>qm6hGq|&%QI>F}~cj%Ds}XXGNn* zYPoo#W?y1laMR3INfN)+SQ~|Kp`W~L`q3VfsfesCa}~A+VuCeCb^Oe+vLPs!lsd=q zvwWs*bj>b0cl5di024qT_SlE?wiVje=iw6x%h`s17cdma@hN9}lcNWc2!+ zrGH3uek8g7yVOeHbY+1DqQgSnhQCbO^ur^&1*5P1c@(AVOo0#f z{y@inX>vI?F{LS{E2pNsmdk$|u_A-D5me10_xpNkvm+{>qB>R7$*g~lYPqB~?>!eg z1CNxQaGVS2R=c?S=%;rdxu0J6PHBuGZ|h z_ryCzwvDC-9Fx-H`LfnWtY_`wyAAJUyqYu@Y#6@u>Dz4DWVy{i{ro4ng=1tFNqt36 zhUgVimyYGS^BwV>)Qi0SmLbo-STp?Xv~snK7vdR>eqT!{KULD^wV{<7bA9(o*&vp! z-;*zYJ)GJjwbbBT?K-l!TKIv)**kMn$%NnblIutb`9{I{(uHr`y}1R)Be{>fX5v5mz5LVy{MK`9}|DBciQ*JF4^nRMXe#CYvy9e9nlWPESa=vhodbXQfRZ z4(nl$Sor$ATM4d}DIiO;V|SD@Re#VQBr`&Jb|p9avEAZe>3N4=p8jlp59Lvp#69R< zJS-SQ9idXlUKsJ8Kk?f1!_|7}hYScOlxf3HtuNa83F-~T&x29)6>>MSDqE$s@3$FC zQD0Fe?_&8TqY#r~T@kM*Z87MdJ`=V2$GPGmM?oUj=IaV)N{(?WzHf(vq;t=RbDQ6E zIQEM)Dns`=B0*}9HfJ+->$&BNcZX#qQ1x><;|eni#T&(P4;5arKArg%V*L#L?mEe@ z!sJuO2M%&PVfSWx;2Cg#5X*CiByN5r-slLse5CBG78!^6Liv7c**UbBeBz}oiRv!B zzDwh@qUrC#hCMDE$Tb?RQbp`{VP^{vkXPtC)7x&Mq8-t0+Z(x`>7>{1uPyiPN3dR) zwA9QnIvzYVce&NtKYDuW;_*@JM*ho;*9?y86ZEd-SxToWzSG}Cm0E_>>71`@eqbQ7 zSK*<01XFscQyHJAPrNqOnT4-oG8?ylO1n*9DP1QG@12i)?0i%2R>x6nhn(%u(TztZ zDH?q@wNJgeYhSf`GU?S+|AS`FZ%=v$PMW!{9SA;tHkEwE!DINUOG^B*>5InNpJUJK zPUgf$TbevGk3QM&W)cwpKsRHfVpO22(S-Fkho{dkGS5F(WJcz?-bOv4Zc}dH(AgBA zl{Ae#T*;AHb+w1#on2S`pm>c_uNno7hokoQg5MT-rb#t(srI`i6U!D0M`T`|xK{Or zugmAw0Uha_{a;L4iqCoRIOM3++VXdP7-n!6GU@SRvvEGWCsZJ+6$ z4f$8|28Vx=1g!-f&Ufsi46-ngo;#)}eBpg{*Qb~! z?@yhLaNOH-GSou%!AV|C(MfK<9I^g@fr}4xXOt?RZED|4QmuNcT#>I_G2zbaUE}(a z!N-nX zck^}h6mzQChQ>v`-t8H`6M=wT0c|n-9fd`Y^qz0-kCH3te0cw zs*A0}=VIk@R}JekURYOa^Vyl5Dj;_~D=MJXsMu7fU1xNbHrr^c;&C(LbRGM9>xz`Z zYZeVcCFz?P2khR|+hztX9(_f#Hskl9^5XncPq%uHpSQ#JE0~Qa*9<;pQ*cN`{q4; z)c2{}9C#Mv_~fAOBbC$l$CY|+lKH>Nx;V}|YB){BQT)B##FlC3#AnqT)n*}C9`{tL zH+X|+j^t+On{p?bUtSnm)gY_U{=Um!g0q@N#*c;S)&sU1LtimT`KjxF_Ohj+rk!Ny z=Dyq+eDpBx)gh5f6`93;M_w4dx*&P=hEHRWmulU-mrU^*%{rX}@VQvi?tx}8y4(3` zPke-b+D#!zl2NCa9HyjZ*rjW{0#R!vVxsPc!+Ps`27GQA(C}K4Fx44Ff03?pJj$3V zjWWzj^!a2a70&zPs&h;7@=FY#Rf%Vq(4PfU{-+f;9I2=J<8GdM{p)Q8d0!INddAuL z3?NZW`g63F#(dUeqinN#B(D5IOLUHW@5?mTFY?yYjMw$!s7KeLj<8Ryzv9@H|7DN`Hs0MvNiUmE?Ojo0Po?vuxp1Xg;Aq|>z6C9dgWa_$cR7znE;bhmweqQl*@`{N zvY>zX!roDPLCx)DO&^N=Q+$YWd)^*Wvxit3!=#rsAIw%>4tY#=eLEsXDi>PHbv;n} z7gD=A713oGT`B(Sq}It7z8|Y57bin+^{y(02A8(Rj-$!Q8f}s;uA~G@{Fpy6OgyOcL7FXim~)zzz0X&Sr;_nG4dx^IePpFFN z9T@CoNN3Pe6dEuxA8Kf%K$UlHE=t1;OoDK=v=QTEfDu16maWa@qPPIX)f?PpsZurmrj{^@jK?vmq!v%ACB8gl!x zQyb@R8{JyDs61j{YWb!_gfb;Hng7YzJgL*;%*SM{bZ>0Vu*nY~-+D3Bcy)j5v0CZR zI3>YP#dhB2$8g!g%;fFt)baFLRbjH}kGZ=`9E)m%4>)A@`%$l8fmfc(j;DuYPX(8$Xn!grZ&h-)lWdX#lzQ6Y-@V`+KL;ADP}kaojM-FpE2CUJ@rtXe&I;U#%Z~NY-ms zQa3Z<#W~a})eu%9SvPWw_R`r9_neBp^<>5T((zfJ;^mcou4+tk&Ur>}&Om)xPCXB9k<^wX$F>{y3|k}>_72LST*@=LV!9&J z1cQs#E+bAJIOMrI;*FEva5fE{^~u~_y7%%u%&D!o#Sj*@4N>a}2OK5C*gTmgP1mjT za(Y$9T%)d{)Iasw<-5I)kq+9w!Qt~-YptvJ?31&+K6f+3`{_-&it`!4wOPGMG$%Hx`NMBc5`@b zToG72reQPvb>F+Ti=1Z=nF619wZ3pYZrA?a)&7(9p!S0aZIL3n{kf_y>*R*z-`}Y3 zFfWWM?K|shoiBMjBhk`Y`#dBI4{rh4YGKONZhCrNz-auuOnW4IpE+j$EkTc?**Tu$L_52?W2|Gk~btY>{e>Wsq^po z2sW_YCyU;bzKF3qSI z%kOJPJ@7Vs728v^y7%7d9%Fyq0M5uWcipH=cahOr(b9AXltg;_J=+(bUtfE5wV)iMFFi3uu(!cDr^|70L9@A!S zKf~)!dhc)Bn=!S^Y}ePOw};=oLJRFac0*^KDn@AtQFGBqp8sal06$X={(=1wnj(?J(_~hZjqh5-*1j`@igjrFvc)Kz+I{+x$IQ#!>p6WjUybcvAH9FP z3AO0ZAB#$7Z#WdV@p(Yhk&Wh$)0g27_srikA3dF`XgIFvZ#|~J8Z*}$>kyv9`T3%C zANnfqv)>eo60IWSOrIl|Gaqco_y=!6?*IOFV{Kz?v4XO6qmpP z`QALGeZS^WdxyNvHTy-)g@k?b-?PW7T){M*ibm_f)QzfTddEY%-b^}MM4mx?v!GWx z^jV}77<9pdn4Bh~)AJPV-@QLBcji78`|hBcH4vIy_Jq{Q7Wg*gD&M@8_*==%ar)>{ z7sskeozCv5M%CDqxO!Pb>W@mzhO6l^Jcb%nMIm>7yc50#e4j&k#k)MmWTS`Gin3%O zsz?}7%#kaGwH+~vth#f3^;=TKyXxAj&&$~YQ3sa!cwX?2Ie%ZiBWw1|!A%yL4t!nJk?8{VRS+%7T9}y#EzbklZ)hf}CaKAI!wnOutxqlgic73~ za=^H2ChG_7a@A9T04?>VKc_pH?20akFyB6XO6ZOb-xnjTIumcf8zv|^1_S+Cmx;g? zVMXctb;B;yy+7(A!eZAeC~8VKj`yGORsYaB8TcZOU1+8&V$$8Yn5WKJe5ZWp zUpIsQXZg-wmFoYG4v zKxP-Kc|3)Qbl2pe2F*p?wmW^N_q$r2JIkZ9Pix_h!WTvRb@C}wX1>dFbCY!F9+sE3 z56o9*OqW*!m%lX}KUucODkhW>wfutf)^UsCoYunCGt1w)#`+z{2F&-R`!9cM(JuLT zKO#p8JNWdIcv|sl-}u?PDw*m>4LLcB{h1%P@2&ZSjO|sr$fi=3BUiZLX`yDZlqJ#f zeay@uJx#PFuene@Rqsc~M#1wZ)q~59U*^pleg@E&WG$`gJx|2WXni&RSX|NA>iVRo z_(Zg>#x3Kw>SAWs)m=ZgPhJ`n>CL@6(CO&=X%FQK|ASbObI$C2-#?+(X6YoQuLUqo zJxssm5|TGCzPj-$s|Z8SLhaVHB^rQntVw*aJNeqI2Ss?QA+L*ll$>$j;q zq)cp;oz-ziYQNuE*=mRo8&6$NOU%B^kQQn^r1{JKjWY9HPIjVkz2=tHa+a-TZuv{L zu`R>?qXRM`zPVSURIipe9IZPcWHub(c=pU&~#s!h`s;c7*a?fHU;!hC_4ed^fx|az7^vP^L*|=P2-0B7@oAp0OUg?|PsiaIwhto5`o-5$2<} z{nDksGm#qY3m5EV*+7zVz89?1SS2yIb+;g9KzY4AC(ttTzR-YF^fk&MK57kbLymsC zyaiQcMRFuZYqL-jM@_L?jhvxd-Rm5l?lTe@-D&>Gk>NE7v_cU^V}7jcOFBwc$4&I^ zzvv;QSGniD#8#lDkCyJtSLrb}G=id+wq_C|UwJO*yVEIr4E4 z|Ei|=m{xv`2yc)5tZU=_WHOIuz5?RQMJ+Z%XJ;EV<2vUA(*8)YXB^1zQx((qba_0Q zU!k2vdS$mRiRKJTWayPvrojiZSuWq6x(f{)moXei#|m+FJQiG(_~lcR`K2MBRizP; z_*nLNSFX>9KJ!oGck!y4vUFAGC5!NQgD(Q>qbolu)ym)d%FWeGrStB&S3~lrQ?Rh$ zv0+X6WW>4DrHrQf#~=NP<*)A(IF)k81+l&h5_z+lyv>ByLG`H#j3-l^l%n7Tb4%qyF>+{b=EyBc(J$JXAw_vx2PE&fLc8s-*_a>^=G- zE?jA5|HVQ|mI3dvK#f-%C1ngDsazynKk4*N7)RKeED5Ul(&x7n_>WzZn* zAG~I$*z-_)ME=CQ!0}6*j#3=WYM+8^6CaMgt>1flGJr4JRP$mJ*B)u?)3%vKoics~ znXFFJlH&Dn<}#oAMT2*`dxei!1(n~mEV`?Gtd$u%IKcY6M*PKNJ9W_~VM5EALfxXW z)W@*_$FkJh6IN_qIt)w=C*1tT_+pFEg2czm3jIpiCR}iZS@roJ0UK4+qr`U(OM9j^ zm1CE0xltaaXnSSG{wi%ic(prc$!~xS;CVzf*IB7QfE4KPo0yjF5Z2r!aA9-+S4#Cz~m6onoy% zS=7@zYTa@+3bgsTR3m5oCS9mtow0e6jGkQ2Y(~IV)p_Vhik0hNhdsZd1`C;0yG|)9 z`^!>AldZr3|0|D`CL3p;|8CqH#>wF0C*XMAfT=un-F4+qh>b55HQoCG+DmkUhnl5N z-};r9)NCDWTy*<-84YLmqiUXr;LriF3#reN$-8bLCy(n(exWw(v=XFqu&tNizi;oO z&;L|q_kplz8ZBKi26^Qpn2B3XyBJ9(itHV$O}^yP7#6R;IALGjayL&rJu~%vhs0ew zTG|{rt@2-g&R(Cr6<^?H){&q|mq({%_50XnR##CHBHbu`kI1uMRS$RnMjyY-o3#^I^58pj% z>m;hu`?z}S*%W0~gwObQjMC+?&EM@}=LRYm!jvxzJh_-Mp?;lYDe#4NO8>XS=aih< z3hIRwi&+J`x}LuN>^NtwCgv)j@i`fvX?hC7b!OwhN$ALPcGyQ%-hc=PR*1p zW-q_L`C9h(m|Qh;`VUh?BeF;|m*lO;3RiKV?90dVT7M_0Jz%lzT^?WhmCDI4Ln7N|KWL+MA+7&2Uz8 zEMB)KL)zx*d85DuKJKr|+UF)o6HONOQeo=T6_JNRjwS7OWILfN+HBF1^0FaSt?yvK zbHv8*b#Y0L=7N4k2A1{B+K0`f24$y<`|5U87Q~$noEMQUV82xKaq#f0Xv(vVv5tLP zjYeXDiDPfgNw!o1X7pdlKMRpX){q>-jEzxTx^S2Kv56JK)XM9;qYm~y_$?Kk<*ADgz4{5r1>5hGJ(OONbb zb0c_vaKGz3Q=F0e$o1$@tbEW=T@QmjiZ7DGDCvChrg#!(#-)$@=u$-aSvyD~j^(`B z+Gwbl`-J>$aqS)D`{AV#Oh5zehA!Dg&c%FRW*Z@Tl_?ns)YqGh`~9OQZinQmQF0E> zi(>qLA5*+I7R5_C*d@;UqW$J-M#a^`d+w8FUMUuNGvvhc=E~`eucAvzn}R*@JeiC3 zylg0tRAwbkxE%-I!VsI*@2_8QBzr4ldaQl-bq8wFl&VG0&O_&Oync!&#KXz zQnGB31@C9IyR_YFg}Ei8TzRh)HQqc+{^wE2^|;a7C+%l8FHGK!_^|s;*O_%r_km*` zrYoO6;+A%#q}aV| z`bWa*&z`pBHrwH+p^+mG*+!kd4p-;WS!cLJy_wUzD1ChT@x=*8&iUex6hoE2b++Pc z#om4PRe!$XdtYwyp7N)$&g6p+PIlFgqLdESNEJV@`t$Y*+L=S0lMSxOzd)a;q#GzT24@06UpB$9W0EndS!V0z!f z82bHt#Dsv%H2&lTU4%K~vROhHExk#Sq5TCbv!X}?hZ^Q^uCU~;VyV0He$_P8E9*B8 zGCQ^Jp}g(CO7~Sl1~Z(R%ep^eWbM(=Yjnl?!@KTYAzRYZyh?uUQUPUAy5-Bdz^8ZP z=v&*~sTcVv2lNl$IA@S5oF&!xfv=XsVqPnpp?;y(lu0u^-5~h%SA|oYewRlV7X22u z(#y=*ecRKx@-HZ+Jvi$=GaJxX6q<4Ot;lA^A@q-Sc`HaL0#jaRN%g1hrv#b5 zvel~3Q!)}us7iT~qHu=nk^t3+0Ak@{&7-)QhN&+JmMg6ZbQ0(|>#`gTrZc-7>O8A! zec3%J%qMa&!mA!kyb8zU$r9P=4E9iT)^!BDdU0%^Q8npS-LfiXRrILe5fs&r5r_TL z@fv{_ zw2xgldClb{A7QQ7=B#VZk>yvKWci#a=3g;Hjn<^tcMOUymqwZev(tUT(ar^GPH6+PdO>>=`F)Vl2)|@x3Uc7&iG)_*YC^u)xHk) z6}wf1z0c&M5S7_SuOdq$m+8|IuAOs7_jgw5?{)3ZonnfAL~k}-m5W76rG_j7nBS6U zm|f#2`cAgql0wI`s$LZqX6P~=xG@)pnYoyMcO%p?(C|FtBMa5Sw86Eeh(`ix^&+E7`=2{|-^#Bst7!Ch-&7U& znz66dz~PYT`+dq?Z(l#X&nT#B!fa!VI>7OTX74&>0^8QB=6AUtfAppPu5y!`@9^pf zQR37DG+Bk3h{oXFobrppzo%HOe(@ed|&GfbXtDfg=?@H1&Ef4mh~Yxqm(+Gzx}a&Ep&i=M32UG=L%^S;mhHSVPL zolMm0WlP9yI;3FaG@=r2OFD>Ny?^B@C&P~s9!KVw9ML1gyY|YYgibw*%}q9-HHjtv z_=wTsG~*fHxxEg%zDyK0MO%uhtz}hC z?@_d{ceK@A{gccgspy~6s)7n6%g5~al6g%@Znbh&s(u%JD=j1XDCI*7w~TKwpNS`( zow}8IG2<;inftfjnOZeAU1xoj+HucUR6H&9`Z9BXGQBn{wO5%p)0WCces~Y<%~+>` zi8Y&wCS#%RCZ0__;!)G~zn;8KTeCdZ#+cqq`c3zco=|4#Gbp?wKm$9qLarjAu@LSSVd_H$HLT&F7n6zwrc} zl@@>aGn+OQg|awy%!xIv@_G6bW8=oUjHh*{Y|OV7Nz#9Nb3uu%cuzn4cMg~T{fU+T z94`O+0>};JtL@;?(>|GJ#=|5$AO-xpZ%?yCHkz>2_P|Jgw^?wt)R-KF&kt{&Fn z!rF0eBdT5n`(!48+qvyB7qvo_&ib4qe^_;Yj{VP5AH#2nbJ^yn^}Me61fw$86wehrb6D%}ltX63Jy&4NsjI?B8;hxXyeO1>I z*vO+*P&0O7$qBD24LmCAO=vgYoVXN{LY-iLnqsmfEw#Qr@T+-!k?E(i_e?DUP`6wP zhEH2e2-EG6<3gQ(crKmP@}AJh$tz+G-0O%@AR%|-YPK+Y`Iu{f#zHrGOoF=Mx*Uq# zzvqx4LfW`;JcG&Xo6V*l*+fK!QysanlG(0eY~j!zXSci4i|d+_-hJn7rEbU8doHq5 z+`PazB@-n+74u~H(jf25d7%E?yF-R-F4Z^W>=5cpEk=9fDEUFhACHDO+C)X@Ne`GL z$|@wZ&arqMP~Vkwq&i%*C+NUi!!)K4%ZLvGjGZaAc^r0A#Ye&ts+=)DHouGIROlU2 z^y|XD8RyJFdm5)1AFXwzi4gl%l9AG+WM}6pANmr5 z8dr%`Xp^_nje0mKkaoZ!Z9LyNMn{RxuKren42@R+1EXijRNv=GPfk{?w#m2yPqS9| z&)H+%E&-RJcP}0gkG)VtzVuK-qxW3!S|-WW59Y^`zBu?eA0M^Y+sta;q19=2k-aTB zNI_%4T<}8UcrYzPZ{bklnPV#5(!2}5_Cz}vuh9QY4rZ%hW!Fi{@)wkit&e>|p7iX5 zT~xruKph0XNK;Kr&Gj1>Zo3?j?eqv3)PKei@y8^s!;?nwddu;p7iXyx=v4&CcIT0J zAP%eOJ_yfb7Au>AGY_f8@kN#K0-4r=0PzSIkLy=RZD}xwF6O+#luz zyX-GIh*qrF8gC%o<}aTiH-^V5YoYx0+M&(n^iL)qJ+HdM;}tkGkAC#S_nbnzdf%t! zkdP}n6Sc=4`tOeuNe=X-ao@+n+=c1#`V`8zp0F_VAVm-PLw5qzay>>NOD=)mSn!*j z;7OHLrw2R+(dYZ`iID7jw?1()oKf-O&DXOXE8WJ|TP&!Rb-{2tF+W(KJ$j7HvQT2b&_w#b5`fQiuBcP$|1^A;U0VD=GAri1RA$EcZ@o<)EPHopx=*Af9B4|F z6)-R@ysSwhdFzyZ2qrD$VkC!A!myHX{E*EhFFg-Gnr zy`wItb@~z)MXKg2$-MW*u~M|?Tc#Tar&{m2AiKM-hq}5}>>B0T*PxkEf9~fp1DWo$ zoI;dji~pS)80YwwJ1@r%UXzcae9djy+BNQ`>O&KYrdb+okHcKm_d~d7^-Hct%4+Gk z$t#pPA2j+LJw0Wx%a@kJ%`fkC;5EuXR;TknRO$j<7^yyY>QY-Z&GE|7l)TL{=;H5@ z5IW5kSMf`4Z`Y%s4^)Tm9!utCaWwaFe^p1u!jYpC+)k>u^}QiDr0LzDl?3`j>-|Jt z)L6AybMzz69}>cvIco6&Y&lSq>{nA#{ zzUIU&*BduMpQQFEK1t{1olCh}k|dQrQO;1=1K#z;|H>YY0T}^Mpk?f5>l@(dz$K15 zz(wFHw%qMJ>|NZQxWvs|+?CyZT>kwR`@~hw_&99i#7$hzIrxaGc(~aU)M!Bz!ToPo z((*my=3@7^EhNN?)BoRWX*#(1JNUZTogpxUJIEzC>Hc3bv>ieNTQ?UkKL-M%e;u!@ zaanRn0~rXea8BIZ;v|>5pPL)r|9~tFzf=zS*J1a67mRnlyiXhiMoLO>VX*(QO=$M7 zEER;5!g3*jta96RLgZfwBM2#p;KBg)29QX+WDUYw0Eq@Z+XspKYgFKD{_DX0pTzes zn*X<;+n1>SO(p^;;4M}HI<~04NC?JBVxS`n)CJ&?7mPz=AcF(EDhCe(x?d6v9n|gG zO}OSEas4O>Z4X2pyv`s(92AH+csRhEBrp`9Iv)k1&EGhz6ihgYkp|a&z@>0Vd&C%n z!vP=gg2JKyn&iOUhmnNtKlBcC!2ngbkoI<>izEz=7+-+)q0!L&fCf!AI3oO`Ne*Bx z0Y(2g6vP@lC_)mTH^5`a@PKH84@6?PB!RkWNFaze1VAkCSA10Q33|7J0l!`zvNdaA<%~5c32Q=vJcfL<5sLByI=3ps|qS9VtOl3J5r4`*z?95_oKeulQ{nZbEQu5Cf5F{{E2z>o-U_tW? zJ{B1GFo_cq-~|z*+cO4qLqWvBHwZ5&B7wa>5rgol6A}rc4!%YB+zAP6ZwW2peE27- z6cX5r{g1I=Z5WMbmq?$0#o@nzaM>&pEDq!2w$oYYWf%$8hw+g_Vha|C@qrj%76&9< zsDT2kCqx2^3l6kMgak{(_!a>m77M)ufHh)5Aiyw4SBdfmXAwGiLvBBf@b_f!Hvurv zSu}2PAs!qIU=_+$uue?SMhq}!Ac5eyhrm@}W`hKRC!W87XlOwb3GB#-w-F7z1p#Ss zC+5J2)5z^m5bF*!3;_T!e+O5A$1EUS-HACUU;_#XBs%Q?osWW636Wr#n1BE%V5mb` z1k1#PK$wgSEE5v|;ZgyxOiT!bKAgZU*~Gg82^XB5n1ckSY{=l?C{2tx2NW7NJ9Z~Ny4l=5Lz*wK_V*; zFv}CMxIIK5`x4kV5#n&P_(x#{6tDj|7Q~_LQ;Yv=7uY_cptt0>%$A5zVnERBgKrT~ zY9ygmG30h-!e4a%hd>Cy7%#R&Xb1d=NE>1GJ0yf&jAxKo#sg@HL@W~F9fV+vZxYxq zK_81Dfumg_7IDFWK8L}Hv&4Z|=#w8LgkX&4Dqs=jkP0bDlsPyc%(fnwv5C71r$0al z#(%qthDiq@1Y-gq^bsy@qe}?Z1UQ(gArx3dCIDig({mJ9MJ5D7XP_vsj7$iG-b&(*1PMkm0T2Vd%|c1+ z#2XBB>WTs@$%Gc6&>f==93G%(g7MluSlB@_I@LxwW_*nR~4E6UDO*l>Rp8~<;!Lj21dW)Mopl5RwSXIWi z2moO+4-{BdCIG^mTcLmw2EwlV+g03WTA;cTEG!dRgkA=4r}R5mgbNOsJb$~2hAuip zfwg46j)X!1VRf@D4^($cz2+n zMH&=XS0=Ow%rB5_1nsW~fJh)yfCTQu9GsX93EYV}FsBkIu%b-pDj*$0Sp+M}gh1%Z zI$ZG!@$NtX!UCklo#q?_^a%ihDU0(&A3cfzIbqU_p6%$Ni7ya}sQF&<%DaWur6l7aOXvXx-&{0)RDAVq;SWdc{RFo^(IQzit$^dzt=C1~TeKJbqM zyM46tmjr>2C9+5Yvpf-_#DF0B;9DfJNN%f^u&xqWB*C&WfkiB^{z7p8SRRP95wM5> zb|8>I5P1kJ!X<-XS(y+BeJ+hV<|ghc8oGc51(uZwETW++HBew#nE(i*xud|cG9eI{ zh@hgnEshZ*0B+uf1cH(sLW?j<7Fbrs2Onsiky?aH0HD!E@+pUB% zNt8a@NI09Ilm}!JCX)mgA>$*rBMay4PW(Xt`+um&ZW|yLSp-a;4FsJC@o@2hHA$2| z+ekQ@MESFggh{o*x-wy8VZGgH0n_Q-y{$|1a!3+3M?$+1GifVXOigrvyFta zNt8d^NSHhXtS#evi{mU@fWYE1J`xuoXdN5{7MBTuF!?rET*e1(w-U}I(ZpvP31^ci zf3}g(Rl+E+zKrkfc4Xna12ihbWtTf}B+>Q^lO*B|)#z$_) z2hQeB{J}u0+i0-XjBgSMEC%>9M10U-tr;JPYbC779r*)mlPG_-Z2~(2NNNniHs9mpTM@0D1&gJ1@tc{XTgFqerRz(Kyrlyf|DS;@wMGbIFm&AvyFtaiL>x` z#ztrpTHQc{1!w$b;%uUU^DM}A?#LiC^dSK5*4z%>qM>hPqrsXp$Xg)0hxB%52Ep|T zQ3h>u52jbZvNOK7I3!$zz`8RC2@@f(@C-u2Lt{42z=&5$bIt zq0=WcSb+vb2s&j$1Ao1fP3WUxG+2WM*@V8gg$9ezASCon6*PnjO|TdtfdT@kUV+e{ z@sK#a!*K{ggeFA7a0n>IAdD@J8~_cNGEbFkzA4l?%@#5|G|tkvq*gxcXJdRubjTwzDwEZCML;fNVPphumr2K|~_ z1lo2M&L&X;;hcpbJGjOfwV4k17jItzy+Ist7v3x_01Ai!A|-3VOfOvnN_Akpau=PDc!%pM#o{!xk#E_L3% zaq*wD2??E3;vU>0oJR1B0^z~k%!gPrF%bIm-#`R(K_&)V>P+A&ba;SIU+&;37JBQ1 zfl#0EJjD$WSR|M`ct~7V!Xm+w4;~T-D;9d+jse#?<40%PSvVw7`fNK3hs3$|_fkvX zEcAvS10g=+0k@rnLxLwCJmj{sa7ggvgNMXL7FsF5y-7!;mD|q3A;FUmp2=-z;gCcL z1UQRoU^b<@brU+#5oI#BuXHhvoHe;X#5V5g+oF}&xFpx*o2Ut@sK!Y zVaN`lJmUekBMXNlN}%n?!Xb$g2%cYkwgiEi!3aXD1mU!LZ5|WAVg=v$ig9sPC(nv!Xb$g2Lt*ZW;?fP`KrFNxi~;M<1QxNt z#uI7>2G*YmfzWm77_k0K2n0^mAT5IULkNUfros9%0TAY_1OwKe34y?$AzcNrhY$#T zKMAvahvlzagb)b*P!8_?A#nnrq2C(E0B65D0HNO?#68lm0}y7O1Zcbi5J=3Sq6*fY z34#N+=4~I!5{oJd`W8P1T>VUF5xSHe_rV0>ZN%M0g>2(a%t1n5qQQWRp9x%ro3FsS zGa(RWJZ?(^#G;CO#Sf~DVAYw>BFs7f%(}#*ih$wj_Pe0SN@JSAS1dFl#dIgEGXU3UfSjqm5(Wv@nDLzjmR9I=4hvS8@o_kda6mA1aIO9)c>oq%-MqcP|7UT9QHrtP;$}i1 z%%lvKmtPlsn+`+|y1!e+QVIKR&f*)%p1VX>| zjRniggh1$`GAvkLCImvi1BUy&1o7Y?pzGpsN!JcQ=*MHQU~!qiRRr`73k!a!`TtaQ zuD^L5#~J?~fd2!5qLBH)B;V^fN3c``anl;L6T^1VpcfRB_}V5SO9Dm5cK-VQX7*fm z=GjB4L6As~cHX_s&dxqNJ0}aStVn+EiKeza^P^JBxkg-!mdX*x@OX{;-al`HC_@yxZPZ3OKA z+M~uZC&4whUPp9+N^N8s(ME`KbLt4J>s_OW8H5S!Q!hQeEcU%{9qK?T>eJP4ZC^L94f<{Yg{20 zlwnSSMwPYJmom&*aK&&b!<+?IC>v#%v)~G4;|Iw=hG)U{o$*mA<}A3PIm$05!IiIZ z*!Qs?SAc!{>EcoOQ%m_91MoCVu&50A<( zC&69&uJEY*au!6lntgoA=IpqlYYIMPb1WTKQ}8Lx*|i^_9+h9teQX~pI^~zMVEgTS zr~GmjY@gOU<(IP{KiwFdPWj~|XnD_@f{$)kY&w?QzbPmlPp+{|EOg2*XTkQ~(J8;2 z1>4t}o$||Buzls%DZiWr+h;@jn)~Bc&c2`68dXxPJTADwMl=P**-1^^w3k(<{Bjm- zFRM=Z+_(cc0 z6;r1KbE&CKI@cV&Vud4ew`A`S+MQUby&d12WQ_td~`}MryBR|FR^r7 z&OcFO`_$4Y!<=huXIktuV@4Ki-}-e*FmK%B`Y3(nB$WCYgdZ`JN-~S&ik;M)8Ci18 zP%6tTk}H;yv3sJQD_=Ud@1Q*;+0L2JY4ozR7Ot>m*Og}$$@Ux2PSa+HWII!A2e0;2 zKihn9r$n>V+0IAODbt)KSH3&ZDb*~J?f1tWjPMivJhZBOw+p%_? zX3-GIb~=~9f#6s9J5HabGLRH$Sjg8mRi~7EV+_PrDNlGLgOtNZEHT+SD%tx zacVV~Sz5bdsWqBeBv&l8lFcHyVyTsF7ReP$t#q?Uu2^d2n?-WPQY+z{CAScSt@%{O zStM61wNlO^xnil6a~8=JORc1{NUm6FWt~NG#ZoKnERrjhT6t%YT(Q(jJZH%br={k6 zKDn1|RxGtr&r;`#rB?1)Bv&l86BL1b7ReP$t?aW%u2^cNpG9)TQu_h*@z$0_&gIp;bp(yyg}%0p+#mE6O<644^r4#w)0i5AKB zglD{D<*W9+Qq#H4m9W=d$!U>nb40yT(<0d>iF)Ox zMRLW0DLE~YD;7-IX_0IPl=ezbi)1_gqgQ@fB-?gy)x7y*?#fcD@84m z?I*vza?~Q(j(6&nq~5p*{+JEFSC%>muW$Ih($pf^=Baz-sk7wDhTkhuoh8>cd}XS$ zq@`7E85E_eMRH}^R<2qk+qY!BlGRyqC4X_RY_&+Xub+FRt3`6fRZzZKB-<>cG9*y<>GXg>z+ zTWocbTyc(DY;`4R(Fm5{sig`ny1EkG!kw&&KB+~AHm}gP`0A=sZ|{m|i?FUly}fIq z4YsioWk1`u*~Y%bSXYwP-c`}Y)mbHK?Ohd>XrXL7_ibjYZ*kUDrQY5(Q7f0u>XoRs zcTKe6UfTufM>!iU;<^%k#Mx*O*HLoiwNBq6u9IY&0PJawj8Y|O18ff@S_`hlTvwtt zz^kGSU8+QBl)XS}R@zXdO48fACMuz48$TD1v+C_#6K&{HRjajk#j|gb*OjEVcTKcm zl`2th@0zHUOS)f)(%zL%@b)eGx{|c^u8KacO4i<0Q9bd~vyWVG4Gy~&rn4&_mgpNC zc9v}45A+QVJ4qhfEPvnNu(RaKdTVglS#rg@*XZd@mTWV$eS^c!k}G>ugTqdeD|g*} zgTu~}?HjSa!C_~~HgDcHIP5IBGPVs4J4>$UP=muxl54wSgTT&`D>PSwz|N9w8oF-~ z*tMj8m}yN^tx+w?0$sUQ9U2UFmTWsZLxaK2l5Hg#8Vq(V>EA4B=TI9O6t;-AIhCQo zVb`KIMs22RXmHqBvdwf2tlYdy)RN`vOigEdXpq<<+P=;m8Z34#YCUbUoA!|(fbCET}xU|S1VQjNJQ6aeOi+? zE6YuTti#^q4Q_`q3=J;3Zm^9~+YAm3E;~!MJ;9;DW!IA4+?7fjWVVQ|)%vt1wL>6= z2Af@1YGc&io`wdST}ygT*D7sjl0hGHei|B#wqLP)oUoqUYGJx->1!JYi=jbkC&`t= z*U%ufYe^fZHPHsEU5nD(l?44mgVN5D?fBUN6%(spO^!FWodj=aaN2dHF1l8$p4)0s z>uH7 zrL|=`cGug1VV*|AW{4!syNff+&{-r$tf$yi=LnhPG-d_b+nmj#QLrQZ^hh>q#t6|T z4^dm7j+Xhky@G5~{6t=1CRsOQ&j)0H>SpjELnhr1$37`mCzwf2qfwwegXZVi>G%1P zA(QS0)e5p^jPJZA9o|!cpDn9m{JtL=7wEw6k56uxlv1Z@m7nvfVhoTU;3~*|zn&*P zl{i>4Vh2q5JQ`?`JTe30>xZdICSdEQpK3IY9oVE*rDaE^a}1f9B)bhztp|KR(R9O4 z7)za%7ga8I<7wBIisz<|Acd46_!duyE95U=GHt5@cnG?5s; z{UugzFf|O;Zz-~MA9SvcRFABs$v*5Z38AAatU|wGuwoO2Vr>2HpaKtOFpYkzF@&A& zudw45tgL<}rTpS{e|@oaM`S6uWvy&SbGwu~f=x;^${wz1&1_vKkk-uBuVAcOut`HE zjB=y-n_F|((!^;`7+XljPOw-r-U2^3t&j49$HUQDGbz{zvTEpJ7#m(%gGFH;7=sn< zpIgH#5x_}R$`5v(VX-TnX`bH;E@MbQ8?Etc#tPg}i(hh8*cN^CE3+E2sV_4+w}$Wu zz&H;5&VFz*=%t0+a)V6^d1w14=Ea6)GNq0|S1^Q2=P1Uxp1w`L<~j^*ORb}=rYR2Y zY`ff!#%{rw&)L{bv$BowHFL%b7E<^|AeNCnPa{|gvK+yt5gaizjy=^|J-3E# z08ZmN7DQ=wvxOWnY@bmbRhRcf0$iN!W*b=w+Tz)brf3{5K5a}Tv%M(g4x7V;rTwuV zoLa+2TL5Pj_JRZ33u6;nIPkR?u+W-ek6JS}ldc!x!=|IzVWzNih6TL=>%ry)H40-8 zcjJDNt*RBB?<^{-I!dyymCo<+SdPi8E@gJ}o-kr;VY_)#C>W_@!6rK~Vl?;6lCf9Q zF_1uyg0cUkC}WgUIhMn2G>g&Hu?ePdf6bQ9*wj;RSWow+y`=mgD;+GXSc-6d z+Rq-~Sdg0c!NO6_S{*DLBWhdVK3FpY_ZR!w zgKcPGSj>j8ruJbq8^|;V+iIA#Fpd|NfvGQpJc?zp)vt-&hpMysA}t1Zbj+iE}8&$g8Su!e0dWp@57 zs%n~v^Pv$vxQvGf%^-^~=kSPRR2 z$0c(VW=#AMV%0)apOH`Vi|+4&|3Q~geM@Z^e$WtOc;zCt8F0!yvooV;I1no$@R$ueFAVVDnGorJN9!?sHIIIo=TXBTz+K{L$rQDVYa zvGZwQ!psJjSzgBGNNd7gYqikqu+@S=y6l4^4AwI?`#XZJIwnJJfB*nfsD<8Y5gxUEI!OdjTz|@pa)KukI%=T%{ zFg8b4^C7L3&YGRr-G02kgornq?t|=I;|G+_~eBGfgN5!L0GV8&Bwv|s^%mra; zn3ZTU!S)w@R5o5ZuttsWo#(OAVxb1#t%l52}Y}< zc_aW6Z|E2|EkODlS1cHV9XB#CW@=oV)7Wrri||Yux$%LEx0=J$!$>m$(b9uiYob-( zaN4GpFjE_zU0)od3E=e4FpMT(ZjJd|$GBZWnKQ8A2+sxz72Ty)%WWRxox2D}Pb)=PZ?A<-vk8zzqpw(*+U*cb6F`IZP^Hj>siD zNsZB(@su`?jqP|PrAS?{2MgX4mC(X?O2dZP*u-NR;D&;!dr%%-Jf2XFR*%QIr8QW^ zZamIq+iF9*YFqia<7``d1_bHlqNyCkyi7^AQS}vPkIRv;==L~!B}GP6&Q9Sa`$Y}z zC>ZB_Z+Z~@cF0>se)KYzzTzo%aX+OXHOKuFjFFF<_GXXjpLOG|J?{8`jC`QE&<(Di zy0o(Q1Farc_R^Yx=}1eP)KXx<`tyU<>NLGr!m}=|!~+{y7dK-vO4Gu)7lYBl(Gt$B zIbcV-v|&CcIChUvP;JLz%JO0&hgxuBi5{o z9^i(YNnlZLFoR&R5^M~u2~5p?Ln>OEJy`Jp> z|04|w3+$N8UXPJKCaXt`Fv?b@eCaEetK=V8M&2CUk{_VLI0%%N|24+_NO{y>gFOY~ zoD(_*7Q07K*hP6LU-@PO+-i9PU;Q99rMzyhu^m{{USh9kO{BEAfId(#&N;zSU{QMq z)<{3HT=Uov-UOJs!r`a9>aJSDS}O0gYm8m6JjJd-x)P}`?!)Oyq`ts#gvT@U(i#qi z<;`>bgLGw%FDTyQfHf=clo!$0a*1c--;8 zIAKKAf}3}+QI{sY;mVv^BGnGYG)J<93l>hWkqHE2h2x*ph6#|fe%!RcI1@)^90SM? zCQI*Dv3xdLIRP7qRojZ>cCxJp;xbyc)ytGmWX}o%#z`}74`7fdaVy}$gcVypA-xDY zc@m8^d@h_wG}a6WyxDkLFpWHvA`2{zJQyY*o}9oi0dXo}%+Sj69)4~OAjT&iU7^gV zB%ZLqFahJ{zO)7&h<&D>N^VwYP2BOpFg|g|2ea11{S~#$d-&2bfh-Y|1<~+#~|VL4@%Hi{oYI-aei>2;#!F z_VL)k?=jf%)B&x^c*Ro(bueDzVPa_wma9C#S`^U^OXZnUjUgP_at`aZCr8&BkQs=c zH9avbc-DLP#0&OiSJNYe8fdO8yNR|ar?zPg)iAhCkBwqvABhT znQ&NBxUpQAjn2R{Hh^3b#$6DM7RFr=j7s7z2!!`!nyHf^hE&Z=$2p6+Jb z$`wk>Z}l>kWxiSuVAkBQXMkCA)0jY!o$(J*n6tiR{tG|I#so#0Fe*tb9!C;tiJLYU zgAzAwPAOCp_hK*``M8qQBnW6%u;DXS!o7nT_;+7Aj+OAN#T}+%2Ko?1T}wOF(Lg+a;J) zlE#az<1pHuWo)nu^f3-1ci}iD3A0M#)E~@#uv@2s)RL^(0sFyL7|UTl7$3)$)?h!_ zR8m2@5(!D@M5`oCirEhaG74iqEd5N-5$p$pn=mRFx7wvO*bhcL6{IUMoD9yAO5$xB z7+OpeXcWeNFf$3WN>W!Wc3|9Um)2lE2=0u+SO)thc<3Ih{t%fA7*x~ZNM!(0OQbTO zRjDL08DLbhglN0p257aUuCVG4kr}6)RT3w~LiK4)?21L=qbH#&_Il?KnG85yDp^9b zOKZ$39>(o5`>m#S>$cU->?7X_m)MLGfI?Vl&);s8~jmv(JXX>un=X75DgXM6bl@ASV|E<7|*^3oOnC zd9>KvxZuJO&WeM?oZszaCeay zPClvxeHDE!zO%!XOI)2?Jagp|7bkbjcFz}AA~#X65vet{t@f!kwypLldW9P%yy!@2 zad&J-v2fnuO4!bJVN$r5r8OlF;_MxB(MA+pJP>fvMzmbCtz5Jbc9v`_H*FTW9tYca zdYGAdR=Bak^^7JHzKT=$F4{~YfVi@ZTL&0dPq7?#1CW`c%Q0y&mjf0j5cE}1uKZ>WP`amgk6o`xUh^lB4o(Hvt_x#0T6@}i`v^D zVq6l4HWF%*K}@WDmE1kcc@3jyo2i!zNKF$}v4GSxa}_g+f!|E7%L4Lhd-7ct&}tfI zZ2_@uo5_1wP^&6;3j4d6{Fk{Tn!cGGm<6S($un6%IyKQM3rI~9uQG!cn6;Ulm<6?} z#<^cWt0{L1zmL`716@rYOM}oAN3%m~W~^a!=UPy)PrklPG(r8ZmPR4YE9+)6Q8Y_Q zT03zx3usd?ku(cRYbTaw23aSTeJ0jqPxNP=W+`e_<$=My*i1~#QqpQllWh-GX;kVI zA+0<-pEQ_rf<2YuMu0bX6P5MFjM|;4rO7RgU0^Fb{qBTX*zj)JbmpJ1*k7KGjs5+S zH{+8V^d)5Dv;%wz$vElimw0`XA^&QBIb5A^iz5RjJy}kVBUr(=pezNO^8L;0zux?CvgVHm?DAVYE8R`MwYl6~ z{`&`hbQ1dWho8Rv@$%;F?InNu?)2e-H)_*S+{Jle)^&^c_VSCjA0BSryt#R}d-wM8 z-S^WEeLdFBBcC#ME)6TwZzgFvvbp@X({Go5c=z`8>HWh8ulKvt{ZAig^t2pYj)~k| zPjY7S{`|Mo{on3Rzc35qoPT|3BRlq#zc6n+ODuKsSB&O#qUCS)AY(Lv{0;7EIr7>xctS=7^D92H}?0XY1|)h zF+4TfZf|GufuiiQlZx^;J8jI>bByA6H3^#KA2sglOX%kD{Af)+5Iymm+_-Kl$2{avTmfLn>!g{_&pFE??dJm3AF3Sp{{b1mF0^E?s^1+xye` z)mNv7o7#Jv_p3hGo zUf~T)`dwaC1f;aEWXq`-*<3KE9MR^;myYGL~Qp<2zsn~y) z8`b#{$(Ns5K_82vCcl64Q2y}d&bspa&CS~%UOfBt)7#VcH$T65c=j?5*k@O!!*A|h zmOr@kRrQnp&(&al{P4d2`TmXT|LyCm)0@*zr?(Fu7~;*Wkhibr5q_lX?d#{S&1#q$ z6wLs6FcZ|Adv7mG^5wF$$*l6?**(kkcl>Ew`BSzP_mgL{Sd7TmI2s=a_Mhzk=o*!+ zzu5e7D;O>RXwOIQesr?O&1dp?F~?Vbc=z+$2aFJZ{QBme@i-sG!ojXN_Eek71~!b& z`!M?JOD(uu@kecMef&p9*Ld`BM@Mz^H^;4cztBvWKYdG>voi^E zwjp6;9Lx3c0*Wz@<#+%k?c;EdlBIHD=h*GQN%%@HHuQO1;rHt7e+ z6{H_9-_j4_0Hhy~|5}IhPN^+U!X(Ue%%Dn#xI>jXxMP$$xR{fEaC0U7;6g_0@L=~; zuRldemV9TFw2iceY9Ixileu zHuViYFxyzl5ty9HkrB`i_Mu*0A!M7l;c-E>CA?_%sQf6)`=q2V_VPLVB~UWX;YV4v z%cRc`cAi!_Y+Ez@~5ou;*O@kT#7wh10mj0eotErqPD@vGW$jVr@ zf3~EveKySQw3DpA?M#^X=*aq`>{QO5o@LB}BopSb!x__Yfm_e^lngo+SQlmShom2@ zX;}+wG}+dX5=m?cnAlSgUB3{Sq8qS{GQVt6+7C~)kow_aC>gWsiG-;EWxokoPY;&LdDw5lJZvvxcJxk| zzuL=~9m5mmX&Vye&rCBWbBR@JjNc%(lay-~dlY|<9X;zVkB?-pAoY|*fh1XH@)PFS z7c-X6280->jR2E%iHk040ZjCd5H`CvPW5`ANycRFA^Dqy4yAJb;3;ALDk5V#=R81> zvEnVH)PWNs^Fan+=?6)-MX$)it95v`vDiM|RA?O@IGxIQz+=KZNlwPZu95soYzdh7 zW}G->?*Y@fB!#TBnS7%S%-FElKIn~XcS%TQ(den1=N-<8hdc`xIYVCK0XMuckt^AN%Gd!BD3VIJU7rLejLUp*e3SX$3QuMI2}`Qiqs=pxxd-~jV;Sk2 zM+YWZPY#qYPh5~OqqY;K=UM`S?K(Y{gUS%Sf)W(HA~;&~iZi?PgRESlSGfE#ADr!F zOgV2!KX^JK^TAnCG0!`Y`sO$N3G=K~8EcG-2co5N{?apJnfoGa>pJswh6!)MyCpe0 zgX!K#V4;jDOHjs?7-$(&(qhS&l4D244<1Q$gM3w@8yssD^Jv#NE)Y|qFYrjBF9bzv z-x@vx32~%vL?KJx2uPK_QLXfi%pB4W=qu5Ch%@O20gloS)J6J1IHJrE59_rbp2R1P zAAGU)!-GUqIk`))%vkD6@mO2?(XhLyxb%ZJ$|B1VyMgJr@OoB%uc5oVVU=;=b*aoR z!6=IP)1NplT=&SFbBvNX9~!zlG<27b0mz(VPPK0h-G!6ReZ#7W?y}{H?%Fn(`$3uw z(OodnUEa)z-360z;T@ff3k;*|0bs&&kwHw(0brTCCKOfeE|~1o_LN`y>o4cS{PHX> z-_LL{A@^m5$(fGWTsaeiiBHYzJ>d#?yeDT3F!ArXu@T+^O#C(8n27HPCVni;wfIQ9 z`;)Z_CO$Rpkl1!GS*w<$Ag?XEy2~~ZOwNP$mOtAAFya5~m3>}=V8Tamt08AoTsXTU zk9vSxr@!Zq6;nCSfSWK+otZJ=jMy2)SLRWo`0Zd~Ct*B>K~td%j~`Xk#W-Z-i~AV^(*uVD|kbI{*YKMeO-^?+33T8F>iO8xb8dkIsHj1?n% z9hj~`Ben9F@^J#`2PBG&JyCmNhoE2d_mtnYYwW!5^8i!VAn8`}p2C|kzo(o6Z^?DP81SZ2^Z?3D#uO?;#(<`X9+0rdr8#dyYat&-DA`{o&3ldLC3OPFU*%9#4{+;>ZV*#@P*BwiAI zAtjQGA8v{Mo`19{wngKS@J=Oe#4vl%n`9*(j&h!rK9%$2tqJp&m>HA%Ei;`u2A)VP z$@(LOfU&EJFApZ%EBOw@j{p;$B(zNQ08DH)sS?DO$J~ofg2`US=*hVoO!R`7Fwp}`bCkyvOwM#{M>&3oXAyi3FX;hvqWBT)3gSnAS=4WwBOVK7y@I6{J%B-x zGaZ*AbPm=9a^#Bu=Z80Zeu}xsA2T*<4K9dwxe0eaj2jmw}Js_WG zw#B#tvR{J9e#yRtxc7#GhP8rLd89Xc)=cf-w{j!WZQhBvO`!nsWP!MRN4mkUhM zQ_f{FznsftemR#(KS+%x^UH;btT!^5$$VhOWqxt>v>%=ZI*uu1uJ%LyFiX!R{jhgx z*`7j(Nk5ESl5+m$HMWJVN7@3ZAY;m5Tz{`&cgYQ;ZNbBrws=DO)E3VZldy)}#c7ps zCO?hn3ofhS1+@=q}Ttzo+qzFEL#J7`az*85eavE<-RGM&ZL~`!X2=?#pCt5mztkgZna>x5j-L@%QSNH15k7W%Wx)mn?eK zxGy6jRs9lD49og$+?SEsNOh9?GU*%BChM2`G8rqbl*A5kUnc$FzD)F)N8B>bywlcx z_=n%3UU9`Dx;uFOq*PAh@LGu#$Hq1hzb3eeuo*KoI^^eF3v0-3h zPszn3_7qHXm-I}s=YfemwY+EA4^C3jH~%O}7z3lFv>zHDMrJ2D|ANW62P$un##iT9%)!@`VPi~tqz1xBHmOYPcLC1xyBCj`| z*@!Oy)hD_OCb~=J2-)+%RCoCS{{2s zfAc!$Nr;?HVQ7Uv1(W-DtZsg*#VZlL>*eK$@B)Oj2rmGpI?4Crr60WKlzwo86&>e| zr;I&RxabD&KD7?L+rf>HeFjX<;)Lf2Cj&JsoD7(7GQ5a1ZTa%J(c<3o8K}YydTs$ln>)Yi0~kIP2yjHNsI$u{1UF- z!l1Mt{-M2Sb2tuaKm1z^shlTb&zRbr#<>i4Quip%WinQnKN%~|Wzr9>4P-tzmq|ak zaMU{FEhtvfKS>+=#z$4M55l()T&}HFVE8@xfcSHdm#&vlYS7#DE(->iQ{A?d?%RjoxIx7{SBvI>+tW&#ChY5 zo$TGXbuu63B;_@Yb0Kw*no)cevMWj*Y${rZr_+z^!?0-`dgs6g9Ocddi>SVZDT4IF zzwegn^<<41)3wDBLe>`Bo7SOskbL@4_fV2~%KEjmmATDiQj|J4cFX$Z0kGHz+(fOz z6Bft*vL$OB`ksVnZ{0)r#*fw^@4LzWro1iJjk<^O3|#x6F-pAr*FBUonCKt$r1Xt% zjmY?sLRa*jGnljmb1(hn3?^%VFbbJV&S2UW|A2O!4`LRzeV)%Xl~YcJ8%VXCgC`?P zvi=#5fZ6lzJbqxZeo<%fOTdJC;HjnT6=1SALQ#khOqj3OD=;}@bL}j5B9`(ukFzD? z&11?Elr;k;YldA*{7x`gGtesHcY=uyancYS;;LNyPB85+cVp5I!g8~oVoJpCgyNAk zV>xGKtcak@Hrv9f^ZMY%Q0JE>=e5AAF|p5>HJxA1TUxKi&fuA8e|bxm_YY=G?!dvs zMi71=HUdocUzmEa5n!_avI2E}2`iOx;aOm|5zuSmZ-9xvf#no`gOCZ;XW|oeTr>{> zU#yd}JzI+S@(!VJwn4QKJjd30 zm5((VQ`_R7p^LV2*BDc1WoaJ|XT`?ygh()46=@$$k@Z0;fh@~wVp)T{d=)*gtt{7J zAsx96ouK1?6c3#uD-qd`^mCwon3wL`G0-J(HYM3aC@`8-5*Xj_N?Gl zce*+3Uhlix*Vm_)pFypi_9St9{r&B$U3WUZI(~mV5q^P}{c3x7ee?2v$ZJLd$D8{H SPvJ$6&;Icr|M|~ 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 when neither UPDN or the file method are +specified. + +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. + + +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 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. +Fat-tree algorithm supports topologies that comply 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. +*ports that are connected to the same remote switch are referenced as +'port group'. + +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. + +The algorithm also dumps CA ordering file (osm-ftree-ca-order.dump) in the +same directory where the OpenSM log resides. This ordering file provides the +CA order that may be used to create efficient communication pattern, that +will match the routing tables. + + +Usage: + +Activation through OpenSM + +Use '-R ftree' option to activate the fat-tree algorithm. + +Note: LMC > 0 is not supported by fat-tree routing. If this is +specified, the default routing algorithm is invoked instead. + diff --git a/branches/WOF2-1/ulp/opensm/user/doc/modular-routing.txt b/branches/WOF2-1/ulp/opensm/user/doc/modular-routing.txt new file mode 100644 index 00000000..0a593467 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/doc/modular-routing.txt @@ -0,0 +1,78 @@ +Modular Routine Engine + +Modular routing engine structure has been added to allow +for ease of "plugging" new routing modules. + +Currently, only unicast callbacks are supported. Multicast +can be added later. + +One of existing routing modules is up-down "updn", which may +be activated with '-R updn' option (instead of old '-u'). + +General usage is: +$ opensm -R 'module-name' + +There is also a trivial routing module which is able +to load LFT tables from a dump 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 dump 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 dump file (in order + to disable this GUIDs may be removed from the dump file or zeroed) + +The dump file format is compatible with output of 'ibroute' util and for +whole fabric may be generated with script like this: + + for sw_lid in `ibswitches | awk '{print $NF}'` ; do + ibroute $sw_lid + done > /path/to/dump_file + +, or using DR paths: + + for sw_dr in `ibnetdiscover -v \ + | sed -ne '/^DR path .* switch /s/^DR path \[\(.*\)\].*$/\1/p' \ + | sed -e 's/\]\[/,/g' \ + | sort -u` ; do + ibroute -D ${sw_dr} + done > /path/to/dump_file + +This script is dump_lfts.sh + +In order to activate new module use: + + opensm -R file -U /path/to/dump_file + +If the dump_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 dump +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 dump 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'. + +NOTE: ibroute has been updated (for switch management ports) to support this. +Also, lmc was added to switch management ports. ibroute needs to be r7855 or +later from the trunk. + + diff --git a/branches/WOF2-1/ulp/opensm/user/doc/opensm_release_notes_openib-2.0.5.txt b/branches/WOF2-1/ulp/opensm/user/doc/opensm_release_notes_openib-2.0.5.txt new file mode 100644 index 00000000..a6555733 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/doc/opensm_release_notes_openib-2.0.5.txt @@ -0,0 +1,487 @@ + OpenSM Release Notes 2.0.5 + ============================ + +Version: OpenFabrics Enterprise Distribution (OFED) 1.1 +Repo: https://openib.org/svn/gen2/branches/1.1/src/userspace/management/osm +Version: 9535 (openib-2.0.5) +Date: October 2006 + +1 Overview +---------- +This document describes the contents of the OpenSM OFED 1.1 release. +OpenSM is an InfiniBand compliant Subnet Manager and Administration, +and runs on top of OpenIB. The OpenSM version for this release +is openib-2.0.5 + +This document includes the following sections: +1 This Overview section (describing new features and software + dependencies) +2 Known Issues And Limitations +3 Unsupported IB compliance statements +4 Major Bug Fixes +5 Main Verification Flows +6 Qualified software stacks and devices + +1.1 Major New Features + +* Partition manager: + The partition manager provides a means to setup multiple partitions + by providing a partition policy file. For details please read the + doc/partition-config.txt or the opensm man page. + +* Basic QoS Manager: + Provides a uniform configuration of the entire fabric with values defined + in the OpenSM options file. The options support different settings for + CAs, Switches, and Routers. Note that this is disabled by default and + using -Q enables QoS fabric setup. + +* Loading pre-routes from a file: + A new routing module enables loading pre-routes from a file. + To use this option you should use the command line options: + "-R file --U " or + "--routing_engine file --ucast_file " + For more information refer to the file doc/modular-routing.txt + or the opensm man page. + +* SA MultiPathRecord support: + The SA can now handle requests for multiple PathRecords in one query. + This includes methods SA GetMulti/GetMultiResp and dual sided RMPP. + +* PPC64 is now QAed and supported + +* Support LMC > 0 for Switch Enhanced Port 0: + Allows enhanced switch port 0 (ESP0) to have a non zero + LMC. Use the configured subnet wide LMC for this. Modifications were + necessary to the LID assignment and routing to support this. + Also, added an option to the configuration to use LMC configured for + subnet for enhanced switch port 0 or set it to 0 even if a non zero + LMC is configured for the subnet. The default is currently the + latter option. The new configuration option is: lmc_esp0 + +1.2 Minor New Features: + +* IPoIB broadcast group configuration: + It is now possible to control the IPoIB broadcast group parameters + (MTU, rate, SL) through the partitions configuration file. + +* Limiting OpenSM log file size: + By providing the command line option: "-L " or + "--log_limit " the user can limit the generated log + file size. When specified, the log file will be truncated upon reaching + this limit. + +* Favor 1K MTU for Tavor (MT23108) HCA + In cases where a PathRecord or MultiPathRecord is queried and the + requestor does not specify the MTU or does specify it in a way + that allows for MTU to be 1K and one of the path ends in a Tavor, + limit the MTU to 1K max. + +* Man pages: + Added opensm.8 and osmtest.8 + +* Leaf VL stall count control: + A new parameter (leaf_vl_stall_count) for controlling the number of + sequential packets dropped on a switch port driving a HCA/TCA/Router + that cause the port to enter the VLStalled state was added to the + options file. + +* SM Polling/Handover defaults changed + The default SMInfo polling retries was decreased from 18 to 4 + which reduces the default handover time from 3 min to 40 seconds. + +1.3 Library API Changes + +* cl_mem* APIs deprecated in complib: + These functions are now considered as deprecated and should be + replaced by direct calls to malloc, free, memset, etc. + +* osm_log_init_v2 API added in libopensm: + Supports providing the new option for log file truncation. + +1.4 Software Dependencies + +OpenSM depends on the installation of either OFED 1.1, OFED 1.0, +OpenIB gen2 (e.g. IBG2 distribution), OpenIB gen1 (e.g. IBGD +distribution), or Mellanox VAPI stacks. The qualified driver versions +are provided in Table 2, "Qualified IB Stacks". + +1.5 Supported Devices Firmware + +The main task of OpenSM is to initialize InfiniBand devices. The +qualified devices and their corresponding firmware versions +are listed in Table 3. + +2 Known Issues And Limitations +------------------------------ + +* No Service / Key associations: + There is no way to manage Service access by Keys. + +* No SM to SM SMDB synchronization: + Puts the burden of re-registering services, multicast groups, and + inform-info on the client application (or IB access layer core). + +* No "port down" event handling: + Changing the switch port through which OpenSM connects to the IB + fabric may cause incorrect operation. Please restart OpenSM whenever + such a connectivity change is made. + +* Changing connections during SM operation: + Under some conditions the SM can get confused by a change in + cabling (moving a cable from one switch port to the other) and + momentarily see this as having the same GUID appear connected + to two different IB ports. Under some conditions, when the SM fails to + get the corresponding change event it might mistakenly report this case + as a "duplicated GUID" case and abort. It is advisable to double-check + the syslog after each such change in connectivity and restart + OpenSM if it has exited. + +3 Unsupported IB Compliance Statements +-------------------------------------- +The following section lists all the IB compliance statements which +OpenSM does not support. Please refer to the IB specification for detailed +information regarding each compliance statement. + +* C14-22 (Authentication): + M_Key M_KeyProtectBits and M_KeyLeasePeriod shall be set in one + SubnSet method. As a work-around, an OpenSM option is provided for + defining the protect bits. + +* C14-67 (Authentication): + On SubnGet(SMInfo) and SubnSet(SMInfo) - if M_Key is not zero then + the SM shall generate a SubnGetResp if the M_Key matches, or + silently drop the packet if M_Key does not match. + +* C15-0.1.23.4 (Authentication): + InformInfoRecords shall always be provided with the QPN set to 0, + except for the case of a trusted request, in which case the actual + subscriber QPN shall be returned. + +* o13-17.1.2 (Event-FWD): + If no permission to forward, the subscription should be removed and + no further forwarding should occur. + +* C14-24.1.1.5 and C14-62.1.1.22 (Initialization): + GUIDInfo - SM should enable assigning Port GUIDInfo. + +* C14-44 (Initialization): + If the SM discovers that it is missing an M_Key to update CA/RT/SW, + it should notify the higher level. + +* C14-62.1.1.12 (Initialization): + PortInfo:M_Key - Set the M_Key to a node based random value. + +* C14-62.1.1.13 (Initialization): + PortInfo:P_KeyProtectBits - set according to an optional policy. + +* C14-62.1.1.24 (Initialization): + SwitchInfo:DefaultPort - should be configured for random FDB. + +* C14-62.1.1.32 (Initialization): + RandomForwardingTable should be configured. + +* o15-0.1.12 (Multicast): + If the JoinState is SendOnlyNonMember = 1 (only), then the endport + should join as sender only. + +* o15-0.1.8 (Multicast): + If a request for creating an MCG with fields that cannot be met, + return ERR_REQ_INVALID (currently ignores SL and FlowLabelTClass). + +* C15-0.1.8.6 (SA-Query): + Respond to SubnAdmGetTraceTable - this is an optional attribute. + +* C15-0.1.13 Services: + Reject ServiceRecord create, modify or delete if the given + ServiceP_Key does not match the one included in the ServiceGID port + and the port that sent the request. + +* C15-0.1.14 (Services): + Provide means to associate service name and ServiceKeys. + +4 Major Bug Fixes +----------------- + +The following is a list of bugs that were fixed. Note that other less critical +or visible bugs were also fixed. + +* "Broken" fabric (duplicated port GUIDs) handling improved + Replace assert with a real check to handle invalid physical port + in osm_node_info_rcv.c which could occur on a broken fabric + +* SA client synchronous request failed but status returned was IB_SUCCESS + even if there was no response. + There was a missing setting of the status in the synchronous case. + +* Memory leak fixes: + 1. In libvendor/osm_vendor_ibumad.c:osm_vendor_get_all_port_attr + 2. In libvendor/osm_vendor_ibumad_sa.c:__osmv_sa_mad_rcv_cb + 3. On receiving SMInfo SA request from a node that does not share a + partition, the response mad was allocated but never free'd + as it was never sent. + +* Set(InformInfo) OpenSM Deadlock: + When receiving a request with unknown LID + +* PathRecord to inconsistent multicast destination: + Fix the return error when multicast destination is not consistently + indicated. + +* Remove double calculation of reversible path + In osm_sa_path_record.c:__osm_pr_rcv_get_lid_pair_path a PathRecord + query used to double check if the path is reversible + +* Some PathRecord log messages use "net order": + Fix GUID net to host conversion in some osm_log messages + +* DR/LID routed SMPs direction bit handling: + osm_resp.c:osm_resp_make_resp_smp, set direction bit only if direct + routed class. This bug caused two issues: + 1. Get/Set responses always had direction bit set. + 2. Trap represses never had direction bit set. + The direction bit needs setting in direct routed responses and it + doesn't exist in LID routed responses. + osm_sm_mad_ctrl.c: did not detect the "direction bit" correctly. + +* OpenSM crash due to transaction lookup (interop with Cisco stack) + When a wire TID that maps to internal TID of zero (after applying + mask) was received the lookup of the transaction was successful. + The stale transaction pointed to "free'd" memory. + +* Better handling for Path/MultiPath requests for raw traffic + +* Wrong ProducerType provided in Notice Reports: + When formating an SM generated report, the ProducerType was using + CL_NTOH32 which can not be used to format a 24bit network order number. + +* OpenSM break on PPC64 + complib: Fixed memory corruption in cl_pool.c:cl_qcpool_init. This + affected big endian 64-bit architectures only. + +* Illegal Set(InformInfo) was wrongly successful in updating the SMDB + osm_sa_informinfo.c: In osm_infr_rcv_process_set_method, if sending + error, don't call osm_infr_rcv_process_set_method + +* RMPP queries of InformInfoRecord fail + ib_types.h: Pad ib_inform_info_record_t to be modulo 8 in size so + that attribute offset is calculated properly + +* Returning "invalid request" rather than "unsupported method/attribute" + In these cases, a noncompliant response was being provided. + +* Noncompliant response for SubnAdmGet(PortInfoRecord) with no match + osm_pir_rcv_process, now returns "SA no records error" for SubnAdmGet + with 0 records found + +* Noncompliant non base LID returned by some queries: + The following attributes used to return the request LID rather than + its base LID in responses: PKeyTableRecord, GUIDInfoRecord, + SLtoVLMappingTableRecord, VLArbitrationTableRecord, LinkRecord + +* Noncompliant SubnAdmGet and SubnAdmGetTable: + Mixing of error codes in case of no records or multiple records + fixed for the attributes: + LinearForwardingTableRecord, GUIDInfoRecord, + VLArbitrationTableRecord, LinkRecord, PathRecord + +* segfault in InformInfo flows + Under stress concurrent Set/Delete/Get flows. Fixed by adding + missing lock. + +* SA queries containing LID out if range did not return ERR_REQ_INVALID + +5 Main Verification Flows +------------------------- + +OpenSM verification is run using the following activities: +* osmtest - a stand-alone program +* ibmgtsim (IB management simulator) based - a set of flows that + simulate clusters, inject errors and verify OpenSM capability to + respond and bring up the network correctly. +* small cluster regression testing - where the SM is used on back to + back or single switch configurations. The regression includes + multiple OpenSM dedicated tests. +* cluster testing - when we run OpenSM to setup a large cluster, perform + hand-off, reboots and reconnects, verify routing correctness and SA + responsiveness at the ULP level (IPoIB and SDP). + +5.1 osmtest + +osmtest is an automated verification tool used for OpenSM +testing. Its verification flows are described by list below. + +* Inventory File: Obtain and verify all port info, node info, link and path + records parameters. + +* Service Record: + - Register new service + - Register another service (with a lease period) + - Register another service (with service p_key set to zero) + - Get all services by name + - Delete the first service + - Delete the third service + - Added bad flows of get/delete non valid service + - Add / Get same service with different data + - Add / Get / Delete by different component mask values (services + by Name & Key / Name & Data / Name & Id / Id only ) + +* Multicast Member Record: + - Query of existing Groups (IPoIB) + - BAD Join with insufficient comp mask (o15.0.1.3) + - Create given MGID=0 (o15.0.1.4) + - Create given MGID=0xFF12A01C,FE800000,00000000,12345678 (o15.0.1.4) + - Create BAD MGID=0xFA. (o15.0.1.6) + - Create BAD MGID=0xFF12A01B w/ link-local not set (o15.0.1.6) + - New MGID with invalid join state (o15.0.1.9) + - Retry of existing MGID - See JoinState update (o15.0.1.11) + - BAD RATE when connecting to existing MGID (o15.0.1.13) + - Partial JoinState delete request - removing FullMember (o15.0.1.14) + - Full Delete of a group (o15.0.1.14) + - Verify Delete by trying to Join deleted group (o15.0.1.14) + - BAD Delete of IPoIB membership (no prev join) (o15.0.1.15) + +* GUIDInfo Record: + - All GUIDInfoRecords in subnet are obtained + +* MultiPathRecord: + - Perform some compliant and noncompliant MultiPathRecord requests + - Validation is via status in responses and IB analyzer + +* PKeyTableRecord: + - Perform some compliant and noncompliant PKeyTableRecord queries + - Validation is via status in responses and IB analyzer + +* LinearForwardingTableRecord: + - Perform some compliant and noncompliant LinearForwardingTableRecord queries + - Validation is via status in responses and IB analyzer + +* Event Forwarding: Register for trap forwarding using reports + - Send a trap and wait for report + - Unregister non-existing + +* Trap 64/65 Flow: Register to Trap 64-65, create traps (by + disconnecting/connecting ports) and wait for report, then unregister. + +* Stress Test: send PortInfoRecord queries, both single and RMPP and + check for the rate of responses as well as their validity. + + +5.2 IB Management Simulator OpenSM Test Flows: + +The simulator provides ability to simulate the SM handling of virtual +topologies that are not limited to actual lab equipment availability. +OpenSM was simulated to bring up clusters of up to 10,000 nodes. Daily +regressions use smaller (16 and 128 nodes clusters). + +The following test flows are run on the IB management simulator: + +* Stability: + Up to 12 links from the fabric are randomly selected to drop packets + at drop rates up to 90%. The SM is required to succeed in bringing the + fabric up. The resulting routing is verified to be correct as well. + +* LID Manager: + Using LMC = 2 the fabric is initialized with LIDs. Faults such as + zero LID, Duplicated LID, non-aligned (to LMC) LIDs are + randomly assigned to various nodes and other errors are randomly + output to the guid2lid cache file. The SM sweep is run 5 times and + after each iteration a complete verification is made to ensure that all + LIDs that could possibly be maintained are kept, as well as that all nodes + were assigned a legal LID range. + +* Multicast Routing: + Nodes randomly join the 0xc000 group and eventually the + resulting routing is verified for completeness and adherence to + Up/Down routing rules. + +* osmtest: + The complete osmtest flow as described in the previous table is run on + the simulated fabrics. + +* Stress Test: + This flow merges fabric, LID and stability issues with continuous + PathRecord, ServiceRecord and Multicast Join/Leave activity to + stress the SM/SA during continuous sweeps. InformInfo Set/Delete/Get + were added to the test such both existing and non existing nodes + perform them in random order. + +5.3 OpenSM Regression + +Using a back-to-back or single switch connection, the following set of +tests is run nightly on the stacks described in table 2. The included +tests are: + +* Stress Testing: Flood the SA with queries from multiple channel + adapters to check the robustness of the entire stack up to the SA. + +* Dynamic Changes: Dynamic Topology changes, through randomly + dropping SMP packets, used to test OpenSM adaptation to an unstable + network & verify DB correctness. + +* Trap Injection: This flow injects traps to the SM and verifies that it + handles them gracefully. + +* SA Query Test: This test exhaustively checks the SA responses to all + possible single component mask. To do that the test examines the + entire set of records the SA can provide, classifies them by their + field values and then selects every field (using component mask and a + value) and verifies that the response matches the expected set of records. + A random selection using multiple component mask bits is also performed. + +5.4 Cluster testing: + +Cluster testing is usually run before a distribution release. It +involves real hardware setups of 16 to 32 nodes (or more if a beta site +is available). Each test is validated by running all-to-all ping through the IB +interface. The test procedure includes: + +* Cluster bringup + +* Hand-off between 2 or 3 SM's while performing: + - Node reboots + - Switch power cycles (disconnecting the SM's) + +* Unresponsive port detection and recovery + +* osmtest from multiple nodes + +* Trap injection and recovery + + +6 Qualification +---------------- + +Table 2 - Qualified IB Stacks +============================= + +Stack | Version +-----------------------------------------|-------------------------- +OFED | 1.1 +OFED | 1.0 +OpenIB Gen2 (IBG2 distribution) | 1.0 +OpenIB Gen1 (IBGD distribution) | 1.8.0 +VAPI (Mellanox InfiniBand HCA Driver) | 3.2 and later + +Table 3 - Qualified Devices and Corresponding Firmware +====================================================== + +Mellanox +Device | FW versions +--------|----------------------------------------------------------- +MT43132 | InfiniScale - fw-43132 5.2.0 (and later) +MT47396 | InfiniScale III - fw-47396 0.5.0 (and later) +MT23108 | InfiniHost - fw-23108 3.3.2 (and later) +MT25204 | InfiniHost III Lx - fw-25204 1.0.1i (and later) +MT25208 | InfiniHost III Ex (InfiniHost Mode) - fw-25208 4.6.2 (and later) +MT25208 | InfiniHost III Ex (MemFree Mode) - fw-25218 5.0.1 (and later) + +QLogic/PathScale +Device | Note +--------|----------------------------------------------------------- +iPath | QHT6040 (PathScale InfiniPath HT-460) +iPath | QHT6140 (PathScale InfiniPath HT-465) +iPath | QLE6140 (PathScale InfiniPath PE-880) + +Note: OpenSM does not run on an IBM Galaxy (eHCA) as it does not expose +QP0 and QP1. However, it does support it as a device on the subnet. + diff --git a/branches/WOF2-1/ulp/opensm/user/doc/qos-config.txt b/branches/WOF2-1/ulp/opensm/user/doc/qos-config.txt new file mode 100644 index 00000000..c90e6f7b --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/doc/qos-config.txt @@ -0,0 +1,45 @@ +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 - High priority VL Arbitration table (IBA 7.6.9) template + qos_vlarb_high - Low 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-1/ulp/opensm/user/ibtrapgen/Makefile b/branches/WOF2-1/ulp/opensm/user/ibtrapgen/Makefile new file mode 100644 index 00000000..9c985f57 --- /dev/null +++ b/branches/WOF2-1/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 Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/branches/WOF2-1/ulp/opensm/user/ibtrapgen/SOURCES b/branches/WOF2-1/ulp/opensm/user/ibtrapgen/SOURCES new file mode 100644 index 00000000..c58e0c79 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/ibtrapgen/SOURCES @@ -0,0 +1,64 @@ +!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 + +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 +OVR_DIR=..\addon + + +SOURCES=\ + main.c \ + ibtrapgen.c + + + +OSM_HOME=.. + +TARGETLIBS=\ +!if $(FREEBUILD) + $(LIBPATH)\*\ibal.lib \ + $(LIBPATH)\*\complib.lib \ + $(TARGETPATH)\*\osmv_ibal.lib \ + $(TARGETPATH)\*\opensm_ibal.lib +!else + $(LIBPATH)\*\ibald.lib \ + $(LIBPATH)\*\complibd.lib \ + $(TARGETPATH)\*\osmv_ibald.lib \ + $(TARGETPATH)\*\opensm_ibald.lib +!endif + +#DO NOT TOUCH the order of search path , until ib_types.h merging process will be done +INCLUDES= \ + $(OSM_HOME)\include; \ + $(OSM_HOME); \ + $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; + +# Could be any special flag needed for this project +USER_C_FLAGS=$(USER_C_FLAGS) /MD +#Add preproccessor definitions +C_DEFINES=$(C_DEFINES) -DWIN32 -D__WIN__ -D__i386__ -Dinline=__inline -DMT_LITTLE_ENDIAN -DOSM_VENDOR_INTF_AL +!if !$(FREEBUILD) +#C_DEFINES=$(C_DEFINES) -D_DEBUG -DDEBUG -DDBG +C_DEFINES=$(C_DEFINES) +!endif + +LINKER_FLAGS= $(LINKER_FLAGS) +MSC_WARNING_LEVEL= /W3 + diff --git a/branches/WOF2-1/ulp/opensm/user/ibtrapgen/ibtrapgen.c b/branches/WOF2-1/ulp/opensm/user/ibtrapgen/ibtrapgen.c new file mode 100644 index 00000000..bd378821 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/ibtrapgen/ibtrapgen.c @@ -0,0 +1,442 @@ +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 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, p_ibtrapgen->p_log ); + 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, __ibtrapgen_rcv_callback ); + + CL_ASSERT( p_madw ); + + osm_log( p_ibtrapgen->p_log, OSM_LOG_VERBOSE, + "__ibtrapgen_rcv_callback: Got callback\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, __ibtrapgen_send_err_callback ); + + 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, ibtrapgen_bind ); + + /* + * 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, ibtrapgen_run ); + + 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: + // sleep(3); + OSM_LOG_EXIT( p_log ); + return(status); +} diff --git a/branches/WOF2-1/ulp/opensm/user/ibtrapgen/ibtrapgen.h b/branches/WOF2-1/ulp/opensm/user/ibtrapgen/ibtrapgen.h new file mode 100644 index 00000000..6fe54862 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/opensm/user/ibtrapgen/main.c b/branches/WOF2-1/ulp/opensm/user/ibtrapgen/main.c new file mode 100644 index 00000000..f7f1de7d --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/opensm/user/include/complib/cl_byteswap.h b/branches/WOF2-1/ulp/opensm/user/include/complib/cl_byteswap.h new file mode 100644 index 00000000..2ba5a771 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/complib/cl_byteswap.h @@ -0,0 +1,547 @@ +/* + * 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 the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF 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 +*********/ +#undef cl_ntoh16 +#undef cl_hton16 +#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 +*********/ +#undef cl_ntoh32 +#undef cl_hton32 +#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 +*********/ +#undef cl_ntoh64 +#undef cl_hton64 +#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-1/ulp/opensm/user/include/complib/cl_dispatcher.h b/branches/WOF2-1/ulp/opensm/user/include/complib/cl_dispatcher.h new file mode 100644 index 00000000..123bd093 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/complib/cl_dispatcher.h @@ -0,0 +1,660 @@ +/* + * 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: + * Declaration of dispatcher abstraction. + * + * Environment: + * All + * + * $Revision: 1.4 $ + */ + +#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-1/ulp/opensm/user/include/complib/cl_event_wheel.h b/branches/WOF2-1/ulp/opensm/user/include/complib/cl_event_wheel.h new file mode 100644 index 00000000..129eadd6 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/complib/cl_event_wheel.h @@ -0,0 +1,493 @@ +/* + * 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: + * Declaration of event wheel abstraction. + * + * Environment: + * All + * + * $Revision: 1.4 $ + */ + +#ifndef _CL_EVENT_WHEEL_H_ +#define _CL_EVENT_WHEEL_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/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; + osm_log_t *p_log; +} 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. +* +* p_log +* Pointer to opensm log object. +* +* 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, + IN osm_log_t *p_log); + +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* p_log +* [in] Pointer to opensm log object to be used for logging +* +* 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 osm_log_t *p_log, + IN cl_spinlock_t *p_external_lock); + +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* p_log +* [in] Pointer to opensm log object to be used for logging +* +* 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-1/ulp/opensm/user/include/complib/cl_signal_osd.h b/branches/WOF2-1/ulp/opensm/user/include/complib/cl_signal_osd.h new file mode 100644 index 00000000..1b731560 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/complib/cl_signal_osd.h @@ -0,0 +1,127 @@ +/* + * 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$ + */ + +/* + * Abstract: + * Declaration of Signal Handler Registration + * + * Environment: + * All + * + * $Revision: 1.3 $ + */ + + +#ifndef _CL_SIG_HDL_H_ +#define _CL_SIG_HDL_H_ + +#include + +/****h* Component Library/Signal Handler +* NAME +* Signal Handler Registration +* +* DESCRIPTION +* The Signal Handler Registration allows to register a callback on the case of incoming signal +* +* SEE ALSO +*********/ +/* TODO : Required when calling signal function in windows*/ +typedef void (__cdecl *cl_sig_hdl)( + IN int sig); +/* Prototypes */ + +/****f* Component Library: Signal Handler/cl_reg_sig_hdl +* NAME +* cl_reg_sig_hdl +* +* DESCRIPTION +* Register the handler for the given signal +* +* SYNOPSIS +*/ + +static inline void +cl_reg_sig_hdl(int sig, cl_sig_hdl pfn_sig_hdl); + + + +/****f* Component Library: Signal Handler/cl_mask_sigint +* NAME +* cl_sig_mask_sigint +* +* DESCRIPTION +* Mask the kill signal +* +* SYNOPSIS +*/ + +static inline void +cl_sig_mask_sigint(void); + + + + +/****f* Component Library: Signal Handler/cl_reg_sig_hdl +* NAME +* cl_reg_sig_hdl +* +* DESCRIPTION +* Register the handler for the given signal +* +* SYNOPSIS +*/ +static inline void +cl_reg_sig_hdl(int sig, cl_sig_hdl pfn_sig_hdl) { + signal(sig,pfn_sig_hdl); + } +/* +*********/ + +/****f* Component Library: Signal Handler/cl_mask_sigint +* NAME +* cl_sig_mask_sigint +* +* DESCRIPTION +* Mask the kill signal +* +* SYNOPSIS +*/ +static inline void +cl_sig_mask_sigint(void) +{ + +} +/* +*********/ + +#endif /* _CL_SIG_HDL_H_ */ diff --git a/branches/WOF2-1/ulp/opensm/user/include/iba/ib_types.h b/branches/WOF2-1/ulp/opensm/user/include/iba/ib_types.h new file mode 100644 index 00000000..92d018b1 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/iba/ib_types.h @@ -0,0 +1,10684 @@ +/* + * 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 +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +#if defined( WIN32 ) || defined( _WIN64 ) + #if defined( EXPORT_AL_SYMBOLS ) + #define OSM_EXPORT __declspec(dllexport) + #else + #define OSM_EXPORT __declspec(dllimport) + #endif + #define OSM_API __stdcall + #define OSM_CDECL __cdecl +#else + #define OSM_EXPORT extern + #define OSM_API + #define OSM_CDECL + #define __ptr64 +#endif + + +#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) ; } + + + +/****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_PKEY_MAX_BLOCKS +* NAME +* IB_PKEY_MAX_BLOCKS +* +* DESCRIPTION +* Maximum number of PKEY blocks (14.2.5.7). +* +* SOURCE +*/ +#define IB_PKEY_MAX_BLOCKS 2048 +/*********/ + +/****d* IBA Base: Constants/IB_MCAST_MAX_BLOCK_ID +* NAME +* IB_MCAST_MAX_BLOCK_ID +* +* DESCRIPTION +* Maximum number of Multicast port mask blocks +* +* SOURCE +*/ +#define IB_MCAST_MAX_BLOCK_ID 511 +/*********/ + +/****d* IBA Base: Constants/IB_MCAST_BLOCK_ID_MASK_HO +* NAME +* IB_MCAST_BLOCK_ID_MASK_HO +* +* DESCRIPTION +* Mask (host order) to recover the Multicast block ID. +* +* SOURCE +*/ +#define IB_MCAST_BLOCK_ID_MASK_HO 0x000001FF +/*********/ + +/****d* IBA Base: Constants/IB_MCAST_BLOCK_SIZE +* NAME +* IB_MCAST_BLOCK_SIZE +* +* DESCRIPTION +* Number of port mask entries in a multicast forwarding table block. +* +* SOURCE +*/ +#define IB_MCAST_BLOCK_SIZE 32 +/*********/ + +/****d* IBA Base: Constants/IB_MCAST_MASK_SIZE +* NAME +* IB_MCAST_MASK_SIZE +* +* DESCRIPTION +* Number of port mask bits in each entry in the multicast forwarding table. +* +* SOURCE +*/ +#define IB_MCAST_MASK_SIZE 16 +/*********/ + +/****d* IBA Base: Constants/IB_MCAST_POSITION_MASK_HO +* NAME +* IB_MCAST_POSITION_MASK_HO +* +* DESCRIPTION +* Mask (host order) to recover the multicast block position. +* +* SOURCE +*/ +#define IB_MCAST_POSITION_MASK_HO 0xF0000000 +/*********/ + +/****d* IBA Base: Constants/IB_MCAST_POSITION_MAX +* NAME +* IB_MCAST_POSITION_MAX +* +* DESCRIPTION +* Maximum value for the multicast block position. +* +* SOURCE +*/ +#define IB_MCAST_POSITION_MAX 0xF +/*********/ + +/****d* IBA Base: Constants/IB_MCAST_POSITION_SHIFT +* NAME +* IB_MCAST_POSITION_SHIFT +* +* DESCRIPTION +* Shift value to normalize the multicast block position value. +* +* SOURCE +*/ +#define IB_MCAST_POSITION_SHIFT 28 +/*********/ + +/****d* IBA Base: Constants/IB_PKEY_ENTRIES_MAX +* NAME +* IB_PKEY_ENTRIES_MAX +* +* DESCRIPTION +* Maximum number of PKEY entries per port (14.2.5.7). +* +* SOURCE +*/ +#define IB_PKEY_ENTRIES_MAX (IB_PKEY_MAX_BLOCKS * IB_NUM_PKEY_ELEMENTS_IN_BLOCK) +/*********/ + +/****d* IBA Base: Constants/IB_PKEY_BASE_MASK +* NAME +* IB_PKEY_BASE_MASK +* +* DESCRIPTION +* Masks for the base P_Key value given a P_Key Entry. +* +* SOURCE +*/ +#define IB_PKEY_BASE_MASK (CL_HTON16(0x7FFF)) +/*********/ + +/****d* IBA Base: Constants/IB_PKEY_TYPE_MASK +* NAME +* IB_PKEY_TYPE_MASK +* +* DESCRIPTION +* Masks for the P_Key membership type given a P_Key Entry. +* +* SOURCE +*/ +#define IB_PKEY_TYPE_MASK (CL_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 +/**********/ + +/****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_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 OSM_API +ib_class_is_vendor_specific_low( + IN const uint8_t class_code ) +{ + return( (class_code >= IB_MCLASS_VENDOR_LOW_RANGE_MIN) && + (class_code <= IB_MCLASS_VENDOR_LOW_RANGE_MAX) ); +} +/* +* PARAMETERS +* class_code +* [in] The Management Datagram Class Code +* +* RETURN VALUE +* TRUE if the class is in the Low range of Vendor Specific MADs +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* IB_MCLASS_VENDOR_LOW_RANGE_MIN, IB_MCLASS_VENDOR_LOW_RANGE_MAX +*********/ + +/****f* IBA Base: Types/ib_class_is_vendor_specific_high +* NAME +* ib_class_is_vendor_specific_high +* +* DESCRIPTION +* Indicates if the Class Code if a vendor specific class from +* the high range +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_class_is_vendor_specific_high( + IN const uint8_t class_code ) +{ + return( (class_code >= IB_MCLASS_VENDOR_HIGH_RANGE_MIN) && + (class_code <= IB_MCLASS_VENDOR_HIGH_RANGE_MAX) ); +} +/* +* PARAMETERS +* class_code +* [in] The Management Datagram Class Code +* +* RETURN VALUE +* TRUE if the class is in the High range of Vendor Specific MADs +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* IB_MCLASS_VENDOR_HIGH_RANGE_MIN, IB_MCLASS_VENDOR_HIGH_RANGE_MAX +*********/ + + +/****f* IBA Base: Types/ib_class_is_vendor_specific +* NAME +* ib_class_is_vendor_specific +* +* DESCRIPTION +* Indicates if the Class Code if a vendor specific class +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_class_is_vendor_specific( + IN const uint8_t class_code ) +{ + return( ib_class_is_vendor_specific_low(class_code) || + ib_class_is_vendor_specific_high(class_code) ); +} +/* +* PARAMETERS +* class_code +* [in] The Management Datagram Class Code +* +* RETURN VALUE +* TRUE if the class is a Vendor Specific MAD +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* ib_class_is_vendor_specific_low, ib_class_is_vendor_specific_high +*********/ + +/****f* IBA Base: Types/ib_class_is_rmpp +* NAME +* ib_class_is_rmpp +* +* DESCRIPTION +* Indicates if the Class Code supports RMPP +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_class_is_rmpp( + IN const uint8_t class_code ) +{ + return( (class_code == IB_MCLASS_SUBN_ADM) || + (class_code == IB_MCLASS_DEV_MGMT) || + (class_code == IB_MCLASS_DEV_ADM) || + (class_code == IB_MCLASS_BIS) || + ib_class_is_vendor_specific_high( class_code ) ); +} +/* +* PARAMETERS +* class_code +* [in] The Management Datagram Class Code +* +* RETURN VALUE +* TRUE if the class supports RMPP +* FALSE otherwise. +* +* NOTES +* +*********/ + +/* + * MAD methods + */ + +/****d* IBA Base: Constants/IB_MAX_METHOD +* NAME +* IB_MAX_METHOD +* +* DESCRIPTION +* Total number of methods available to a class, not including the R-bit. +* +* SOURCE +*/ +#define IB_MAX_METHODS 128 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_RESP_MASK +* NAME +* IB_MAD_METHOD_RESP_MASK +* +* DESCRIPTION +* Response mask to extract 'R' bit from the method field. (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_RESP_MASK 0x80 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_GET +* NAME +* IB_MAD_METHOD_GET +* +* DESCRIPTION +* Get() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_GET 0x01 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_SET +* NAME +* IB_MAD_METHOD_SET +* +* DESCRIPTION +* Set() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_SET 0x02 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_GET_RESP +* NAME +* IB_MAD_METHOD_GET_RESP +* +* DESCRIPTION +* GetResp() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_GET_RESP 0x81 +/**********/ + +#define IB_MAD_METHOD_DELETE 0x15 + +/****d* IBA Base: Constants/IB_MAD_METHOD_GETTABLE +* NAME +* IB_MAD_METHOD_GETTABLE +* +* DESCRIPTION +* SubnAdmGetTable() Method (15.2.2) +* +* SOURCE +*/ +#define IB_MAD_METHOD_GETTABLE 0x12 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_GETTABLE_RESP +* NAME +* IB_MAD_METHOD_GETTABLE_RESP +* +* DESCRIPTION +* SubnAdmGetTableResp() Method (15.2.2) +* +* SOURCE +*/ +#define IB_MAD_METHOD_GETTABLE_RESP 0x92 + +/**********/ + +#define IB_MAD_METHOD_GETTRACETABLE 0x13 +#define IB_MAD_METHOD_GETMULTI 0x14 +#define IB_MAD_METHOD_GETMULTI_RESP 0x94 + + +/****d* IBA Base: Constants/IB_MAD_METHOD_SEND +* NAME +* IB_MAD_METHOD_SEND +* +* DESCRIPTION +* Send() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_SEND 0x03 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_TRAP +* NAME +* IB_MAD_METHOD_TRAP +* +* DESCRIPTION +* Trap() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_TRAP 0x05 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_REPORT +* NAME +* IB_MAD_METHOD_REPORT +* +* DESCRIPTION +* Report() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_REPORT 0x06 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_REPORT_RESP +* NAME +* IB_MAD_METHOD_REPORT_RESP +* +* DESCRIPTION +* ReportResp() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_REPORT_RESP 0x86 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_TRAP_REPRESS +* NAME +* IB_MAD_METHOD_TRAP_REPRESS +* +* DESCRIPTION +* TrapRepress() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_TRAP_REPRESS 0x07 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_STATUS_BUSY +* NAME +* IB_MAD_STATUS_BUSY +* +* DESCRIPTION +* Temporarily busy, MAD discarded (13.4.7) +* +* SOURCE +*/ +#define IB_MAD_STATUS_BUSY (CL_HTON16(0x0001)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_STATUS_REDIRECT +* NAME +* IB_MAD_STATUS_REDIRECT +* +* DESCRIPTION +* QP Redirection required (13.4.7) +* +* SOURCE +*/ +#define IB_MAD_STATUS_REDIRECT (CL_HTON16(0x0002)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_STATUS_UNSUP_CLASS_VER +* NAME +* IB_MAD_STATUS_UNSUP_CLASS_VER +* +* DESCRIPTION +* Unsupported class version (13.4.7) +* +* SOURCE +*/ +#define IB_MAD_STATUS_UNSUP_CLASS_VER (CL_HTON16(0x0004)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_STATUS_UNSUP_METHOD +* NAME +* IB_MAD_STATUS_UNSUP_METHOD +* +* DESCRIPTION +* Unsupported method (13.4.7) +* +* SOURCE +*/ +#define IB_MAD_STATUS_UNSUP_METHOD (CL_HTON16(0x0008)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_STATUS_UNSUP_METHOD_ATTR +* NAME +* IB_MAD_STATUS_UNSUP_METHOD_ATTR +* +* DESCRIPTION +* Unsupported method/attribute combination (13.4.7) +* +* SOURCE +*/ +#define IB_MAD_STATUS_UNSUP_METHOD_ATTR (CL_HTON16(0x000C)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_STATUS_INVALID_FIELD +* NAME +* IB_MAD_STATUS_INVALID_FIELD +* +* DESCRIPTION +* Attribute contains one or more invalid fields (13.4.7) +* +* SOURCE +*/ +#define IB_MAD_STATUS_INVALID_FIELD (CL_HTON16(0x001C)) +/**********/ + +#define IB_MAD_STATUS_CLASS_MASK (CL_HTON16(0xFF00)) + +#define IB_SA_MAD_STATUS_SUCCESS (CL_HTON16(0x0000)) +#define IB_SA_MAD_STATUS_NO_RESOURCES (CL_HTON16(0x0100)) +#define IB_SA_MAD_STATUS_REQ_INVALID (CL_HTON16(0x0200)) +#define IB_SA_MAD_STATUS_NO_RECORDS (CL_HTON16(0x0300)) +#define IB_SA_MAD_STATUS_TOO_MANY_RECORDS (CL_HTON16(0x0400)) +#define IB_SA_MAD_STATUS_INVALID_GID (CL_HTON16(0x0500)) +#define IB_SA_MAD_STATUS_INSUF_COMPS (CL_HTON16(0x0600)) + +#define IB_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 +* NodeDescription attribute (16.1.2) +* +* 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 +* NodeInfo attribute (16.1.2) +* +* 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 +* SwitchInfo attribute (16.1.2) +* +* 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_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_NTOH16(0x003B)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_INFORM_INFO_RECORD +* NAME +* IB_MAD_ATTR_INFORM_INFO_RECORD +* +* DESCRIPTION +* InformInfo Record attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_INFORM_INFO_RECORD (CL_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_NTOH16(0x003B)) +/**********/ + +/****d* IBA Base: Constants/IB_NODE_TYPE_CA +* NAME +* IB_NODE_TYPE_CA +* +* DESCRIPTION +* Encoded generic node type used in MAD attributes (13.4.8.2) +* +* SOURCE +*/ +#define IB_NODE_TYPE_CA 0x01 +/**********/ + +/****d* IBA Base: Constants/IB_NODE_TYPE_SWITCH +* NAME +* IB_NODE_TYPE_SWITCH +* +* DESCRIPTION +* Encoded generic node type used in MAD attributes (13.4.8.2) +* +* SOURCE +*/ +#define IB_NODE_TYPE_SWITCH 0x02 +/**********/ + +/****d* IBA Base: Constants/IB_NODE_TYPE_ROUTER +* NAME +* IB_NODE_TYPE_ROUTER +* +* DESCRIPTION +* Encoded generic node type used in MAD attributes (13.4.8.2) +* +* SOURCE +*/ +#define IB_NODE_TYPE_ROUTER 0x03 +/**********/ + +/****d* IBA Base: Constants/IB_NOTICE_NODE_TYPE_CA +* 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)) +/**********/ + +/****d* IBA Base: Constants/IB_NOTICE_NODE_TYPE_SWITCH +* 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)) +/**********/ + +/****d* IBA Base: Constants/IB_NOTICE_NODE_TYPE_ROUTER +* 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)) +/**********/ + +/****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 +*/ +static inline const char* OSM_API +ib_get_node_type_str( + IN uint32_t node_type ) +{ + if( node_type >= IB_NOTICE_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_port_state_str[] = +{ + "No State Change (NOP)", + "DOWN", + "INIT", + "ARMED", + "ACTIVE", + "ACTDEFER", + "UNKNOWN" +}; + +/****f* IBA Base: Types/ib_get_port_state_str +* NAME +* ib_get_port_state_str +* +* DESCRIPTION +* Returns a string for the specified port state. +* +* SYNOPSIS +*/ +static inline const char* OSM_API +ib_get_port_state_str( + IN uint8_t port_state ) +{ + if( port_state > IB_LINK_ACTIVE ) + port_state = IB_LINK_ACTIVE + 1; + return( __ib_port_state_str[port_state] ); +} +/* +* PARAMETERS +* node_type +* [in] Encoded port state as returned in the PortInfo attribute. + +* RETURN VALUES +* Pointer to the port state string. +* +* NOTES +* +* SEE ALSO +* ib_port_info_t +*********/ + +/****f* IBA Base: Types/ib_get_port_state_from_str +* NAME +* ib_get_port_state_from_str +* +* DESCRIPTION +* Returns a string for the specified port state. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_get_port_state_from_str( + IN char* p_port_state_str ) +{ + if( !strncmp(p_port_state_str,"No State Change (NOP)", 12) ) + return(0); + else if( !strncmp(p_port_state_str, "DOWN", 4) ) + return(1); + else if( !strncmp(p_port_state_str, "INIT", 4) ) + return(2); + else if( !strncmp(p_port_state_str, "ARMED" , 5) ) + return(3); + else if( !strncmp(p_port_state_str, "ACTIVE", 6) ) + return(4); + else if( !strncmp(p_port_state_str, "ACTDEFER", 8) ) + return(5); + return(6); +} +/* +* PARAMETERS +* p_port_state_str +* [in] A string matching one returned by ib_get_port_state_str +* +* RETURN VALUES +* The appropriate code. +* +* NOTES +* +* SEE ALSO +* ib_port_info_t +*********/ + +/****d* IBA Base: Constants/Join States +* NAME +* Join States +* +* DESCRIPTION +* Defines the join state flags for multicast group management. +* +* SOURCE +*/ +#define IB_JOIN_STATE_FULL 1 +#define IB_JOIN_STATE_NON 2 +#define IB_JOIN_STATE_SEND_ONLY 4 +/**********/ + +/****f* IBA Base: Types/ib_pkey_get_base +* NAME +* ib_pkey_get_base +* +* DESCRIPTION +* Returns the base P_Key value with the membership bit stripped. +* +* SYNOPSIS +*/ +static inline ib_net16_t OSM_API +ib_pkey_get_base( + IN const ib_net16_t pkey ) +{ + return( (ib_net16_t)(pkey & IB_PKEY_BASE_MASK) ); +} +/* +* PARAMETERS +* pkey +* [in] P_Key value +* +* RETURN VALUE +* Returns the base P_Key value with the membership bit stripped. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_pkey_is_full_member +* NAME +* ib_pkey_is_full_member +* +* DESCRIPTION +* Indicates if the port is a full member of the parition. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_pkey_is_full_member( + IN const ib_net16_t pkey ) +{ + return( (pkey & IB_PKEY_TYPE_MASK) == IB_PKEY_TYPE_MASK ); +} +/* +* PARAMETERS +* pkey +* [in] P_Key value +* +* RETURN VALUE +* TRUE if the port is a full member of the partition. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* ib_pkey_get_base, ib_net16_t +*********/ + +/****f* IBA Base: Types/ib_pkey_is_invalid +* NAME +* ib_pkey_is_invalid +* +* DESCRIPTION +* Returns TRUE if the given P_Key is an invalid P_Key +* C10-116: the CI shall regard a P_Key as invalid if its low-order +* 15 bits are all zero... +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_pkey_is_invalid( + IN const ib_net16_t pkey ) +{ + if (ib_pkey_get_base(pkey) == 0x0000) + return TRUE; + + return FALSE; +} +/* +* PARAMETERS +* pkey +* [in] P_Key value +* +* RETURN VALUE +* Returns the base P_Key value with the membership bit stripped. +* +* NOTES +* +* SEE ALSO +*********/ + +/****d* IBA Base: Types/ib_gid_t +* NAME +* ib_gid_t +* +* DESCRIPTION +* +* SYNOPSIS +*/ +#include +typedef union _ib_gid +{ + uint8_t raw[16]; + struct _ib_gid_unicast + { + ib_gid_prefix_t prefix; + ib_net64_t interface_id; + + } PACK_SUFFIX unicast; + + struct _ib_gid_multicast + { + uint8_t header[2]; + uint8_t raw_group_id[14]; + + } PACK_SUFFIX multicast; + +} PACK_SUFFIX ib_gid_t; +#include +/* +* FIELDS +* raw +* GID represented as an unformated byte array. +* +* unicast +* Typical unicast representation with subnet prefix and +* port GUID. +* +* multicast +* Representation for multicast use. +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_gid_is_multicast +* NAME +* ib_gid_is_multicast +* +* DESCRIPTION +* Returns a boolean indicating whether a GID is a multicast GID. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_gid_is_multicast( + IN const ib_gid_t* p_gid ) +{ + return( p_gid->raw[0] == 0xFF ); +} + +/****f* IBA Base: Types/ib_gid_get_scope +* NAME +* ib_gid_get_scope +* +* DESCRIPTION +* Returns scope of (assumed) multicast GID. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_mgid_get_scope( + IN const ib_gid_t* p_gid ) +{ + return( p_gid->raw[1] & 0x0F ); +} + +/****f* IBA Base: Types/ib_gid_set_scope +* NAME +* ib_gid_set_scope +* +* DESCRIPTION +* Sets scope of (assumed) multicast GID. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_mgid_set_scope( + IN ib_gid_t* const p_gid, + IN const uint8_t scope ) +{ + p_gid->raw[1] &= 0xF0; + p_gid->raw[1] |= scope & 0x0F; +} + +/****f* IBA Base: Types/ib_gid_set_default +* NAME +* ib_gid_set_default +* +* DESCRIPTION +* Sets a GID to the default value. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_gid_set_default( + IN ib_gid_t* const p_gid, + IN const ib_net64_t interface_id ) +{ + p_gid->unicast.prefix = IB_DEFAULT_SUBNET_PREFIX; + p_gid->unicast.interface_id = interface_id; +} +/* +* PARAMETERS +* p_gid +* [in] Pointer to the GID object. +* +* interface_id +* [in] Manufacturer assigned EUI64 value of a port. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* ib_gid_t +*********/ + +/****f* IBA Base: Types/ib_gid_get_subnet_prefix +* NAME +* ib_gid_get_subnet_prefix +* +* DESCRIPTION +* Gets the subnet prefix from a GID. +* +* SYNOPSIS +*/ +static inline ib_net64_t OSM_API +ib_gid_get_subnet_prefix( + IN const ib_gid_t* const p_gid ) +{ + return( p_gid->unicast.prefix ); +} +/* +* PARAMETERS +* p_gid +* [in] Pointer to the GID object. +* +* RETURN VALUES +* 64-bit subnet prefix value. +* +* NOTES +* +* SEE ALSO +* ib_gid_t +*********/ + +/****f* IBA Base: Types/ib_gid_is_link_local +* NAME +* ib_gid_is_link_local +* +* DESCRIPTION +* Returns TRUE if the unicast GID scoping indicates link local, +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_gid_is_link_local( + IN const ib_gid_t* const p_gid ) +{ + return( ( ib_gid_get_subnet_prefix( p_gid ) & + CL_HTON64( 0xFFC0000000000000ULL ) ) == IB_DEFAULT_SUBNET_PREFIX ); +} +/* +* PARAMETERS +* p_gid +* [in] Pointer to the GID object. +* +* RETURN VALUES +* Returns TRUE if the unicast GID scoping indicates link local, +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* ib_gid_t +*********/ + +/****f* IBA Base: Types/ib_gid_is_site_local +* NAME +* ib_gid_is_site_local +* +* DESCRIPTION +* Returns TRUE if the unicast GID scoping indicates site local, +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_gid_is_site_local( + IN const ib_gid_t* const p_gid ) +{ + return( ( ib_gid_get_subnet_prefix( p_gid ) & + CL_HTON64( 0xFFFFFFFFFFFF0000ULL ) ) == CL_HTON64( 0xFEC0000000000000ULL ) ); +} +/* +* PARAMETERS +* p_gid +* [in] Pointer to the GID object. +* +* RETURN VALUES +* Returns TRUE if the unicast GID scoping indicates site local, +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* ib_gid_t +*********/ + +/****f* IBA Base: Types/ib_gid_get_guid +* NAME +* ib_gid_get_guid +* +* DESCRIPTION +* Gets the guid from a GID. +* +* SYNOPSIS +*/ +static inline ib_net64_t OSM_API +ib_gid_get_guid( + IN const ib_gid_t* const p_gid ) +{ + return( p_gid->unicast.interface_id ); +} +/* +* PARAMETERS +* p_gid +* [in] Pointer to the GID object. +* +* RETURN VALUES +* 64-bit GUID value. +* +* NOTES +* +* SEE ALSO +* ib_gid_t +*********/ + +/****s* IBA Base: Types/ib_path_rec_t +* NAME +* ib_path_rec_t +* +* DESCRIPTION +* Path records encapsulate the properties of a given +* route between two end-points on a subnet. +* +* SYNOPSIS +*/ +#include +typedef struct _ib_path_rec +{ + ib_net64_t service_id; + ib_gid_t dgid; + ib_gid_t sgid; + ib_net16_t dlid; + ib_net16_t slid; + ib_net32_t hop_flow_raw; + uint8_t tclass; + uint8_t num_path; + ib_net16_t pkey; + ib_net16_t qos_class_sl; + uint8_t mtu; + uint8_t rate; + uint8_t pkt_life; + uint8_t preference; + uint8_t resv2[6]; + +} PACK_SUFFIX ib_path_rec_t; +#include +/* +* FIELDS +* 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 +* 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. +* +* 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. +* +* resv2 +* Reserved bytes. +* SEE ALSO +*********/ + +/* Path Record Component Masks */ +#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_RESV1 (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_RESV1 (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_RESV2 (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_RESV4 (CL_HTON64(((uint64_t)1)<<21)) + +/* SMInfo Record Component Masks */ +#define IB_SMIR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_SMIR_COMPMASK_RESV0 (CL_HTON64(((uint64_t)1)<<1)) +#define IB_SMIR_COMPMASK_GUID (CL_HTON64(((uint64_t)1)<<2)) +#define IB_SMIR_COMPMASK_SMKEY (CL_HTON64(((uint64_t)1)<<3)) +#define IB_SMIR_COMPMASK_ACTCOUNT (CL_HTON64(((uint64_t)1)<<4)) +#define IB_SMIR_COMPMASK_PRIORITY (CL_HTON64(((uint64_t)1)<<5)) +#define IB_SMIR_COMPMASK_SMSTATE (CL_HTON64(((uint64_t)1)<<6)) + +/* InformInfo Record Component Masks */ +#define IB_IIR_COMPMASK_SUBSCRIBERGID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_IIR_COMPMASK_ENUM (CL_HTON64(((uint64_t)1)<<1)) +#define IB_IIR_COMPMASK_RESV0 (CL_HTON64(((uint64_t)1)<<2)) +#define IB_IIR_COMPMASK_GID (CL_HTON64(((uint64_t)1)<<3)) +#define IB_IIR_COMPMASK_LIDRANGEBEGIN (CL_HTON64(((uint64_t)1)<<4)) +#define IB_IIR_COMPMASK_LIDRANGEEND (CL_HTON64(((uint64_t)1)<<5)) +#define IB_IIR_COMPMASK_RESV1 (CL_HTON64(((uint64_t)1)<<6)) +#define IB_IIR_COMPMASK_ISGENERIC (CL_HTON64(((uint64_t)1)<<7)) +#define IB_IIR_COMPMASK_SUBSCRIBE (CL_HTON64(((uint64_t)1)<<8)) +#define IB_IIR_COMPMASK_TYPE (CL_HTON64(((uint64_t)1)<<9)) +#define IB_IIR_COMPMASK_TRAPNUMB (CL_HTON64(((uint64_t)1)<<10)) +#define IB_IIR_COMPMASK_DEVICEID (CL_HTON64(((uint64_t)1)<<10)) +#define IB_IIR_COMPMASK_QPN (CL_HTON64(((uint64_t)1)<<11)) +#define IB_IIR_COMPMASK_RESV2 (CL_HTON64(((uint64_t)1)<<12)) +#define IB_IIR_COMPMASK_RESPTIME (CL_HTON64(((uint64_t)1)<<13)) +#define IB_IIR_COMPMASK_RESV3 (CL_HTON64(((uint64_t)1)<<14)) +#define IB_IIR_COMPMASK_PRODTYPE (CL_HTON64(((uint64_t)1)<<15)) +#define IB_IIR_COMPMASK_VENDID (CL_HTON64(((uint64_t)1)<<15)) + +/****f* IBA Base: Types/ib_path_rec_init_local +* NAME +* ib_path_rec_init_local +* +* DESCRIPTION +* Initializes a subnet local path record. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_path_rec_init_local( + IN ib_path_rec_t* const p_rec, + IN ib_gid_t* const p_dgid, + IN ib_gid_t* const p_sgid, + IN ib_net16_t dlid, + IN ib_net16_t slid, + IN uint8_t num_path, + IN ib_net16_t pkey, + IN uint8_t sl, + IN uint8_t mtu_selector, + IN uint8_t mtu, + IN uint8_t rate_selector, + IN uint8_t rate, + IN uint8_t pkt_life_selector, + IN uint8_t pkt_life, + IN uint8_t preference ) +{ + p_rec->dgid = *p_dgid; + p_rec->sgid = *p_sgid; + p_rec->dlid = dlid; + p_rec->slid = slid; + p_rec->num_path = num_path; + p_rec->pkey = pkey; + /* Lower 4 bits of path rec's SL are reserved. */ + p_rec->qos_class_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 = 0; + p_rec->tclass = 0; + + *((uint64_t*)p_rec->service_id) = 0; + *((uint32_t*)p_rec->resv2) = 0; + *((uint16_t*)p_rec->resv2 + 2) = 0; +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* dgid +* [in] GID of destination port. +* +* sgid +* [in] GID of source port. +* +* dlid +* [in] LID of destination port. +* +* slid +* [in] LID of source port. +* +* num_path +* [in] Reversible path - 1 bit to say if path is reversible. +* num_path [6:0] In queries, maximum number of paths to return. +* In responses, undefined. +* +* pkey +* [in] Partition key (P_Key) to use on this path. +* +* sl +* [in] Service level to use on this path. Lower 4-bits are valid. +* +* mtu_selector +* [in] Encoded MTU selector value to use on this path +* +* mtu +* [in] Encoded MTU to use on this path +* +* rate_selector +* [in] Encoded rate selector value to use on this path. +* +* rate +* [in] Encoded rate to use on this path. +* +* pkt_life_selector +* [in] Encoded Packet selector value lifetime for this path. +* +* pkt_life +* [in] Encoded Packet lifetime for this path. +* +* preference +* [in] Indicates the relative merit of this path versus other path +* records returned from the SA. Lower numbers are better. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* ib_gid_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_num_path +* NAME +* ib_path_rec_num_path +* +* DESCRIPTION +* Get max number of paths to return. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_num_path( + IN const ib_path_rec_t* const p_rec ) +{ + return( p_rec->num_path &0x7F ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Maximum number of paths to return for each unique SGID_DGID combination. +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_sl +* NAME +* ib_path_rec_sl +* +* DESCRIPTION +* Get path service level. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_sl( + IN const ib_path_rec_t* const p_rec ) +{ + return( (uint8_t)((cl_ntoh16( p_rec->qos_class_sl )) & 0xF) ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* SL. +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_set_qos_class +* NAME +* ib_path_rec_set_qos_class +* +* DESCRIPTION +* Set path QoS class. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_path_rec_set_qos_class(IN ib_path_rec_t * const p_rec, + IN const uint16_t qos_class) +{ + p_rec->qos_class_sl = + (p_rec->qos_class_sl & CL_HTON16(IB_PATH_REC_SL_MASK)) | + cl_hton16(qos_class << 4); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* qos_class +* [in] QoS class to set. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_qos_class +* NAME +* ib_path_rec_qos_class +* +* DESCRIPTION +* Get QoS class. +* +* SYNOPSIS +*/ +static inline uint16_t OSM_API +ib_path_rec_qos_class(IN const ib_path_rec_t * const p_rec) +{ + return (cl_ntoh16(p_rec->qos_class_sl) >> 4); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* QoS class of the path record. +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + + +/****f* IBA Base: Types/ib_path_rec_mtu +* NAME +* ib_path_rec_mtu +* +* DESCRIPTION +* Get encoded path MTU. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_mtu( + IN const ib_path_rec_t* const p_rec ) +{ + return( (uint8_t)(p_rec->mtu & IB_PATH_REC_BASE_MASK) ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Encoded path MTU. +* 1: 256 +* 2: 512 +* 3: 1024 +* 4: 2048 +* 5: 4096 +* others: reserved +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_mtu_sel +* NAME +* ib_path_rec_mtu_sel +* +* DESCRIPTION +* Get encoded path MTU selector. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_mtu_sel( + IN const ib_path_rec_t* const p_rec ) +{ + return( (uint8_t)((p_rec->mtu & IB_PATH_REC_SELECTOR_MASK) >> 6) ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Encoded path MTU selector value (for queries). +* 0: greater than MTU specified +* 1: less than MTU specified +* 2: exactly the MTU specified +* 3: largest MTU available +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_rate +* NAME +* ib_path_rec_rate +* +* DESCRIPTION +* Get encoded path rate. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_rate( + IN const ib_path_rec_t* const p_rec ) +{ + return( (uint8_t)(p_rec->rate & IB_PATH_REC_BASE_MASK) ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Encoded path rate. +* 2: 2.5 Gb/sec. +* 3: 10 Gb/sec. +* 4: 30 Gb/sec. +* 5: 5 Gb/sec. +* 6: 20 Gb/sec. +* 7: 40 Gb/sec. +* 8: 60 Gb/sec. +* 9: 80 Gb/sec. +* 10: 120 Gb/sec. +* others: reserved +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_rate_sel +* NAME +* ib_path_rec_rate_sel +* +* DESCRIPTION +* Get encoded path rate selector. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_rate_sel( + IN const ib_path_rec_t* const p_rec ) +{ + return( (uint8_t)((p_rec->rate & IB_PATH_REC_SELECTOR_MASK) >> 6) ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Encoded path rate selector value (for queries). +* 0: greater than rate specified +* 1: less than rate specified +* 2: exactly the rate specified +* 3: largest rate available +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_pkt_life +* NAME +* ib_path_rec_pkt_life +* +* DESCRIPTION +* Get encoded path pkt_life. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_pkt_life( + IN const ib_path_rec_t* const p_rec ) +{ + return( (uint8_t)(p_rec->pkt_life & IB_PATH_REC_BASE_MASK) ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Encoded path pkt_life = 4.096 µ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 +*/ +static inline uint8_t OSM_API +ib_path_rec_pkt_life_sel( + IN const ib_path_rec_t* const p_rec ) +{ + return( (uint8_t)((p_rec->pkt_life & IB_PATH_REC_SELECTOR_MASK) >> 6 )); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Encoded path pkt_lifetime selector value (for queries). +* 0: greater than rate specified +* 1: less than rate specified +* 2: exactly the rate specified +* 3: smallest packet lifetime available +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_flow_lbl +* NAME +* ib_path_rec_flow_lbl +* +* DESCRIPTION +* Get flow label. +* +* SYNOPSIS +*/ +static inline uint32_t OSM_API +ib_path_rec_flow_lbl( + IN const ib_path_rec_t* const p_rec ) +{ + return( ((cl_ntoh32(p_rec->hop_flow_raw) >> 8) & 0x000FFFFF) ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Flow label of the path record. +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_hop_limit +* NAME +* ib_path_rec_hop_limit +* +* DESCRIPTION +* Get hop limit. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_hop_limit( + IN const ib_path_rec_t* const p_rec ) +{ + return( (uint8_t)(p_rec->hop_flow_raw & 0x000000FF ) ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Hop limit of the path record. +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****s* IBA Base: Constants/IB_CLASS_CAP_TRAP +* NAME +* IB_CLASS_CAP_TRAP +* +* DESCRIPTION +* ClassPortInfo CapabilityMask bits. This bit will be set +* if the class supports Trap() MADs (13.4.8.1). +* +* SEE ALSO +* ib_class_port_info_t, IB_CLASS_CAP_GETSET +* +* SOURCE +*/ +#define IB_CLASS_CAP_TRAP 0x0001 +/*********/ + +/****s* IBA Base: Constants/IB_CLASS_CAP_GETSET +* NAME +* IB_CLASS_CAP_GETSET +* +* DESCRIPTION +* ClassPortInfo CapabilityMask bits. This bit will be set +* if the class supports Get(Notice) and Set(Notice) MADs (13.4.8.1). +* +* SEE ALSO +* ib_class_port_info_t, IB_CLASS_CAP_TRAP +* +* SOURCE +*/ +#define IB_CLASS_CAP_GETSET 0x0002 +/*********/ + +/****s* IBA Base: Constants/IB_CLASS_RESP_TIME_MASK +* NAME +* IB_CLASS_RESP_TIME_MASK +* +* DESCRIPTION +* Mask bits to extract the reponse time value from the +* resp_time_val field of ib_class_port_info_t. +* +* SEE ALSO +* ib_class_port_info_t +* +* SOURCE +*/ +#define IB_CLASS_RESP_TIME_MASK 0x1F +/*********/ +/****s* IBA Base: Types/ib_class_port_info_t +* NAME +* ib_class_port_info_t +* +* DESCRIPTION +* IBA defined ClassPortInfo attribute (13.4.8.1) +* route between two end-points on a subnet. +* +* SYNOPSIS +*/ +#include +typedef struct _ib_class_port_info +{ + uint8_t base_ver; + uint8_t class_ver; + ib_net16_t cap_mask; + ib_net32_t cap_mask2_resp_time; + ib_gid_t redir_gid; + ib_net32_t redir_tc_sl_fl; + ib_net16_t redir_lid; + ib_net16_t redir_pkey; + ib_net32_t redir_qp; + ib_net32_t redir_qkey; + ib_gid_t trap_gid; + ib_net32_t trap_tc_sl_fl; + ib_net16_t trap_lid; + ib_net16_t trap_pkey; + ib_net32_t trap_hop_qp; + ib_net32_t trap_qkey; + +} PACK_SUFFIX ib_class_port_info_t; +#include +/* +* FIELDS +* base_ver +* Maximum supported MAD Base Version. +* +* class_ver +* Maximum supported management class version. +* +* cap_mask +* Supported capabilities of this management class. +* +* cap_mask2_resp_time +* Maximum expected response time and additional +* supported capabilities of this management class. +* +* redr_gid +* GID to use for redirection, or zero +* +* recdir_tc_sl_fl +* Traffic class, service level and flow label the requester +* should use if the service is redirected. +* +* redir_lid +* LID used for redirection, or zero +* +* redir_pkey +* P_Key used for redirection +* +* redir_qp +* QP number used for redirection +* +* redir_qkey +* Q_Key associated with the redirected QP. This shall be the +* well known Q_Key value. +* +* trap_gid +* GID value used for trap messages from this service. +* +* trap_tc_sl_fl +* Traffic class, service level and flow label used for +* trap messages originated by this service. +* +* trap_lid +* LID used for trap messages, or zero +* +* trap_pkey +* P_Key used for trap messages +* +* trap_hop_qp +* Hop limit (upper 8 bits) and QP number used for trap messages +* +* trap_qkey +* Q_Key associated with the trap messages QP. +* +* SEE ALSO +* IB_CLASS_CAP_GETSET, IB_CLASS_CAP_TRAP +* +*********/ + +/****f* IBA Base: Types/ib_class_set_resp_time_val +* NAME +* ib_class_set_resp_time_val +* +* DESCRIPTION +* Set maximum expected response time. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_class_set_resp_time_val(IN ib_class_port_info_t * const p_cpi, + IN const uint8_t val) +{ + p_cpi->cap_mask2_resp_time = + (p_cpi->cap_mask2_resp_time & CL_HTON32(~IB_CLASS_RESP_TIME_MASK)) | + cl_hton32(val & IB_CLASS_RESP_TIME_MASK); +} + +/* +* PARAMETERS +* p_cpi +* [in] Pointer to the class port info object. +* +* val +* [in] Response time value to set. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* ib_class_port_info_t +*********/ + +/****f* IBA Base: Types/ib_class_resp_time_val +* NAME +* ib_class_resp_time_val +* +* DESCRIPTION +* Get response time value. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_class_resp_time_val(IN ib_class_port_info_t * const p_cpi) +{ + return (uint8_t)(cl_ntoh32(p_cpi->cap_mask2_resp_time) & + IB_CLASS_RESP_TIME_MASK); +} + +/* +* PARAMETERS +* p_cpi +* [in] Pointer to the class port info object. +* +* RETURN VALUES +* Response time value. +* +* NOTES +* +* SEE ALSO +* ib_class_port_info_t +*********/ + +/****f* IBA Base: Types/ib_class_set_cap_mask2 +* NAME +* ib_class_set_cap_mask2 +* +* DESCRIPTION +* Set ClassPortInfo:CapabilityMask2. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_class_set_cap_mask2(IN ib_class_port_info_t * const p_cpi, + IN const uint32_t cap_mask2) +{ + p_cpi->cap_mask2_resp_time = (p_cpi->cap_mask2_resp_time & + CL_HTON32(IB_CLASS_RESP_TIME_MASK)) | + cl_hton32(cap_mask2 << 5); +} + +/* +* PARAMETERS +* p_cpi +* [in] Pointer to the class port info object. +* +* cap_mask2 +* [in] CapabilityMask2 value to set. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* ib_class_port_info_t +*********/ + +/****f* IBA Base: Types/ib_class_cap_mask2 +* NAME +* ib_class_cap_mask2 +* +* DESCRIPTION +* Get ClassPortInfo:CapabilityMask2. +* +* SYNOPSIS +*/ +static inline uint32_t OSM_API +ib_class_cap_mask2(IN const ib_class_port_info_t * const p_cpi) +{ + return (cl_ntoh32(p_cpi->cap_mask2_resp_time) >> 5); +} + +/* +* PARAMETERS +* p_cpi +* [in] Pointer to the class port info object. +* +* RETURN VALUES +* CapabilityMask2 of the ClassPortInfo. +* +* NOTES +* +* SEE ALSO +* ib_class_port_info_t +*********/ + +/****s* IBA Base: Types/ib_sm_info_t +* NAME +* ib_sm_info_t +* +* DESCRIPTION +* SMInfo structure (14.2.5.13). +* +* SYNOPSIS +*/ +#include +typedef struct _ib_sm_info +{ + ib_net64_t guid; + ib_net64_t sm_key; + ib_net32_t act_count; + uint8_t pri_state; + +} PACK_SUFFIX ib_sm_info_t; +#include +/* +* FIELDS +* guid +* Port GUID for this SM. +* +* sm_key +* SM_Key of this SM. +* +* act_count +* Activity counter used as a heartbeat. +* +* pri_state +* Priority and State information +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_sminfo_get_priority +* NAME +* ib_sminfo_get_priority +* +* DESCRIPTION +* Returns the priority value. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_sminfo_get_priority( + IN const ib_sm_info_t* const p_smi ) +{ + return( (uint8_t)((p_smi->pri_state & 0xF0)>>4) ); +} +/* +* PARAMETERS +* p_smi +* [in] Pointer to the SMInfo Attribute. +* +* RETURN VALUES +* Returns the priority value. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_sminfo_get_state +* NAME +* ib_sminfo_get_state +* +* DESCRIPTION +* Returns the state value. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_sminfo_get_state( + IN const ib_sm_info_t* const p_smi ) +{ + return( (uint8_t)(p_smi->pri_state & 0x0F) ); +} +/* +* PARAMETERS +* p_smi +* [in] Pointer to the SMInfo Attribute. +* +* RETURN VALUES +* Returns the state value. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* IBA Base: Types/ib_mad_t +* NAME +* ib_mad_t +* +* DESCRIPTION +* IBA defined MAD header (13.4.3) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_mad +{ + uint8_t base_ver; + uint8_t mgmt_class; + uint8_t class_ver; + uint8_t method; + ib_net16_t status; + ib_net16_t class_spec; + ib_net64_t trans_id; + ib_net16_t attr_id; + ib_net16_t resv; + ib_net32_t attr_mod; +} PACK_SUFFIX ib_mad_t; +#include +/* +* FIELDS +* base_ver +* MAD base format. +* +* mgmt_class +* Class of operation. +* +* class_ver +* Version of MAD class-specific format. +* +* method +* Method to perform, including 'R' bit. +* +* status +* Status of operation. +* +* class_spec +* Reserved for subnet management. +* +* trans_id +* Transaction ID. +* +* attr_id +* Attribute ID. +* +* resv +* Reserved field. +* +* attr_mod +* Attribute modifier. +* +* SEE ALSO +*********/ + + +/****s* IBA Base: Types/ib_rmpp_mad_t +* NAME +* ib_rmpp_mad_t +* +* DESCRIPTION +* IBA defined MAD RMPP header (13.6.2.1) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_rmpp_mad +{ + ib_mad_t common_hdr; + + uint8_t rmpp_version; + uint8_t rmpp_type; + uint8_t rmpp_flags; + uint8_t rmpp_status; + + ib_net32_t seg_num; + ib_net32_t paylen_newwin; + +} PACK_SUFFIX ib_rmpp_mad_t; +#include +/* +* SEE ALSO +* ib_mad_t +*********/ + + +/****f* IBA Base: Types/ib_mad_init_new +* NAME +* ib_mad_init_new +* +* DESCRIPTION +* Initializes a MAD common header. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_mad_init_new( + IN ib_mad_t* const p_mad, + IN const uint8_t mgmt_class, + IN const uint8_t class_ver, + IN const uint8_t method, + IN const ib_net64_t trans_id, + IN const ib_net16_t attr_id, + IN const ib_net32_t attr_mod ) +{ + CL_ASSERT( p_mad ); + p_mad->base_ver = 1; + p_mad->mgmt_class = mgmt_class; + p_mad->class_ver = class_ver; + p_mad->method = method; + p_mad->status = 0; + p_mad->class_spec = 0; + p_mad->trans_id = trans_id; + p_mad->attr_id = attr_id; + p_mad->resv = 0; + p_mad->attr_mod = attr_mod; +} +/* +* PARAMETERS +* p_mad +* [in] Pointer to the MAD common header. +* +* mgmt_class +* [in] Class of operation. +* +* class_ver +* [in] Version of MAD class-specific format. +* +* method +* [in] Method to perform, including 'R' bit. +* +* trans_Id +* [in] Transaction ID. +* +* attr_id +* [in] Attribute ID. +* +* attr_mod +* [in] Attribute modifier. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* ib_mad_t +*********/ + +/****f* IBA Base: Types/ib_mad_init_response +* NAME +* ib_mad_init_response +* +* DESCRIPTION +* Initializes a MAD common header as a response. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_mad_init_response( + IN const ib_mad_t* const p_req_mad, + IN ib_mad_t* const p_mad, + IN const ib_net16_t status ) +{ + CL_ASSERT( p_req_mad ); + CL_ASSERT( p_mad ); + *p_mad = *p_req_mad; + p_mad->status = status; + if( p_mad->method == IB_MAD_METHOD_SET ) + p_mad->method = IB_MAD_METHOD_GET; + p_mad->method |= IB_MAD_METHOD_RESP_MASK; +} +/* +* PARAMETERS +* p_req_mad +* [in] Pointer to the MAD common header in the original request MAD. +* +* p_mad +* [in] Pointer to the MAD common header to initialize. +* +* status +* [in] MAD Status value to return; +* +* RETURN VALUES +* None. +* +* NOTES +* p_req_mad and p_mad may point to the same MAD. +* +* SEE ALSO +* ib_mad_t +*********/ + +/****f* IBA Base: Types/ib_mad_is_response +* NAME +* ib_mad_is_response +* +* DESCRIPTION +* Returns TRUE if the MAD is a response ('R' bit set), +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_mad_is_response( + IN const ib_mad_t* const p_mad ) +{ + CL_ASSERT( p_mad ); + return( (p_mad->method & IB_MAD_METHOD_RESP_MASK) == + IB_MAD_METHOD_RESP_MASK ); +} +/* +* PARAMETERS +* p_mad +* [in] Pointer to the MAD. +* +* RETURN VALUES +* Returns TRUE if the MAD is a response ('R' bit set), +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* ib_mad_t +*********/ + +#define IB_RMPP_TYPE_DATA 1 +#define IB_RMPP_TYPE_ACK 2 +#define IB_RMPP_TYPE_STOP 3 +#define IB_RMPP_TYPE_ABORT 4 + +#define IB_RMPP_NO_RESP_TIME 0x1F +#define IB_RMPP_FLAG_ACTIVE 0x01 +#define IB_RMPP_FLAG_FIRST 0x02 +#define IB_RMPP_FLAG_LAST 0x04 + +#define IB_RMPP_STATUS_SUCCESS 0 +#define IB_RMPP_STATUS_RESX 1 /* resources exhausted */ +#define IB_RMPP_STATUS_T2L 118 /* time too long */ +#define IB_RMPP_STATUS_BAD_LEN 119 /* incon. last and payload len */ +#define IB_RMPP_STATUS_BAD_SEG 120 /* incon. first and segment no */ +#define IB_RMPP_STATUS_BADT 121 /* bad rmpp type */ +#define IB_RMPP_STATUS_W2S 122 /* newwindowlast too small */ +#define IB_RMPP_STATUS_S2B 123 /* segment no too big */ +#define IB_RMPP_STATUS_BAD_STATUS 124 /* illegal status */ +#define IB_RMPP_STATUS_UNV 125 /* unsupported version */ +#define IB_RMPP_STATUS_TMR 126 /* too many retries */ +#define IB_RMPP_STATUS_UNSPEC 127 /* unspecified */ + +/****f* IBA Base: Types/ib_rmpp_is_flag_set +* NAME +* ib_rmpp_is_flag_set +* +* DESCRIPTION +* Returns TRUE if the MAD has the given RMPP flag set. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_rmpp_is_flag_set( + IN const ib_rmpp_mad_t* const p_rmpp_mad, + IN const uint8_t flag ) +{ + CL_ASSERT( p_rmpp_mad ); + return( (p_rmpp_mad->rmpp_flags & flag) == flag ); +} +/* +* PARAMETERS +* ib_rmpp_mad_t +* [in] Pointer to a MAD with an RMPP header. +* +* flag +* [in] The RMPP flag being examined. +* +* RETURN VALUES +* Returns TRUE if the MAD has the given RMPP flag set. +* +* NOTES +* +* SEE ALSO +* ib_mad_t, ib_rmpp_mad_t +*********/ + +static inline void OSM_API +ib_rmpp_set_resp_time( + IN ib_rmpp_mad_t* const p_rmpp_mad, + IN const uint8_t resp_time ) +{ + CL_ASSERT( p_rmpp_mad ); + p_rmpp_mad->rmpp_flags |= (resp_time << 3); +} + + +static inline uint8_t OSM_API +ib_rmpp_get_resp_time( + IN const ib_rmpp_mad_t* const p_rmpp_mad ) +{ + CL_ASSERT( p_rmpp_mad ); + return( (uint8_t)(p_rmpp_mad->rmpp_flags >> 3) ); +} + +/****d* IBA Base: Constants/IB_SMP_DIRECTION +* NAME +* IB_SMP_DIRECTION +* +* DESCRIPTION +* The Direction bit for directed route SMPs. +* +* SOURCE +*/ +#define IB_SMP_DIRECTION_HO 0x8000 +#define IB_SMP_DIRECTION (CL_HTON16(IB_SMP_DIRECTION_HO)) +/**********/ + +/****d* IBA Base: Constants/IB_SMP_STATUS_MASK +* NAME +* IB_SMP_STATUS_MASK +* +* DESCRIPTION +* Mask value for extracting status from a directed route SMP. +* +* SOURCE +*/ +#define IB_SMP_STATUS_MASK_HO 0x7FFF +#define IB_SMP_STATUS_MASK (CL_HTON16(IB_SMP_STATUS_MASK_HO)) +/**********/ + +/****s* IBA Base: Types/ib_smp_t +* NAME +* ib_smp_t +* +* DESCRIPTION +* IBA defined SMP. (14.2.1.2) +* +* SYNOPSIS +*/ +#define IB_SMP_DATA_SIZE 64 +#include +typedef struct _ib_smp +{ + uint8_t base_ver; + uint8_t mgmt_class; + uint8_t class_ver; + uint8_t method; + ib_net16_t status; + uint8_t hop_ptr; + uint8_t hop_count; + ib_net64_t trans_id; + ib_net16_t attr_id; + ib_net16_t resv; + ib_net32_t attr_mod; + ib_net64_t m_key; + ib_net16_t dr_slid; + ib_net16_t dr_dlid; + uint32_t resv1[7]; + uint8_t data[IB_SMP_DATA_SIZE]; + uint8_t initial_path[IB_SUBNET_PATH_HOPS_MAX]; + uint8_t return_path[IB_SUBNET_PATH_HOPS_MAX]; + +} PACK_SUFFIX ib_smp_t; +#include +/* +* FIELDS +* base_ver +* MAD base format. +* +* mgmt_class +* Class of operation. +* +* class_ver +* Version of MAD class-specific format. +* +* method +* Method to perform, including 'R' bit. +* +* status +* Status of operation. +* +* hop_ptr +* Hop pointer for directed route MADs. +* +* hop_count +* Hop count for directed route MADs. +* +* trans_Id +* Transaction ID. +* +* attr_id +* Attribute ID. +* +* resv +* Reserved field. +* +* attr_mod +* Attribute modifier. +* +* m_key +* Management key value. +* +* dr_slid +* Directed route source LID. +* +* dr_dlid +* Directed route destination LID. +* +* resv0 +* Reserved for 64 byte alignment. +* +* data +* MAD data payload. +* +* initial_path +* Outbound port list. +* +* return_path +* Inbound port list. +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_smp_get_status +* NAME +* ib_smp_get_status +* +* DESCRIPTION +* Returns the SMP status value in network order. +* +* SYNOPSIS +*/ +static inline ib_net16_t OSM_API +ib_smp_get_status( + IN const ib_smp_t* const p_smp ) +{ + return( (ib_net16_t)(p_smp->status & IB_SMP_STATUS_MASK) ); +} +/* +* PARAMETERS +* p_smp +* [in] Pointer to the SMP packet. +* +* RETURN VALUES +* Returns the SMP status value in network order. +* +* NOTES +* +* SEE ALSO +* ib_smp_t +*********/ + +/****f* IBA Base: Types/ib_smp_is_response +* NAME +* ib_smp_is_response +* +* DESCRIPTION +* Returns TRUE if the SMP is a response MAD, FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_smp_is_response( + IN const ib_smp_t* const p_smp ) +{ + return( ib_mad_is_response( (const ib_mad_t*)p_smp ) ); +} +/* +* PARAMETERS +* p_smp +* [in] Pointer to the SMP packet. +* +* RETURN VALUES +* Returns TRUE if the SMP is a response MAD, FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* ib_smp_t +*********/ + +/****f* IBA Base: Types/ib_smp_is_d +* NAME +* ib_smp_is_d +* +* DESCRIPTION +* Returns TRUE if the SMP 'D' (direction) bit is set. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_smp_is_d( + IN const ib_smp_t* const p_smp ) +{ + return( (p_smp->status & IB_SMP_DIRECTION) == IB_SMP_DIRECTION ); +} +/* +* PARAMETERS +* p_smp +* [in] Pointer to the SMP packet. +* +* RETURN VALUES +* Returns TRUE if the SMP 'D' (direction) bit is set. +* +* NOTES +* +* SEE ALSO +* ib_smp_t +*********/ + +/****f* IBA Base: Types/ib_smp_init_new +* NAME +* ib_smp_init_new +* +* DESCRIPTION +* Initializes a MAD common header. +* +* TODO +* This is too big for inlining, but leave it here for now +* since there is not yet another convient spot. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_smp_init_new( + IN ib_smp_t* const p_smp, + IN const uint8_t method, + IN const ib_net64_t trans_id, + IN const ib_net16_t attr_id, + IN const ib_net32_t attr_mod, + IN const uint8_t hop_count, + IN const ib_net64_t m_key, + IN const uint8_t* path_out, + IN const ib_net16_t dr_slid, + IN const ib_net16_t dr_dlid ) +{ + CL_ASSERT( p_smp ); + CL_ASSERT( hop_count < IB_SUBNET_PATH_HOPS_MAX ); + p_smp->base_ver = 1; + p_smp->mgmt_class = IB_MCLASS_SUBN_DIR; + p_smp->class_ver = 1; + p_smp->method = method; + p_smp->status = 0; + p_smp->hop_ptr = 0; + p_smp->hop_count = hop_count; + p_smp->trans_id = trans_id; + p_smp->attr_id = attr_id; + p_smp->resv = 0; + p_smp->attr_mod = attr_mod; + p_smp->m_key = m_key; + p_smp->dr_slid = dr_slid; + p_smp->dr_dlid = dr_dlid; + + memset( p_smp->resv1, 0, + sizeof(p_smp->resv1) + + sizeof(p_smp->data) + + sizeof(p_smp->initial_path) + + sizeof(p_smp->return_path) ); + + /* copy the path */ + memcpy( &p_smp->initial_path, path_out, + sizeof( p_smp->initial_path ) ); +} +/* +* PARAMETERS +* p_smp +* [in] Pointer to the SMP packet. +* +* method +* [in] Method to perform, including 'R' bit. +* +* trans_Id +* [in] Transaction ID. +* +* attr_id +* [in] Attribute ID. +* +* attr_mod +* [in] Attribute modifier. +* +* hop_count +* [in] Number of hops in the path. +* +* m_key +* [in] Management key for this SMP. +* +* path_out +* [in] Port array for outbound path. +* +* +* RETURN VALUES +* None. +* +* NOTES +* Payload area is initialized to zero. +* +* +* SEE ALSO +* ib_mad_t +*********/ + +/****f* IBA Base: Types/ib_smp_get_payload_ptr +* NAME +* ib_smp_get_payload_ptr +* +* DESCRIPTION +* Gets a pointer to the SMP payload area. +* +* SYNOPSIS +*/ +static inline void* OSM_API +ib_smp_get_payload_ptr( + IN const ib_smp_t* const p_smp ) +{ + return( (void*)p_smp->data ); +} +/* +* PARAMETERS +* p_smp +* [in] Pointer to the SMP packet. +* +* RETURN VALUES +* Pointer to SMP payload area. +* +* NOTES +* +* SEE ALSO +* ib_mad_t +*********/ + +/****s* IBA Base: Types/ib_node_info_t +* NAME +* ib_node_info_t +* +* DESCRIPTION +* IBA defined NodeInfo. (14.2.5.3) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_node_info +{ + uint8_t base_version; + uint8_t class_version; + uint8_t node_type; + uint8_t num_ports; + ib_net64_t sys_guid; + ib_net64_t node_guid; + ib_net64_t port_guid; + ib_net16_t partition_cap; + ib_net16_t device_id; + ib_net32_t revision; + ib_net32_t port_num_vendor_id; + +} PACK_SUFFIX ib_node_info_t; +#include +/************/ + +/****s* IBA Base: Types/ib_sa_mad_t +* NAME +* ib_sa_mad_t +* +* DESCRIPTION +* IBA defined SA MAD format. (15.2.1) +* +* SYNOPSIS +*/ +#define IB_SA_DATA_SIZE 200 + +#include +typedef struct _ib_sa_mad +{ + uint8_t base_ver; + uint8_t mgmt_class; + uint8_t class_ver; + uint8_t method; + ib_net16_t status; + ib_net16_t resv; + ib_net64_t trans_id; + ib_net16_t attr_id; + ib_net16_t resv1; + ib_net32_t attr_mod; + + uint8_t rmpp_version; + uint8_t rmpp_type; + uint8_t rmpp_flags; + uint8_t rmpp_status; + + ib_net32_t seg_num; + ib_net32_t paylen_newwin; + + ib_net64_t sm_key; + + ib_net16_t attr_offset; + ib_net16_t resv3; + + ib_net64_t comp_mask; + + uint8_t data[IB_SA_DATA_SIZE]; +} PACK_SUFFIX ib_sa_mad_t; +#include +/**********/ +#define IB_SA_MAD_HDR_SIZE (sizeof(ib_sa_mad_t) - IB_SA_DATA_SIZE) + +static inline uint32_t OSM_API +ib_get_attr_size( + IN const ib_net16_t attr_offset ) +{ + return( ((uint32_t)cl_ntoh16( attr_offset )) << 3 ); +} + +static inline ib_net16_t OSM_API +ib_get_attr_offset( + IN const uint32_t attr_size ) +{ + return( cl_hton16( (uint16_t)(attr_size >> 3) ) ); +} + +/****f* IBA Base: Types/ib_sa_mad_get_payload_ptr +* NAME +* ib_sa_mad_get_payload_ptr +* +* DESCRIPTION +* Gets a pointer to the SA MAD's payload area. +* +* SYNOPSIS +*/ +static inline void* OSM_API +ib_sa_mad_get_payload_ptr( + IN const ib_sa_mad_t* const p_sa_mad ) +{ + return( (void*)p_sa_mad->data ); +} +/* +* PARAMETERS +* p_smp +* [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 +* Gets a the local port number from the NodeInfo attribute. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_node_info_get_local_port_num( + IN const ib_node_info_t* const p_ni ) +{ + return( (uint8_t)(( p_ni->port_num_vendor_id & + IB_NODE_INFO_PORT_NUM_MASK ) + >> IB_NODE_INFO_PORT_NUM_SHIFT )); +} +/* +* PARAMETERS +* p_ni +* [in] Pointer to a NodeInfo attribute. +* +* RETURN VALUES +* Local port number that returned the attribute. +* +* NOTES +* +* SEE ALSO +* ib_node_info_t +*********/ + +/****f* IBA Base: Types/ib_node_info_get_vendor_id +* NAME +* ib_node_info_get_vendor_id +* +* DESCRIPTION +* Gets the VendorID from the NodeInfo attribute. +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_node_info_get_vendor_id( + IN const ib_node_info_t* const p_ni ) +{ + return( (ib_net32_t)( p_ni->port_num_vendor_id & + IB_NODE_INFO_VEND_ID_MASK ) ); +} +/* +* PARAMETERS +* p_ni +* [in] Pointer to a NodeInfo attribute. +* +* RETURN VALUES +* VendorID that returned the attribute. +* +* NOTES +* +* SEE ALSO +* ib_node_info_t +*********/ + +#define IB_NODE_DESCRIPTION_SIZE 64 + +#include +typedef struct _ib_node_desc +{ + // Node String is an array of UTF-8 character that + // describes the node in text format + // Note that this string is NOT NULL TERMINATED! + uint8_t description[IB_NODE_DESCRIPTION_SIZE]; + +} PACK_SUFFIX ib_node_desc_t; +#include + +#include +typedef struct _ib_node_record_t +{ + ib_net16_t lid; + ib_net16_t resv; + ib_node_info_t node_info; + ib_node_desc_t node_desc; + uint8_t pad[4]; + +} PACK_SUFFIX ib_node_record_t; +#include + +/****s* IBA Base: Types/ib_port_info_t +* NAME +* ib_port_info_t +* +* DESCRIPTION +* IBA defined PortInfo. (14.2.5.6) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_port_info +{ + ib_net64_t m_key; + ib_net64_t subnet_prefix; + ib_net16_t base_lid; + ib_net16_t master_sm_base_lid; + ib_net32_t capability_mask; + ib_net16_t diag_code; + ib_net16_t m_key_lease_period; + uint8_t local_port_num; + uint8_t link_width_enabled; + uint8_t link_width_supported; + uint8_t link_width_active; + uint8_t state_info1; /* LinkSpeedSupported and PortState */ + uint8_t state_info2; /* PortPhysState and LinkDownDefaultState */ + uint8_t mkey_lmc; + uint8_t link_speed; /* LinkSpeedEnabled and LinkSpeedActive */ + uint8_t mtu_smsl; + uint8_t vl_cap; /* VLCap and InitType */ + uint8_t vl_high_limit; + uint8_t vl_arb_high_cap; + uint8_t vl_arb_low_cap; + uint8_t mtu_cap; + uint8_t vl_stall_life; + uint8_t vl_enforce; + ib_net16_t m_key_violations; + ib_net16_t p_key_violations; + ib_net16_t q_key_violations; + uint8_t guid_cap; + uint8_t subnet_timeout; /* cli_rereg(1b), resrv( +2b), timeout(5b) */ + uint8_t resp_time_value; + uint8_t error_threshold; + +} PACK_SUFFIX ib_port_info_t; +#include +/************/ + +#define IB_PORT_STATE_MASK 0x0F +#define IB_PORT_LMC_MASK 0x07 +#define IB_PORT_LMC_MAX 0x07 +#define IB_PORT_MPB_MASK 0xC0 +#define IB_PORT_MPB_SHIFT 6 +#define IB_PORT_LINK_SPEED_SHIFT 4 +#define IB_PORT_LINK_SPEED_SUPPORTED_MASK 0xF0 +#define IB_PORT_LINK_SPEED_ACTIVE_MASK 0xF0 +#define IB_PORT_LINK_SPEED_ENABLED_MASK 0x0F +#define IB_PORT_PHYS_STATE_MASK 0xF0 +#define IB_PORT_PHYS_STATE_SHIFT 4 +#define IB_PORT_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_RESV26 (CL_NTOH32(0x04000000)) +#define IB_PORT_CAP_RESV27 (CL_NTOH32(0x08000000)) +#define IB_PORT_CAP_RESV28 (CL_NTOH32(0x10000000)) +#define IB_PORT_CAP_RESV29 (CL_NTOH32(0x20000000)) +#define IB_PORT_CAP_RESV30 (CL_NTOH32(0x40000000)) +#define IB_PORT_CAP_RESV31 (CL_NTOH32(0x80000000)) + +/****f* IBA Base: Types/ib_port_info_get_port_state +* NAME +* ib_port_info_get_port_state +* +* DESCRIPTION +* Returns the port state. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_port_state( + IN const ib_port_info_t* const p_pi ) +{ + return( (uint8_t)(p_pi->state_info1 & IB_PORT_STATE_MASK) ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Port state. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_port_state +* NAME +* ib_port_info_set_port_state +* +* DESCRIPTION +* Sets the port state. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_port_state( + IN ib_port_info_t* const p_pi, + IN const uint8_t port_state ) +{ + p_pi->state_info1 = (uint8_t)((p_pi->state_info1 & 0xF0) | port_state ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* port_state +* [in] Port state value to set. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_vl_cap +* NAME +* ib_port_info_get_vl_cap +* +* DESCRIPTION +* Gets the VL Capability of a port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_vl_cap( + IN const ib_port_info_t* const p_pi) +{ + return((p_pi->vl_cap >> 4) & 0x0F); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* VL_CAP field +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_init_type +* NAME +* ib_port_info_get_init_type +* +* DESCRIPTION +* Gets the init type of a port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_init_type( + IN const ib_port_info_t* const p_pi) +{ + return (uint8_t) (p_pi->vl_cap & 0x0F); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* InitType field +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_op_vls +* NAME +* ib_port_info_get_op_vls +* +* DESCRIPTION +* Gets the operational VLs on a port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_op_vls( + IN const ib_port_info_t* const p_pi) +{ + return((p_pi->vl_enforce >> 4) & 0x0F); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* OP_VLS field +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_op_vls +* NAME +* ib_port_info_set_op_vls +* +* DESCRIPTION +* Sets the operational VLs on a port. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_op_vls( + IN ib_port_info_t* const p_pi, + IN const uint8_t op_vls ) +{ + p_pi->vl_enforce = (uint8_t)((p_pi->vl_enforce & 0x0F) | (op_vls << 4) ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* op_vls +* [in] Encoded operation VLs value. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_state_no_change +* NAME +* ib_port_info_set_state_no_change +* +* DESCRIPTION +* Sets the port state fields to the value for "no change". +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_state_no_change( + IN ib_port_info_t* const p_pi ) +{ + ib_port_info_set_port_state( p_pi, IB_LINK_NO_CHANGE ); + p_pi->state_info2 = 0; +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_link_speed_sup +* NAME +* ib_port_info_get_link_speed_sup +* +* DESCRIPTION +* Returns the encoded value for the link speed supported. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_link_speed_sup( + IN const ib_port_info_t* const p_pi ) +{ + return( (uint8_t)((p_pi->state_info1 & + IB_PORT_LINK_SPEED_SUPPORTED_MASK) >> + IB_PORT_LINK_SPEED_SHIFT) ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the encoded value for the link speed supported. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_link_speed_sup +* NAME +* ib_port_info_set_link_speed_sup +* +* DESCRIPTION +* Given an integer of the supported link speed supported. +* Set the appropriate bits in state_info1 +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_link_speed_sup( + IN uint8_t const speed, + IN ib_port_info_t* p_pi ) +{ + p_pi->state_info1 = + ( ~IB_PORT_LINK_SPEED_SUPPORTED_MASK & p_pi->state_info1 ) | + ( IB_PORT_LINK_SPEED_SUPPORTED_MASK & + (speed << IB_PORT_LINK_SPEED_SHIFT) ); +} +/* +* PARAMETERS +* speed +* [in] Supported Speeds Code. +* +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_port_phys_state +* NAME +* ib_port_info_get_port_phys_state +* +* DESCRIPTION +* Returns the encoded value for the port physical state. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_port_phys_state( + IN const ib_port_info_t* const p_pi ) +{ + return( (uint8_t)((p_pi->state_info2 & + IB_PORT_PHYS_STATE_MASK) >> + IB_PORT_PHYS_STATE_SHIFT) ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the encoded value for the port physical state. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_port_phys_state +* NAME +* ib_port_info_set_port_phys_state +* +* DESCRIPTION +* Given an integer of the port physical state, +* Set the appropriate bits in state_info2 +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_port_phys_state( + IN uint8_t const phys_state, + IN ib_port_info_t* p_pi ) +{ + p_pi->state_info2 = + ( ~IB_PORT_PHYS_STATE_MASK & p_pi->state_info2 ) | + ( IB_PORT_PHYS_STATE_MASK & + (phys_state << IB_PORT_PHYS_STATE_SHIFT) ); +} +/* +* PARAMETERS +* phys_state +* [in] port physical state. +* +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_link_down_def_state +* NAME +* ib_port_info_get_link_down_def_state +* +* DESCRIPTION +* Returns the link down default state. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_link_down_def_state( + IN const ib_port_info_t* const p_pi ) +{ + return( (uint8_t)(p_pi->state_info2 & IB_PORT_LNKDWNDFTSTATE_MASK) ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* link down default state of the port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_link_down_def_state +* NAME +* ib_port_info_set_link_down_def_state +* +* DESCRIPTION +* Sets the link down default state of the port. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_link_down_def_state( + IN ib_port_info_t* const p_pi, + IN const uint8_t link_dwn_state ) +{ + p_pi->state_info2 = (uint8_t)((p_pi->state_info2 & 0xF0) | link_dwn_state ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* link_dwn_state +* [in] Link down default state of the port. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_link_speed_active +* NAME +* ib_port_info_get_link_speed_active +* +* DESCRIPTION +* Returns the Link Speed Active value assigned to this port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_link_speed_active( + IN const ib_port_info_t* const p_pi ) +{ + return( (uint8_t)((p_pi->link_speed & + IB_PORT_LINK_SPEED_ACTIVE_MASK) >> + IB_PORT_LINK_SPEED_SHIFT) ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the link speed active value assigned to this port. +* +* NOTES +* +* SEE ALSO +*********/ + +#define IB_LINK_WIDTH_ACTIVE_1X 1 +#define IB_LINK_WIDTH_ACTIVE_4X 2 +#define IB_LINK_WIDTH_ACTIVE_12X 8 +#define IB_LINK_SPEED_ACTIVE_2_5 1 +#define IB_LINK_SPEED_ACTIVE_5 2 +#define IB_LINK_SPEED_ACTIVE_10 4 + +/* following v1 ver1.2 p901 */ +#define IB_PATH_RECORD_RATE_2_5_GBS 2 +#define IB_PATH_RECORD_RATE_10_GBS 3 +#define IB_PATH_RECORD_RATE_30_GBS 4 +#define IB_PATH_RECORD_RATE_5_GBS 5 +#define IB_PATH_RECORD_RATE_20_GBS 6 +#define IB_PATH_RECORD_RATE_40_GBS 7 +#define IB_PATH_RECORD_RATE_60_GBS 8 +#define IB_PATH_RECORD_RATE_80_GBS 9 +#define IB_PATH_RECORD_RATE_120_GBS 10 + +#define IB_MIN_RATE IB_PATH_RECORD_RATE_2_5_GBS +#define IB_MAX_RATE IB_PATH_RECORD_RATE_120_GBS + +/****f* IBA Base: Types/ib_port_info_compute_rate +* NAME +* ib_port_info_compute_rate +* +* DESCRIPTION +* Returns the encoded value for the path rate. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_compute_rate( + IN const ib_port_info_t* const p_pi ) +{ + uint8_t rate = 0; + + switch (ib_port_info_get_link_speed_active(p_pi)) + { + case IB_LINK_SPEED_ACTIVE_2_5: + switch (p_pi->link_width_active) + { + case IB_LINK_WIDTH_ACTIVE_1X: + rate = IB_PATH_RECORD_RATE_2_5_GBS; + break; + + case IB_LINK_WIDTH_ACTIVE_4X: + rate = IB_PATH_RECORD_RATE_10_GBS; + break; + + case IB_LINK_WIDTH_ACTIVE_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 +*/ +static inline uint8_t OSM_API +ib_path_get_ipd( + IN uint8_t local_link_width_supported, + IN uint8_t path_rec_rate ) +{ + uint8_t ipd = 0; + + switch(local_link_width_supported) + { + /* link_width_supported = 1: 1x */ + case 1: + break; + + /* link_width_supported = 3: 1x or 4x */ + case 3: + switch(path_rec_rate & 0x3F) + { + case IB_PATH_RECORD_RATE_2_5_GBS: + ipd = 3; + break; + default: + break; + } + break; + + /* link_width_supported = 11: 1x or 4x or 12x */ + case 11: + switch(path_rec_rate & 0x3F) + { + case IB_PATH_RECORD_RATE_2_5_GBS: + ipd = 11; + break; + case IB_PATH_RECORD_RATE_10_GBS: + ipd = 2; + break; + default: + break; + } + break; + + default: + break; + } + + return ipd; +} +/* +* PARAMETERS +* local_link_width_supported +* [in] link with supported for this port +* +* path_rec_rate +* [in] rate field of the path record +* +* RETURN VALUES +* Returns the ipd +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_mtu_cap +* NAME +* ib_port_info_get_mtu_cap +* +* DESCRIPTION +* Returns the encoded value for the maximum MTU supported by this port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_mtu_cap( + IN const ib_port_info_t* const p_pi ) +{ + return( (uint8_t)(p_pi->mtu_cap & 0x0F) ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the LMC value assigned to 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 +*/ +static inline uint8_t OSM_API +ib_port_info_get_neighbor_mtu( + IN const ib_port_info_t* const p_pi ) +{ + return( (uint8_t)((p_pi->mtu_smsl & 0xF0) >> 4) ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the encoded value for the neighbor MTU at this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_neighbor_mtu +* NAME +* ib_port_info_set_neighbor_mtu +* +* DESCRIPTION +* Sets the Neighbor MTU value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_neighbor_mtu( + IN ib_port_info_t* const p_pi, + IN const uint8_t mtu ) +{ + CL_ASSERT( mtu <= 5 ); + CL_ASSERT( mtu != 0 ); + p_pi->mtu_smsl = (uint8_t)((p_pi->mtu_smsl & 0x0F) | (mtu << 4)); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* mtu +* [in] Encoded MTU value to set +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_master_smsl +* NAME +* ib_port_info_get_master_smsl +* +* DESCRIPTION +* Returns the encoded value for the Master SMSL at this port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_master_smsl( + IN const ib_port_info_t* const p_pi ) +{ + return (uint8_t) (p_pi->mtu_smsl & 0x0F); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the encoded value for the Master SMSL at this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_master_smsl +* NAME +* ib_port_info_set_master_smsl +* +* DESCRIPTION +* Sets the Master SMSL value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_master_smsl( + IN ib_port_info_t* const p_pi, + IN const uint8_t smsl ) +{ + p_pi->mtu_smsl = (uint8_t)((p_pi->mtu_smsl & 0xF0) | smsl ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* mtu +* [in] Encoded Master SMSL value to set +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_timeout +* NAME +* ib_port_info_set_timeout +* +* DESCRIPTION +* Sets the encoded subnet timeout value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_timeout( + IN ib_port_info_t* const p_pi, + IN const uint8_t timeout ) +{ + CL_ASSERT( timeout <= 0x1F ); + p_pi->subnet_timeout = + (uint8_t)( + (p_pi->subnet_timeout & 0x80) | (timeout & 0x1F)); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* timeout +* [in] Encoded timeout value to set +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_client_rereg +* NAME +* ib_port_info_set_client_rereg +* +* DESCRIPTION +* Sets the encoded client reregistration bit value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_client_rereg( + IN ib_port_info_t* const p_pi, + IN const uint8_t client_rereg ) +{ + CL_ASSERT( client_rereg <= 0x1 ); + p_pi->subnet_timeout = + (uint8_t)( + (p_pi->subnet_timeout & 0x1F) | ((client_rereg << 7) & 0x80)); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* client_rereg +* [in] Client reregistration value to set (either 1 or 0). +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_timeout +* NAME +* ib_port_info_get_timeout +* +* DESCRIPTION +* Gets the encoded subnet timeout value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_timeout( + IN ib_port_info_t const* p_pi ) +{ + return(p_pi->subnet_timeout & 0x1F ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* The encoded timeout value +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_client_rereg +* NAME +* ib_port_info_get_client_rereg +* +* DESCRIPTION +* Gets the encoded client reregistration bit value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_client_rereg( + IN ib_port_info_t const* p_pi ) +{ + return ( (p_pi->subnet_timeout & 0x80 ) >> 7); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Client reregistration value (either 1 or 0). +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_hoq_lifetime +* NAME +* ib_port_info_set_hoq_lifetime +* +* DESCRIPTION +* Sets the Head of Queue Lifetime for which a packet can live in the head +* of VL queue +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_hoq_lifetime( + IN ib_port_info_t* const p_pi, + IN const uint8_t hoq_life ) +{ + p_pi->vl_stall_life = (uint8_t)((hoq_life & 0x1f) | + (p_pi->vl_stall_life & 0xe0)); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* hoq_life +* [in] Encoded lifetime value to set +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_hoq_lifetime +* NAME +* ib_port_info_get_hoq_lifetime +* +* DESCRIPTION +* Gets the Head of Queue Lifetime for which a packet can live in the head +* of VL queue +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_hoq_lifetime( + IN const ib_port_info_t* const p_pi ) +{ + return( (uint8_t)(p_pi->vl_stall_life & 0x1f) ); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Encoded lifetime value +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_vl_stall_count +* NAME +* ib_port_info_set_vl_stall_count +* +* DESCRIPTION +* Sets the VL Stall Count which define the number of contiguous +* HLL (hoq) drops that will put the VL into stalled mode. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_vl_stall_count( + IN ib_port_info_t* const p_pi, + IN const uint8_t vl_stall_count ) +{ + p_pi->vl_stall_life = (uint8_t)((p_pi->vl_stall_life & 0x1f) | + ((vl_stall_count << 5) & 0xe0)); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* vl_stall_count +* [in] value to set +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_vl_stall_count +* NAME +* ib_port_info_get_vl_stall_count +* +* DESCRIPTION +* Gets the VL Stall Count which define the number of contiguous +* HLL (hoq) drops that will put the VL into stalled mode +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_vl_stall_count( + IN const ib_port_info_t* const p_pi ) +{ + return( (uint8_t)(p_pi->vl_stall_life & 0xe0) >> 5); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* vl stall count +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_lmc +* NAME +* ib_port_info_get_lmc +* +* DESCRIPTION +* Returns the LMC value assigned to this port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_lmc( + IN const ib_port_info_t* const p_pi ) +{ + return( (uint8_t)(p_pi->mkey_lmc & IB_PORT_LMC_MASK) ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the LMC value assigned to this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_lmc +* NAME +* ib_port_info_set_lmc +* +* DESCRIPTION +* Sets the LMC value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_lmc( + IN ib_port_info_t* const p_pi, + IN const uint8_t lmc ) +{ + CL_ASSERT( lmc <= IB_PORT_LMC_MAX ); + p_pi->mkey_lmc = (uint8_t)((p_pi->mkey_lmc & 0xF8) | lmc); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* lmc +* [in] LMC value to set, must be less than 7. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_link_speed_enabled +* NAME +* ib_port_info_get_link_speed_enabled +* +* DESCRIPTION +* Returns the link speed enabled value assigned to this port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_link_speed_enabled( + IN const ib_port_info_t* const p_pi ) +{ + return( (uint8_t)(p_pi->link_speed & IB_PORT_LINK_SPEED_ENABLED_MASK) ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Port state. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_link_speed_enabled +* NAME +* ib_port_info_set_link_speed_enabled +* +* DESCRIPTION +* Sets the link speed enabled value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_link_speed_enabled( + IN ib_port_info_t* const p_pi, + IN const uint8_t link_speed_enabled ) +{ + p_pi->link_speed = (uint8_t)((p_pi->link_speed & 0xF0) | link_speed_enabled ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* link_speed_enabled +* [in] link speed enabled value to set. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_mpb +* NAME +* ib_port_info_get_mpb +* +* DESCRIPTION +* Returns the M_Key protect bits assigned to this port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_mpb( + IN const ib_port_info_t* const p_pi ) +{ + return( (uint8_t)((p_pi->mkey_lmc & IB_PORT_MPB_MASK) >> + IB_PORT_MPB_SHIFT) ); +} +/* +* PARAMETERS +* p_ni +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the M_Key protect bits assigned to this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_mpb +* NAME +* ib_port_info_set_mpb +* +* DESCRIPTION +* Set the M_Key protect bits of this port. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_mpb( + IN ib_port_info_t* p_pi, + IN uint8_t mpb ) +{ + p_pi->mkey_lmc = + (~IB_PORT_MPB_MASK & p_pi->mkey_lmc) | + ( IB_PORT_MPB_MASK & (mpb << IB_PORT_MPB_SHIFT) ); +} +/* +* PARAMETERS +* mpb +* [in] M_Key protect bits +* p_ni +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_local_phy_err_thd +* NAME +* ib_port_info_get_local_phy_err_thd +* +* DESCRIPTION +* Returns the Phy Link Threshold +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_local_phy_err_thd( + IN const ib_port_info_t* const p_pi ) +{ + return (uint8_t)( (p_pi->error_threshold & 0xF0) >> 4); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the Phy Link error threshold assigned to this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_overrun_err_thd +* NAME +* ib_port_info_get_local_overrun_err_thd +* +* DESCRIPTION +* Returns the Credits Overrun Errors Threshold +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_overrun_err_thd( + IN const ib_port_info_t* const p_pi ) +{ + return (uint8_t)(p_pi->error_threshold & 0x0F); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the Credits Overrun errors threshold assigned to this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_phy_and_overrun_err_thd +* NAME +* ib_port_info_set_phy_and_overrun_err_thd +* +* DESCRIPTION +* Sets the Phy Link and Credits Overrun Errors Threshold +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_phy_and_overrun_err_thd( + IN ib_port_info_t* const p_pi, + IN uint8_t phy_threshold, + IN uint8_t overrun_threshold ) +{ + p_pi->error_threshold = + (uint8_t)( ((phy_threshold & 0x0F) << 4) | (overrun_threshold & 0x0F) ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* phy_threshold +* [in] Physical Link Errors Threshold above which Trap 129 is generated +* +* overrun_threshold +* [in] Credits overrun Errors Threshold above which Trap 129 is generated +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +typedef uint8_t ib_svc_name_t[64]; + +#include +typedef struct _ib_service_record +{ + ib_net64_t service_id; + ib_gid_t service_gid; + ib_net16_t service_pkey; + ib_net16_t resv; + ib_net32_t service_lease; + uint8_t service_key[16]; + ib_svc_name_t service_name; + uint8_t service_data8[16]; + ib_net16_t service_data16[8]; + ib_net32_t service_data32[4]; + ib_net64_t service_data64[2]; + +} PACK_SUFFIX ib_service_record_t; +#include + +#include +typedef struct _ib_portinfo_record +{ + ib_net16_t lid; + uint8_t port_num; + uint8_t resv; + ib_port_info_t port_info; + uint8_t pad[6]; + +} PACK_SUFFIX ib_portinfo_record_t; +#include + +#include +typedef struct _ib_link_record +{ + ib_net16_t from_lid; + uint8_t from_port_num; + uint8_t to_port_num; + ib_net16_t to_lid; + uint8_t pad[2]; + +} PACK_SUFFIX ib_link_record_t; +#include + +#include +typedef struct _ib_sminfo_record +{ + ib_net16_t lid; + uint16_t resv0; + ib_sm_info_t sm_info; + uint8_t pad[7]; + +} PACK_SUFFIX ib_sminfo_record_t; +#include + +/****s* IBA Base: Types/ib_lft_record_t +* NAME +* ib_lft_record_t +* +* DESCRIPTION +* IBA defined LinearForwardingTableRecord (15.2.5.6) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_lft_record +{ + ib_net16_t lid; + ib_net16_t block_num; + uint32_t resv0; + uint8_t lft[64]; +} PACK_SUFFIX ib_lft_record_t; +#include +/************/ + +/****s* IBA Base: Types/ib_mft_record_t +* NAME +* ib_mft_record_t +* +* DESCRIPTION +* IBA defined MulticastForwardingTableRecord (15.2.5.8) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_mft_record +{ + ib_net16_t lid; + ib_net16_t position_block_num; + uint32_t resv0; + ib_net16_t mft[IB_MCAST_BLOCK_SIZE]; +} PACK_SUFFIX ib_mft_record_t; +#include +/************/ + +/****s* IBA Base: Types/ib_switch_info_t +* NAME +* ib_switch_info_t +* +* DESCRIPTION +* IBA defined SwitchInfo. (14.2.5.4) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_switch_info +{ + ib_net16_t lin_cap; + ib_net16_t rand_cap; + ib_net16_t mcast_cap; + ib_net16_t lin_top; + uint8_t def_port; + uint8_t def_mcast_pri_port; + uint8_t def_mcast_not_port; + uint8_t life_state; + ib_net16_t lids_per_port; + ib_net16_t enforce_cap; + uint8_t flags; + +} PACK_SUFFIX ib_switch_info_t; +#include +/************/ + +#include +typedef struct _ib_switch_info_record +{ + ib_net16_t lid; + uint16_t resv0; + ib_switch_info_t switch_info; + uint8_t pad[3]; + +} PACK_SUFFIX ib_switch_info_record_t; +#include + +#define IB_SWITCH_PSC 0x04 + +/****f* IBA Base: Types/ib_switch_info_get_state_change +* NAME +* ib_switch_info_get_state_change +* +* DESCRIPTION +* Returns the value of the state change flag. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_switch_info_get_state_change( + IN const ib_switch_info_t* const p_si ) +{ + return( (p_si->life_state & IB_SWITCH_PSC) == IB_SWITCH_PSC ); +} +/* +* PARAMETERS +* p_si +* [in] Pointer to a SwitchInfo attribute. +* +* RETURN VALUES +* Returns the value of the state change flag. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_switch_info_clear_state_change +* NAME +* ib_switch_info_clear_state_change +* +* DESCRIPTION +* Clears the switch's state change bit. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_switch_info_clear_state_change( + IN ib_switch_info_t* const p_si ) +{ + p_si->life_state = (uint8_t)(p_si->life_state & 0xFB); +} +/* +* PARAMETERS +* p_ni +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the LMC value assigned to this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_switch_info_is_enhanced_port0 +* NAME +* ib_switch_info_is_enhanced_port0 +* +* DESCRIPTION +* Returns TRUE if the enhancedPort0 bit is on (meaning the switch +* port zero supports enhanced functions). +* Returns FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_switch_info_is_enhanced_port0( + IN const ib_switch_info_t* const p_si ) +{ + return( (p_si->flags & 0x08) == 0x08 ); +} +/* +* PARAMETERS +* p_si +* [in] Pointer to a SwitchInfo attribute. +* +* RETURN VALUES +* Returns TRUE if the switch supports enhanced port 0. FALSE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* IBA Base: Types/ib_guid_info_t +* NAME +* ib_guid_info_t +* +* DESCRIPTION +* IBA defined GuidInfo. (14.2.5.5) +* +* SYNOPSIS +*/ +#define GUID_TABLE_MAX_ENTRIES 8 + +#include +typedef struct _ib_guid_info +{ + ib_net64_t guid[GUID_TABLE_MAX_ENTRIES]; + +} PACK_SUFFIX ib_guid_info_t; +#include +/************/ + +#include +typedef struct _ib_guidinfo_record +{ + ib_net16_t lid; + uint8_t block_num; + uint8_t resv; + uint32_t reserved; + ib_guid_info_t guid_info; +} PACK_SUFFIX ib_guidinfo_record_t; +#include + +#define IB_MULTIPATH_MAX_GIDS 11 /* Support max that can fit into first MAD (for now) */ + +#include +typedef struct _ib_multipath_rec_t +{ + ib_net32_t hop_flow_raw; + uint8_t tclass; + uint8_t num_path; + ib_net16_t pkey; + uint8_t resv0; + uint8_t sl; + uint8_t mtu; + uint8_t rate; + uint8_t pkt_life; + uint8_t resv1; + uint8_t independence; /* formerly resv2 */ + uint8_t sgid_count; + uint8_t dgid_count; + uint8_t resv3[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. +* +* 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. +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_num_path +* NAME +* ib_multipath_rec_num_path +* +* DESCRIPTION +* Get max number of paths to return. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_num_path( + IN const ib_multipath_rec_t* const p_rec ) +{ + return( p_rec->num_path &0x7F ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Maximum number of paths to return for each unique SGID_DGID combination. +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_sl +* NAME +* ib_multipath_rec_sl +* +* DESCRIPTION +* Get multipath service level. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_sl( + IN const ib_multipath_rec_t* const p_rec ) +{ + return( (uint8_t)((cl_ntoh16( p_rec->sl )) & 0xF) ); +} +/* +* 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_mtu +* NAME +* ib_multipath_rec_mtu +* +* DESCRIPTION +* Get encoded path MTU. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_mtu( + IN const ib_multipath_rec_t* const p_rec ) +{ + return( (uint8_t)(p_rec->mtu & IB_MULTIPATH_REC_BASE_MASK) ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Encoded path MTU. +* 1: 256 +* 2: 512 +* 3: 1024 +* 4: 2048 +* 5: 4096 +* others: reserved +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_mtu_sel +* NAME +* ib_multipath_rec_mtu_sel +* +* DESCRIPTION +* Get encoded multipath MTU selector. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_mtu_sel( + IN const ib_multipath_rec_t* const p_rec ) +{ + return( (uint8_t)((p_rec->mtu & IB_MULTIPATH_REC_SELECTOR_MASK) >> 6) ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Encoded path MTU selector value (for queries). +* 0: greater than MTU specified +* 1: less than MTU specified +* 2: exactly the MTU specified +* 3: largest MTU available +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_rate +* NAME +* ib_multipath_rec_rate +* +* DESCRIPTION +* Get encoded multipath rate. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_rate( + IN const ib_multipath_rec_t* const p_rec ) +{ + return( (uint8_t)(p_rec->rate & IB_MULTIPATH_REC_BASE_MASK) ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Encoded multipath rate. +* 2: 2.5 Gb/sec. +* 3: 10 Gb/sec. +* 4: 30 Gb/sec. +* others: reserved +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_rate_sel +* NAME +* ib_multipath_rec_rate_sel +* +* DESCRIPTION +* Get encoded multipath rate selector. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_rate_sel( + IN const ib_multipath_rec_t* const p_rec ) +{ + return( (uint8_t)((p_rec->rate & IB_MULTIPATH_REC_SELECTOR_MASK) >> 6) ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Encoded path rate selector value (for queries). +* 0: greater than rate specified +* 1: less than rate specified +* 2: exactly the rate specified +* 3: largest rate available +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_pkt_life +* NAME +* ib_multipath_rec_pkt_life +* +* DESCRIPTION +* Get encoded multipath pkt_life. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_pkt_life( + IN const ib_multipath_rec_t* const p_rec ) +{ + return( (uint8_t)(p_rec->pkt_life & IB_MULTIPATH_REC_BASE_MASK) ); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Encoded multipath pkt_life = 4.096 µ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 +*/ +static inline uint8_t OSM_API +ib_multipath_rec_pkt_life_sel( + IN const ib_multipath_rec_t* const p_rec ) +{ + return( (uint8_t)((p_rec->pkt_life & IB_MULTIPATH_REC_SELECTOR_MASK) >> 6 )); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Encoded path pkt_lifetime selector value (for queries). +* 0: greater than rate specified +* 1: less than rate specified +* 2: exactly the rate specified +* 3: smallest packet lifetime available +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +#define IB_NUM_PKEY_ELEMENTS_IN_BLOCK 32 +/****s* IBA Base: Types/ib_pkey_table_t +* NAME +* ib_pkey_table_t +* +* DESCRIPTION +* IBA defined PKey table. (14.2.5.7) +* +* SYNOPSIS +*/ + +#include +typedef struct _ib_pkey_table +{ + ib_net16_t pkey_entry[IB_NUM_PKEY_ELEMENTS_IN_BLOCK]; + +} PACK_SUFFIX ib_pkey_table_t; +#include +/************/ + +/****s* IBA Base: Types/ib_pkey_table_record_t +* NAME +* ib_pkey_table_record_t +* +* DESCRIPTION +* IBA defined P_Key Table Record for SA Query. (15.2.5.11) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_pkey_table_record +{ + ib_net16_t lid; // for CA: lid of port, for switch lid of port 0 + uint16_t block_num; + uint8_t port_num; // for switch: port number, for CA: reserved + uint8_t reserved1; + uint16_t reserved2; + ib_pkey_table_t pkey_tbl; + +} PACK_SUFFIX ib_pkey_table_record_t; +#include +/************/ + +#define IB_DROP_VL 15 +#define IB_MAX_NUM_VLS 16 +/****s* IBA Base: Types/ib_slvl_table_t +* NAME +* ib_slvl_table_t +* +* DESCRIPTION +* IBA defined SL2VL Mapping Table Attribute. (14.2.5.8) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_slvl_table +{ + uint8_t raw_vl_by_sl[IB_MAX_NUM_VLS/2]; +} PACK_SUFFIX ib_slvl_table_t; +#include +/************/ + +/****s* IBA Base: Types/ib_slvl_table_record_t +* NAME +* ib_slvl_table_record_t +* +* DESCRIPTION +* IBA defined SL to VL Mapping Table Record for SA Query. (15.2.5.4) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_slvl_table_record +{ + ib_net16_t lid; // for CA: lid of port, for switch lid of port 0 + uint8_t in_port_num; // reserved for CAs + uint8_t out_port_num; // reserved for CAs + uint32_t resv; + ib_slvl_table_t slvl_tbl; + +} PACK_SUFFIX ib_slvl_table_record_t; +#include +/************/ + +/****f* IBA Base: Types/ib_slvl_table_set +* NAME +* ib_slvl_table_set +* +* DESCRIPTION +* Set slvl table entry. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_slvl_table_set( + IN ib_slvl_table_t* p_slvl_tbl, + IN uint8_t sl_index, + IN uint8_t vl ) +{ + uint8_t idx = sl_index/2; + CL_ASSERT(vl <= 15); + CL_ASSERT(sl_index <= 15); + + if (sl_index%2) + { + /* this is an odd sl. Need to update the ls bits */ + p_slvl_tbl->raw_vl_by_sl[idx] = ( p_slvl_tbl->raw_vl_by_sl[idx] & 0xF0 ) | vl ; + } + else + { + /* this is an even sl. Need to update the ms bits */ + p_slvl_tbl->raw_vl_by_sl[idx] = ( vl << 4 ) | ( p_slvl_tbl->raw_vl_by_sl[idx] & 0x0F ); + } +} +/* +* PARAMETERS +* p_slvl_tbl +* [in] pointer to ib_slvl_table_t object. +* +* sl_index +* [in] the sl index in the table to be updated. +* +* vl +* [in] the vl value to update for that sl. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* ib_slvl_table_t +*********/ + +/****f* IBA Base: Types/ib_slvl_table_get +* NAME +* ib_slvl_table_get +* +* DESCRIPTION +* Get slvl table entry. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_slvl_table_get( + IN const ib_slvl_table_t* p_slvl_tbl, + IN uint8_t sl_index ) +{ + uint8_t idx = sl_index/2; + CL_ASSERT(sl_index <= 15); + + if (sl_index%2) + { + /* this is an odd sl. Need to return the ls bits. */ + return ( p_slvl_tbl->raw_vl_by_sl[idx] & 0x0F ); + } + else + { + /* this is an even sl. Need to return the ms bits. */ + return ( (p_slvl_tbl->raw_vl_by_sl[idx] & 0xF0) >> 4 ); + } +} +/* +* PARAMETERS +* p_slvl_tbl +* [in] pointer to ib_slvl_table_t object. +* +* sl_index +* [in] the sl index in the table whose value should be returned. +* +* RETURN VALUES +* vl for the requested sl_index. +* +* NOTES +* +* SEE ALSO +* ib_slvl_table_t +*********/ + +/****s* IBA Base: Types/ib_vl_arb_element_t +* NAME +* ib_vl_arb_element_t +* +* DESCRIPTION +* IBA defined VL Arbitration Table Element. (14.2.5.9) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_vl_arb_element +{ + uint8_t vl; + uint8_t weight; +} PACK_SUFFIX ib_vl_arb_element_t; +#include +/************/ + +#define IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK 32 + +/****s* IBA Base: Types/ib_vl_arb_table_t +* NAME +* ib_vl_arb_table_t +* +* DESCRIPTION +* IBA defined VL Arbitration Table. (14.2.5.9) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_vl_arb_table +{ + ib_vl_arb_element_t vl_entry[IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]; +} PACK_SUFFIX ib_vl_arb_table_t; +#include +/************/ + +/****s* IBA Base: Types/ib_vl_arb_table_record_t +* NAME +* ib_vl_arb_table_record_t +* +* DESCRIPTION +* IBA defined VL Arbitration Table Record for SA Query. (15.2.5.9) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_vl_arb_table_record +{ + ib_net16_t lid; // for CA: lid of port, for switch lid of port 0 + uint8_t port_num; + uint8_t block_num; + uint32_t reserved; + ib_vl_arb_table_t vl_arb_tbl; +} PACK_SUFFIX ib_vl_arb_table_record_t; +#include +/************/ + +/* + * Global route header information received with unreliable datagram messages + */ +#include +typedef struct _ib_grh +{ + ib_net32_t ver_class_flow; + 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 +*/ +static inline void OSM_API +ib_grh_get_ver_class_flow( + IN const ib_net32_t ver_class_flow, + OUT uint8_t* const p_ver, + OUT uint8_t* const p_tclass, + OUT uint32_t* const p_flow_lbl ) +{ + ib_net32_t tmp_ver_class_flow; + + if (p_ver) + *p_ver = (uint8_t)(ver_class_flow & 0x0f); + + tmp_ver_class_flow = ver_class_flow >> 4; + + if (p_tclass) + *p_tclass = (uint8_t)(tmp_ver_class_flow & 0xff); + + tmp_ver_class_flow = tmp_ver_class_flow >> 8; + + if (p_flow_lbl) + *p_flow_lbl = tmp_ver_class_flow & 0xfffff; +} +/* +* PARAMETERS +* ver_class_flow +* [in] the version, traffic class and flow label info. +* +* RETURN VALUES +* p_ver +* [out] pointer to the version info. +* +* p_tclass +* [out] pointer to the traffic class info. +* +* p_flow_lbl +* [out] pointer to the flow label info +* +* NOTES +* +* SEE ALSO +* ib_grh_t +*********/ + +/****f* IBA Base: Types/ib_grh_set_ver_class_flow +* NAME +* ib_grh_set_ver_class_flow +* +* DESCRIPTION +* Set encoded version, traffic class and flow label in grh +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_grh_set_ver_class_flow( + IN const uint8_t ver, + IN const uint8_t tclass, + IN const uint32_t flow_lbl ) +{ + ib_net32_t ver_class_flow; + + ver_class_flow = flow_lbl; + ver_class_flow = ver_class_flow << 8; + ver_class_flow = ver_class_flow | tclass; + ver_class_flow = ver_class_flow << 4; + ver_class_flow = ver_class_flow | ver; + return (ver_class_flow); +} +/* +* PARAMETERS +* ver +* [in] the version info. +* +* tclass +* [in] the traffic class info. +* +* flow_lbl +* [in] the flow label info +* +* RETURN VALUES +* ver_class_flow +* [out] the version, traffic class and flow label info. +* +* NOTES +* +* SEE ALSO +* ib_grh_t +*********/ + +/****s* IBA Base: Types/ib_member_rec_t +* NAME +* ib_member_rec_t +* +* DESCRIPTION +* Multicast member record, used to create, join, and leave multicast +* groups. +* +* SYNOPSIS +*/ +#include +typedef struct _ib_member_rec +{ + ib_gid_t mgid; + ib_gid_t port_gid; + ib_net32_t qkey; + ib_net16_t mlid; + uint8_t mtu; + uint8_t tclass; + ib_net16_t pkey; + uint8_t rate; + uint8_t pkt_life; + ib_net32_t sl_flow_hop; + uint8_t scope_state; + uint8_t proxy_join:1; + uint8_t reserved[2]; + uint8_t pad[4]; + +} PACK_SUFFIX ib_member_rec_t; +#include +/* +* FIELDS +* mgid +* Multicast GID address for this multicast group. +* +* port_gid +* Valid GID of the endpoint joining this multicast group. +* +* qkey +* Q_Key to be sued by this multicast group. +* +* mlid +* Multicast LID for this multicast group. +* +* mtu +* MTU and MTU selector fields to use on this path +* +* tclass +* Another global routing parameter. +* +* pkey +* Partition key (P_Key) to use for this member. +* +* rate +* Rate and rate selector fields to use on this path. +* +* pkt_life +* Packet lifetime +* +* sl_flow_hop +* Global routing parameters: service level, hop count, and flow label. +* +* scope_state +* MGID scope and JoinState of multicast request. +* +* proxy_join +* Enables others in the Partition to proxy add/remove from the group +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_member_get_sl_flow_hop +* NAME +* ib_member_get_sl_flow_hop +* +* DESCRIPTION +* Get encoded sl, flow label, and hop limit +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_member_get_sl_flow_hop( + IN const ib_net32_t sl_flow_hop, + OUT uint8_t* const p_sl, + OUT uint32_t* const p_flow_lbl, + OUT uint8_t* const p_hop ) +{ + uint32_t tmp; + + tmp = cl_ntoh32(sl_flow_hop); + if (p_hop) + *p_hop = (uint8_t)tmp; + tmp >>= 8; + + if (p_flow_lbl) + *p_flow_lbl = (uint32_t)(tmp & 0xfffff); + tmp >>= 20; + + if (p_sl) + *p_sl = (uint8_t)tmp; +} +/* +* PARAMETERS +* sl_flow_hop +* [in] the sl, flow label, and hop limit of MC Group +* +* RETURN VALUES +* p_sl +* [out] pointer to the service level +* +* p_flow_lbl +* [out] pointer to the flow label info +* +* p_hop +* [out] pointer to the hop count limit. +* +* NOTES +* +* SEE ALSO +* ib_member_rec_t +*********/ + +/****f* IBA Base: Types/ib_member_set_sl_flow_hop +* NAME +* ib_member_set_sl_flow_hop +* +* DESCRIPTION +* Set encoded sl, flow label, and hop limit +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_member_set_sl_flow_hop( + IN const uint8_t sl, + IN const uint32_t flow_label, + IN const uint8_t hop_limit ) +{ + uint32_t tmp; + + tmp = (sl << 28) | ((flow_label & 0xfffff) << 8) | hop_limit; + return cl_hton32(tmp); +} +/* +* PARAMETERS +* sl +* [in] the service level. +* +* flow_lbl +* [in] the flow label info +* +* hop_limit +* [in] the hop limit. +* +* RETURN VALUES +* sl_flow_hop +* [out] the encoded sl, flow label, and hop limit +* +* NOTES +* +* SEE ALSO +* ib_member_rec_t +*********/ + +/****f* IBA Base: Types/ib_member_get_scope_state +* NAME +* ib_member_get_scope_state +* +* DESCRIPTION +* Get encoded MGID scope and JoinState +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_member_get_scope_state( + IN const uint8_t scope_state, + OUT uint8_t* const p_scope, + OUT uint8_t* const p_state ) +{ + uint8_t tmp_scope_state; + + if (p_state) + *p_state = (uint8_t)(scope_state & 0x0f); + + tmp_scope_state = scope_state >> 4; + + if (p_scope) + *p_scope = (uint8_t)(tmp_scope_state & 0x0f); + +} +/* +* PARAMETERS +* scope_state +* [in] the scope and state +* +* RETURN VALUES +* p_scope +* [out] pointer to the MGID scope +* +* p_state +* [out] pointer to the join state +* +* NOTES +* +* SEE ALSO +* ib_member_rec_t +*********/ + +/****f* IBA Base: Types/ib_member_set_scope_state +* NAME +* ib_member_set_scope_state +* +* DESCRIPTION +* Set encoded version, MGID scope and JoinState +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_member_set_scope_state( + IN const uint8_t scope, + IN const uint8_t state ) +{ + uint8_t scope_state; + + scope_state = scope; + scope_state = scope_state << 4; + scope_state = scope_state | state; + return (scope_state); +} +/* +* PARAMETERS +* scope +* [in] the MGID scope +* +* state +* [in] the JoinState +* +* RETURN VALUES +* scope_state +* [out] the encoded one +* +* NOTES +* +* SEE ALSO +* ib_member_rec_t +*********/ + +/****f* IBA Base: Types/ib_member_set_join_state +* NAME +* ib_member_set_join_state +* +* DESCRIPTION +* Set JoinState +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_member_set_join_state( + IN OUT ib_member_rec_t *p_mc_rec, + IN const uint8_t state ) +{ + /* keep the scope as it is */ + p_mc_rec->scope_state = (p_mc_rec->scope_state & 0xF0) | (0x0f & state); +} +/* +* PARAMETERS +* p_mc_rec +* [in] pointer to the member record +* +* state +* [in] the JoinState +* +* RETURN VALUES +* NONE +* +* NOTES +* +* SEE ALSO +* ib_member_rec_t +*********/ + +/* + * Join State Codes: + */ +#define IB_MC_REC_STATE_FULL_MEMBER 0x01 +#define IB_MC_REC_STATE_NON_MEMBER 0x02 +#define IB_MC_REC_STATE_SEND_ONLY_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 + ib_net16_t pad2; + ib_net32_t new_cap_mask; // new capability mask + } 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 with sw info 53 + { + ib_net16_t data_valid; // 2 + ib_net16_t lid1; // 2 + ib_net16_t lid2; // 2 + ib_net32_t key; // 4 + uint8_t sl; // 1 + ib_net32_t qp1; // 4 + uint8_t qp2_msb; // 1 + ib_net16_t qp2_lsb; // 2 + ib_gid_t gid1; // 16 + ib_gid_t gid2; // 16 + ib_net16_t sw_lid; // 2 + uint8_t port_no; // 1 + } PACK_SUFFIX ntc_259; + + } data_details; + + ib_gid_t issuer_gid; // 16 80 + +} PACK_SUFFIX ib_mad_notice_attr_t; +#include + +/****f* IBA Base: Types/ib_notice_is_generic +* NAME +* ib_notice_is_generic +* +* DESCRIPTION +* Check if the notice is generic +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_notice_is_generic( + IN const ib_mad_notice_attr_t *p_ntc ) +{ + return (p_ntc->generic_type & 0x80); +} +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* RETURN VALUES +* TRUE if mad is generic +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_get_type +* NAME +* ib_notice_get_type +* +* DESCRIPTION +* Get the notice type +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_notice_get_type( + IN const ib_mad_notice_attr_t *p_ntc ) +{ + return p_ntc->generic_type & 0x7f; +} +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* RETURN VALUES +* TRUE if mad is generic +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_get_prod_type +* NAME +* ib_notice_get_prod_type +* +* DESCRIPTION +* Get the notice Producer Type of Generic Notice +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_notice_get_prod_type( + IN const ib_mad_notice_attr_t *p_ntc ) +{ + uint32_t pt; + + pt = cl_ntoh16(p_ntc->g_or_v.generic.prod_type_lsb) | + (p_ntc->g_or_v.generic.prod_type_msb << 16); + return cl_hton32(pt); +} +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* RETURN VALUES +* The producer type +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_set_prod_type +* NAME +* ib_notice_set_prod_type +* +* DESCRIPTION +* Set the notice Producer Type of Generic Notice +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_notice_set_prod_type( + IN ib_mad_notice_attr_t *p_ntc, + IN ib_net32_t prod_type_val ) +{ + uint32_t ptv = cl_ntoh32(prod_type_val); + p_ntc->g_or_v.generic.prod_type_lsb = cl_hton16((uint16_t)(ptv & 0x0000ffff)); + p_ntc->g_or_v.generic.prod_type_msb = (uint8_t)( (ptv & 0x00ff0000) >> 16); +} +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* prod_type +* [in] The producer Type code +* +* RETURN VALUES +* None +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_set_prod_type_ho +* NAME +* ib_notice_set_prod_type_ho +* +* DESCRIPTION +* Set the notice Producer Type of Generic Notice given Host Order +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_notice_set_prod_type_ho( + IN ib_mad_notice_attr_t *p_ntc, + IN uint32_t prod_type_val_ho ) +{ + p_ntc->g_or_v.generic.prod_type_lsb = + cl_hton16( (uint16_t)(prod_type_val_ho & 0x0000ffff) ); + p_ntc->g_or_v.generic.prod_type_msb = + (uint8_t)( (prod_type_val_ho & 0x00ff0000) >> 16); +} +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* prod_type +* [in] The producer Type code in host order +* +* RETURN VALUES +* None +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_get_vend_id +* NAME +* ib_notice_get_vend_id +* +* DESCRIPTION +* Get the Vendor Id of Vendor type Notice +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_notice_get_vend_id( + IN const ib_mad_notice_attr_t *p_ntc ) +{ + uint32_t vi; + + vi = cl_ntoh16(p_ntc->g_or_v.vend.vend_id_lsb) | + (p_ntc->g_or_v.vend.vend_id_msb << 16); + return cl_hton32(vi); +} +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* RETURN VALUES +* The Vendor Id of Vendor type Notice +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_set_vend_id +* NAME +* ib_notice_set_vend_id +* +* DESCRIPTION +* Set the notice Producer Type of Generic Notice +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_notice_set_vend_id( + IN ib_mad_notice_attr_t *p_ntc, + IN ib_net32_t vend_id ) +{ + uint32_t vi = cl_ntoh32(vend_id); + p_ntc->g_or_v.vend.vend_id_lsb = cl_hton16((uint16_t)(vi & 0x0000ffff)); + p_ntc->g_or_v.vend.vend_id_msb = (uint8_t)((vi & 0x00ff0000) >> 16); +} +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* vend_id +* [in] The producer Type code +* +* RETURN VALUES +* None +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_set_vend_id_ho +* NAME +* ib_notice_set_vend_id_ho +* +* DESCRIPTION +* Set the notice Producer Type of Generic Notice given a host order value +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_notice_set_vend_id_ho( + IN ib_mad_notice_attr_t *p_ntc, + IN uint32_t vend_id_ho ) +{ + p_ntc->g_or_v.vend.vend_id_lsb = + cl_hton16((uint16_t)(vend_id_ho & 0x0000ffff)); + p_ntc->g_or_v.vend.vend_id_msb = + (uint8_t)((vend_id_ho & 0x00ff0000) >> 16); +} +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* vend_id_ho +* [in] The producer Type code in host order +* +* RETURN VALUES +* None +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +#include +typedef struct _ib_inform_info +{ + ib_gid_t gid; + ib_net16_t lid_range_begin; + ib_net16_t lid_range_end; + ib_net16_t reserved1; + uint8_t is_generic; + uint8_t subscribe; + ib_net16_t trap_type; + union _inform_g_or_v + { + struct _inform_generic + { + ib_net16_t trap_num; + ib_net32_t qpn_resp_time_val; + uint8_t reserved2; + uint8_t node_type_msb; + ib_net16_t node_type_lsb; + } PACK_SUFFIX generic; + + struct _inform_vend + { + ib_net16_t dev_id; + ib_net32_t qpn_resp_time_val; + uint8_t reserved2; + uint8_t vendor_id_msb; + ib_net16_t vendor_id_lsb; + } PACK_SUFFIX vend; + + } PACK_SUFFIX g_or_v; + +} PACK_SUFFIX ib_inform_info_t; +#include + +/****f* IBA Base: Types/ib_inform_info_get_qpn_resp_time +* NAME +* ib_inform_info_get_qpn_resp_time +* +* DESCRIPTION +* Get QPN of the inform info +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_inform_info_get_qpn_resp_time( + IN const ib_net32_t qpn_resp_time_val, + OUT ib_net32_t* const p_qpn, + OUT uint8_t* const p_resp_time_val ) +{ + uint32_t tmp = cl_ntoh32(qpn_resp_time_val); + + if (p_qpn) + *p_qpn = cl_hton32((tmp & 0xffffff00) >> 8); + + if (p_resp_time_val) + *p_resp_time_val = (uint8_t)(tmp & 0x0000001f); +} +/* +* PARAMETERS +* qpn_resp_time_val +* [in] the qpn and resp time val from the mad +* +* RETURN VALUES +* p_qpn +* [out] pointer to the qpn +* +* p_state +* [out] pointer to the resp time val +* +* NOTES +* +* SEE ALSO +* ib_inform_info_t +*********/ + +/****f* IBA Base: Types/ib_inform_info_set_qpn +* NAME +* ib_inform_info_set_qpn +* +* DESCRIPTION +* Set the QPN of the inform info +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_inform_info_set_qpn( + IN ib_inform_info_t *p_ii, + IN ib_net32_t const qpn) +{ + uint32_t tmp = cl_ntoh32(p_ii->g_or_v.generic.qpn_resp_time_val); + + p_ii->g_or_v.generic.qpn_resp_time_val = + cl_hton32( + (tmp & 0x000000ff) | + ((cl_ntoh32(qpn) << 8) & 0xffffff00) + ); +} +/* +* PARAMETERS +* +* NOTES +* +* SEE ALSO +* ib_inform_info_t +*********/ + +/****f* IBA Base: Types/ib_inform_info_get_prod_type +* NAME +* ib_inform_info_get_prod_type +* +* DESCRIPTION +* Get Producer Type of the Inform Info +* 13.4.8.3 InformInfo +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_inform_info_get_prod_type(IN const ib_inform_info_t * p_inf) +{ + uint32_t nt; + + nt = cl_ntoh16(p_inf->g_or_v.generic.node_type_lsb) | + (p_inf->g_or_v.generic.node_type_msb << 16); + return cl_hton32(nt); +} + +/* +* PARAMETERS +* p_inf +* [in] pointer to an inform info +* +* RETURN VALUES +* The producer type +* +* NOTES +* +* SEE ALSO +* ib_inform_info_t +*********/ + +/****f* IBA Base: Types/ib_inform_info_get_node_type +* NAME +* ib_inform_info_get_node_type +* +* DESCRIPTION +* Get Node Type of the Inform Info +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_inform_info_get_node_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 node type +* +* NOTES +* +* SEE ALSO +* ib_inform_info_t +*********/ + +/****f* IBA Base: Types/ib_inform_info_get_vend_id +* NAME +* ib_inform_info_get_vend_id +* +* DESCRIPTION +* Get Node Type of the Inform Info +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_inform_info_get_vend_id( + IN const ib_inform_info_t *p_inf) +{ + uint32_t vi; + + vi = cl_ntoh16(p_inf->g_or_v.vend.vendor_id_lsb) | + (p_inf->g_or_v.vend.vendor_id_msb << 16); + return cl_hton32(vi); +} +/* +* PARAMETERS +* p_inf +* [in] pointer to an inform info +* +* RETURN VALUES +* The node type +* +* NOTES +* +* SEE ALSO +* ib_inform_info_t +*********/ + +/****s* IBA Base: Types/ib_inform_info_record_t +* NAME +* ib_inform_info_record_t +* +* DESCRIPTION +* IBA defined InformInfo Record. (15.2.5.12) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_inform_info_record +{ + ib_gid_t subscriber_gid; + ib_net16_t subscriber_enum; + uint8_t reserved[6]; + ib_inform_info_t inform_info; + uint8_t pad[4]; +} PACK_SUFFIX ib_inform_info_record_t; +#include + +/****d* IBA Base: Types/DM_SVC_NAME +* NAME +* DM_SVC_NAME +* +* DESCRIPTION +* IBA defined Device Management service name (16.3) +* +* SYNOPSIS +*/ +#define DM_SVC_NAME "DeviceManager.IBTA" +/* +* SEE ALSO +*********/ + +/****s* IBA Base: Types/ib_dm_mad_t +* NAME +* ib_dm_mad_t +* +* DESCRIPTION +* IBA defined Device Management MAD (16.3.1) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_dm_mad +{ + ib_mad_t header; + uint8_t resv[40]; + +#define IB_DM_DATA_SIZE 192 + uint8_t data[IB_DM_DATA_SIZE]; + +} PACK_SUFFIX ib_dm_mad_t; +#include +/* +* FIELDS +* header +* Common MAD header. +* +* resv +* Reserved. +* +* data +* Device Management payload. The structure and content of this field +* depend upon the method, attr_id, and attr_mod fields in the header. +* +* SEE ALSO +* ib_mad_t +*********/ + +/****s* IBA Base: Types/ib_iou_info_t +* NAME +* ib_iou_info_t +* +* DESCRIPTION +* IBA defined IO Unit information structure (16.3.3.3) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_iou_info +{ + ib_net16_t change_id; + uint8_t max_controllers; + uint8_t diag_rom; + +#define IB_DM_CTRL_LIST_SIZE 128 + + uint8_t controller_list[IB_DM_CTRL_LIST_SIZE]; +#define IOC_NOT_INSTALLED 0x0 +#define IOC_INSTALLED 0x1 +// Reserved values 0x02-0xE +#define SLOT_DOES_NOT_EXIST 0xF + +} PACK_SUFFIX ib_iou_info_t; +#include +/* +* FIELDS +* change_id +* Value incremented, with rollover, by any change to the controller_list. +* +* max_controllers +* Number of slots in controller_list. +* +* diag_rom +* A byte containing two fields: DiagDeviceID and OptionROM. +* These fields may be read using the ib_iou_info_diag_dev_id +* and ib_iou_info_option_rom functions. +* +* controller_list +* A series of 4-bit nibbles, with each nibble representing a slot +* in the IO Unit. Individual nibbles may be read using the +* ioc_at_slot function. +* +* SEE ALSO +* ib_dm_mad_t, ib_iou_info_diag_dev_id, ib_iou_info_option_rom, ioc_at_slot +*********/ + +/****f* IBA Base: Types/ib_iou_info_diag_dev_id +* NAME +* ib_iou_info_diag_dev_id +* +* DESCRIPTION +* Returns the DiagDeviceID. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_iou_info_diag_dev_id( + IN const ib_iou_info_t* const p_iou_info ) +{ + return( (uint8_t)(p_iou_info->diag_rom >> 6 & 1) ); +} +/* +* PARAMETERS +* p_iou_info +* [in] Pointer to the IO Unit information structure. +* +* RETURN VALUES +* DiagDeviceID field of the IO Unit information. +* +* NOTES +* +* SEE ALSO +* ib_iou_info_t +*********/ + +/****f* IBA Base: Types/ib_iou_info_option_rom +* NAME +* ib_iou_info_option_rom +* +* DESCRIPTION +* Returns the OptionROM. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_iou_info_option_rom( + IN const ib_iou_info_t* const p_iou_info ) +{ + return( (uint8_t)(p_iou_info->diag_rom >> 7) ); +} +/* +* PARAMETERS +* p_iou_info +* [in] Pointer to the IO Unit information structure. +* +* RETURN VALUES +* OptionROM field of the IO Unit information. +* +* NOTES +* +* SEE ALSO +* ib_iou_info_t +*********/ + +/****f* IBA Base: Types/ioc_at_slot +* NAME +* ioc_at_slot +* +* DESCRIPTION +* Returns the IOC value at the specified slot. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ioc_at_slot( + IN const ib_iou_info_t* const p_iou_info, + IN uint8_t slot ) +{ + if( slot >= IB_DM_CTRL_LIST_SIZE ) return SLOT_DOES_NOT_EXIST; + else return (int8_t) + ( (slot%2) ? + ((p_iou_info->controller_list[slot/2] & 0xf0) >> 4 ): + (p_iou_info->controller_list[slot/2] & 0x0f) ); +} +/* +* PARAMETERS +* p_iou_info +* [in] Pointer to the IO Unit information structure. +* +* slot +* [in] Pointer to the IO Unit information structure. +* +* RETURN VALUES +* OptionROM field of the IO Unit information. +* +* NOTES +* +* SEE ALSO +* ib_iou_info_t +*********/ + +/****s* IBA Base: Types/ib_ioc_profile_t +* NAME +* ib_ioc_profile_t +* +* DESCRIPTION +* IBA defined IO Controller profile structure (16.3.3.4) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_ioc_profile +{ + ib_net64_t ioc_guid; + + ib_net32_t vend_id; + + ib_net32_t dev_id; + ib_net16_t dev_ver; + ib_net16_t resv2; + + ib_net32_t subsys_vend_id; + ib_net32_t subsys_id; + + ib_net16_t io_class; + ib_net16_t io_subclass; + ib_net16_t protocol; + ib_net16_t protocol_ver; + + ib_net32_t resv3; + ib_net16_t send_msg_depth; + uint8_t resv4; + uint8_t rdma_read_depth; + ib_net32_t send_msg_size; + ib_net32_t rdma_size; + + uint8_t ctrl_ops_cap; +#define CTRL_OPS_CAP_ST 0x01 +#define CTRL_OPS_CAP_SF 0x02 +#define CTRL_OPS_CAP_RT 0x04 +#define CTRL_OPS_CAP_RF 0x08 +#define CTRL_OPS_CAP_WT 0x10 +#define CTRL_OPS_CAP_WF 0x20 +#define CTRL_OPS_CAP_AT 0x40 +#define CTRL_OPS_CAP_AF 0x80 + + uint8_t resv5; + + uint8_t num_svc_entries; +#define MAX_NUM_SVC_ENTRIES 0xff + + uint8_t resv6[9]; + +#define CTRL_ID_STRING_LEN 64 + char id_string[CTRL_ID_STRING_LEN]; + +} PACK_SUFFIX ib_ioc_profile_t; +#include +/* +* FIELDS +* ioc_guid +* An EUI-64 GUID used to uniquely identify the IO controller. +* +* vend_id +* IO controller vendor ID, IEEE format. +* +* dev_id +* A number assigned by the vendor to identify the type of controller. +* +* dev_ver +* A number assigned by the vendor to identify the divice version. +* +* subsys_vend_id +* ID of the vendor of the enclosure, if any, in which the IO controller +* resides in IEEE format; otherwise zero. +* +* subsys_id +* A number identifying the subsystem where the controller resides. +* +* io_class +* 0x0000 - 0xfffe = reserved for IO classes encompased by InfiniBand +* Architecture. 0xffff = Vendor specific. +* +* io_subclass +* 0x0000 - 0xfffe = reserved for IO subclasses encompased by InfiniBand +* Architecture. 0xffff = Vendor specific. This shall be set to 0xfff +* if the io_class component is 0xffff. +* +* protocol +* 0x0000 - 0xfffe = reserved for IO subclasses encompased by InfiniBand +* Architecture. 0xffff = Vendor specific. This shall be set to 0xfff +* if the io_class component is 0xffff. +* +* protocol_ver +* Protocol specific. +* +* send_msg_depth +* Maximum depth of the send message queue. +* +* rdma_read_depth +* Maximum depth of the per-channel RDMA read queue. +* +* send_msg_size +* Maximum size of send messages. +* +* ctrl_ops_cap +* Supported operation types of this IO controller. A bit set to one +* for affirmation of supported capability. +* +* num_svc_entries +* Number of entries in the service entries table. +* +* id_string +* UTF-8 encoded string for identifying the controller to an operator. +* +* SEE ALSO +* ib_dm_mad_t +*********/ + +static inline uint32_t OSM_API +ib_ioc_profile_get_vend_id( + IN const ib_ioc_profile_t* const p_ioc_profile ) +{ + return( cl_ntoh32(p_ioc_profile->vend_id) >> 8 ); +} + + +static inline void OSM_API +ib_ioc_profile_set_vend_id( + IN ib_ioc_profile_t* const p_ioc_profile, + IN const uint32_t vend_id ) +{ + p_ioc_profile->vend_id = (cl_hton32(vend_id) << 8); +} + +/****s* IBA Base: Types/ib_svc_entry_t +* NAME +* ib_svc_entry_t +* +* DESCRIPTION +* IBA defined IO Controller service entry structure (16.3.3.5) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_svc_entry +{ +#define MAX_SVC_ENTRY_NAME_LEN 40 + char name[MAX_SVC_ENTRY_NAME_LEN]; + + ib_net64_t id; + +} PACK_SUFFIX ib_svc_entry_t; +#include +/* +* FIELDS +* name +* UTF-8 encoded, null-terminated name of the service. +* +* id +* An identifier of the associated Service. +* +* SEE ALSO +* ib_svc_entries_t +*********/ + +/****s* IBA Base: Types/ib_svc_entries_t +* NAME +* ib_svc_entries_t +* +* DESCRIPTION +* IBA defined IO Controller service entry array (16.3.3.5) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_svc_entries +{ +#define SVC_ENTRY_COUNT 4 + ib_svc_entry_t service_entry[SVC_ENTRY_COUNT]; + +} PACK_SUFFIX ib_svc_entries_t; +#include +/* +* FIELDS +* service_entry +* An array of IO controller service entries. +* +* SEE ALSO +* ib_dm_mad_t, ib_svc_entry_t +*********/ + +static inline void OSM_API +ib_dm_get_slot_lo_hi( + IN const ib_net32_t slot_lo_hi, + OUT uint8_t *const p_slot, + OUT uint8_t *const p_lo, + OUT uint8_t *const p_hi ) +{ + ib_net32_t tmp_slot_lo_hi = CL_NTOH32( slot_lo_hi ); + + if( p_slot ) + *p_slot = (uint8_t)( ( tmp_slot_lo_hi >> 16 ) & 0x0f ); + + if( p_hi ) + *p_hi = (uint8_t)( ( tmp_slot_lo_hi >> 8 ) & 0xff ); + + if( p_lo ) + *p_lo = (uint8_t)( ( tmp_slot_lo_hi >> 0 ) & 0xff ); +} + +/* + * IBA defined information describing an I/O controller + */ +#include +typedef struct _ib_ioc_info +{ + ib_net64_t module_guid; + ib_net64_t iou_guid; + ib_ioc_profile_t ioc_profile; + ib_net64_t access_key; + uint16_t initiators_conf; + uint8_t resv[38]; + +} PACK_SUFFIX ib_ioc_info_t; +#include + +/* + * 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_CM_RDMA_PDATA_SIZE 56 +#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 + +/* + * 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_rdd* ib_rdd_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_eec* ib_eec_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; +/* Currently for windows branch, use the extended version of ib special verbs struct + in order to be compliant with Infinicon ib_types; later we'll change it to support + OpenSM ib_types.h */ + +#ifndef WIN32 +/****d* Access Layer/ib_api_status_t +* NAME +* ib_api_status_t +* +* DESCRIPTION +* Function return codes indicating the success or failure of an API call. +* Note that success is indicated by the return value IB_SUCCESS, which +* is always zero. +* +* NOTES +* IB_VERBS_PROCESSING_DONE is used by UVP library to terminate a verbs call +* in the pre-ioctl step itself. +* +* SYNOPSIS +*/ +typedef enum _ib_api_status_t +{ + IB_SUCCESS, + IB_INSUFFICIENT_RESOURCES, + IB_INSUFFICIENT_MEMORY, + IB_INVALID_PARAMETER, + IB_INVALID_SETTING, + IB_NOT_FOUND, + IB_TIMEOUT, + IB_CANCELED, + IB_INTERRUPTED, + IB_INVALID_PERMISSION, + IB_UNSUPPORTED, + IB_OVERFLOW, + IB_MAX_MCAST_QPS_REACHED, + IB_INVALID_QP_STATE, + IB_INVALID_EEC_STATE, + IB_INVALID_APM_STATE, + IB_INVALID_PORT_STATE, + IB_INVALID_STATE, + IB_RESOURCE_BUSY, + IB_INVALID_PKEY, + IB_INVALID_LKEY, + IB_INVALID_RKEY, + IB_INVALID_MAX_WRS, + IB_INVALID_MAX_SGE, + IB_INVALID_CQ_SIZE, + IB_INVALID_SERVICE_TYPE, + IB_INVALID_GID, + IB_INVALID_LID, + IB_INVALID_GUID, + IB_INVALID_GUID_MASK, + IB_INVALID_CA_HANDLE, + IB_INVALID_AV_HANDLE, + IB_INVALID_CQ_HANDLE, + IB_INVALID_EEC_HANDLE, + IB_INVALID_QP_HANDLE, + IB_INVALID_PD_HANDLE, + IB_INVALID_MR_HANDLE, + IB_INVALID_MW_HANDLE, + IB_INVALID_RDD_HANDLE, + IB_INVALID_MCAST_HANDLE, + IB_INVALID_CALLBACK, + IB_INVALID_AL_HANDLE, /* InfiniBand Access Layer */ + IB_INVALID_HANDLE, /* InfiniBand Access Layer */ + IB_ERROR, /* InfiniBand Access Layer */ + IB_REMOTE_ERROR, /* Infiniband Access Layer */ + IB_VERBS_PROCESSING_DONE, /* See Notes above */ + IB_INVALID_WR_TYPE, + IB_QP_IN_TIMEWAIT, + IB_EE_IN_TIMEWAIT, + IB_INVALID_PORT, + IB_NOT_DONE, + IB_UNKNOWN_ERROR /* ALWAYS LAST ENUM VALUE! */ + +} ib_api_status_t; +/*****/ + +OSM_EXPORT const char* ib_error_str[]; + +/****f* IBA Base: Types/ib_get_err_str +* NAME +* ib_get_err_str +* +* DESCRIPTION +* Returns a string for the specified status value. +* +* SYNOPSIS +*/ +static inline const char* OSM_API +ib_get_err_str( + IN ib_api_status_t status ) +{ + if( status > IB_UNKNOWN_ERROR ) + status = IB_UNKNOWN_ERROR; + return( ib_error_str[status] ); +} +/* +* PARAMETERS +* status +* [in] status value +* +* RETURN VALUES +* Pointer to the status description string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****d* Verbs/ib_async_event_t +* NAME +* ib_async_event_t -- Async event types +* +* DESCRIPTION +* This type indicates the reason the async callback was called. +* The context in the ib_event_rec_t indicates the resource context +* that associated with the callback. For example, for IB_AE_CQ_ERROR +* the context provided during the ib_create_cq is returned in the event. +* +* SYNOPSIS +*/ +typedef enum _ib_async_event_t +{ + IB_AE_SQ_ERROR = 1, + IB_AE_SQ_DRAINED, + IB_AE_RQ_ERROR, + IB_AE_CQ_ERROR, + IB_AE_QP_FATAL, + IB_AE_QP_COMM, + IB_AE_QP_APM, + IB_AE_EEC_FATAL, + IB_AE_EEC_COMM, + IB_AE_EEC_APM, + IB_AE_LOCAL_FATAL, + IB_AE_PKEY_TRAP, + IB_AE_QKEY_TRAP, + IB_AE_MKEY_TRAP, + IB_AE_PORT_TRAP, + IB_AE_SYSIMG_GUID_TRAP, + IB_AE_BUF_OVERRUN, + IB_AE_LINK_INTEGRITY, + IB_AE_FLOW_CTRL_ERROR, + IB_AE_BKEY_TRAP, + IB_AE_QP_APM_ERROR, + IB_AE_EEC_APM_ERROR, + IB_AE_WQ_REQ_ERROR, + IB_AE_WQ_ACCESS_ERROR, + IB_AE_PORT_ACTIVE, + IB_AE_PORT_DOWN, + IB_AE_UNKNOWN /* ALWAYS LAST ENUM VALUE */ + +} ib_async_event_t; +/* +* VALUES +* IB_AE_SQ_ERROR +* An error occurred when accessing the send queue of the QP or EEC. +* This event is optional. +* +* IB_AE_SQ_DRAINED +* The send queue of the specified QP has completed the outstanding +* messages in progress when the state change was requested and, if +* applicable, has received all acknowledgements for those messages. +* +* IB_AE_RQ_ERROR +* An error occurred when accessing the receive queue of the QP or EEC. +* This event is optional. +* +* IB_AE_CQ_ERROR +* An error occurred when writing an entry to the CQ. +* +* IB_AE_QP_FATAL +* A catastrophic error occurred while accessing or processing the +* work queue that prevents reporting of completions. +* +* IB_AE_QP_COMM +* The first packet has arrived for the receive work queue where the +* QP is still in the RTR state. +* +* IB_AE_QP_APM +* If alternate path migration is supported, this event indicates that +* the QP connection has migrated to the alternate path. +* +* IB_AE_EEC_FATAL +* If reliable datagram service is supported, this event indicates that +* a catastrophic error occurred while accessing or processing the EEC +* that prevents reporting of completions. +* +* IB_AE_EEC_COMM +* If reliable datagram service is supported, this event indicates that +* the first packet has arrived for the receive work queue where the +* EEC is still in the RTR state. +* +* IB_AE_EEC_APM +* If reliable datagram service and alternate path migration is supported, +* this event indicates that the EEC connection has migrated to the +* alternate path. +* +* IB_AE_LOCAL_FATAL +* A catastrophic HCA error occurred which cannot be attributed to any +* resource; behavior is indeterminate. +* +* IB_AE_PKEY_TRAP +* A PKEY violation was detected. This event is optional. +* +* IB_AE_QKEY_TRAP +* A QKEY violation was detected. This event is optional. +* +* IB_AE_MKEY_TRAP +* An MKEY violation was detected. This event is optional. +* +* IB_AE_PORT_TRAP +* A port capability change was detected. This event is optional. +* +* IB_AE_SYSIMG_GUID_TRAP +* If the system image GUID is supported, this event indicates that the +* system image GUID of this HCA has been changed. This event is +* optional. +* +* IB_AE_BUF_OVERRUN +* The number of consecutive flow control update periods with at least +* one overrun error in each period has exceeded the threshold specified +* in the port info attributes. This event is optional. +* +* IB_AE_LINK_INTEGRITY +* The detection of excessively frequent local physical errors has +* exceeded the threshold specified in the port info attributes. This +* event is optional. +* +* IB_AE_FLOW_CTRL_ERROR +* An HCA watchdog timer monitoring the arrival of flow control updates +* has expired without receiving an update. This event is optional. +* +* IB_AE_BKEY_TRAP +* An BKEY violation was detected. This event is optional. +* +* IB_AE_QP_APM_ERROR +* If alternate path migration is supported, this event indicates that +* an incoming path migration request to this QP was not accepted. +* +* IB_AE_EEC_APM_ERROR +* If reliable datagram service and alternate path migration is supported, +* this event indicates that an incoming path migration request to this +* EEC was not accepted. +* +* IB_AE_WQ_REQ_ERROR +* An OpCode violation was detected at the responder. +* +* IB_AE_WQ_ACCESS_ERROR +* An access violation was detected at the responder. +* +* IB_AE_PORT_ACTIVE +* If the port active event is supported, this event is generated +* when the link becomes active: IB_LINK_ACTIVE. +* +* IB_AE_PORT_DOWN +* The link is declared unavailable: IB_LINK_INIT, IB_LINK_ARMED, +* IB_LINK_DOWN. +* +* IB_AE_UNKNOWN +* An unknown error occurred which cannot be attributed to any +* resource; behavior is indeterminate. +* +*****/ + +OSM_EXPORT const char* ib_async_event_str[]; + +/****f* IBA Base: Types/ib_get_async_event_str +* NAME +* ib_get_async_event_str +* +* DESCRIPTION +* Returns a string for the specified asynchronous event. +* +* SYNOPSIS +*/ +static inline const char* OSM_API +ib_get_async_event_str( + IN ib_async_event_t event ) +{ + if( event > IB_AE_UNKNOWN ) + event = IB_AE_UNKNOWN; + return( ib_async_event_str[event] ); +} +/* +* PARAMETERS +* event +* [in] event value +* +* RETURN VALUES +* Pointer to the asynchronous event description string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* Verbs/ib_event_rec_t +* NAME +* ib_event_rec_t -- Async event notification record +* +* DESCRIPTION +* When an async event callback is made, this structure is passed to indicate +* the type of event, the source of event that caused it, and the context +* associated with this event. +* +* context -- Context of the resource that caused the event. +* -- ca_context if this is a port/adapter event. +* -- qp_context if the source is a QP event +* -- cq_context if the source is a CQ event. +* -- ee_context if the source is an EE event. +* +* SYNOPSIS +*/ +typedef struct _ib_event_rec +{ + void *context; + ib_async_event_t type; + + /* HCA vendor specific event information. */ + uint64_t vendor_specific; + + /* The following structures are valid only for trap types. */ + union _trap + { + struct + { + uint16_t lid; + ib_net64_t port_guid; + uint8_t port_num; + + /* + * The following structure is valid only for + * P_KEY, Q_KEY, and M_KEY violation traps. + */ + struct + { + uint8_t sl; + uint16_t src_lid; + uint16_t dest_lid; + union _key + { + uint16_t pkey; + uint32_t qkey; + uint64_t mkey; + } key; + uint32_t src_qp; + uint32_t dest_qp; + ib_gid_t src_gid; + ib_gid_t dest_gid; + + } violation; + + } info; + + ib_net64_t sysimg_guid; + + } trap; + +} ib_event_rec_t; +/*******/ + +/****d* Access Layer/ib_atomic_t +* NAME +* ib_atomic_t +* +* DESCRIPTION +* Indicates atomicity levels supported by an adapter. +* +* SYNOPSIS +*/ +typedef enum _ib_atomic_t +{ + IB_ATOMIC_NONE, + IB_ATOMIC_LOCAL, + IB_ATOMIC_GLOBAL + +} ib_atomic_t; +/* +* VALUES +* IB_ATOMIC_NONE +* Atomic operations not supported. +* +* IB_ATOMIC_LOCAL +* Atomic operations guaranteed between QPs of a single CA. +* +* IB_ATOMIC_GLOBAL +* Atomic operations are guaranteed between CA and any other entity +* in the system. +*****/ + +/****s* Access Layer/ib_port_cap_t +* NAME +* ib_port_cap_t +* +* DESCRIPTION +* Indicates which management agents are currently available on the specified +* port. +* +* SYNOPSIS +*/ +typedef struct _ib_port_cap +{ + boolean_t cm; + boolean_t snmp; + boolean_t dev_mgmt; + boolean_t vend; + boolean_t sm; + boolean_t sm_disable; + boolean_t qkey_ctr; + boolean_t pkey_ctr; + boolean_t notice; + boolean_t trap; + boolean_t apm; + boolean_t slmap; + boolean_t pkey_nvram; + boolean_t mkey_nvram; + boolean_t sysguid; + boolean_t dr_notice; + boolean_t boot_mgmt; + boolean_t capm_notice; + boolean_t reinit; + boolean_t ledinfo; + boolean_t port_active; + +} ib_port_cap_t; +/*****/ + +/****d* Access Layer/ib_init_type_t +* NAME +* ib_init_type_t +* +* DESCRIPTION +* If supported by the HCA, the type of initialization requested by +* this port before SM moves it to the active or armed state. If the +* SM implements reinitialization, it shall set these bits to indicate +* the type of initialization performed prior to activating the port. +* Otherwise, these bits shall be set to 0. +* +* SYNOPSIS +*/ +typedef uint8_t ib_init_type_t; +#define IB_INIT_TYPE_NO_LOAD 0x01 +#define IB_INIT_TYPE_PRESERVE_CONTENT 0x02 +#define IB_INIT_TYPE_PRESERVE_PRESENCE 0x04 +#define IB_INIT_TYPE_DO_NOT_RESUSCITATE 0x08 +/*****/ + +/****s* Access Layer/ib_port_attr_mod_t +* NAME +* ib_port_attr_mod_t +* +* DESCRIPTION +* Port attributes that may be modified. +* +* SYNOPSIS +*/ +typedef struct _ib_port_attr_mod +{ + ib_port_cap_t cap; + uint16_t pkey_ctr; + uint16_t qkey_ctr; + + ib_init_type_t init_type; + ib_net64_t system_image_guid; + +} ib_port_attr_mod_t; +/* +* SEE ALSO +* ib_port_cap_t +*****/ + +/****s* Access Layer/ib_port_attr_t +* NAME +* ib_port_attr_t +* +* DESCRIPTION +* Information about a port on a given channel adapter. +* +* SYNOPSIS +*/ +typedef struct _ib_port_attr +{ + ib_net64_t port_guid; + uint8_t port_num; + uint8_t mtu; + uint64_t max_msg_size; + ib_net16_t lid; + uint8_t lmc; + + /* + * LinkWidthSupported as defined in PortInfo. Required to calculate + * inter-packet delay (a.k.a. static rate). + */ + uint8_t link_width_supported; + + uint16_t max_vls; + + ib_net16_t sm_lid; + uint8_t sm_sl; + uint8_t link_state; + + ib_init_type_t init_type_reply; /* Optional */ + + /* + * subnet_timeout: + * The maximum expected subnet propagation delay to reach any port on + * the subnet. This value also determines the rate at which traps can + * be generated from this node. + * + * timeout = 4.096 microseconds * 2^subnet_timeout + */ + uint8_t subnet_timeout; + + ib_port_cap_t cap; + uint16_t pkey_ctr; + uint16_t qkey_ctr; + + uint16_t num_gids; + uint16_t num_pkeys; + /* + * Pointers at the end of the structure to allow doing a simple + * memory comparison of contents up to the first pointer. + */ + ib_gid_t *p_gid_table; + ib_net16_t *p_pkey_table; + +} ib_port_attr_t; +/* +* SEE ALSO +* uint8_t, ib_port_cap_t, ib_link_states_t +*****/ + +/****s* Access Layer/ib_ca_attr_t +* NAME +* ib_ca_attr_t +* +* DESCRIPTION +* Information about a channel adapter. +* +* SYNOPSIS +*/ +typedef struct _ib_ca_attr +{ + ib_net64_t ca_guid; + + uint32_t vend_id; + uint16_t dev_id; + uint16_t revision; + uint64_t fw_ver; + + /* + * Total size of the ca attributes in bytes + */ + uint32_t size; + uint32_t max_qps; + uint32_t max_wrs; + + uint32_t max_sges; + uint32_t max_rd_sges; + + uint32_t max_cqs; + uint32_t max_cqes; + + uint32_t max_pds; + + uint32_t init_regions; + uint64_t init_region_size; + + uint32_t init_windows; + uint64_t max_addr_handles; + + uint32_t max_partitions; + + ib_atomic_t atomicity; + + uint8_t max_qp_resp_res; + uint8_t max_eec_resp_res; + uint8_t max_resp_res; + + uint8_t max_qp_init_depth; + uint8_t max_eec_init_depth; + + uint32_t max_eecs; + uint32_t max_rdds; + + uint32_t max_ipv6_qps; + uint32_t max_ether_qps; + + uint32_t max_mcast_grps; + uint32_t max_mcast_qps; + uint32_t max_qps_per_mcast_grp; + uint32_t max_fmr; + uint32_t max_map_per_fmr; + + /* + * local_ack_delay: + * Specifies the maximum time interval between the local CA receiving + * a message and the transmission of the associated ACK or NAK. + * + * timeout = 4.096 microseconds * 2^local_ack_delay + */ + uint8_t local_ack_delay; + + boolean_t bad_pkey_ctr_support; + boolean_t bad_qkey_ctr_support; + boolean_t raw_mcast_support; + boolean_t apm_support; + boolean_t av_port_check; + boolean_t change_primary_port; + boolean_t modify_wr_depth; + boolean_t current_qp_state_support; + boolean_t shutdown_port_capability; + boolean_t init_type_support; + boolean_t port_active_event_support; + boolean_t system_image_guid_support; + boolean_t hw_agents; + + ib_net64_t system_image_guid; + + uint32_t num_page_sizes; + uint8_t num_ports; + + uint32_t *p_page_size; + ib_port_attr_t *p_port_attr; + +} ib_ca_attr_t; +/* +* FIELDS +* ca_guid +* GUID for this adapter. +* +* vend_id +* IEEE vendor ID for this adapter +* +* dev_id +* Device ID of this adapter. (typically from PCI device ID) +* +* revision +* Revision ID of this adapter +* +* fw_ver +* Device Firmware version. +* +* size +* Total size in bytes for the HCA attributes. This size includes total +* size required for all the variable members of the structure. If a +* vendor requires to pass vendor specific fields beyond this structure, +* the HCA vendor can choose to report a larger size. If a vendor is +* reporting extended vendor specific features, they should also provide +* appropriate access functions to aid with the required interpretation. +* +* max_qps +* Maximum number of QP's supported by this HCA. +* +* max_wrs +* Maximum number of work requests supported by this HCA. +* +* max_sges +* Maximum number of scatter gather elements supported per work request. +* +* max_rd_sges +* Maximum number of scatter gather elements supported for READ work +* requests for a Reliable Datagram QP. This value must be zero if RD +* service is not supported. +* +* max_cqs +* Maximum number of Completion Queues supported. +* +* max_cqes +* Maximum number of CQ elements supported per CQ. +* +* max_pds +* Maximum number of protection domains supported. +* +* init_regions +* Initial number of memory regions supported. These are only informative +* values. HCA vendors can extended and grow these limits on demand. +* +* init_region_size +* Initial limit on the size of the registered memory region. +* +* init_windows +* Initial number of window entries supported. +* +* max_addr_handles +* Maximum number of address handles supported. +* +* max_partitions +* Maximum number of partitions supported. +* +* atomicity +* Indicates level of atomic operations supported by this HCA. +* +* max_qp_resp_res +* max_eec_resp_res +* Maximum limit on number of responder resources for incoming RDMA +* operations, on QPs and EEC's respectively. +* +* max_resp_res +* Maximum number of responder resources per HCA, with this HCA used as +* the target. +* +* max_qp_init_depth +* max_eec_init_depth +* Maximimum initiator depth per QP or EEC for initiating RDMA reads and +* atomic operations. +* +* max_eecs +* Maximimum number of EEC's supported by the HCA. +* +* max_rdds +* Maximum number of Reliable datagram domains supported. +* +* max_ipv6_qps +* max_ether_qps +* Maximum number of IPV6 and raw ether QP's supported by this HCA. +* +* max_mcast_grps +* Maximum number of multicast groups supported. +* +* max_mcast_qps +* Maximum number of QP's that can support multicast operations. +* +* max_qps_per_mcast_grp +* Maximum number of multicast QP's per multicast group. +* +* local_ack_delay +* Specifies the maximum time interval between the local CA receiving +* a message and the transmission of the associated ACK or NAK. +* timeout = 4.096 microseconds * 2^local_ack_delay +* +* bad_pkey_ctr_support +* bad_qkey_ctr_support +* Indicates support for the bad pkey and qkey counters. +* +* raw_mcast_support +* Indicates support for raw packet multicast. +* +* apm_support +* Indicates support for Automatic Path Migration. +* +* av_port_check +* Indicates ability to check port number in address handles. +* +* change_primary_port +* Indicates ability to change primary port for a QP or EEC during a +* SQD->RTS transition. +* +* modify_wr_depth +* Indicates ability to modify QP depth during a modify QP operation. +* Check the verb specification for permitted states. +* +* current_qp_state_support +* Indicates ability of the HCA to support the current QP state modifier +* during a modify QP operation. +* +* shutdown_port_capability +* Shutdown port capability support indicator. +* +* init_type_support +* Indicates init_type_reply and ability to set init_type is supported. +* +* port_active_event_support +* Port active event support indicator. +* +* system_image_guid_support +* System image GUID support indicator. +* +* hw_agents +* Indicates SMA is implemented in HW. +* +* system_image_guid +* Optional system image GUID. This field is valid only if the +* system_image_guid_support flag is set. +* +* num_page_sizes +* Indicates support for different page sizes supported by the HCA. +* The variable size array can be obtained from p_page_size. +* +* num_ports +* Number of physical ports supported on this HCA. +* +* p_page_size +* Array holding different page size supported. +* +* p_port_attr +* Array holding port attributes. +* +* NOTES +* This structure contains the attributes of a channel adapter. Users must +* call ib_copy_ca_attr to copy the contents of this structure to a new +* memory region. +* +* SEE ALSO +* ib_port_attr_t, ib_atomic_t, ib_copy_ca_attr +*****/ + +/****f* Access layer/ib_copy_ca_attr +* NAME +* ib_copy_ca_attr +* +* DESCRIPTION +* Copies CA attributes. +* +* SYNOPSIS +*/ +ib_ca_attr_t* +ib_copy_ca_attr( + IN ib_ca_attr_t* const p_dest, + IN const ib_ca_attr_t* const p_src ); +/* +* PARAMETERS +* p_dest +* Pointer to the buffer that is the destination of the copy. +* +* p_src +* Pointer to the CA attributes to copy. +* +* RETURN VALUE +* Pointer to the copied CA attributes. +* +* NOTES +* The buffer pointed to by the p_dest parameter must be at least the size +* specified in the size field of the buffer pointed to by p_src. +* +* SEE ALSO +* ib_ca_attr_t, ib_dup_ca_attr, ib_free_ca_attr +*****/ + +/****s* Access Layer/ib_av_attr_t +* NAME +* ib_av_attr_t +* +* DESCRIPTION +* IBA address vector. +* +* SYNOPSIS +*/ +typedef struct _ib_av_attr +{ + uint8_t port_num; + + uint8_t sl; + ib_net16_t dlid; + + boolean_t grh_valid; + ib_grh_t grh; + uint8_t static_rate; + uint8_t path_bits; + + struct _av_conn + { + uint8_t path_mtu; + uint8_t local_ack_timeout; + uint8_t seq_err_retry_cnt; + uint8_t rnr_retry_cnt; + + } conn; + +} ib_av_attr_t; +/* +* SEE ALSO +* ib_gid_t +*****/ + +/****d* Access Layer/ib_qp_type_t +* NAME +* ib_qp_type_t +* +* DESCRIPTION +* Indicates the type of queue pair being created. +* +* SYNOPSIS +*/ +typedef enum _ib_qp_type +{ + IB_QPT_RELIABLE_CONN = 0, /* Matches CM REQ transport type */ + IB_QPT_UNRELIABLE_CONN = 1, /* Matches CM REQ transport type */ + IB_QPT_RELIABLE_DGRM = 2, /* Matches CM REQ transport type */ + IB_QPT_UNRELIABLE_DGRM, + IB_QPT_QP0, + IB_QPT_QP1, + IB_QPT_RAW_IPV6, + IB_QPT_RAW_ETHER, + IB_QPT_MAD, /* InfiniBand Access Layer */ + IB_QPT_QP0_ALIAS, /* InfiniBand Access Layer */ + IB_QPT_QP1_ALIAS /* InfiniBand Access Layer */ + +} ib_qp_type_t; +/* +* VALUES +* IB_QPT_RELIABLE_CONN +* Reliable, connected queue pair. +* +* IB_QPT_UNRELIABLE_CONN +* Unreliable, connected queue pair. +* +* IB_QPT_RELIABLE_DGRM +* Reliable, datagram queue pair. +* +* IB_QPT_UNRELIABLE_DGRM +* Unreliable, datagram queue pair. +* +* IB_QPT_QP0 +* Queue pair 0. +* +* IB_QPT_QP1 +* Queue pair 1. +* +* IB_QPT_RAW_DGRM +* Raw datagram queue pair. +* +* IB_QPT_RAW_IPV6 +* Raw IP version 6 queue pair. +* +* IB_QPT_RAW_ETHER +* Raw Ethernet queue pair. +* +* IB_QPT_MAD +* Unreliable, datagram queue pair that will send and receive management +* datagrams with assistance from the access layer. +* +* IB_QPT_QP0_ALIAS +* Alias to queue pair 0. Aliased QPs can only be created on an aliased +* protection domain. +* +* IB_QPT_QP1_ALIAS +* Alias to queue pair 1. Aliased QPs can only be created on an aliased +* protection domain. +*****/ + +/****d* Access Layer/ib_access_t +* NAME +* ib_access_t +* +* DESCRIPTION +* Indicates the type of access is permitted on resources such as QPs, +* memory regions and memory windows. +* +* SYNOPSIS +*/ +typedef uint32_t ib_access_t; +#define IB_AC_RDMA_READ 0x00000001 +#define IB_AC_RDMA_WRITE 0x00000002 +#define IB_AC_ATOMIC 0x00000004 +#define IB_AC_LOCAL_WRITE 0x00000008 +#define IB_AC_MW_BIND 0x00000010 +/* +* NOTES +* Users may combine access rights using a bit-wise or operation to specify +* additional access. For example: IB_AC_RDMA_READ | IB_AC_RDMA_WRITE grants +* RDMA read and write access. +*****/ + +/****d* Access Layer/ib_qp_state_t +* NAME +* ib_qp_state_t +* +* DESCRIPTION +* Indicates or sets the state of a queue pair. The current state of a queue +* pair is returned through the ib_qp_query call and set via the +* ib_qp_modify call. +* +* SYNOPSIS +*/ +typedef uint32_t ib_qp_state_t; +#define IB_QPS_RESET 0x00000001 +#define IB_QPS_INIT 0x00000002 +#define IB_QPS_RTR 0x00000004 +#define IB_QPS_RTS 0x00000008 +#define IB_QPS_SQD 0x00000010 +#define IB_QPS_SQD_DRAINING 0x00000030 +#define IB_QPS_SQD_DRAINED 0x00000050 +#define IB_QPS_SQERR 0x00000080 +#define IB_QPS_ERROR 0x00000100 +#define IB_QPS_TIME_WAIT 0xDEAD0000 /* InfiniBand Access Layer */ +/*****/ + +/****d* Access Layer/ib_apm_state_t +* NAME +* ib_apm_state_t +* +* DESCRIPTION +* The current automatic path migration state of a queue pair +* +* SYNOPSIS +*/ +typedef enum _ib_apm_state +{ + IB_APM_MIGRATED = 1, + IB_APM_REARM, + IB_APM_ARMED + +} ib_apm_state_t; +/*****/ + +/****s* Access Layer/ib_qp_create_t +* NAME +* ib_qp_create_t +* +* DESCRIPTION +* Attributes used to initialize a queue pair at creation time. +* +* SYNOPSIS +*/ +typedef struct _ib_qp_create +{ + ib_qp_type_t qp_type; + +TO_LONG_PTR( struct _ib_rdd* , h_rdd) ; + + 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) ; + + boolean_t sq_signaled; + +} ib_qp_create_t; +/* +* FIELDS +* type +* Specifies the type of queue pair to create. +* +* h_rdd +* A handle to a reliable datagram domain to associate with the queue +* pair. This field is ignored if the queue pair is not a reliable +* datagram type queue pair. +* +* sq_depth +* Indicates the requested maximum number of work requests that may be +* outstanding on the queue pair's send queue. This value must be less +* than or equal to the maximum reported by the channel adapter associated +* with the queue pair. +* +* rq_depth +* Indicates the requested maximum number of work requests that may be +* outstanding on the queue pair's receive queue. This value must be less +* than or equal to the maximum reported by the channel adapter associated +* with the queue pair. +* +* sq_sge +* Indicates the maximum number scatter-gather elements that may be +* given in a send work request. This value must be less +* than or equal to the maximum reported by the channel adapter associated +* with the queue pair. +* +* rq_sge +* Indicates the maximum number scatter-gather elements that may be +* given in a receive work request. This value must be less +* than or equal to the maximum reported by the channel adapter associated +* with the queue pair. +* +* h_sq_cq +* A handle to the completion queue that will be used to report send work +* request completions. This handle must be NULL if the type is +* IB_QPT_MAD, IB_QPT_QP0_ALIAS, or IB_QPT_QP1_ALIAS. +* +* h_rq_cq +* A handle to the completion queue that will be used to report receive +* work request completions. This handle must be NULL if the type is +* IB_QPT_MAD, IB_QPT_QP0_ALIAS, or IB_QPT_QP1_ALIAS. +* +* sq_signaled +* A flag that is used to indicate whether the queue pair will signal +* an event upon completion of a send work request. If set to +* TRUE, send work requests will always generate a completion +* event. If set to FALSE, a completion event will only be +* generated if the send_opt field of the send work request has the +* IB_SEND_OPT_SIGNALED flag set. +* +* SEE ALSO +* ib_qp_type_t, ib_qp_attr_t +*****/ + +/****s* Access Layer/ib_qp_attr_t +* NAME +* ib_qp_attr_t +* +* DESCRIPTION +* Queue pair attributes returned through ib_query_qp. +* +* SYNOPSIS +*/ +typedef struct _ib_qp_attr +{ +TO_LONG_PTR( struct _ib_pd* , h_pd) ; + ib_qp_type_t qp_type; + ib_access_t access_ctrl; + uint16_t pkey_index; + + uint32_t sq_depth; + uint32_t rq_depth; + uint32_t sq_sge; + uint32_t rq_sge; + uint8_t init_depth; + uint8_t resp_res; + +TO_LONG_PTR( ib_cq_handle_t , h_sq_cq) ; +TO_LONG_PTR( ib_cq_handle_t , h_rq_cq) ; +TO_LONG_PTR( struct _ib_rdd* , h_rdd) ; + + boolean_t sq_signaled; + + ib_qp_state_t state; + ib_net32_t num; + ib_net32_t dest_num; + ib_net32_t qkey; + + ib_net32_t sq_psn; + ib_net32_t rq_psn; + + uint8_t primary_port; + uint8_t alternate_port; + ib_av_attr_t primary_av; + ib_av_attr_t alternate_av; + ib_apm_state_t apm_state; + +} ib_qp_attr_t; +/* +* FIELDS +* h_pd +* This is a handle to a protection domain associated with the queue +* pair, or NULL if the queue pair is type IB_QPT_RELIABLE_DGRM. +* +* NOTES +* Other fields are defined by the Infiniband specification. +* +* SEE ALSO +* ib_qp_type_t, ib_access_t, ib_qp_state_t, ib_av_attr_t, ib_apm_state_t +*****/ + +/****d* Access Layer/ib_qp_opts_t +* NAME +* ib_qp_opts_t +* +* DESCRIPTION +* Optional fields supplied in the modify QP operation. +* +* SYNOPSIS +*/ +typedef uint32_t ib_qp_opts_t; +#define IB_MOD_QP_ALTERNATE_AV 0x00000001 +#define IB_MOD_QP_PKEY 0x00000002 +#define IB_MOD_QP_APM_STATE 0x00000004 +#define IB_MOD_QP_PRIMARY_AV 0x00000008 +#define IB_MOD_QP_RNR_NAK_TIMEOUT 0x00000010 +#define IB_MOD_QP_RESP_RES 0x00000020 +#define IB_MOD_QP_INIT_DEPTH 0x00000040 +#define IB_MOD_QP_PRIMARY_PORT 0x00000080 +#define IB_MOD_QP_ACCESS_CTRL 0x00000100 +#define IB_MOD_QP_QKEY 0x00000200 +#define IB_MOD_QP_SQ_DEPTH 0x00000400 +#define IB_MOD_QP_RQ_DEPTH 0x00000800 +#define IB_MOD_QP_CURRENT_STATE 0x00001000 +#define IB_MOD_QP_RETRY_CNT 0x00002000 +#define IB_MOD_QP_LOCAL_ACK_TIMEOUT 0x00004000 +#define IB_MOD_QP_RNR_RETRY_CNT 0x00008000 +/* +* SEE ALSO +* ib_qp_mod_t +*****/ + +/****s* Access Layer/ib_qp_mod_t +* NAME +* ib_qp_mod_t +* +* DESCRIPTION +* Information needed to change the state of a queue pair through the +* ib_modify_qp call. +* +* SYNOPSIS +*/ +typedef struct _ib_qp_mod +{ + ib_qp_state_t req_state; + + union _qp_state + { + struct _qp_reset + { + /* + * Time, in milliseconds, that the QP needs to spend in + * the time wait state before being reused. + */ + uint32_t timewait; + + } reset; + + struct _qp_init + { + ib_qp_opts_t opts; + uint8_t primary_port; + ib_net32_t qkey; + uint16_t pkey_index; + ib_access_t access_ctrl; + + } init; + + struct _qp_rtr + { + ib_net32_t rq_psn; + ib_net32_t dest_qp; + ib_av_attr_t primary_av; + uint8_t resp_res; + + ib_qp_opts_t opts; + ib_av_attr_t alternate_av; + ib_net32_t qkey; + uint16_t pkey_index; + ib_access_t access_ctrl; + uint32_t sq_depth; + uint32_t rq_depth; + uint8_t rnr_nak_timeout; + + } rtr; + + struct _qp_rts + { + ib_net32_t sq_psn; + uint8_t retry_cnt; + uint8_t rnr_retry_cnt; + uint8_t rnr_nak_timeout; + uint8_t local_ack_timeout; + uint8_t init_depth; + + ib_qp_opts_t opts; + ib_qp_state_t current_state; + ib_net32_t qkey; + ib_access_t access_ctrl; + uint8_t resp_res; + + ib_av_attr_t primary_av; + ib_av_attr_t alternate_av; + + uint32_t sq_depth; + uint32_t rq_depth; + + ib_apm_state_t apm_state; + uint8_t primary_port; + uint16_t pkey_index; + + } rts; + + struct _qp_sqd + { + boolean_t sqd_event; + + } sqd; + + } state; + +} ib_qp_mod_t; +/* +* SEE ALSO +* ib_qp_state_t, ib_access_t, ib_av_attr_t, ib_apm_state_t +*****/ + +/****s* Access Layer/ib_eec_attr_t +* NAME +* ib_eec_attr_t +* +* DESCRIPTION +* Information about an end-to-end context. +* +* SYNOPSIS +*/ +typedef struct _ib_eec_attr +{ + ib_qp_state_t state; +TO_LONG_PTR( struct _ib_rdd* , h_rdd) ; + ib_net32_t local_eecn; + + ib_net32_t sq_psn; + ib_net32_t rq_psn; + uint8_t primary_port; + uint16_t pkey_index; + uint32_t resp_res; + ib_net32_t remote_eecn; + uint32_t init_depth; + uint32_t dest_num; // ??? What is this? + ib_av_attr_t primary_av; + ib_av_attr_t alternate_av; + ib_apm_state_t apm_state; + +} ib_eec_attr_t; +/* +* SEE ALSO +* ib_qp_state_t, ib_av_attr_t, ib_apm_state_t +*****/ + +/****d* Access Layer/ib_eec_opts_t +* NAME +* ib_eec_opts_t +* +* DESCRIPTION +* Optional fields supplied in the modify EEC operation. +* +* SYNOPSIS +*/ +typedef uint32_t ib_eec_opts_t; +#define IB_MOD_EEC_ALTERNATE_AV 0x00000001 +#define IB_MOD_EEC_PKEY 0x00000002 +#define IB_MOD_EEC_APM_STATE 0x00000004 +#define IB_MOD_EEC_PRIMARY_AV 0x00000008 +#define IB_MOD_EEC_RNR 0x00000010 +#define IB_MOD_EEC_RESP_RES 0x00000020 +#define IB_MOD_EEC_OUTSTANDING 0x00000040 +#define IB_MOD_EEC_PRIMARY_PORT 0x00000080 +/* +* NOTES +* +* +*****/ + +/****s* Access Layer/ib_eec_mod_t +* NAME +* ib_eec_mod_t +* +* DESCRIPTION +* Information needed to change the state of an end-to-end context through +* the ib_modify_eec function. +* +* SYNOPSIS +*/ +typedef struct _ib_eec_mod +{ + ib_qp_state_t req_state; + + union _eec_state + { + struct _eec_init + { + uint8_t primary_port; + uint16_t pkey_index; + + } init; + + struct _eec_rtr + { + ib_net32_t rq_psn; + ib_net32_t remote_eecn; + ib_av_attr_t primary_av; + uint8_t resp_res; + + ib_eec_opts_t opts; + ib_av_attr_t alternate_av; + uint16_t pkey_index; + + } rtr; + + struct _eec_rts + { + ib_net32_t sq_psn; + uint8_t retry_cnt; + uint8_t rnr_retry_cnt; + uint8_t local_ack_timeout; + uint8_t init_depth; + + ib_eec_opts_t opts; + ib_av_attr_t alternate_av; + ib_apm_state_t apm_state; + + ib_av_attr_t primary_av; + uint16_t pkey_index; + uint8_t primary_port; + + } rts; + + struct _eec_sqd + { + boolean_t sqd_event; + + } sqd; + + } state; + +} ib_eec_mod_t; +/* +* SEE ALSO +* ib_qp_state_t, ib_av_attr_t, ib_apm_state_t +*****/ + +/****d* Access Layer/ib_wr_type_t +* NAME +* ib_wr_type_t +* +* DESCRIPTION +* Identifies the type of work request posted to a queue pair. +* +* SYNOPSIS +*/ +typedef enum _ib_wr_type_t +{ + WR_SEND = 1, + WR_RDMA_WRITE, + WR_RDMA_READ, + WR_COMPARE_SWAP, + WR_FETCH_ADD + +} ib_wr_type_t; +/*****/ + +/****s* Access Layer/ib_local_ds_t +* NAME +* ib_local_ds_t +* +* DESCRIPTION +* Local data segment information referenced by send and receive work +* requests. This is used to specify local data buffers used as part of a +* work request. +* +* SYNOPSIS +*/ +typedef struct _ib_local_ds +{ + void *vaddr; + uint32_t length; + uint32_t lkey; + +} ib_local_ds_t; +/*****/ + +/****d* Access Layer/ib_send_opt_t +* NAME +* ib_send_opt_t +* +* DESCRIPTION +* Optional flags used when posting send work requests. These flags +* indicate specific processing for the send operation. +* +* SYNOPSIS +*/ +typedef uint32_t ib_send_opt_t; +#define IB_SEND_OPT_IMMEDIATE 0x00000001 +#define IB_SEND_OPT_FENCE 0x00000002 +#define IB_SEND_OPT_SIGNALED 0x00000004 +#define IB_SEND_OPT_SOLICITED 0x00000008 +#define IB_SEND_OPT_INLINE 0x00000010 +#define IB_SEND_OPT_LOCAL 0x00000020 +#define IB_SEND_OPT_VEND_MASK 0xFFFF0000 +/* +* VALUES +* The following flags determine the behavior of a work request when +* posted to the send side. +* +* IB_SEND_OPT_IMMEDIATE +* Send immediate data with the given request. +* +* IB_SEND_OPT_FENCE +* The operation is fenced. Complete all pending send operations +* before processing this request. +* +* IB_SEND_OPT_SIGNALED +* If the queue pair is configured for signaled completion, then +* generate a completion queue entry when this request completes. +* +* IB_SEND_OPT_SOLICITED +* Set the solicited bit on the last packet of this request. +* +* IB_SEND_OPT_INLINE +* Indicates that the requested send data should be copied into a VPD +* owned data buffer. This flag permits the user to issue send operations +* without first needing to register the buffer(s) associated with the +* send operation. Verb providers that support this operation may place +* vendor specific restrictions on the size of send operation that may +* be performed as inline. +* +* +* IB_SEND_OPT_LOCAL +* Indicates that a sent MAD request should be given to the local VPD for +* processing. MADs sent using this option are not placed on the wire. +* This send option is only valid for MAD send operations. +* +* +* IB_SEND_OPT_VEND_MASK +* This mask indicates bits reserved in the send options that may be used +* by the verbs provider to indicate vendor specific options. Bits set +* in this area of the send options are ignored by the Access Layer, but +* may have specific meaning to the underlying VPD. +* +*****/ + +/****s* Access Layer/ib_send_wr_t +* NAME +* ib_send_wr_t +* +* DESCRIPTION +* Information used to submit a work request to the send queue of a queue +* pair. +* +* SYNOPSIS +*/ +typedef struct _ib_send_wr +{ + struct _ib_send_wr *p_next; + uint64_t wr_id; + ib_wr_type_t wr_type; + ib_send_opt_t send_opt; + uint32_t num_ds; + ib_local_ds_t *ds_array; + ib_net32_t immediate_data; + + union _send_dgrm + { + struct _send_ud + { + ib_net32_t remote_qp; + ib_net32_t remote_qkey; +TO_LONG_PTR( ib_av_handle_t , h_av) ; + + } ud; + + struct _send_rd + { + ib_net32_t remote_qp; + ib_net32_t remote_qkey; + ib_net32_t eecn; + + } rd; + + struct _send_raw_ether + { + ib_net16_t dest_lid; + uint8_t path_bits; + uint8_t sl; + uint8_t max_static_rate; + ib_net16_t ether_type; + + } raw_ether; + + struct _send_raw_ipv6 + { + ib_net16_t dest_lid; + uint8_t path_bits; + uint8_t sl; + uint8_t max_static_rate; + + } raw_ipv6; + + } dgrm; + + struct _send_remote_ops + { + uint64_t vaddr; + uint32_t rkey; + + ib_net64_t atomic1; + ib_net64_t atomic2; + + } remote_ops; + +} ib_send_wr_t; +/* +* FIELDS +* p_next +* A pointer used to chain work requests together. This permits multiple +* work requests to be posted to a queue pair through a single function +* call. This value is set to NULL to mark the end of the chain. +* +* wr_id +* A 64-bit work request identifier that is returned to the consumer +* as part of the work completion. +* +* wr_type +* The type of work request being submitted to the send queue. +* +* send_opt +* Optional send control parameters. +* +* num_ds +* Number of local data segments specified by this work request. +* +* ds_array +* A reference to an array of local data segments used by the send +* operation. +* +* immediate_data +* 32-bit field sent as part of a message send or RDMA write operation. +* This field is only valid if the send_opt flag IB_SEND_OPT_IMMEDIATE +* has been set. +* +* dgrm.ud.remote_qp +* Identifies the destination queue pair of an unreliable datagram send +* operation. +* +* dgrm.ud.remote_qkey +* The qkey for the destination queue pair. +* +* dgrm.ud.h_av +* An address vector that specifies the path information used to route +* the outbound datagram to the destination queue pair. +* +* dgrm.rd.remote_qp +* Identifies the destination queue pair of a reliable datagram send +* operation. +* +* dgrm.rd.remote_qkey +* The qkey for the destination queue pair. +* +* dgrm.rd.eecn +* The local end-to-end context number to use with the reliable datagram +* send operation. +* +* dgrm.raw_ether.dest_lid +* The destination LID that will receive this raw ether send. +* +* dgrm.raw_ether.path_bits +* path bits... +* +* dgrm.raw_ether.sl +* service level... +* +* dgrm.raw_ether.max_static_rate +* static rate... +* +* dgrm.raw_ether.ether_type +* ether type... +* +* dgrm.raw_ipv6.dest_lid +* The destination LID that will receive this raw ether send. +* +* dgrm.raw_ipv6.path_bits +* path bits... +* +* dgrm.raw_ipv6.sl +* service level... +* +* dgrm.raw_ipv6.max_static_rate +* static rate... +* +* remote_ops.vaddr +* The registered virtual memory address of the remote memory to access +* with an RDMA or atomic operation. +* +* remote_ops.rkey +* The rkey associated with the specified remote vaddr. This data must +* be presented exactly as obtained from the remote node. No swapping +* of data must be performed. +* +* atomic1 +* The first operand for an atomic operation. +* +* atomic2 +* The second operand for an atomic operation. +* +* NOTES +* The format of data sent over the fabric is user-defined and is considered +* opaque to the access layer. The sole exception to this are MADs posted +* to a MAD QP service. MADs are expected to match the format defined by +* the Infiniband specification and must be in network-byte order when posted +* to the MAD QP service. +* +* SEE ALSO +* ib_wr_type_t, ib_local_ds_t, ib_send_opt_t +*****/ + +/****s* Access Layer/ib_recv_wr_t +* NAME +* ib_recv_wr_t +* +* DESCRIPTION +* Information used to submit a work request to the receive queue of a queue +* pair. +* +* SYNOPSIS +*/ +typedef struct _ib_recv_wr +{ + struct _ib_recv_wr *p_next; + uint64_t wr_id; + uint32_t num_ds; + ib_local_ds_t *ds_array; +} ib_recv_wr_t; +/* +* FIELDS +* p_next +* A pointer used to chain work requests together. This permits multiple +* work requests to be posted to a queue pair through a single function +* call. This value is set to NULL to mark the end of the chain. +* +* wr_id +* A 64-bit work request identifier that is returned to the consumer +* as part of the work completion. +* +* num_ds +* Number of local data segments specified by this work request. +* +* ds_array +* A reference to an array of local data segments used by the send +* operation. +* +* SEE ALSO +* ib_local_ds_t +*****/ + +/****s* Access Layer/ib_bind_wr_t +* NAME +* ib_bind_wr_t +* +* DESCRIPTION +* Information used to submit a memory window bind work request to the send +* queue of a queue pair. +* +* SYNOPSIS +*/ +typedef struct _ib_bind_wr +{ + uint64_t wr_id; + ib_send_opt_t send_opt; + +TO_LONG_PTR( struct _ib_mr* , h_mr) ; + ib_access_t access_ctrl; + uint32_t current_rkey; + + ib_local_ds_t local_ds; + +} ib_bind_wr_t; +/* +* FIELDS +* wr_id +* A 64-bit work request identifier that is returned to the consumer +* as part of the work completion. +* +* send_opt +* Optional send control parameters. +* +* h_mr +* Handle to the memory region to which this window is being bound. +* +* access_ctrl +* Access rights for this memory window. +* +* current_rkey +* The current rkey assigned to this window for remote access. +* +* local_ds +* A reference to a local data segment used by the bind operation. +* +* SEE ALSO +* ib_send_opt_t, ib_access_t, ib_local_ds_t +*****/ + +/****d* Access Layer/ib_wc_status_t +* NAME +* ib_wc_status_t +* +* DESCRIPTION +* Indicates the status of a completed work request. These VALUES are +* returned to the user when retrieving completions. Note that success is +* identified as IB_WCS_SUCCESS, which is always zero. +* +* SYNOPSIS +*/ +typedef enum _ib_wc_status_t +{ + IB_WCS_SUCCESS, + IB_WCS_LOCAL_LEN_ERR, + IB_WCS_LOCAL_OP_ERR, + IB_WCS_LOCAL_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_EEC_OP_ERR +* An internal EEC consistency error was generated while processing +* this work request. This may indicate that the EEC was in an incorrect +* state for the requested operation. +* +* IB_WCS_LOCAL_PROTECTION_ERR +* The data segments of the locally posted work request did not refer to +* a valid memory region. The memory may not have been properly +* registered for the requested operation. +* +* IB_WCS_WR_FLUSHED_ERR +* The work request was flushed from the QP before being completed. +* +* IB_WCS_MEM_WINDOW_BIND_ERR +* A memory window bind operation failed due to insufficient access +* rights. +* +* IB_WCS_REM_ACCESS_ERR, +* A protection error was detected at the remote node for a RDMA or atomic +* operation. +* +* IB_WCS_REM_OP_ERR, +* The operation could not be successfully completed at the remote node. +* This may indicate that the remote QP was in an invalid state or +* contained an invalid work request. +* +* IB_WCS_RNR_RETRY_ERR, +* The RNR retry count was exceeded while trying to send this message. +* +* IB_WCS_TIMEOUT_RETRY_ERR +* The local transport timeout counter expired while trying to send this +* message. +* +* IB_WCS_REM_INVALID_REQ_ERR, +* The remote node detected an invalid message on the channel. This error +* is usually a result of one of the following: +* - The operation was not supported on receive queue. +* - There was insufficient buffers to receive a new RDMA request. +* - There was insufficient buffers to receive a new atomic operation. +* - An RDMA request was larger than 2^31 bytes. +* +* IB_WCS_REM_INVALID_RD_REQ_ERR, +* Responder detected an invalid RD message. This may be the result of an +* invalid qkey or an RDD mismatch. +* +* IB_WCS_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. +*****/ + +OSM_EXPORT const char* ib_wc_status_str[]; + +/****f* IBA Base: Types/ib_get_wc_status_str +* NAME +* ib_get_wc_status_str +* +* DESCRIPTION +* Returns a string for the specified work completion status. +* +* SYNOPSIS +*/ +static inline const char* OSM_API +ib_get_wc_status_str( + IN ib_wc_status_t wc_status ) +{ + if( wc_status > IB_WCS_UNKNOWN ) + wc_status = IB_WCS_UNKNOWN; + return( ib_wc_status_str[wc_status] ); +} +/* +* PARAMETERS +* wc_status +* [in] work completion status value +* +* RETURN VALUES +* Pointer to the work completion status description string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****d* Access Layer/ib_wc_type_t +* NAME +* ib_wc_type_t +* +* DESCRIPTION +* Indicates the type of work completion. +* +* SYNOPSIS +*/ +typedef enum _ib_wc_type_t +{ + IB_WC_SEND, + IB_WC_RDMA_WRITE, + IB_WC_RECV, + IB_WC_RDMA_READ, + IB_WC_MW_BIND, + IB_WC_FETCH_ADD, + IB_WC_COMPARE_SWAP, + IB_WC_RECV_RDMA_WRITE + +} ib_wc_type_t; +/*****/ + +/****d* Access Layer/ib_recv_opt_t +* NAME +* ib_recv_opt_t +* +* DESCRIPTION +* Indicates optional fields valid in a receive work completion. +* +* SYNOPSIS +*/ +typedef uint32_t ib_recv_opt_t; +#define IB_RECV_OPT_IMMEDIATE 0x00000001 +#define IB_RECV_OPT_FORWARD 0x00000002 +#define IB_RECV_OPT_GRH_VALID 0x00000004 +#define IB_RECV_OPT_VEND_MASK 0xFFFF0000 +/* +* VALUES +* IB_RECV_OPT_IMMEDIATE +* Indicates that immediate data is valid for this work completion. +* +* IB_RECV_OPT_FORWARD +* Indicates that the received trap should be forwarded to the SM. +* +* IB_RECV_OPT_GRH_VALID +* Indicates presence of the global route header. When set, the first +* 40 bytes received are the GRH. +* +* IB_RECV_OPT_VEND_MASK +* This mask indicates bits reserved in the receive options that may be +* used by the verbs provider to indicate vendor specific options. Bits +* set in this area of the receive options are ignored by the Access Layer, +* but may have specific meaning to the underlying VPD. +*****/ + +/****s* Access Layer/ib_wc_t +* NAME +* ib_wc_t +* +* DESCRIPTION +* Work completion information. +* +* SYNOPSIS +*/ +typedef struct _ib_wc +{ + struct _ib_wc *p_next; + uint64_t wr_id; + ib_wc_type_t wc_type; + + uint32_t length; + ib_wc_status_t status; + uint64_t vendor_specific; + + union _wc_recv + { + struct _wc_conn + { + ib_recv_opt_t recv_opt; + ib_net32_t immediate_data; + + } conn; + + struct _wc_ud + { + ib_recv_opt_t recv_opt; + ib_net32_t immediate_data; + ib_net32_t remote_qp; + uint16_t pkey_index; + ib_net16_t remote_lid; + uint8_t remote_sl; + uint8_t path_bits; + + } ud; + + struct _wc_rd + { + ib_net32_t remote_eecn; + ib_net32_t remote_qp; + ib_net16_t remote_lid; + uint8_t remote_sl; + uint32_t free_cnt; + + } rd; + + struct _wc_raw_ipv6 + { + ib_net16_t remote_lid; + uint8_t remote_sl; + uint8_t path_bits; + + } raw_ipv6; + + struct _wc_raw_ether + { + ib_net16_t remote_lid; + uint8_t remote_sl; + uint8_t path_bits; + ib_net16_t ether_type; + + } raw_ether; + + } recv; + +} ib_wc_t; +/* +* FIELDS +* p_next +* A pointer used to chain work completions. This permits multiple +* work completions to be retrieved from a completion queue through a +* single function call. This value is set to NULL to mark the end of +* the chain. +* +* wr_id +* The 64-bit work request identifier that was specified when posting the +* work request. +* +* wc_type +* Indicates the type of work completion. +* +* +* length +* The total length of the data sent or received with the work request. +* +* status +* The result of the work request. +* +* vendor_specific +* HCA vendor specific information returned as part of the completion. +* +* recv.conn.recv_opt +* Indicates optional fields valid as part of a work request that +* completed on a connected (reliable or unreliable) queue pair. +* +* recv.conn.immediate_data +* 32-bit field received as part of an inbound message on a connected +* queue pair. This field is only valid if the recv_opt flag +* IB_RECV_OPT_IMMEDIATE has been set. +* +* recv.ud.recv_opt +* Indicates optional fields valid as part of a work request that +* completed on an unreliable datagram queue pair. +* +* recv.ud.immediate_data +* 32-bit field received as part of an inbound message on a unreliable +* datagram queue pair. This field is only valid if the recv_opt flag +* IB_RECV_OPT_IMMEDIATE has been set. +* +* recv.ud.remote_qp +* Identifies the source queue pair of a received datagram. +* +* recv.ud.pkey_index +* The pkey index for the source queue pair. This is valid only for +* GSI type QP's. +* +* recv.ud.remote_lid +* The source LID of the received datagram. +* +* recv.ud.remote_sl +* The service level used by the source of the received datagram. +* +* recv.ud.path_bits +* path bits... +* +* recv.rd.remote_eecn +* The remote end-to-end context number that sent the received message. +* +* recv.rd.remote_qp +* Identifies the source queue pair of a received message. +* +* recv.rd.remote_lid +* The source LID of the received message. +* +* recv.rd.remote_sl +* The service level used by the source of the received message. +* +* recv.rd.free_cnt +* The number of available entries in the completion queue. Reliable +* datagrams may complete out of order, so this field may be used to +* determine the number of additional completions that may occur. +* +* recv.raw_ipv6.remote_lid +* The source LID of the received message. +* +* recv.raw_ipv6.remote_sl +* The service level used by the source of the received message. +* +* recv.raw_ipv6.path_bits +* path bits... +* +* recv.raw_ether.remote_lid +* The source LID of the received message. +* +* recv.raw_ether.remote_sl +* The service level used by the source of the received message. +* +* recv.raw_ether.path_bits +* path bits... +* +* recv.raw_ether.ether_type +* ether type... +* NOTES +* When the work request completes with error, the only values that the +* consumer can depend on are the wr_id field, and the status of the +* operation. +* +* If the consumer is using the same CQ for completions from more than +* one type of QP (i.e Reliable Connected, Datagram etc), then the consumer +* must have additional information to decide what fields of the union are +* valid. +* SEE ALSO +* ib_wc_type_t, ib_qp_type_t, ib_wc_status_t, ib_recv_opt_t +*****/ + +/****s* Access Layer/ib_mr_create_t +* NAME +* ib_mr_create_t +* +* DESCRIPTION +* Information required to create a registered memory region. +* +* SYNOPSIS +*/ +typedef struct _ib_mr_create +{ + void *vaddr; + uint64_t length; + ib_access_t access_ctrl; +} ib_mr_create_t; +/* +* FIELDS +* vaddr +* Starting virtual address of the region being registered. +* +* length +* Length of the buffer to register. +* +* access_ctrl +* Access rights of the registered region. +* +* SEE ALSO +* ib_access_t +*****/ + +/****s* Access Layer/ib_phys_create_t +* NAME +* ib_phys_create_t +* +* DESCRIPTION +* Information required to create a physical memory region. +* +* SYNOPSIS +*/ +typedef struct _ib_phys_create +{ + uint64_t length; + uint32_t num_bufs; + uint64_t *buf_array; + uint32_t buf_offset; + uint32_t page_size; + ib_access_t access_ctrl; +} ib_phys_create_t; +/* +* length +* The length of the memory region in bytes. +* +* num_bufs +* Number of buffers listed in the specified buffer array. +* +* buf_array +* An array of physical buffers to be registered as a single memory +* region. +* +* buf_offset +* The offset into the first physical page of the specified memory +* region to start the virtual address. +* +* page_size +* The physical page size of the memory being registered. +* +* access_ctrl +* Access rights of the registered region. +* +* SEE ALSO +* ib_access_t +*****/ + +/****s* Access Layer/ib_mr_attr_t +* NAME +* ib_mr_attr_t +* +* DESCRIPTION +* Attributes of a registered memory region. +* +* SYNOPSIS +*/ +typedef struct _ib_mr_attr +{ +TO_LONG_PTR( struct _ib_pd* , h_pd) ; + void *local_lb; + void *local_ub; + void *remote_lb; + void *remote_ub; + ib_access_t access_ctrl; + uint32_t lkey; + uint32_t rkey; +} ib_mr_attr_t; +/* +* DESCRIPTION +* h_pd +* Handle to the protection domain for this memory region. +* +* local_lb +* The virtual address of the lower bound of protection for local +* memory access. +* +* local_ub +* The virtual address of the upper bound of protection for local +* memory access. +* +* remote_lb +* The virtual address of the lower bound of protection for remote +* memory access. +* +* remote_ub +* The virtual address of the upper bound of protection for remote +* memory access. +* +* access_ctrl +* Access rights for the specified memory region. +* +* lkey +* The lkey associated with this memory region. +* +* rkey +* The rkey associated with this memory region. +* +* NOTES +* The remote_lb, remote_ub, and rkey are only valid if remote memory access +* is enabled for this memory region. +* +* SEE ALSO +* ib_access_t +*****/ + +/****d* Access Layer/ib_ca_mod_t +* NAME +* ib_ca_mod_t -- Modify port attributes and error counters +* +* DESCRIPTION +* Specifies modifications to the port attributes of a channel adapter. +* +* SYNOPSIS +*/ +typedef uint32_t ib_ca_mod_t; +#define IB_CA_MOD_IS_CM_SUPPORTED 0x00000001 +#define IB_CA_MOD_IS_SNMP_SUPPORTED 0x00000002 +#define IB_CA_MOD_IS_DEV_MGMT_SUPPORTED 0x00000004 +#define IB_CA_MOD_IS_VEND_SUPPORTED 0x00000008 +#define IB_CA_MOD_IS_SM 0x00000010 +#define IB_CA_MOD_IS_SM_DISABLED 0x00000020 +#define IB_CA_MOD_QKEY_CTR 0x00000040 +#define IB_CA_MOD_PKEY_CTR 0x00000080 +#define IB_CA_MOD_IS_NOTICE_SUPPORTED 0x00000100 +#define IB_CA_MOD_IS_TRAP_SUPPORTED 0x00000200 +#define IB_CA_MOD_IS_APM_SUPPORTED 0x00000400 +#define IB_CA_MOD_IS_SLMAP_SUPPORTED 0x00000800 +#define IB_CA_MOD_IS_PKEY_NVRAM_SUPPORTED 0x00001000 +#define IB_CA_MOD_IS_MKEY_NVRAM_SUPPORTED 0x00002000 +#define IB_CA_MOD_IS_SYSGUID_SUPPORTED 0x00004000 +#define IB_CA_MOD_IS_DR_NOTICE_SUPPORTED 0x00008000 +#define IB_CA_MOD_IS_BOOT_MGMT_SUPPORTED 0x00010000 +#define IB_CA_MOD_IS_CAPM_NOTICE_SUPPORTED 0x00020000 +#define IB_CA_MOD_IS_REINIT_SUPORTED 0x00040000 +#define IB_CA_MOD_IS_LEDINFO_SUPPORTED 0x00080000 +#define IB_CA_MOD_SHUTDOWN_PORT 0x00100000 +#define IB_CA_MOD_INIT_TYPE_VALUE 0x00200000 +#define IB_CA_MOD_SYSTEM_IMAGE_GUID 0x00400000 +/* +* VALUES +* IB_CA_MOD_IS_CM_SUPPORTED +* Indicates if there is a communication manager accessible through +* the port. +* +* IB_CA_MOD_IS_SNMP_SUPPORTED +* Indicates if there is an SNMP agent accessible through the port. +* +* IB_CA_MOD_IS_DEV_MGMT_SUPPORTED +* Indicates if there is a device management agent accessible +* through the port. +* +* IB_CA_MOD_IS_VEND_SUPPORTED +* Indicates if there is a vendor supported agent accessible +* through the port. +* +* IB_CA_MOD_IS_SM +* Indicates if there is a subnet manager accessible through +* the port. +* +* IB_CA_MOD_IS_SM_DISABLED +* Indicates if the port has been disabled for configuration by the +* subnet manager. +* +* IB_CA_MOD_QKEY_CTR +* Used to reset the qkey violation counter associated with the +* port. +* +* IB_CA_MOD_PKEY_CTR +* Used to reset the pkey violation counter associated with the +* port. +* +* IB_CA_MOD_IS_NOTICE_SUPPORTED +* Indicates that this CA supports ability to generate Notices for +* Port State changes. (only applicable to switches) +* +* IB_CA_MOD_IS_TRAP_SUPPORTED +* Indicates that this management port supports ability to generate +* trap messages. (only applicable to switches) +* +* IB_CA_MOD_IS_APM_SUPPORTED +* Indicates that this port is capable of performing Automatic +* Path Migration. +* +* IB_CA_MOD_IS_SLMAP_SUPPORTED +* Indicates this port supports SLMAP capability. +* +* IB_CA_MOD_IS_PKEY_NVRAM_SUPPORTED +* Indicates that PKEY is supported in NVRAM +* +* IB_CA_MOD_IS_MKEY_NVRAM_SUPPORTED +* Indicates that MKEY is supported in NVRAM +* +* IB_CA_MOD_IS_SYSGUID_SUPPORTED +* Indicates System Image GUID support. +* +* IB_CA_MOD_IS_DR_NOTICE_SUPPORTED +* Indicate support for generating Direct Routed Notices +* +* IB_CA_MOD_IS_BOOT_MGMT_SUPPORTED +* Indicates support for Boot Management +* +* IB_CA_MOD_IS_CAPM_NOTICE_SUPPORTED +* Indicates capability to generate notices for changes to CAPMASK +* +* IB_CA_MOD_IS_REINIT_SUPORTED +* Indicates type of node init supported. Refer to Chapter 14 for +* Initialization actions. +* +* IB_CA_MOD_IS_LEDINFO_SUPPORTED +* Indicates support for LED info. +* +* IB_CA_MOD_SHUTDOWN_PORT +* Used to modify the port active indicator. +* +* IB_CA_MOD_INIT_TYPE_VALUE +* Used to modify the init_type value for the port. +* +* IB_CA_MOD_SYSTEM_IMAGE_GUID +* Used to modify the system image GUID for the port. +*****/ + +/****d* Access Layer/ib_mr_mod_t +* NAME +* ib_mr_mod_t +* +* DESCRIPTION +* Mask used to specify which attributes of a registered memory region are +* being modified. +* +* SYNOPSIS +*/ +typedef uint32_t ib_mr_mod_t; +#define IB_MR_MOD_ADDR 0x00000001 +#define IB_MR_MOD_PD 0x00000002 +#define IB_MR_MOD_ACCESS 0x00000004 +/* +* PARAMETERS +* IB_MEM_MOD_ADDR +* The address of the memory region is being modified. +* +* IB_MEM_MOD_PD +* The protection domain associated with the memory region is being +* modified. +* +* IB_MEM_MOD_ACCESS +* The access rights the memory region are being modified. +*****/ + +/****d* IBA Base: Constants/IB_SMINFO_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 OUT void* p_buf OPTIONAL; + IN uint32_t buf_size; + IN OUT uint32_t num_bytes_ret; + IN OUT int32_t status; + +} ib_ci_op_t; +/* +* FIELDS +* command +* A command code that is understood by the verbs provider. +* +* p_buf +* A reference to a buffer containing vendor specific data. The verbs +* provider must not access pointers in the p_buf between user-mode and +* kernel-mode. Any pointers embedded in the p_buf are invalidated by +* the user-mode/kernel-mode transition. +* +* buf_size +* The size of the buffer in bytes. +* +* num_bytes_ret +* The size in bytes of the vendor specific data returned in the buffer. +* This field is set by the verbs provider. The verbs provider should +* verify that the buffer size is sufficient to hold the data being +* returned. +* +* status +* The completion status from the verbs provider. This field should be +* initialize to indicate an error to allow detection and cleanup in +* case a communication error occurs between user-mode and kernel-mode. +* +* NOTES +* This structure is provided to allow the exchange of vendor specific +* data between the originator and the verbs provider. Users of this +* structure are expected to know the format of data in the p_buf based +* on the structure command field or the usage context. +*****/ + +END_C_DECLS + +#endif /* ndef WIN */ +#if defined( __WIN__ ) + #include +#endif + +#endif /* __IB_TYPES_H__ */ + + diff --git a/branches/WOF2-1/ulp/opensm/user/include/iba/ib_types_extended.h b/branches/WOF2-1/ulp/opensm/user/include/iba/ib_types_extended.h new file mode 100644 index 00000000..edd978dc --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/iba/ib_types_extended.h @@ -0,0 +1,2809 @@ +/* + * 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. + * 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_EXTENDED_H__) +#define __IB_TYPES_EXTENDED_H__ + + +#if defined( WIN32 ) + #if defined( EXPORT_AL_SYMBOLS ) + #define AL_EXPORT __declspec(dllexport) + #else + #define AL_EXPORT __declspec(dllimport) + #endif + + #ifdef CL_KERNEL + #define AL_API + #define AL_INLINE static inline + #else + #define AL_API __stdcall + #define AL_INLINE static inline + #endif /* CL_KERNEL */ +#else + #define AL_EXPORT extern + #define AL_INLINE static inline + #define AL_API + #define __ptr64 +#endif + +/* + * 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 + +/* following v1 ver1.2 p901 */ +#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 + + + +typedef struct _ib_srq* ib_srq_handle_t ; + +/* + * The following definitions are shared between the Access Layer and VPD + */ + + + +/****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_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. +* +*****/ + + + +/****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 +*****/ + + +/****s* Access Layer/ib_port_attr_t +* NAME +* ib_port_attr_t +* +* DESCRIPTION +* Information about a port on a given channel adapter. +* +* SYNOPSIS +*/ +typedef struct _ib_port_attr +{ + ib_net64_t port_guid; + uint8_t port_num; + uint8_t mtu; + uint64_t max_msg_size; + ib_net16_t lid; + uint8_t lmc; + + /* + * LinkWidthSupported as defined in PortInfo. Required to calculate + * inter-packet delay (a.k.a. static rate). + */ + uint8_t link_width_supported; + + uint16_t max_vls; + + ib_net16_t sm_lid; + uint8_t sm_sl; + uint8_t link_state; + + ib_init_type_t init_type_reply; /* Optional */ + + /* + * subnet_timeout: + * The maximum expected subnet propagation delay to reach any port on + * the subnet. This value also determines the rate at which traps can + * be generated from this node. + * + * timeout = 4.096 microseconds * 2^subnet_timeout + */ + uint8_t subnet_timeout; + 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 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_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_WR_LSO, + 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_VEND_MASK 0xFFFF0000 +/* +* VALUES +* IB_RECV_OPT_IMMEDIATE +* Indicates that immediate data is valid for this work completion. +* +* IB_RECV_OPT_FORWARD +* Indicates that the received trap should be forwarded to the SM. +* +* IB_RECV_OPT_GRH_VALID +* Indicates presence of the global route header. When set, the first +* 40 bytes received are the GRH. +* +* IB_RECV_OPT_VEND_MASK +* This mask indicates bits reserved in the receive options that may be +* used by the verbs provider to indicate vendor specific options. Bits +* set in this area of the receive options are ignored by the Access Layer, +* but may have specific meaning to the underlying VPD. +*****/ + + +/****s* Access Layer/ib_wc_t +* NAME +* ib_wc_t +* +* DESCRIPTION +* Work completion information. +* +* SYNOPSIS +*/ +typedef struct _ib_wc +{ + 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; + uint8_t csum_ok; + + } 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. +*****/ + + +#endif // __IB_TYPES_EXTENDED_H__ diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/cl_dispatcher.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/cl_dispatcher.h new file mode 100644 index 00000000..7b5a3ec1 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/cl_dispatcher.h @@ -0,0 +1,673 @@ +/* + * 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 the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF 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 dispatcher abstraction. + * + * Environment: + * All + * + * $Revision: 1.4 $ + */ + + +#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-1/ulp/opensm/user/include/opensm/cl_event_wheel.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/cl_event_wheel.h new file mode 100644 index 00000000..559f2aaa --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/cl_event_wheel.h @@ -0,0 +1,497 @@ +/* + * 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 the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF 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 wheel abstraction. + * + * Environment: + * All + * + * $Revision: 1.4 $ + */ + + +#ifndef _CL_EVENT_WHEEL_H_ +#define _CL_EVENT_WHEEL_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/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; + osm_log_t *p_log; +} 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. +* +* p_log +* Pointer to opensm log object. +* +* 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, + IN osm_log_t *p_log); + +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* p_log +* [in] Pointer to opensm log object to be used for logging +* +* 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 osm_log_t *p_log, + IN cl_spinlock_t *p_external_lock); + +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* p_log +* [in] Pointer to opensm log object to be used for logging +* +* 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-1/ulp/opensm/user/include/opensm/osm_attrib_req.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_attrib_req.h new file mode 100644 index 00000000..7344b4a2 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_attrib_req.h @@ -0,0 +1,119 @@ +/* + * 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$ + */ + + +#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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +/****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-1/ulp/opensm/user/include/opensm/osm_base.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_base.h new file mode 100644 index 00000000..58644e8b --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_base.h @@ -0,0 +1,823 @@ +/* + * 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: + * Basic OpenSM definitions and structures. + * This object represents an OpenSM "base class". + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.15 $ + */ + +#ifndef _OSM_BASE_H_ +#define _OSM_BASE_H_ + +#ifdef __WIN__ +#include +#define OSM_CDECL __cdecl +#else +#define OSM_CDECL +#endif + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +/****h* OpenSM/Constants +* NAME +* Constants +* +* DESCRIPTION +* The following constants are used throughout the OpenSM. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****h* OpenSM/Base +* NAME +* Base +* +* DESCRIPTION +* The Base object encapsulates basic information needed by the +* OpenSM to manage objects. Each OpenSM object includes the +* Base object as the first member. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Base/OSM_DEFAULT_M_KEY +* NAME +* OSM_DEFAULT_M_KEY +* +* DESCRIPTION +* Managment key value used by the OpenSM. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_M_KEY 0 +/********/ + +/****s* OpenSM: Base/OSM_DEFAULT_SM_KEY +* NAME +* OSM_DEFAULT_SM_KEY +* +* DESCRIPTION +* Subnet Manager key value used by the OpenSM. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SM_KEY 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 1 +/********/ + +/****d* OpenSM: Base/OSM_DEFAULT_TMP_DIR +* NAME +* OSM_DEFAULT_TMP_DIR +* +* DESCRIPTION +* Specifies the default temporary directory for the log file, +* osm-subnet.lst, and other log files. +* +* SYNOPSIS +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_TMP_DIR GetOsmTempPath() +#else +#define OSM_DEFAULT_TMP_DIR "/var/log/" +#endif +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_CACHE_DIR +* NAME +* OSM_DEFAULT_CACHE_DIR +* +* DESCRIPTION +* Specifies the default cache directory for the db files. +* Note that the directory must appear with "/" ("\\" for windows) at the end. +* +* SYNOPSIS +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_CACHE_DIR GetOsmCachePath() +#else +#define OSM_DEFAULT_CACHE_DIR "/var/cache/osm/" +#endif +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_LOG_FILE +* NAME +* OSM_DEFAULT_LOG_FILE +* +* DESCRIPTION +* Specifies the default log file name +* +* SYNOPSIS +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_LOG_FILE strcat(GetOsmTempPath(), "osm.log") +#else +#define OSM_DEFAULT_LOG_FILE "/var/log/osm.log" +#endif +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_PARTITION_CONFIG_FILE +* NAME +* OSM_DEFAULT_PARTITION_CONFIG_FILE +* +* DESCRIPTION +* Specifies the default partition config file name +* +* SYNOPSIS +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_PARTITION_CONFIG_FILE strcat(GetOsmCachePath(), "osm-partitions.conf") +#else +#define OSM_DEFAULT_PARTITION_CONFIG_FILE "/etc/osm-partitions.conf" +#endif +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_SWEEP_INTERVAL_SECS +* NAME +* OSM_DEFAULT_SWEEP_INTERVAL_SECS +* +* DESCRIPTION +* Specifies the default number of seconds between subnet sweeps. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SWEEP_INTERVAL_SECS 10 +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC +* NAME +* OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC +* +* DESCRIPTION +* Specifies the default transaction timeout in milliseconds. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC 200 +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_SUBNET_TIMEOUT +* NAME +* OSM_DEFAULT_SUBNET_TIMEOUT +* +* DESCRIPTION +* Specifies the default transaction 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 ~130usec +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_LEAF_HEAD_OF_QUEUE_LIFE 0xC +/***********/ + +/****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. +* We use the value of 1 here - so any drop due to HOQ means stalling the VL +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_LEAF_VL_STALL_COUNT 0x1 +/***********/ + +/****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 SubnMgt(Set.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_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: 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_thread_state_t +* NAME +* osm_thread_state_t +* +* DESCRIPTION +* Enumerates the possible states of worker threads, such +* as the subnet sweeper. +* +* SYNOPSIS +*/ +typedef enum _osm_thread_state +{ + OSM_THREAD_STATE_NONE = 0, + OSM_THREAD_STATE_INIT, + OSM_THREAD_STATE_RUN, + OSM_THREAD_STATE_EXIT + +} osm_thread_state_t; +/***********/ + +/* + * OSM_CAP are from Table 117 and C15-0.1.7 Table 186 + */ + +/****d* OpenSM: Base/OSM_CAP_IS_TRAP_SUP +* Name +* OSM_CAP_IS_SUBN_TRAP_SUP +* +* DESCRIPTION +* Management class generates Trap() MADs +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_SUBN_TRAP_SUP (1 << 0) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_GET_SET_NOTICE_SUP +* Name +* OSM_CAP_IS_GET_SET_NOTICE_SUP +* +* DESCRIPTION +* Management class supports Get/Set(Notice) +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_SUBN_GET_SET_NOTICE_SUP (1 << 1) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_SUBN_OPT_RECS_SUP +* Name +* OSM_CAP_IS_SUBN_OPT_RECS_SUP +* +* DESCRIPTION +* Support all optional attributes except: +* MCMemberRecord, TraceRecord, MultiPathRecord +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_SUBN_OPT_RECS_SUP (1 << 8) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_UD_MCAST_SUP +* Name +* OSM_CAP_IS_UD_MCAST_SUP +* +* DESCRIPTION +* Multicast is supported +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_UD_MCAST_SUP (1 << 9) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_MULTIPATH_SUP +* Name +* OSM_CAP_IS_MULTIPATH_SUP +* +* DESCRIPTION +* MultiPathRecord and TraceRecord are supported +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_MULTIPATH_SUP (1 << 10) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_REINIT_SUP +* Name +* OSM_CAP_IS_REINIT_SUP +* +* DESCRIPTION +* SM/SA supports re-initialization supported +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_REINIT_SUP (1 << 11) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED +* Name +* OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED +* +* DESCRIPTION +* SM/SA supports enhanced SA PortInfoRecord searches per 1.2 Errata: +* ClassPortInfo:CapabilityMask.IsPortInfoCapMaskMatchSupported is 1, +* then the AttributeModifier of the SubnAdmGet() and SubnAdmGetTable() +* methods affects the matching behavior on the PortInfo:CapabilityMask +* component. If the high-order bit (bit 31) of the AttributeModifier +* is set to 1, matching on the CapabilityMask component will not be an +* exact bitwise match as described in . Instead, +* matching will only be performed on those bits which are set to 1 in +* the PortInfo:CapabilityMask embedded in the query. +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED (1 << 13) +/***********/ + +/****d* OpenSM: Base/osm_sm_state_t +* NAME +* osm_sm_state_t +* +* DESCRIPTION +* Enumerates the possible states of the SM object. +* +* SYNOPSIS +*/ +typedef enum _osm_sm_state +{ + OSM_SM_STATE_NO_STATE = 0, + OSM_SM_STATE_INIT, + OSM_SM_STATE_IDLE, + OSM_SM_STATE_SWEEP_LIGHT, + OSM_SM_STATE_SWEEP_LIGHT_WAIT, + OSM_SM_STATE_SWEEP_HEAVY_SELF, + OSM_SM_STATE_SWEEP_HEAVY_SUBNET, + OSM_SM_STATE_SET_SM_UCAST_LID, + OSM_SM_STATE_SET_SM_UCAST_LID_WAIT, + OSM_SM_STATE_SET_SM_UCAST_LID_DONE, + OSM_SM_STATE_SET_SUBNET_UCAST_LIDS, + OSM_SM_STATE_SET_SUBNET_UCAST_LIDS_WAIT, + OSM_SM_STATE_SET_SUBNET_UCAST_LIDS_DONE, + OSM_SM_STATE_SET_UCAST_TABLES, + OSM_SM_STATE_SET_UCAST_TABLES_WAIT, + OSM_SM_STATE_SET_UCAST_TABLES_DONE, + OSM_SM_STATE_SET_MCAST_TABLES, + OSM_SM_STATE_SET_MCAST_TABLES_WAIT, + OSM_SM_STATE_SET_MCAST_TABLES_DONE, + OSM_SM_STATE_SET_LINK_PORTS, + OSM_SM_STATE_SET_LINK_PORTS_WAIT, + OSM_SM_STATE_SET_LINK_PORTS_DONE, + OSM_SM_STATE_SET_ARMED, + OSM_SM_STATE_SET_ARMED_WAIT, + OSM_SM_STATE_SET_ARMED_DONE, + OSM_SM_STATE_SET_ACTIVE, + OSM_SM_STATE_SET_ACTIVE_WAIT, + OSM_SM_STATE_LOST_NEGOTIATION, + OSM_SM_STATE_STANDBY, + OSM_SM_STATE_SUBNET_UP, + OSM_SM_STATE_PROCESS_REQUEST, + OSM_SM_STATE_PROCESS_REQUEST_WAIT, + OSM_SM_STATE_PROCESS_REQUEST_DONE, + OSM_SM_STATE_MASTER_OR_HIGHER_SM_DETECTED, + OSM_SM_STATE_SET_PKEY, + OSM_SM_STATE_SET_PKEY_WAIT, + OSM_SM_STATE_SET_PKEY_DONE, + OSM_SM_STATE_MAX +} osm_sm_state_t; +/***********/ + +/****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_CHANGE_DETECTED 2 +#define OSM_SIGNAL_NO_PENDING_TRANSACTIONS 3 +#define OSM_SIGNAL_DONE 4 +#define OSM_SIGNAL_DONE_PENDING 5 +#define OSM_SIGNAL_LOST_SM_NEGOTIATION 6 +#define OSM_SIGNAL_LIGHT_SWEEP_FAIL 7 +#define OSM_SIGNAL_IDLE_TIME_PROCESS 8 +#define OSM_SIGNAL_IDLE_TIME_PROCESS_REQUEST 9 +#define OSM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED 10 +#define OSM_SIGNAL_EXIT_STBY 11 +#define OSM_SIGNAL_MAX 12 + +typedef uintn_t osm_signal_t; +/***********/ + +/****d* OpenSM: Base/osm_state_mgr_mode_t +* NAME +* osm_state_mgr_mode_t +* +* DESCRIPTION +* Enumerates the possible state progressing codes used by the OSM +* state manager. +* +* SYNOPSIS +*/ +typedef enum _osm_state_mgr_mode +{ + OSM_STATE_STEP_CONTINUOUS = 0, + OSM_STATE_STEP_TAKE_ONE, + OSM_STATE_STEP_BREAK +} osm_state_mgr_mode_t; +/* +* OSM_STATE_STEP_CONTINUOUS +* normal automatic progress mode +* +* OSM_STATE_STEP_TAKE_ONE +* Do one step +* +* OSM_STATE_STEP_BREAK +* Stop before taking next step (the while loop in the state +* manager automatically change to this state). +* +**********/ + +/****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_INIT = 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_MASTER_OR_HIGHER_SM_DETECTED_DONE, + OSM_SM_SIGNAL_WAIT_FOR_HANDOVER, + OSM_SM_SIGNAL_MAX + +} osm_sm_signal_t; +/***********/ + +/****d* OpenSM/osm_mcast_req_type_t +* NAME +* osm_mcast_req_type_t +* +* DESCRIPTION +* Enumerates the possible signals used by the OSM_MCAST_REQUEST +* +* SYNOPSIS +*/ +typedef enum _osm_mcast_req_type +{ + OSM_MCAST_REQ_TYPE_CREATE, + OSM_MCAST_REQ_TYPE_JOIN, + OSM_MCAST_REQ_TYPE_LEAVE, + OSM_MCAST_REQ_TYPE_SUBNET_CHANGE + +} osm_mcast_req_type_t; +/***********/ + +/****s* OpenSM: Base/MAX_UPDN_GUID_FILE_LINE_LENGTH +* NAME +* MAX_UPDN_GUID_FILE_LINE_LENGTH +* +* DESCRIPTION +* The maximum line number when reading updn guid file +* +* SYNOPSIS +*/ +#define MAX_UPDN_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 + +/**********/ + +END_C_DECLS + +#endif /* _OSM_BASE_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_console.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_console.h new file mode 100644 index 00000000..da0fac3a --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_console.h @@ -0,0 +1,58 @@ +/* + * 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$ + */ + + +#ifndef _OSM_CONSOLE_H_ +#define _OSM_CONSOLE_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 + +void osm_console(osm_opensm_t *p_osm); +void osm_console_prompt(void); + +END_C_DECLS + +#endif /* _OSM_CONSOLE_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_db.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_db.h new file mode 100644 index 00000000..cb68b474 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_db.h @@ -0,0 +1,455 @@ +/* + * 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$ + */ + + +#ifndef _OSM_DB_H_ +#define _OSM_DB_H_ + +/* + * Abstract: + * Declaration of the DB interface. + * + * $Revision: 1.4 $ + */ + +#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 persistat +* data, query, modify, delete and evemtually commit it back to the +* persistent media. +* +* The interface is defined such that it can is not "data dependant": +* All keys and data items are texts. +* +* The DB implementation should be thread safe, thus callers do not need to +* provide serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox Technologies LTD +* +*********/ + +/****s* OpenSM: Database/osm_db_domain_t +* NAME +* osm_db_domain_t +* +* DESCRIPTION +* A domain of the database. Can be viewed as a database table. +* +* The osm_db_domain_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_db_domain { + struct _osm_db *p_db; + void *p_domain_imp; +} osm_db_domain_t; +/* +* FIELDS +* p_db +* Pointer to the parent database object. +* +* p_domain_imp +* Pointer to the db implementation object +* +* SEE ALSO +* osm_db_t +*********/ + +/****s* OpenSM: Database/osm_db_t +* NAME +* osm_db_t +* +* DESCRIPTION +* The main database object. +* +* The osm_db_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_db +{ + void *p_db_imp; + osm_log_t *p_log; + cl_list_t domains; +} osm_db_t; +/* +* FIELDS +* p_db_imp +* Pointer to the database implementation object +* +* p_log +* Pointer to the OSM logging facility +* +* domains +* List of initialize domains +* +* SEE ALSO +*********/ + +/****f* OpenSM: Database/osm_db_construct +* NAME +* osm_db_construct +* +* DESCRIPTION +* Construct a database. +* +* SYNOPSIS +*/ +void +osm_db_construct( + IN osm_db_t* const p_db ); +/* +* PARAMETERS +* p_db +* [in] Pointer to the database object to custruct +* +* RETURN VALUES +* NONE +* +* SEE ALSO +* Database, osm_db_init, osm_db_destroy +*********/ + +/****f* OpenSM: Database/osm_db_destroy +* NAME +* osm_db_destroy +* +* DESCRIPTION +* Destroys the osm_db_t structure. +* +* SYNOPSIS +*/ +void +osm_db_destroy( + IN osm_db_t* const p_db ); +/* +* PARAMETERS +* p_db +* [in] Pointer to osm_db_t structure to destroy +* +* SEE ALSO +* Database, osm_db_construct, osm_db_init +*********/ + +/****f* OpenSM: Database/osm_db_init +* NAME +* osm_db_init +* +* DESCRIPTION +* Initializes the osm_db_t structure. +* +* SYNOPSIS +*/ +int +osm_db_init( + IN osm_db_t* const p_db, + IN osm_log_t *p_log ); +/* +* PARAMETERS +* +* p_db +* [in] Pointer to the database object to initialize +* +* p_log +* [in] Pointer to the OSM logging facility +* +* RETURN VALUES +* 0 on success 1 otherwise +* +* SEE ALSO +* Database, osm_db_construct, osm_db_destroy +*********/ + +/****f* OpenSM: Database/osm_db_domain_init +* NAME +* osm_db_domain_init +* +* DESCRIPTION +* Initializes the osm_db_domain_t structure. +* +* SYNOPSIS +*/ +osm_db_domain_t* +osm_db_domain_init( + IN osm_db_t* const p_db, + IN char *domain_name); +/* +* PARAMETERS +* +* p_db +* [in] Pointer to the database object to initialize +* +* domain_name +* [in] a char array with the domain name. +* +* RETURN VALUES +* pointer to the new domain object or NULL if failed. +* +* SEE ALSO +* Database, osm_db_construct, osm_db_destroy +*********/ + +/****f* OpenSM: Database/osm_db_restore +* NAME +* osm_db_restore +* +* DESCRIPTION +* Reads the entire domain from persistent storage - overrides all +* existing cached data (if any). +* +* SYNOPSIS +*/ +int +osm_db_restore( + IN osm_db_domain_t *p_domain); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object to restore from persistent db +* +* RETURN VALUES +* 0 if successful 1 otherwize +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_clear, osm_db_store, +* osm_db_keys, osm_db_lookup, osm_db_update, osm_db_delete +*********/ + +/****f* OpenSM: Database/osm_db_clear +* NAME +* osm_db_clear +* +* DESCRIPTION +* Clears the entire domain values from/in the cache +* +* SYNOPSIS +*/ +int +osm_db_clear( + IN osm_db_domain_t *p_domain); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object to clear +* +* RETURN VALUES +* 0 if successful 1 otherwize +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_restore, osm_db_store, +* osm_db_keys, osm_db_lookup, osm_db_update, osm_db_delete +*********/ + +/****f* OpenSM: Database/osm_db_store +* NAME +* osm_db_store +* +* DESCRIPTION +* Store the domain cache back to the database (commit) +* +* SYNOPSIS +*/ +int osm_db_store( + IN osm_db_domain_t *p_domain); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object to restore from persistent db +* +* RETURN VALUES +* 0 if successful 1 otherwize +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_restore, osm_db_clear, +* osm_db_keys, osm_db_lookup, osm_db_update, osm_db_delete +*********/ + +/****f* OpenSM: Database/osm_db_keys +* NAME +* osm_db_keys +* +* DESCRIPTION +* Retrive all keys of the domain +* +* SYNOPSIS +*/ +int +osm_db_keys( + IN osm_db_domain_t *p_domain, + OUT cl_list_t* p_key_list); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object +* +* p_key_list +* [out] List of key values. It should be PRE constructed and initialized. +* +* RETURN VALUES +* 0 if successful 1 otherwize +* +* NOTE: the caller needs to free and destruct the list, +* the keys returned are intrnal to the hash and should NOT be free'ed +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_restore, osm_db_clear, osm_db_store, +* osm_db_lookup, osm_db_update, osm_db_delete +*********/ + +/****f* OpenSM: Database/osm_db_lookup +* NAME +* osm_db_lookup +* +* DESCRIPTION +* Lookup an entry in the domain by the given key +* +* SYNOPSIS +*/ +/* lookup value by key */ +char *osm_db_lookup( + IN osm_db_domain_t *p_domain, + IN char *const p_key); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object +* +* key +* [in] The key to look for +* +* RETURN VALUES +* the value as char * or NULL if not found +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_restore, osm_db_clear, osm_db_store, +* osm_db_keys, osm_db_update, osm_db_delete +*********/ + +/****f* OpenSM: Database/osm_db_update +* NAME +* osm_db_update +* +* DESCRIPTION +* Set the value of the given key +* +* SYNOPSIS +*/ +int +osm_db_update( + IN osm_db_domain_t *p_domain, + IN char *const p_key, + IN char *const p_val); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object +* +* p_key +* [in] The key to update +* +* p_val +* [in] The value to update +* +* RETURN VALUES +* 0 on success +* +* NOTE: the value will be duplicated so can be free'ed +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_restore, osm_db_clear, osm_db_store, +* osm_db_keys, osm_db_lookup, osm_db_delete +*********/ + +/****f* OpenSM: Database/osm_db_delete +* NAME +* osm_db_delete +* +* DESCRIPTION +* Delete an entry by the given key +* +* SYNOPSIS +*/ +int +osm_db_delete( + IN osm_db_domain_t *p_domain, + IN char *const p_key); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object +* +* p_key +* [in] The key to look for +* +* RETURN VALUES +* 0 on success +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_restore, osm_db_clear, osm_db_store, +* osm_db_keys, osm_db_lookup, osm_db_update +*********/ + +END_C_DECLS + +#endif /* _OSM_DB_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_db_pack.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_db_pack.h new file mode 100644 index 00000000..52cdaacc --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_db_pack.h @@ -0,0 +1,255 @@ +/* + * 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$ + */ + + +/****h* OpenSM/DB-Pack +* NAME +* Database Types +* +* DESCRIPTION +* This module provides packing and unpacking of the database +* storage into specific types. +* +* The following domains/conversions are supported: +* guid2lid - key is a guid and data is a lid. +* +* AUTHOR +* Eitan Zahavi, Mellanox Technologies LTD +* +*********/ + +#ifndef _OSM_DB_PACK_H_ +#define _OSM_DB_PACK_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +/****f* OpenSM: DB-Pack/osm_db_guid2lid_init +* NAME +* osm_db_guid2lid_init +* +* DESCRIPTION +* Initialize a domain for the guid2lid table +* +* SYNOPSIS +*/ +static inline osm_db_domain_t* +osm_db_guid2lid_init( + IN osm_db_t* const p_db ) +{ + return( osm_db_domain_init( p_db, "guid2lid" ) ); +} +/* +* PARAMETERS +* p_db +* [in] Pointer to the database object to construct +* +* RETURN VALUES +* The pointer to the new allocated domain object or NULL. +* +* NOTE: DB domains are destroyed by the osm_db_destroy +* +* SEE ALSO +* Database, osm_db_init, osm_db_destroy +*********/ + +/****f* OpenSM: DB-Pack/osm_db_guid2lid_init +* NAME +* osm_db_guid2lid_init +* +* DESCRIPTION +* Initialize a domain for the guid2lid table +* +* SYNOPSIS +*/ +typedef struct _osm_db_guid_elem { + cl_list_item_t item; + uint64_t guid; +} osm_db_guid_elem_t; +/* +* FIELDS +* item +* required for list manipulations +* +* guid +* +************/ + +/****f* OpenSM: DB-Pack/osm_db_guid2lid_guids +* NAME +* osm_db_guid2lid_guids +* +* DESCRIPTION +* Provides back a list of guid elements. +* +* SYNOPSIS +*/ +int +osm_db_guid2lid_guids( + IN osm_db_domain_t* const p_g2l, + OUT cl_qlist_t* p_guid_list ); +/* +* PARAMETERS +* p_g2l +* [in] Pointer to the guid2lid domain +* +* p_guid_list +* [out] A quick list of guid elements of type osm_db_guid_elem_t +* +* RETURN VALUES +* 0 if successful +* +* NOTE: the output qlist should be initialized and each item freed +* by the caller, then destroyed. +* +* SEE ALSO +* osm_db_guid2lid_init, osm_db_guid2lid_guids, osm_db_guid2lid_get +* osm_db_guid2lid_set, osm_db_guid2lid_delete +*********/ + +/****f* OpenSM: DB-Pack/osm_db_guid2lid_get +* NAME +* osm_db_guid2lid_get +* +* DESCRIPTION +* Get a lid range by given guid. +* +* SYNOPSIS +*/ +int +osm_db_guid2lid_get( + IN osm_db_domain_t* const p_g2l, + IN uint64_t guid, + OUT uint16_t *p_min_lid, + OUT uint16_t *p_max_lid); +/* +* PARAMETERS +* p_g2l +* [in] Pointer to the guid2lid domain +* +* guid +* [in] The guid to look for +* +* p_min_lid +* [out] Pointer to the resulting min lid in host order. +* +* p_max_lid +* [out] Pointer to the resulting max lid in host order. +* +* RETURN VALUES +* 0 if successful. The lid will be set to 0 if not found. +* +* SEE ALSO +* osm_db_guid2lid_init, osm_db_guid2lid_guids +* osm_db_guid2lid_set, osm_db_guid2lid_delete +*********/ + +/****f* OpenSM: DB-Pack/osm_db_guid2lid_set +* NAME +* osm_db_guid2lid_set +* +* DESCRIPTION +* Set a lid range for the given guid. +* +* SYNOPSIS +*/ +int +osm_db_guid2lid_set( + IN osm_db_domain_t* const p_g2l, + IN uint64_t guid, + IN uint16_t min_lid, + IN uint16_t max_lid); +/* +* PARAMETERS +* p_g2l +* [in] Pointer to the guid2lid domain +* +* guid +* [in] The guid to look for +* +* min_lid +* [in] The min lid value to set +* +* max_lid +* [in] The max lid value to set +* +* RETURN VALUES +* 0 if successful +* +* SEE ALSO +* osm_db_guid2lid_init, osm_db_guid2lid_guids +* osm_db_guid2lid_get, osm_db_guid2lid_delete +*********/ + +/****f* OpenSM: DB-Pack/osm_db_guid2lid_delete +* NAME +* osm_db_guid2lid_delete +* +* DESCRIPTION +* Delete the entry by the given guid +* +* SYNOPSIS +*/ +int +osm_db_guid2lid_delete( + IN osm_db_domain_t* const p_g2l, + IN uint64_t guid ); +/* +* PARAMETERS +* p_g2l +* [in] Pointer to the guid2lid domain +* +* guid +* [in] The guid to look for +* +* RETURN VALUES +* 0 if successful otherwise 1 +* +* SEE ALSO +* osm_db_guid2lid_init, osm_db_guid2lid_guids +* osm_db_guid2lid_get, osm_db_guid2lid_set +*********/ + +END_C_DECLS + +#endif /* _OSM_DB_PACK_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_drop_mgr.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_drop_mgr.h new file mode 100644 index 00000000..81c51fa4 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_drop_mgr.h @@ -0,0 +1,259 @@ +/* + * 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: + * Declaration of osm_drop_mgr_t. + * This object represents the Drop Manager object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_DROP_MGR_H_ +#define _OSM_DROP_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 + +/****h* OpenSM/Drop Manager +* NAME +* Drop Manager +* +* DESCRIPTION +* The Drop Manager object encapsulates the information +* needed to receive the SwitchInfo attribute from a node. +* +* The Drop 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 +* +*********/ + +/****s* OpenSM: Drop Manager/osm_drop_mgr_t +* NAME +* osm_drop_mgr_t +* +* DESCRIPTION +* Drop Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_drop_mgr +{ + osm_subn_t *p_subn; + osm_log_t *p_log; + osm_req_t *p_req; + cl_plock_t *p_lock; + +} osm_drop_mgr_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_log +* Pointer to the log object. +* +* p_req +* Pointer to the Request object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* Drop Manager object +*********/ + +/****f* OpenSM: Drop Manager/osm_drop_mgr_construct +* NAME +* osm_drop_mgr_construct +* +* DESCRIPTION +* This function constructs a Drop Manager object. +* +* SYNOPSIS +*/ +void osm_drop_mgr_construct( + IN osm_drop_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to a Drop Manager object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_drop_mgr_init, osm_drop_mgr_destroy +* +* Calling osm_drop_mgr_construct is a prerequisite to calling any other +* method except osm_drop_mgr_init. +* +* SEE ALSO +* Drop Manager object, osm_drop_mgr_init, +* osm_drop_mgr_destroy +*********/ + +/****f* OpenSM: Drop Manager/osm_drop_mgr_destroy +* NAME +* osm_drop_mgr_destroy +* +* DESCRIPTION +* The osm_drop_mgr_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_drop_mgr_destroy( + IN osm_drop_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Drop Manager object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_drop_mgr_construct or osm_drop_mgr_init. +* +* SEE ALSO +* Drop Manager object, osm_drop_mgr_construct, +* osm_drop_mgr_init +*********/ + +/****f* OpenSM: Drop Manager/osm_drop_mgr_init +* NAME +* osm_drop_mgr_init +* +* DESCRIPTION +* The osm_drop_mgr_init function initializes a +* Drop Manager object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_drop_mgr_init( + IN osm_drop_mgr_t* const p_mgr, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_req_t* const p_req, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_drop_mgr_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the Drop Manager object was initialized +* successfully. +* +* NOTES +* Allows calling other Drop Manager methods. +* +* SEE ALSO +* Drop Manager object, osm_drop_mgr_construct, +* osm_drop_mgr_destroy +*********/ + +/****f* OpenSM: Drop Manager/osm_drop_mgr_process +* NAME +* osm_drop_mgr_process +* +* DESCRIPTION +* Process the SwitchInfo attribute. +* +* SYNOPSIS +*/ +void osm_drop_mgr_process( + IN const osm_drop_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_drop_mgr_t object. +* +* RETURN VALUES +* None +* +* NOTES +* This function processes a SwitchInfo attribute. +* +* SEE ALSO +* Drop Manager, Switch Info Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_DROP_MGR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_errors.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_errors.h new file mode 100644 index 00000000..c1ffb723 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_errors.h @@ -0,0 +1,181 @@ +/* + * 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: + * Declaration of error code ranges for the various OpenSM modules. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#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-1/ulp/opensm/user/include/opensm/osm_fwd_tbl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_fwd_tbl.h new file mode 100644 index 00000000..ac31131d --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_fwd_tbl.h @@ -0,0 +1,388 @@ +/* + * 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: + * Declaration of osm_fwd_tbl_t. + * This object represents a unicast forwarding table. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_FWD_TBL_H_ +#define _OSM_FWD_TBL_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/Forwarding Table +* NAME +* Forwarding Table +* +* DESCRIPTION +* The Forwarding Table objects encapsulate the information +* needed by the OpenSM to manage forwarding tables. The OpenSM +* allocates one Forwarding Table object per switch in the +* IBA subnet. +* +* The Forwarding Table objects are not thread safe, thus +* callers must provide serialization. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Forwarding Table/osm_fwd_tbl_t +* NAME +* osm_fwd_tbl_t +* +* DESCRIPTION +* Forwarding Table structure. This object hides the type +* of fowarding table (linear or random) actually used by +* the switch. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_fwd_tbl_t +{ + osm_rand_fwd_tbl_t *p_rnd_tbl; + osm_lin_fwd_tbl_t *p_lin_tbl; + +} osm_fwd_tbl_t; +/* +* FIELDS +* p_rnd_tbl +* Pointer to the switch's Random Forwarding Table object. +* If the switch does not use a Random Forwarding Table, +* then this pointer is NULL. +* +* p_lin_tbl +* Pointer to the switch's Linear Forwarding Table object. +* If the switch does not use a Linear Forwarding Table, +* then this pointer is NULL. +* +* SEE ALSO +* Forwarding Table object, Random Forwarding Table object. +*********/ + +/****f* OpenSM: Forwarding Table/osm_fwd_tbl_init +* NAME +* osm_fwd_tbl_init +* +* DESCRIPTION +* Initializes a Forwarding Table object. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_fwd_tbl_init( + IN osm_fwd_tbl_t* const p_tbl, + IN const ib_switch_info_t* const p_si ); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* p_si +* [in] Pointer to the SwitchInfo attribute of the associated +* switch. +* +* RETURN VALUE +* IB_SUCCESS if the operation is successful. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_fwd_tbl_destroy +* NAME +* osm_fwd_tbl_destroy +* +* DESCRIPTION +* Destroys a Forwarding Table object. +* +* SYNOPSIS +*/ +void +osm_fwd_tbl_destroy( + IN osm_fwd_tbl_t* const p_tbl ); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_fwd_tbl_get +* NAME +* osm_fwd_tbl_get +* +* DESCRIPTION +* Returns the port that routes the specified LID. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_fwd_tbl_get( + IN const osm_fwd_tbl_t* const p_tbl, + IN uint16_t const lid_ho ) +{ + if( p_tbl->p_lin_tbl ) + return( osm_lin_fwd_tbl_get( p_tbl->p_lin_tbl, lid_ho ) ); + else + return( osm_rand_fwd_tbl_get( p_tbl->p_rnd_tbl, lid_ho ) ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* lid_ho +* [in] LID (host order) for which to find the route. +* +* RETURN VALUE +* Returns the port that routes the specified LID. +* IB_INVALID_PORT_NUM if the table does not have a route for this LID. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_fwd_tbl_set +* NAME +* osm_fwd_tbl_set +* +* DESCRIPTION +* Sets the port to route the specified LID. +* +* SYNOPSIS +*/ +static inline void +osm_fwd_tbl_set( + IN osm_fwd_tbl_t* const p_tbl, + IN const uint16_t lid_ho, + IN const uint8_t port ) +{ + CL_ASSERT( p_tbl ); + if( p_tbl->p_lin_tbl ) + osm_lin_fwd_tbl_set( p_tbl->p_lin_tbl, lid_ho, port ); + else + osm_rand_fwd_tbl_set( p_tbl->p_rnd_tbl, lid_ho, port ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* lid_ho +* [in] LID value (host order) for which to set the route. +* +* port +* [in] Port to route the specified LID value. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_fwd_tbl_set_block +* NAME +* osm_fwd_tbl_set_block +* +* DESCRIPTION +* Copies the specified block into the Forwarding Table. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +osm_fwd_tbl_set_block( + IN osm_fwd_tbl_t* const p_tbl, + IN const uint8_t* const p_block, + IN const uint32_t block_num ) +{ + CL_ASSERT( p_tbl ); + if( p_tbl->p_lin_tbl ) + return( osm_lin_fwd_tbl_set_block( p_tbl->p_lin_tbl, + p_block, block_num ) ); + else + return( osm_rand_fwd_tbl_set_block( p_tbl->p_rnd_tbl, + p_block, block_num ) ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_fwd_tbl_get_size +* NAME +* osm_fwd_tbl_get_size +* +* DESCRIPTION +* Returns the number of entries available in the forwarding table. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_fwd_tbl_get_size( + IN const osm_fwd_tbl_t* const p_tbl ) +{ + CL_ASSERT( p_tbl ); + if( p_tbl->p_lin_tbl ) + return( osm_lin_fwd_tbl_get_size( p_tbl->p_lin_tbl ) ); + else + return( osm_rand_fwd_tbl_get_size( p_tbl->p_rnd_tbl ) ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* RETURN VALUE +* Returns the number of entries available in the forwarding table. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_fwd_tbl_get_lids_per_block +* NAME +* osm_fwd_tbl_get_lids_per_block +* +* DESCRIPTION +* Returns the number of LIDs per LID block. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_fwd_tbl_get_lids_per_block( + IN const osm_fwd_tbl_t* const p_tbl ) +{ + CL_ASSERT( p_tbl ); + if( p_tbl->p_lin_tbl ) + return( osm_lin_fwd_tbl_get_lids_per_block( p_tbl->p_lin_tbl ) ); + else + return( osm_rand_fwd_tbl_get_lids_per_block( p_tbl->p_rnd_tbl ) ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* RETURN VALUE +* Returns the number of LIDs per LID block. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_fwd_tbl_get_max_block_id_in_use +* NAME +* osm_fwd_tbl_get_max_block_id_in_use +* +* DESCRIPTION +* Returns the number of LIDs per LID block. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_fwd_tbl_get_max_block_id_in_use( + IN const osm_fwd_tbl_t* const p_tbl, + IN const uint16_t lid_top_ho ) +{ + CL_ASSERT( p_tbl ); + if( p_tbl->p_lin_tbl ) + return( osm_lin_fwd_tbl_get_max_block_id_in_use( + p_tbl->p_lin_tbl, lid_top_ho ) ); + else + return( osm_rand_fwd_tbl_get_max_block_id_in_use( + p_tbl->p_rnd_tbl, lid_top_ho ) ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* RETURN VALUE +* Returns the number of LIDs per LID block. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_FWD_TBL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_helper.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_helper.h new file mode 100644 index 00000000..a713c5c6 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_helper.h @@ -0,0 +1,620 @@ +/* + * 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$ + */ + + +#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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +/****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/osm_dump_port_info +* NAME +* osm_dump_port_info +* +* DESCRIPTION +* Dumps the PortInfo attribute to the log. +* +* SYNOPSIS +*/ +void osm_dump_port_info( + IN osm_log_t* const p_log, + IN const ib_net64_t node_guid, + IN const ib_net64_t port_guid, + IN const uint8_t port_num, + IN const ib_port_info_t* const p_pi, + IN const osm_log_level_t log_level ); +/* +* PARAMETERS +* p_log +* [in] Pointer to the osm_log_t object +* +* node_guid +* [in] Node GUID that owns this port. +* +* port_guid +* [in] Port GUID for this port. +* +* port_num +* [in] Port number for this port. +* +* p_pi +* [in] Pointer to the PortInfo attribute +* +* log_level +* [in] Log verbosity level with which to dump the data. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +void +osm_dump_path_record( + IN osm_log_t* const p_log, + IN const ib_path_rec_t* const p_pr, + IN const osm_log_level_t log_level ); + +void +osm_dump_multipath_record( + IN osm_log_t* const p_log, + IN const ib_multipath_rec_t* const p_mpr, + IN const osm_log_level_t log_level ); + +void +osm_dump_node_record( + IN osm_log_t* const p_log, + IN const ib_node_record_t* const p_nr, + IN const osm_log_level_t log_level ); + +void +osm_dump_mc_record( + IN osm_log_t* const p_log, + IN const ib_member_rec_t* const p_mcmr, + IN const osm_log_level_t log_level ); + +void +osm_dump_link_record( + IN osm_log_t* const p_log, + IN const ib_link_record_t* const p_lr, + IN const osm_log_level_t log_level ); + +void +osm_dump_service_record( + IN osm_log_t* const p_log, + IN const ib_service_record_t* const p_sr, + IN const osm_log_level_t log_level ); + +void +osm_dump_portinfo_record( + IN osm_log_t* const p_log, + IN const ib_portinfo_record_t* const p_pir, + IN const osm_log_level_t log_level ); + +void +osm_dump_guidinfo_record( + IN osm_log_t* const p_log, + IN const ib_guidinfo_record_t* const p_gir, + IN const osm_log_level_t log_level ); + +void +osm_dump_inform_info( + IN osm_log_t* const p_log, + IN const ib_inform_info_t* const p_ii, + IN const osm_log_level_t log_level ); + +void +osm_dump_inform_info_record( + IN osm_log_t* const p_log, + IN const ib_inform_info_record_t* const p_iir, + IN const osm_log_level_t log_level ); + +void +osm_dump_switch_info_record( + IN osm_log_t* const p_log, + IN const ib_switch_info_record_t* const p_sir, + IN const osm_log_level_t log_level ); + +void +osm_dump_sm_info_record( + IN osm_log_t* const p_log, + IN const ib_sminfo_record_t* const p_smir, + IN const osm_log_level_t log_level ); + +void +osm_dump_pkey_block( + IN osm_log_t* const p_log, + IN uint64_t port_guid, + IN uint16_t block_num, + IN uint8_t port_num, + IN const ib_pkey_table_t* const p_pkey_tbl, + IN const osm_log_level_t log_level ); + +void +osm_dump_slvl_map_table( + IN osm_log_t* const p_log, + IN uint64_t port_guid, + IN uint8_t in_port_num, + IN uint8_t out_port_num, + IN const ib_slvl_table_t* const p_slvl_tbl, + IN const osm_log_level_t log_level ); + +void +osm_dump_vl_arb_table( + IN osm_log_t* const p_log, + IN uint64_t port_guid, + IN uint8_t block_num, + IN uint8_t port_num, + IN const ib_vl_arb_table_t* const p_vla_tbl, + IN const osm_log_level_t log_level ); + +/****f* OpenSM: Helper/osm_dump_port_info +* NAME +* osm_dump_port_info +* +* DESCRIPTION +* Dumps the PortInfo attribute to the log. +* +* SYNOPSIS +*/ +void osm_dump_node_info( + IN osm_log_t* const p_log, + IN const ib_node_info_t* const p_ni, + IN const osm_log_level_t log_level ); +/* +* PARAMETERS +* p_log +* [in] Pointer to the osm_log_t object +* +* p_ni +* [in] Pointer to the NodeInfo attribute +* +* log_level +* [in] Log verbosity level with which to dump the data. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/osm_dump_sm_info +* NAME +* osm_dump_sm_info +* +* DESCRIPTION +* Dumps the SMInfo attribute to the log. +* +* SYNOPSIS +*/ +void +osm_dump_sm_info( + IN osm_log_t* const p_log, + IN const ib_sm_info_t* const p_smi, + IN const osm_log_level_t log_level ); +/* +* PARAMETERS +* p_log +* [in] Pointer to the osm_log_t object +* +* p_smi +* [in] Pointer to the SMInfo attribute +* +* log_level +* [in] Log verbosity level with which to dump the data. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/osm_dump_switch_info +* NAME +* osm_dump_switch_info +* +* DESCRIPTION +* Dumps the SwitchInfo attribute to the log. +* +* SYNOPSIS +*/ +void +osm_dump_switch_info( + IN osm_log_t* const p_log, + IN const ib_switch_info_t* const p_si, + IN const osm_log_level_t log_level ); +/* +* PARAMETERS +* p_log +* [in] Pointer to the osm_log_t object +* +* p_si +* [in] Pointer to the SwitchInfo attribute +* +* log_level +* [in] Log verbosity level with which to dump the data. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/osm_dump_notice +* NAME +* osm_dump_notice +* +* DESCRIPTION +* Dumps the Notice attribute to the log. +* +* SYNOPSIS +*/ +void +osm_dump_notice( + IN osm_log_t* const p_log, + IN const ib_mad_notice_attr_t *p_ntci, + IN const osm_log_level_t log_level ); +/* +* PARAMETERS +* p_log +* [in] Pointer to the osm_log_t object +* +* p_ntci +* [in] Pointer to the Notice attribute +* +* log_level +* [in] Log verbosity level with which to dump the data. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/osm_get_disp_msg_str +* NAME +* osm_get_disp_msg_str +* +* DESCRIPTION +* Returns a string for the specified Dispatcher message. +* +* SYNOPSIS +*/ +const char* +osm_get_disp_msg_str( + IN cl_disp_msgid_t msg ); +/* +* PARAMETERS +* msg +* [in] Dispatcher message ID value. +* +* RETURN VALUES +* Pointer to the message discription string. +* +* NOTES +* +* SEE ALSO +*********/ + +void osm_dump_dr_path( + IN osm_log_t* const p_log, + IN const osm_dr_path_t* const p_path, + IN const osm_log_level_t level ); + +void osm_dump_smp_dr_path( + IN osm_log_t* const p_log, + IN const ib_smp_t* const p_smp, + IN const osm_log_level_t level ); + +void osm_dump_dr_smp( + IN osm_log_t* const p_log, + IN const ib_smp_t* const p_smp, + IN const osm_log_level_t level ); + +void osm_dump_sa_mad( + IN osm_log_t* const p_log, + IN const ib_sa_mad_t* const p_smp, + IN const osm_log_level_t level ); + +/****f* IBA Base: Types/osm_get_sm_state_str +* NAME +* osm_get_sm_state_str +* +* DESCRIPTION +* Returns a string for the specified SM state. +* +* SYNOPSIS +*/ +const char* +osm_get_sm_state_str( + IN osm_sm_state_t state ); +/* +* PARAMETERS +* state +* [in] SM State value +* +* RETURN VALUES +* Pointer to the state discription string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/osm_get_sm_signal_str +* NAME +* osm_get_sm_signal_str +* +* DESCRIPTION +* Returns a string for the specified SM state. +* +* SYNOPSIS +*/ +const char* +osm_get_sm_signal_str( + IN osm_signal_t signal ); +/* +* PARAMETERS +* state +* [in] Signal value +* +* RETURN VALUES +* Pointer to the signal discription string. +* +* NOTES +* +* SEE ALSO +*********/ + +const char* +osm_get_port_state_str_fixed_width( + IN uint8_t port_state ); + +const char* +osm_get_node_type_str_fixed_width( + IN uint32_t node_type ); + +const char* +osm_get_manufacturer_str( + IN uint64_t const guid_ho ); + +const char* +osm_get_mtu_str( + IN uint8_t const mtu ); + +const char* +osm_get_lwa_str( + IN uint8_t const lwa ); + +const char* +osm_get_mtu_str( + IN uint8_t const mtu ); + +const char* +osm_get_lwa_str( + IN uint8_t const lwa ); + +const char* +osm_get_lsa_str( + IN uint8_t const lsa ); + + +/****f* IBA Base: Types/osm_get_sm_mgr_signal_str +* NAME +* osm_get_sm_mgr_signal_str +* +* DESCRIPTION +* Returns a string for the specified SM manager signal. +* +* SYNOPSIS +*/ +const char* +osm_get_sm_mgr_signal_str( + IN osm_sm_signal_t signal ); +/* +* PARAMETERS +* signal +* [in] SM manager signal +* +* RETURN VALUES +* Pointer to the signal discription string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/osm_get_sm_mgr_state_str +* NAME +* osm_get_sm_mgr_state_str +* +* DESCRIPTION +* Returns a string for the specified SM manager state. +* +* SYNOPSIS +*/ +const char* +osm_get_sm_mgr_state_str( + IN uint16_t state ); +/* +* PARAMETERS +* state +* [in] SM manager state +* +* RETURN VALUES +* Pointer to the state discription string. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_HELPER_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_inform.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_inform.h new file mode 100644 index 00000000..70849ea7 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_inform.h @@ -0,0 +1,305 @@ +/* + * 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: + * Declaration of osm_inform_rec_t. + * This object represents an IBA Inform Record. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * Author: + * Eitan Zahavi, Mellanox + * + * $Revision: 1.5 $ + */ + +#ifndef _OSM_INFR_H_ +#define _OSM_INFR_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/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_t +{ + cl_list_item_t list_item; + osm_bind_handle_t h_bind; + osm_infr_rcv_t* p_infr_rcv; + 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 +* +* p_infr_rcv +* The receiver of inform_info's +* +* 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 service record methods. +* +* SEE ALSO +* Inform Record, osm_infr_construct, osm_infr_destroy +*********/ + +/****f* OpenSM: Inform Record/osm_infr_init +* NAME +* osm_infr_new +* +* DESCRIPTION +* Initializes the osm_infr_t structure. +* +* SYNOPSIS +*/ +void +osm_infr_init( + IN osm_infr_t* const p_infr, + IN const osm_infr_t *p_infr_rec ); +/* +* PARAMETERS +* p_infr +* [in] Pointer to osm_infr_t structure +* p_inf_rec +* [in] Pointer to the ib_inform_info_record_t +* +* SEE ALSO +* Inform Record, osm_infr_construct, osm_infr_destroy +*********/ + +/****f* OpenSM: Inform Record/osm_infr_construct +* NAME +* osm_infr_construct +* +* DESCRIPTION +* Constructs the osm_infr_t structure. +* +* SYNOPSIS +*/ +void +osm_infr_construct( + IN osm_infr_t* const p_infr ); +/* +* PARAMETERS +* p_infr +* [in] Pointer to osm_infr_t structure +* +* SEE ALSO +* Inform Record, osm_infr_construct, osm_infr_destroy +*********/ + +/****f* OpenSM: Inform Record/osm_infr_destroy +* NAME +* osm_infr_destroy +* +* DESCRIPTION +* Constructs the osm_infr_t structure. +* +* SYNOPSIS +*/ +void +osm_infr_destroy( + IN osm_infr_t* const p_infr ); +/* +* PARAMETERS +* p_infr +* [in] Pointer to osm_infr_t structure +* +* SEE ALSO +* Inform Record, osm_infr_construct, osm_infr_destroy +*********/ + +/****f* OpenSM: Inform Record/osm_infr_get_by_rec +* NAME +* osm_infr_get_by_rec +* +* DESCRIPTION +* Find a matching osm_infr_t in the subnet DB by inform_info_record +* +* SYNOPSIS +*/ +osm_infr_t* +osm_infr_get_by_rec( + IN osm_subn_t const *p_subn, + IN osm_log_t *p_log, + IN osm_infr_t* const p_infr_rec ); +/* +* PARAMETERS +* p_subn +* [in] Pointer to the subnet object +* +* p_log +* [in] Pointer to the log object +* +* p_inf_rec +* [in] Pointer to an inform_info record +* +* RETURN +* The matching osm_infr_t +* SEE ALSO +* Inform Record, osm_infr_construct, osm_infr_destroy +*********/ + +void +osm_infr_insert_to_db( + IN osm_subn_t *p_subn, + IN osm_log_t *p_log, + IN osm_infr_t *p_infr); + +void +osm_infr_remove_from_db( + IN osm_subn_t *p_subn, + IN osm_log_t *p_log, + IN osm_infr_t *p_infr); + +/****f* OpenSM: Inform Record/osm_report_notice +* NAME +* osm_report_notice +* +* DESCRIPTION +* Once a Trap was received by the osm_trap_rcv, or a Trap sourced in +* the SM was sent (Traps 64-67) this routine is called with a copy of +* the notice data. +* Given a notice attribute - compare and see if it matches the InformInfo +* Element and if it does - call the Report(Notice) for the +* target QP registered by the address stored in the InformInfo element +* +* SYNOPSIS +*/ +ib_api_status_t +osm_report_notice( + IN osm_log_t* const p_log, + IN osm_subn_t* p_subn, + IN ib_mad_notice_attr_t* p_ntc ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the trap receiver +* +* p_ntc +* [in] Pointer to a copy of the incoming trap notice attribute. +* +* RETURN +* IB_SUCCESS on good completion +* +* SEE ALSO +* Inform Record, osm_trap_rcv +*********/ + +END_C_DECLS + +#endif /* _OSM_INFR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lid_mgr.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lid_mgr.h new file mode 100644 index 00000000..0d63d2e5 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lid_mgr.h @@ -0,0 +1,322 @@ +/* + * 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: + * Declaration of osm_lid_mgr_t. + * This object represents the LID Manager object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_LID_MGR_H_ +#define _OSM_LID_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 + +#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 +* +*********/ + +/****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 +{ + osm_subn_t *p_subn; + osm_db_t *p_db; + osm_req_t *p_req; + osm_log_t *p_log; + cl_plock_t *p_lock; + boolean_t send_set_reqs; + osm_db_domain_t *p_g2l; + cl_ptr_vector_t used_lids; + cl_qlist_t free_ranges; +} osm_lid_mgr_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_db +* Pointer to the database (persistency) object +* +* p_req +* Pointer to the Requester object sending SMPs. +* +* 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 +* A vector the maps from the lid to its guid. keeps track of +* existing and non existing mapping of guid->lid +* +* free_ranges +* A list of available free lid ranges. The list is initialized +* by the code that initializes the lid assignment and is consumed +* by the procedure that finds a free range. It holds elements of +* type osm_lid_mgr_range_t +* +* SEE ALSO +* LID Manager object +*********/ + +/****f* OpenSM: LID Manager/osm_lid_mgr_construct +* NAME +* osm_lid_mgr_construct +* +* DESCRIPTION +* This function constructs a LID Manager object. +* +* SYNOPSIS +*/ +void +osm_lid_mgr_construct( + IN osm_lid_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to a LID Manager object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows osm_lid_mgr_destroy +* +* Calling osm_lid_mgr_construct is a prerequisite to calling any other +* method except osm_lid_mgr_init. +* +* SEE ALSO +* LID Manager object, osm_lid_mgr_init, +* osm_lid_mgr_destroy +*********/ + +/****f* OpenSM: LID Manager/osm_lid_mgr_destroy +* NAME +* osm_lid_mgr_destroy +* +* DESCRIPTION +* The osm_lid_mgr_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_lid_mgr_destroy( + IN osm_lid_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* LID Manager object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_lid_mgr_construct or osm_lid_mgr_init. +* +* SEE ALSO +* LID Manager object, osm_lid_mgr_construct, +* osm_lid_mgr_init +*********/ + +/****f* OpenSM: LID Manager/osm_lid_mgr_init +* NAME +* osm_lid_mgr_init +* +* DESCRIPTION +* The osm_lid_mgr_init function initializes a +* LID Manager object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_lid_mgr_init( + IN osm_lid_mgr_t* const p_mgr, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_db_t* const p_db, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_lid_mgr_t object to initialize. +* +* p_req +* [in] Pointer to the attribute Requester object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_db +* [in] Pointer to the database object. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the LID Manager object was initialized +* successfully. +* +* NOTES +* Allows calling other LID Manager methods. +* +* SEE ALSO +* LID Manager object, osm_lid_mgr_construct, +* osm_lid_mgr_destroy +*********/ + +/****f* OpenSM: LID Manager/osm_lid_mgr_process_sm +* NAME +* osm_lid_mgr_process_sm +* +* DESCRIPTION +* Configures the SM's port with its designated LID values. +* +* SYNOPSIS +*/ +osm_signal_t +osm_lid_mgr_process_sm( + IN osm_lid_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_lid_mgr_t object. +* +* RETURN VALUES +* Returns the appropriate signal to the caller: +* OSM_SIGNAL_DONE - operation is complete +* OSM_SIGNAL_DONE_PENDING - local operations are complete, but +* transactions are still pending on the wire. +* +* NOTES +* +* SEE ALSO +* LID Manager +*********/ + +/****f* OpenSM: LID Manager/osm_lid_mgr_process_subnet +* NAME +* osm_lid_mgr_process_subnet +* +* DESCRIPTION +* Configures subnet ports (except the SM port itself) with their +* designated LID values. +* +* SYNOPSIS +*/ +osm_signal_t +osm_lid_mgr_process_subnet( + IN osm_lid_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_lid_mgr_t object. +* +* RETURN VALUES +* Returns the appropriate signal to the caller: +* OSM_SIGNAL_DONE - operation is complete +* OSM_SIGNAL_DONE_PENDING - local operations are complete, but +* transactions are still pending on the wire. +* +* NOTES +* +* SEE ALSO +* LID Manager +*********/ + +END_C_DECLS + +#endif /* _OSM_LID_MGR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lin_fwd_rcv.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lin_fwd_rcv.h new file mode 100644 index 00000000..3ba174d0 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lin_fwd_rcv.h @@ -0,0 +1,255 @@ +/* + * 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: + * Declaration of osm_lft_rcv_t. + * This object represents the LFT Receiver object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_LFT_RCV_H_ +#define _OSM_LFT_RCV_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/LFT Receiver +* NAME +* LFT Receiver +* +* DESCRIPTION +* The LFT Receiver object encapsulates the information +* needed to receive the LFT attribute from a node. +* +* The LFT Receiver 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: LFT Receiver/osm_lft_rcv_t +* NAME +* osm_lft_rcv_t +* +* DESCRIPTION +* LFT Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_lft_rcv +{ + osm_subn_t *p_subn; + osm_log_t *p_log; + cl_plock_t *p_lock; + +} osm_lft_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* LFT Receiver object +*********/ + +/****f* OpenSM: LFT Receiver/osm_lft_rcv_construct +* NAME +* osm_lft_rcv_construct +* +* DESCRIPTION +* This function constructs a LFT Receiver object. +* +* SYNOPSIS +*/ +void osm_lft_rcv_construct( + IN osm_lft_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a LFT Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_lft_rcv_init, osm_lft_rcv_destroy +* +* Calling osm_lft_rcv_construct is a prerequisite to calling any other +* method except osm_lft_rcv_init. +* +* SEE ALSO +* LFT Receiver object, osm_lft_rcv_init, +* osm_lft_rcv_destroy +*********/ + +/****f* OpenSM: LFT Receiver/osm_lft_rcv_destroy +* NAME +* osm_lft_rcv_destroy +* +* DESCRIPTION +* The osm_lft_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_lft_rcv_destroy( + IN osm_lft_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* LFT Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_lft_rcv_construct or osm_lft_rcv_init. +* +* SEE ALSO +* LFT Receiver object, osm_lft_rcv_construct, +* osm_lft_rcv_init +*********/ + +/****f* OpenSM: LFT Receiver/osm_lft_rcv_init +* NAME +* osm_lft_rcv_init +* +* DESCRIPTION +* The osm_lft_rcv_init function initializes a +* LFT Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_lft_rcv_init( + IN osm_lft_rcv_t* const p_rcv, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_lft_rcv_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the LFT Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other LFT Receiver methods. +* +* SEE ALSO +* LFT Receiver object, osm_lft_rcv_construct, +* osm_lft_rcv_destroy +*********/ + +/****f* OpenSM: LFT Receiver/osm_lft_rcv_process +* NAME +* osm_lft_rcv_process +* +* DESCRIPTION +* Process the LFT attribute. +* +* SYNOPSIS +*/ +void osm_lft_rcv_process( + IN const osm_lft_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_lft_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's LFT attribute. +* +* RETURN VALUES +* CL_SUCCESS if the LFT processing was successful. +* +* NOTES +* This function processes a LFT attribute. +* +* SEE ALSO +* LFT Receiver, Node Description Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_LFT_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lin_fwd_rcv_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lin_fwd_rcv_ctrl.h new file mode 100644 index 00000000..907034d4 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lin_fwd_rcv_ctrl.h @@ -0,0 +1,233 @@ +/* + * 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: + * Declaration of osm_lft_rcv_ctrl_t. + * This object represents a controller that receives the IBA + * LFT attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_LFT_RCV_CTRL_H_ +#define _OSM_LFT_RCV_CTRL_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/LFT Receive Controller +* NAME +* LFT Receive Controller +* +* DESCRIPTION +* The LFT Receive Controller object +* encapsulates the information +* needed to receive the NodeDescription attribute from a node. +* +* The LFT Receive 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: LFT Receive Controller/osm_lft_rcv_ctrl_t +* NAME +* osm_lft_rcv_ctrl_t +* +* DESCRIPTION +* LFT Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_lft_rcv_ctrl +{ + osm_lft_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_lft_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the LFT Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* LFT Receive Controller object +*********/ + +/****f* OpenSM: LFT Receive Controller/osm_lft_rcv_ctrl_construct +* NAME +* osm_lft_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a LFT Receive Controller object. +* +* SYNOPSIS +*/ +void +osm_lft_rcv_ctrl_construct( + IN osm_lft_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a LFT Receive Controller object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_lft_rcv_ctrl_init, osm_lft_rcv_ctrl_destroy +* +* Calling osm_lft_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_lft_rcv_ctrl_init. +* +* SEE ALSO +* LFT Receive Controller object, osm_lft_rcv_ctrl_init, +* osm_lft_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: LFT Receive Controller/osm_lft_rcv_ctrl_destroy +* NAME +* osm_lft_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_lft_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_lft_rcv_ctrl_destroy( + IN osm_lft_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* LFT Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_lft_rcv_ctrl_construct or osm_lft_rcv_ctrl_init. +* +* SEE ALSO +* LFT Receive Controller object, osm_lft_rcv_ctrl_construct, +* osm_lft_rcv_ctrl_init +*********/ + +/****f* OpenSM: LFT Receive Controller/osm_lft_rcv_ctrl_init +* NAME +* osm_lft_rcv_ctrl_init +* +* DESCRIPTION +* The osm_lft_rcv_ctrl_init function initializes a +* LFT Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_lft_rcv_ctrl_init( + IN osm_lft_rcv_ctrl_t* const p_ctrl, + IN osm_lft_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_lft_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_lft_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the LFT Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other LFT Receive Controller methods. +* +* SEE ALSO +* LFT Receive Controller object, osm_lft_rcv_ctrl_construct, +* osm_lft_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* OSM_LFT_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lin_fwd_tbl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lin_fwd_tbl.h new file mode 100644 index 00000000..b7763aba --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_lin_fwd_tbl.h @@ -0,0 +1,379 @@ +/* + * 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: + * Declaration of osm_lin_fwd_tbl_t. + * This object represents a linear forwarding table. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_LIN_FWD_TBL_H_ +#define _OSM_LIN_FWD_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 + +/****h* OpenSM/Linear Forwarding Table +* NAME +* Linear Forwarding Table +* +* DESCRIPTION +* The Linear Forwarding Table objects encapsulate the information +* needed by the OpenSM to manage linear forwarding tables. The OpenSM +* allocates one Linear Forwarding Table object per switch in the +* IBA subnet, if that switch uses a linear table. +* +* The Linear Forwarding Table objects are not thread safe, thus +* callers must provide serialization. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Forwarding Table/osm_lin_fwd_tbl_t +* NAME +* osm_lin_fwd_tbl_t +* +* DESCRIPTION +* Linear Forwarding Table structure. +* +* Callers may directly access this object. +* +* SYNOPSIS +*/ +typedef struct _osm_lin_fwd_tbl +{ + uint16_t size; + uint8_t port_tbl[1]; + +} osm_lin_fwd_tbl_t; +/* +* FIELDS +* Size +* Number of entries in the linear forwarding table. This value +* is taken from the SwitchInfo attribute. +* +* port_tbl +* The array that specifies the port number which routes the +* corresponding LID. Index is by LID. +* +* SEE ALSO +* Forwarding Table object, Random Forwarding Table object. +*********/ + +/****f* OpenSM: Forwarding Table/osm_lin_tbl_new +* NAME +* osm_lin_tbl_new +* +* DESCRIPTION +* This function creates and initializes a Linear Forwarding Table object. +* +* SYNOPSIS +*/ +osm_lin_fwd_tbl_t* +osm_lin_tbl_new( + IN uint16_t const size ); +/* +* PARAMETERS +* size +* [in] Number of entries in the Linear Forwarding Table. +* +* RETURN VALUE +* On success, returns a pointer to a new Linear Forwarding Table object +* of the specified size. +* NULL otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_lin_tbl_delete +* NAME +* osm_lin_tbl_delete +* +* DESCRIPTION +* This destroys and deallocates a Linear Forwarding Table object. +* +* SYNOPSIS +*/ +void +osm_lin_tbl_delete( + IN osm_lin_fwd_tbl_t** const pp_tbl ); +/* +* PARAMETERS +* pp_tbl +* [in] Pointer a Pointer to the Linear Forwarding Table object. +* +* RETURN VALUE +* On success, returns a pointer to a new Linear Forwarding Table object +* of the specified size. +* NULL otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_lin_fwd_tbl_set +* NAME +* osm_lin_fwd_tbl_set +* +* DESCRIPTION +* Sets the port to route the specified LID. +* +* SYNOPSIS +*/ +static inline void +osm_lin_fwd_tbl_set( + IN osm_lin_fwd_tbl_t* const p_tbl, + IN const uint16_t lid_ho, + IN const uint8_t port ) +{ + CL_ASSERT( lid_ho < p_tbl->size ); + if( lid_ho < p_tbl->size ) + p_tbl->port_tbl[lid_ho] = port; +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Linear Forwarding Table object. +* +* lid_ho +* [in] LID value (host order) for which to set the route. +* +* port +* [in] Port to route the specified LID value. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_lin_fwd_tbl_get +* NAME +* osm_lin_fwd_tbl_get +* +* DESCRIPTION +* Returns the port that routes the specified LID. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_lin_fwd_tbl_get( + IN const osm_lin_fwd_tbl_t* const p_tbl, + IN const uint16_t lid_ho ) +{ + if( lid_ho < p_tbl->size ) + return( p_tbl->port_tbl[lid_ho] ); + else + return( 0xFF ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Linear Forwarding Table object. +* +* lid_ho +* [in] LID value (host order) for which to get the route. +* +* RETURN VALUE +* Returns the port that routes the specified LID. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_lin_fwd_tbl_get_size +* NAME +* osm_lin_fwd_tbl_get_size +* +* DESCRIPTION +* Returns the number of entries available in the forwarding table. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_lin_fwd_tbl_get_size( + IN const osm_lin_fwd_tbl_t* const p_tbl ) +{ + return( p_tbl->size ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* RETURN VALUE +* Returns the number of entries available in the forwarding table. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_lin_fwd_tbl_get_lids_per_block +* NAME +* osm_lin_fwd_tbl_get_lids_per_block +* +* DESCRIPTION +* Returns the number of LIDs per LID block. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_lin_fwd_tbl_get_lids_per_block( + IN const osm_lin_fwd_tbl_t* const p_tbl ) +{ + UNUSED_PARAM( p_tbl ); + return( 64 ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* RETURN VALUE +* Returns the number of LIDs per LID block. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_lin_fwd_tbl_get_max_block_id_in_use +* NAME +* osm_lin_fwd_tbl_get_max_block_id_in_use +* +* DESCRIPTION +* Returns the maximum block ID in actual use by the forwarding table. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_lin_fwd_tbl_get_max_block_id_in_use( + IN const osm_lin_fwd_tbl_t* const p_tbl, + IN const uint16_t lid_top_ho ) +{ + return( (uint16_t)(lid_top_ho / + osm_lin_fwd_tbl_get_lids_per_block( p_tbl ) ) ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* RETURN VALUE +* Returns the maximum block ID in actual use by the forwarding table. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_lin_fwd_tbl_set_block +* NAME +* osm_lin_fwd_tbl_set_block +* +* DESCRIPTION +* Copies the specified block into the Linear Forwarding Table. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +osm_lin_fwd_tbl_set_block( + IN osm_lin_fwd_tbl_t* const p_tbl, + IN const uint8_t* const p_block, + IN const uint32_t block_num ) +{ + uint16_t lid_start; + uint16_t num_lids; + + CL_ASSERT( p_tbl ); + CL_ASSERT( p_block ); + + num_lids = osm_lin_fwd_tbl_get_lids_per_block( p_tbl ); + lid_start = (uint16_t)(block_num * num_lids); + + if( lid_start + num_lids > p_tbl->size ) + return( IB_INVALID_PARAMETER ); + + memcpy( &p_tbl->port_tbl[lid_start], p_block, num_lids ); + return( IB_SUCCESS ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Linear 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 +*********/ + +END_C_DECLS + +#endif /* _OSM_LIN_FWD_TBL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_link_mgr.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_link_mgr.h new file mode 100644 index 00000000..c61b8a16 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_link_mgr.h @@ -0,0 +1,271 @@ +/* + * 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: + * Declaration of osm_link_mgr_t. + * This object represents the Link Manager object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_LINK_MGR_H_ +#define _OSM_LINK_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 + +/****h* OpenSM/Link Manager +* NAME +* Link Manager +* +* DESCRIPTION +* The Link Manager object encapsulates the information +* needed to control unicast LID forwarding on the subnet. +* +* The Link 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 +* +*********/ + +/****s* OpenSM: Link Manager/osm_link_mgr_t +* NAME +* osm_link_mgr_t +* +* DESCRIPTION +* Link Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_link_mgr +{ + osm_subn_t *p_subn; + osm_req_t *p_req; + osm_log_t *p_log; + cl_plock_t *p_lock; + boolean_t send_set_reqs; + +} osm_link_mgr_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_req +* Pointer to the Requester object sending SMPs. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* Link Manager object +*********/ + +/****f* OpenSM: Link Manager/osm_link_mgr_construct +* NAME +* osm_link_mgr_construct +* +* DESCRIPTION +* This function constructs a Link Manager object. +* +* SYNOPSIS +*/ +void +osm_link_mgr_construct( + IN osm_link_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to a Link Manager object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows osm_link_mgr_destroy +* +* Calling osm_link_mgr_construct is a prerequisite to calling any other +* method except osm_link_mgr_init. +* +* SEE ALSO +* Link Manager object, osm_link_mgr_init, +* osm_link_mgr_destroy +*********/ + +/****f* OpenSM: Link Manager/osm_link_mgr_destroy +* NAME +* osm_link_mgr_destroy +* +* DESCRIPTION +* The osm_link_mgr_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_link_mgr_destroy( + IN osm_link_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Link Manager object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_link_mgr_construct or osm_link_mgr_init. +* +* SEE ALSO +* Link Manager object, osm_link_mgr_construct, +* osm_link_mgr_init +*********/ + +/****f* OpenSM: Link Manager/osm_link_mgr_init +* NAME +* osm_link_mgr_init +* +* DESCRIPTION +* The osm_link_mgr_init function initializes a +* Link Manager object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_link_mgr_init( + IN osm_link_mgr_t* const p_mgr, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_link_mgr_t object to initialize. +* +* p_req +* [in] Pointer to the attribute Requester object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the Link Manager object was initialized +* successfully. +* +* NOTES +* Allows calling other Link Manager methods. +* +* SEE ALSO +* Link Manager object, osm_link_mgr_construct, +* osm_link_mgr_destroy +*********/ + +/****f* OpenSM: Link Manager/osm_link_mgr_process +* NAME +* osm_link_mgr_process +* +* DESCRIPTION +* Processes all ports in the subnet per the link manager command. +* +* SYNOPSIS +*/ +osm_signal_t +osm_link_mgr_process( + IN osm_link_mgr_t* const p_mgr, + IN const uint8_t link_state ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_link_mgr_t object. +* +* link_state +* [in] state to which to the set the port. +* +* +* RETURN VALUES +* Returns the appropriate signal to the caller: +* OSM_SIGNAL_DONE - operation is complete +* OSM_SIGNAL_DONE_PENDING - local operations are complete, but +* transactions are still pending on the wire. +* +* NOTES +* +* SEE ALSO +* Link Manager, Node Info Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_LINK_MGR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_log.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_log.h new file mode 100644 index 00000000..f111a6e7 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_log.h @@ -0,0 +1,474 @@ +/* + * 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: + * Declaration of osm_log_t. + * This object represents the log file. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +#ifndef _OSM_LOG_H_ +#define _OSM_LOG_H_ + +#ifndef __WIN__ +#include +#endif +#include +#include +#include +#include +#include + +#ifdef __GNUC__ +#define STRICT_OSM_LOG_FORMAT __attribute__((format(printf, 3, 4))) +#else +#define STRICT_OSM_LOG_FORMAT +#endif + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +#define LOG_ENTRY_SIZE_MAX 4096 +#define BUF_SIZE LOG_ENTRY_SIZE_MAX + +#define __func__ __FUNCTION__ + +#define OSM_LOG_ENTER( OSM_LOG_PTR, NAME ) \ + 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_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; +} osm_log_t; +/*********/ + +/****f* OpenSM: Log/osm_log_construct +* NAME +* osm_log_construct +* +* DESCRIPTION +* This function constructs a Log object. +* +* SYNOPSIS +*/ +static inline void +osm_log_construct( + IN osm_log_t* const p_log ) +{ + cl_spinlock_construct( &p_log->lock ); +} +/* +* PARAMETERS +* p_log +* [in] Pointer to a Log object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_log_init, osm_log_init_v2, osm_log_destroy +* +* Calling osm_log_construct is a prerequisite to calling any other +* method except osm_log_init or osm_log_init_v2. +* +* SEE ALSO +* Log object, osm_log_init, osm_log_init_v2, +* osm_log_destroy +*********/ + +/****f* OpenSM: Log/osm_log_destroy +* NAME +* osm_log_destroy +* +* DESCRIPTION +* The osm_log_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +static inline void +osm_log_destroy( + IN osm_log_t* const p_log ) +{ + cl_spinlock_destroy( &p_log->lock ); + if (p_log->out_port != stdout) { + fclose(p_log->out_port); + p_log->out_port = stdout; + } + closelog(); +} +/* +* PARAMETERS +* p_log +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Log object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_log_construct, osm_log_init, or osm_log_init_v2. +* +* SEE ALSO +* Log object, osm_log_construct, +* osm_log_init, osm_log_init_v2 +*********/ + +/****f* OpenSM: Log/osm_log_init_v2 +* NAME +* osm_log_init_v2 +* +* DESCRIPTION +* The osm_log_init_v2 function initializes a +* Log object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_log_init_v2( + IN osm_log_t* const p_log, + IN const boolean_t flush, + IN const uint8_t log_flags, + IN const char *log_file, + IN const unsigned long max_size, + IN const boolean_t accum_log_file ); +/* +* PARAMETERS +* p_log +* [in] Pointer to the log object. +* +* flush +* [in] Set to TRUE directs the log to flush all log messages +* immediately. This severely degrades log performance, +* and is normally used for debugging only. +* +* log_flags +* [in] The log verbosity level to be used. +* +* log_file +* [in] if not NULL defines the name of the log file. Otherwise it is stdout. +* +* RETURN VALUES +* CL_SUCCESS if the Log object was initialized +* successfully. +* +* NOTES +* Allows calling other Log methods. +* +* SEE ALSO +* Log object, osm_log_construct, +* osm_log_destroy +*********/ + +/****f* OpenSM: Log/osm_log_init +* NAME +* osm_log_init +* +* DESCRIPTION +* The osm_log_init function initializes a +* Log object for use. It is a wrapper for osm_log_init_v2(). +* +* SYNOPSIS +*/ +ib_api_status_t +osm_log_init( + IN osm_log_t* const p_log, + IN const boolean_t flush, + IN const uint8_t log_flags, + IN const char *log_file, + IN const boolean_t accum_log_file ); +/* + * Same as osm_log_init_v2() but without max_size parameter + */ + +/****f* OpenSM: Log/osm_log_get_level +* NAME +* osm_log_get_level +* +* DESCRIPTION +* Returns the current log level. +* +* SYNOPSIS +*/ +static inline osm_log_level_t +osm_log_get_level( + IN const osm_log_t* const p_log ) +{ + return( p_log->level ); +} +/* +* PARAMETERS +* p_log +* [in] Pointer to the log object. +* +* RETURN VALUES +* Returns the current log level. +* +* NOTES +* +* SEE ALSO +* Log object, osm_log_construct, +* osm_log_destroy +*********/ + +/****f* OpenSM: Log/osm_log_set_level +* NAME +* osm_log_set_level +* +* DESCRIPTION +* Sets the current log level. +* +* SYNOPSIS +*/ +static inline void +osm_log_set_level( + IN osm_log_t* const p_log, + IN const osm_log_level_t level ) +{ + p_log->level = level; +} +/* +* PARAMETERS +* p_log +* [in] Pointer to the log object. +* +* level +* [in] New level to set. +* +* RETURN VALUES +* Returns the current log level. +* +* NOTES +* +* SEE ALSO +* Log object, osm_log_construct, +* osm_log_destroy +*********/ + +/****f* OpenSM: Log/osm_log_is_active +* NAME +* osm_log_is_active +* +* DESCRIPTION +* Returns TRUE if the specified log level would be logged. +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_log_is_active( + IN const osm_log_t* const p_log, + IN const osm_log_level_t level ) +{ + return( (p_log->level & level) != 0 ); +} +/* +* PARAMETERS +* p_log +* [in] Pointer to the log object. +* +* level +* [in] Level to check. +* +* RETURN VALUES +* Returns TRUE if the specified log level would be logged. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Log object, osm_log_construct, +* osm_log_destroy +*********/ + +extern int osm_log_printf(osm_log_t *p_log, osm_log_level_t level, + const char *fmt, ...); + +void +osm_log( + IN osm_log_t* const p_log, + IN const osm_log_level_t verbosity, + IN const char *p_str, ... ) STRICT_OSM_LOG_FORMAT; + +void +osm_log_raw( + IN osm_log_t* const p_log, + IN const osm_log_level_t verbosity, + IN const char *p_buf ); + +#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-1/ulp/opensm/user/include/opensm/osm_mad_pool.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mad_pool.h new file mode 100644 index 00000000..c2512088 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mad_pool.h @@ -0,0 +1,405 @@ +/* + * 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: + * 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#ifndef _OSM_MAD_POOL_H_ +#define _OSM_MAD_POOL_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/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 +{ + osm_log_t *p_log; + cl_qlock_pool_t madw_pool; + atomic32_t mads_out; +} osm_mad_pool_t; +/* +* FIELDS +* p_log +* Pointer to the log object. +* +* lock +* Spinlock guarding the pool. +* +* mads_out +* Running total of the number of MADs outstanding. +* +* SEE ALSO +* MAD Pool +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_construct +* NAME +* osm_mad_pool_construct +* +* DESCRIPTION +* This function constructs a MAD Pool. +* +* SYNOPSIS +*/ +void osm_mad_pool_construct( + IN osm_mad_pool_t* const p_pool ); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a MAD Pool to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_mad_pool_init, osm_mad_pool_destroy +* +* Calling osm_mad_pool_construct is a prerequisite to calling any other +* method except osm_mad_pool_init. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_init, osm_mad_pool_destroy +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_destroy +* NAME +* osm_mad_pool_destroy +* +* DESCRIPTION +* The osm_mad_pool_destroy function destroys a node, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_mad_pool_destroy( + IN osm_mad_pool_t* const p_pool ); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a MAD Pool to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified MAD Pool. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_mad_pool_construct or +* osm_mad_pool_init. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_construct, osm_mad_pool_init +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_init +* NAME +* osm_mad_pool_init +* +* DESCRIPTION +* The osm_mad_pool_init function initializes a MAD Pool for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_mad_pool_init( + IN osm_mad_pool_t* const p_pool, + IN osm_log_t* const p_log ); +/* +* PARAMETERS +* p_pool +* [in] Pointer to an osm_mad_pool_t object to initialize. +* +* p_log +* [in] Pointer to the log object. +* +* +* RETURN VALUES +* CL_SUCCESS if the MAD Pool was initialized successfully. +* +* NOTES +* Allows calling other MAD Pool methods. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_construct, osm_mad_pool_destroy +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_get +* NAME +* osm_mad_pool_get +* +* DESCRIPTION +* Gets a MAD wrapper and wire MAD from the pool. +* +* SYNOPSIS +*/ +osm_madw_t* +osm_mad_pool_get( + IN osm_mad_pool_t* const p_pool, + IN osm_bind_handle_t h_bind, + IN const uint32_t total_size, + IN const osm_mad_addr_t* const p_mad_addr ); +/* +* PARAMETERS +* p_pool +* [in] Pointer to an osm_mad_pool_t object. +* +* h_bind +* [in] Handle returned from osm_vendor_bind() call to the +* port over which this mad will be sent. +* +* total_size +* [in] Total size, including MAD header of the requested MAD. +* +* p_mad_addr +* [in] Pointer to the MAD address structure. This parameter +* may be NULL for directed route MADs. +* +* RETURN VALUES +* Returns a pointer to a MAD wrapper containing the MAD. +* A return value of NULL means no MADs are available. +* +* NOTES +* The MAD must eventually be returned to the pool with a call to +* osm_mad_pool_put. +* +* The osm_mad_pool_construct or osm_mad_pool_init must be called before +* using this function. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_put +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_put +* NAME +* osm_mad_pool_put +* +* DESCRIPTION +* Returns a MAD to the pool. +* +* SYNOPSIS +*/ +void osm_mad_pool_put( + IN osm_mad_pool_t* const p_pool, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_pool +* [in] Pointer to an osm_mad_pool_t object. +* +* p_madw +* [in] Pointer to a MAD Wrapper for a MAD that was previously +* retrieved from the pool. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* The osm_mad_pool_construct or osm_mad_pool_init must be called before +* using this function. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_get +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_get_wrapper +* NAME +* osm_mad_pool_get_wrapper +* +* DESCRIPTION +* Gets a only MAD wrapper from the pool (no wire MAD). +* +* SYNOPSIS +*/ +osm_madw_t* +osm_mad_pool_get_wrapper( + IN osm_mad_pool_t* const p_pool, + IN osm_bind_handle_t h_bind, + IN const uint32_t total_size, + IN const ib_mad_t* const p_mad, + IN const osm_mad_addr_t* const p_mad_addr ); +/* +* PARAMETERS +* p_pool +* [in] Pointer to an osm_mad_pool_t object. +* +* h_bind +* [in] Handle returned from osm_vendor_bind() call to the +* port for which this mad wrapper will be used. +* +* total_size +* [in] Total size, including MAD header of the MAD that will +* be attached to this wrapper. +* +* p_mad +* [in] Pointer to the MAD to attach to this wrapper. +* +* p_mad_addr +* [in] Pointer to the MAD address structure. This parameter +* may be NULL for directed route MADs. +* +* RETURN VALUES +* Returns a pointer to a MAD wrapper. +* A return value of NULL means no MAD wrappers are available. +* +* NOTES +* The MAD must eventually be returned to the pool with a call to +* osm_mad_pool_put. +* +* The osm_mad_pool_construct or osm_mad_pool_init must be called before +* using this function. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_put +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_get_wrapper_raw +* NAME +* osm_mad_pool_get_wrapper_raw +* +* DESCRIPTION +* Gets a only an uninitialized MAD wrapper from the pool (no wire MAD). +* +* SYNOPSIS +*/ +osm_madw_t* +osm_mad_pool_get_wrapper_raw( + IN osm_mad_pool_t* const p_pool ); +/* +* PARAMETERS +* p_pool +* [in] Pointer to an osm_mad_pool_t object. +* +* RETURN VALUES +* Returns a pointer to a MAD wrapper. +* A return value of NULL means no MAD wrappers are available. +* +* NOTES +* The MAD must eventually be returned to the pool with a call to +* osm_mad_pool_put. +* +* The osm_mad_pool_construct or osm_mad_pool_init must be called before +* using this function. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_put +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_get_outstanding +* NAME +* osm_mad_pool_get_count +* +* DESCRIPTION +* Returns the running count of MADs currently outstanding from the pool. +* +* SYNOPSIS +*/ +static inline uint32_t +osm_mad_pool_get_outstanding( + IN const osm_mad_pool_t* const p_pool ) +{ + return( p_pool->mads_out ); +} +/* +* PARAMETERS +* p_pool +* [in] Pointer to an osm_mad_pool_t object. +* +* RETURN VALUES +* Returns the running count of MADs currently outstanding from the pool. +* +* NOTES +* The osm_mad_pool_construct or osm_mad_pool_init must be called before +* using this function. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_get +*********/ + +END_C_DECLS + +#endif /* _OSM_MAD_POOL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_madw.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_madw.h new file mode 100644 index 00000000..a0aa29ea --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_madw.h @@ -0,0 +1,1160 @@ +/* + * 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: + * 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#ifndef _OSM_MADW_H_ +#define _OSM_MADW_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +/****s* OpenSM: MAD Wrapper/osm_bind_info_t +* NAME +* osm_bind_info_t +* +* DESCRIPTION +* +* SYNOPSIS +*/ +typedef struct _osm_bind_info +{ + ib_net64_t port_guid; + uint8_t mad_class; + uint8_t class_version; + boolean_t is_responder; + boolean_t is_trap_processor; + boolean_t is_report_processor; + uint32_t send_q_size; + uint32_t recv_q_size; +} osm_bind_info_t; +/* +* FIELDS +* portguid +* PortGuid of local port +* +* 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_processo +* True if GSI Report msgs are handled +* +* send_q_size +* SendQueueSize +* +* recv_q_size +* Receive Queue Size +* +* SEE ALSO +*********/ + +/****h* OpenSM/MAD Wrapper +* NAME +* MAD Wrapper +* +* DESCRIPTION +* The MAD Wrapper object encapsulates the information needed by the +* OpenSM to manage individual MADs. The OpenSM allocates one MAD Wrapper +* per MAD. +* +* The MAD Wrapper is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: MAD Wrapper/osm_ni_context_t +* NAME +* osm_ni_context_t +* +* DESCRIPTION +* Context needed by recipient of NodeInfo attribute. +* +* SYNOPSIS +*/ +typedef struct _osm_ni_context +{ + ib_net64_t node_guid; + uint8_t port_num; +} 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 update_master_sm_base_lid; + boolean_t ignore_errors; + 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; +} 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; +/*********/ + +#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; +#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; + ib_net16_t pkey; + 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_pool_item_t pool_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 +* pool_item +* List linkage for pools and 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_construct +* NAME +* osm_madw_construct +* +* DESCRIPTION +* This function constructs a MAD Wrapper object. +* +* SYNOPSIS +*/ +static inline void +osm_madw_construct( + IN osm_madw_t* const p_madw ) +{ + /* + Don't touch the pool_item since that is an opaque object. + Clear all other objects in the mad wrapper. + */ + memset( ((uint8_t *)p_madw) + sizeof( cl_pool_item_t ), 0, + sizeof(*p_madw) - sizeof( cl_pool_item_t ) ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to a MAD Wrapper object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_madw_init, osm_madw_destroy +* +* Calling osm_madw_construct is a prerequisite to calling any other +* method except osm_madw_init. +* +* SEE ALSO +* MAD Wrapper object, osm_madw_init, osm_madw_destroy +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_destroy +* NAME +* osm_madw_destroy +* +* DESCRIPTION +* The osm_madw_destroy function destroys a node, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_madw_destroy( + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_madw +* [in] Pointer to a MAD Wrapper object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified MAD Wrapper object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_madw_construct or +* osm_madw_init. +* +* SEE ALSO +* MAD Wrapper object, osm_madw_construct, osm_madw_init +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_init +* NAME +* osm_madw_init +* +* DESCRIPTION +* Initializes a MAD Wrapper object for use. +* +* SYNOPSIS +*/ +static inline void +osm_madw_init( + IN osm_madw_t* const p_madw, + IN osm_bind_handle_t h_bind, + IN const uint32_t mad_size, + IN const osm_mad_addr_t* const p_mad_addr ) +{ + osm_madw_construct( p_madw ); + p_madw->h_bind = h_bind; + p_madw->fail_msg = CL_DISP_MSGID_NONE; + p_madw->mad_size = mad_size; + if( p_mad_addr ) + p_madw->mad_addr = *p_mad_addr; + p_madw->resp_expected = FALSE; +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object to initialize. +* +* h_bind +* [in] Pointer to the wire MAD. +* +* p_mad_addr +* [in] Pointer to the MAD address structure. This parameter may +* be NULL for directed route MADs. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_smp_ptr +* NAME +* osm_madw_get_smp_ptr +* +* DESCRIPTION +* Gets a pointer to the SMP in this MAD. +* +* SYNOPSIS +*/ +static inline ib_smp_t* +osm_madw_get_smp_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (ib_smp_t*)p_madw->p_mad ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object to initialize. +* +* RETURN VALUES +* Pointer to the start of the SMP MAD. +* +* NOTES +* +* SEE ALSO +* MAD Wrapper object, osm_madw_construct, osm_madw_destroy +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_sa_mad_ptr +* NAME +* osm_madw_get_sa_mad_ptr +* +* DESCRIPTION +* Gets a pointer to the SA MAD in this MAD wrapper. +* +* SYNOPSIS +*/ +static inline ib_sa_mad_t* +osm_madw_get_sa_mad_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (ib_sa_mad_t*)p_madw->p_mad ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object to initialize. +* +* RETURN VALUES +* Pointer to the start of the SMP MAD. +* +* NOTES +* +* SEE ALSO +* MAD Wrapper object, osm_madw_construct, osm_madw_destroy +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_ni_context_ptr +* NAME +* osm_madw_get_ni_context_ptr +* +* DESCRIPTION +* Gets a pointer to the NodeInfo context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_ni_context_t* +osm_madw_get_ni_context_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_ni_context_t*)&p_madw->context ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_pi_context_ptr +* NAME +* osm_madw_get_pi_context_ptr +* +* DESCRIPTION +* Gets a pointer to the PortInfo context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_pi_context_t* +osm_madw_get_pi_context_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_pi_context_t*)&p_madw->context ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_nd_context_ptr +* NAME +* osm_madw_get_nd_context_ptr +* +* DESCRIPTION +* Gets a pointer to the NodeDescription context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_nd_context_t* +osm_madw_get_nd_context_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_nd_context_t*)&p_madw->context ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_lft_context_ptr +* NAME +* osm_madw_get_lft_context_ptr +* +* DESCRIPTION +* Gets a pointer to the LFT context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_lft_context_t* +osm_madw_get_lft_context_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_lft_context_t*)&p_madw->context ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_mft_context_ptr +* NAME +* osm_madw_get_mft_context_ptr +* +* DESCRIPTION +* Gets a pointer to the MFT context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_mft_context_t* +osm_madw_get_mft_context_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_mft_context_t*)&p_madw->context ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_si_context_ptr +* NAME +* osm_madw_get_si_context_ptr +* +* DESCRIPTION +* Gets a pointer to the SwitchInfo context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_si_context_t* +osm_madw_get_si_context_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_si_context_t*)&p_madw->context ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_smi_context_ptr +* NAME +* osm_madw_get_smi_context_ptr +* +* DESCRIPTION +* Gets a pointer to the SMInfo context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_smi_context_t* +osm_madw_get_smi_context_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_smi_context_t*)&p_madw->context ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_pkey_context_ptr +* NAME +* osm_madw_get_pkey_context_ptr +* +* DESCRIPTION +* Gets a pointer to the P_Key context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_pkey_context_t* +osm_madw_get_pkey_context_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_pkey_context_t*)&p_madw->context ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_slvl_context_ptr +* NAME +* osm_madw_get_slvl_context_ptr +* +* DESCRIPTION +* Gets a pointer to the PortInfo context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_slvl_context_t* +osm_madw_get_slvl_context_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_slvl_context_t*)&p_madw->context ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_vla_context_ptr +* NAME +* osm_madw_get_vla_context_ptr +* +* DESCRIPTION +* Gets a pointer to the Vl Arb context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_vla_context_t* +osm_madw_get_vla_context_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_vla_context_t*)&p_madw->context ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +#ifndef OSM_VENDOR_INTF_OPENIB +/****f* OpenSM: MAD Wrapper/osm_madw_get_arbitrary_context_ptr +* NAME +* osm_madw_get_arbitrary_context_ptr +* +* DESCRIPTION +* Gets a pointer to the arbitrary context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_arbitrary_context_t* +osm_madw_get_arbitrary_context_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_arbitrary_context_t*)&p_madw->context ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ +#endif + +/****f* OpenSM: MAD Wrapper/osm_madw_get_vend_ptr +* NAME +* osm_madw_get_vend_ptr +* +* DESCRIPTION +* Gets a pointer to the vendor specific MAD wrapper component. +* +* SYNOPSIS +*/ +static inline osm_vend_wrap_t* +osm_madw_get_vend_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_vend_wrap_t*)&p_madw->vend_wrap ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Gets a pointer to the vendor specific MAD wrapper component. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_vend_ptr +* NAME +* osm_madw_get_vend_ptr +* +* DESCRIPTION +* Returns the bind handle associated with this MAD. +* +* SYNOPSIS +*/ +static inline osm_bind_handle_t +osm_madw_get_bind_handle( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_bind_handle_t)p_madw->h_bind ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Returns the bind handle associated with this MAD. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_mad_addr_ptr +* NAME +* osm_madw_get_mad_addr_ptr +* +* DESCRIPTION +* Returns the mad address structure associated with this MAD. +* +* SYNOPSIS +*/ +static inline osm_mad_addr_t* +osm_madw_get_mad_addr_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (osm_mad_addr_t*)&p_madw->mad_addr ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Returns the mad address structure associated with this MAD. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_mad_ptr +* NAME +* osm_madw_get_mad_ptr +* +* DESCRIPTION +* Returns the mad address structure associated with this MAD. +* +* SYNOPSIS +*/ +static inline ib_mad_t* +osm_madw_get_mad_ptr( + IN const osm_madw_t* const p_madw ) +{ + return( (ib_mad_t*)p_madw->p_mad ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Returns the mad address structure associated with this MAD. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_err_msg +* NAME +* osm_madw_get_err_msg +* +* DESCRIPTION +* Returns the message with which to post this mad wrapper if +* an error occurs during processing the mad. +* +* SYNOPSIS +*/ +static inline cl_disp_msgid_t +osm_madw_get_err_msg( + IN const osm_madw_t* const p_madw ) +{ + return( (cl_disp_msgid_t)p_madw->fail_msg ); +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Returns the message with which to post this mad wrapper if +* an error occurs during processing the mad. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_set_mad +* NAME +* osm_madw_set_mad +* +* DESCRIPTION +* Associates a wire MAD with this MAD Wrapper object. +* +* SYNOPSIS +*/ +static inline void +osm_madw_set_mad( + IN osm_madw_t* const p_madw, + IN const ib_mad_t* const p_mad ) +{ + p_madw->p_mad = p_mad; +} +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* p_mad +* [in] Pointer to the wire MAD to attach to this wrapper. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_copy_context +* NAME +* osm_madw_copy_context +* +* DESCRIPTION +* Copies the controller context from one MAD Wrapper to another. +* +* SYNOPSIS +*/ +static inline void +osm_madw_copy_context( + IN osm_madw_t* const p_dest, + IN const osm_madw_t* const p_src ) +{ + p_dest->context = p_src->context; +} +/* +* PARAMETERS +* p_dest +* [in] Pointer to the destination osm_madw_t object. +* +* p_src +* [in] Pointer to the source osm_madw_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_MADW_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_matrix.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_matrix.h new file mode 100644 index 00000000..a6de3854 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_matrix.h @@ -0,0 +1,454 @@ +/* + * 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: + * Declaration of osm_lid_matrix_t. + * This object represents a two dimensional array of port numbers + * and LID values. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + + +#ifndef _OSM_MATRIX_H_ +#define _OSM_MATRIX_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/LID Matrix +* NAME +* LID Matrix +* +* DESCRIPTION +* The LID Matrix object encapsulates the information needed by the +* OpenSM to manage fabric routes. It is a two dimensional array +* index by LID value and Port Number. Each element contains the +* number of hops from that Port Number to the LID. +* Every Switch object contains a LID Matrix. +* +* The LID Matrix 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: LID Matrix/osm_lid_matrix_t +* NAME +* osm_lid_matrix_t +* +* DESCRIPTION +* +* The LID Matrix object encapsulates the information needed by the +* OpenSM to manage fabric routes. It is a two dimensional array +* index by LID value and Port Number. Each element contains the +* number of hops from that Port Number to the LID. +* Every Switch object contains a LID Matrix. +* +* The LID Matrix is not thread safe, thus callers must provide +* serialization. +* +* The num_ports index into the matrix serves a special purpose, in that it +* contains the shortest hop path for that LID through any port. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_lid_matrix_t +{ + cl_vector_t lid_vec; + uint8_t num_ports; + +} osm_lid_matrix_t; +/* +* FIELDS +* lid_vec +* Vector (indexed by LID) of port arrays (indexed by port number) +* +* num_ports +* Number of ports at each entry in the LID vector. +* +* SEE ALSO +*********/ + +/****f* OpenSM: LID Matrix/osm_lid_matrix_construct +* NAME +* osm_lid_matrix_construct +* +* DESCRIPTION +* This function constructs a LID Matrix object. +* +* SYNOPSIS +*/ +static inline void +osm_lid_matrix_construct( + IN osm_lid_matrix_t* const p_lmx ) +{ + p_lmx->num_ports = 0; + cl_vector_construct( &p_lmx->lid_vec ); +} +/* +* PARAMETERS +* p_lmx +* [in] Pointer to a LID Matrix object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_lid_matrix_init, osm_lid_matrix_destroy +* +* Calling osm_lid_matrix_construct is a prerequisite to calling any other +* method except osm_lid_matrix_init. +* +* SEE ALSO +* LID Matrix object, osm_lid_matrix_init, osm_lid_matrix_destroy +*********/ + +/****f* OpenSM: LID Matrix/osm_lid_matrix_destroy +* NAME +* osm_lid_matrix_destroy +* +* DESCRIPTION +* The osm_lid_matrix_destroy function destroys a node, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_lid_matrix_destroy( + IN osm_lid_matrix_t* const p_lmx ); +/* +* PARAMETERS +* p_lmx +* [in] Pointer to a LID Matrix object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified LID Matrix object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_lid_matrix_construct or +* osm_lid_matrix_init. +* +* SEE ALSO +* LID Matrix object, osm_lid_matrix_construct, osm_lid_matrix_init +*********/ + +/****f* OpenSM: LID Matrix/osm_lid_matrix_init +* NAME +* osm_lid_matrix_init +* +* DESCRIPTION +* Initializes a LID Matrix object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_lid_matrix_init( + IN osm_lid_matrix_t* const p_lmx, + IN const uint8_t num_ports ); +/* +* PARAMETERS +* p_lmx +* [in] Pointer to an osm_lid_matrix_t object to initialize. +* +* num_ports +* [in] Number of ports at each LID index. This value is fixed +* at initialization time. +* +* RETURN VALUES +* IB_SUCCESS on success +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: LID Matrix/osm_lid_matrix_get +* NAME +* osm_lid_matrix_get +* +* DESCRIPTION +* Returns the hop count at the specified LID/Port intersection. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_lid_matrix_get( + IN const osm_lid_matrix_t* const p_lmx, + IN const uint16_t lid_ho, + IN const uint8_t port_num ) +{ + CL_ASSERT( port_num < p_lmx->num_ports ); + CL_ASSERT( lid_ho lid_vec) ); + return( ((uint8_t *)cl_vector_get_ptr( + &p_lmx->lid_vec, lid_ho ))[port_num] ); +} +/* +* PARAMETERS +* p_lmx +* [in] Pointer to an osm_lid_matrix_t 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: LID Matrix/osm_lid_matrix_get_max_lid_ho +* NAME +* osm_lid_matrix_get_max_lid_ho +* +* DESCRIPTION +* Returns the maximum LID (host order) value contained +* in the matrix. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_lid_matrix_get_max_lid_ho( + IN const osm_lid_matrix_t* const p_lmx ) +{ + return( (uint16_t)(cl_vector_get_size( &p_lmx->lid_vec ) - 1 ) ); +} +/* +* PARAMETERS +* p_lmx +* [in] Pointer to an osm_lid_matrix_t object. +* +* RETURN VALUES +* Returns the maximum LID (host order) value contained +* in the matrix. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: LID Matrix/osm_lid_matrix_get_num_ports +* NAME +* osm_lid_matrix_get_num_ports +* +* DESCRIPTION +* Returns the number of ports in this lid matrix. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_lid_matrix_get_num_ports( + IN const osm_lid_matrix_t* const p_lmx ) +{ + return( p_lmx->num_ports ); +} +/* +* PARAMETERS +* p_lmx +* [in] Pointer to an osm_lid_matrix_t object. +* +* RETURN VALUES +* Returns the number of ports in this lid matrix. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: LID Matrix/osm_lid_matrix_get_least_hops +* NAME +* osm_lid_matrix_get_least_hops +* +* DESCRIPTION +* Returns the least number of hops for specified lid +* +* SYNOPSIS +*/ +static inline uint8_t +osm_lid_matrix_get_least_hops( + IN const osm_lid_matrix_t* const p_lmx, + IN const uint16_t lid_ho ) +{ + if( lid_ho > osm_lid_matrix_get_max_lid_ho( p_lmx ) ) + return( OSM_NO_PATH ); + + return( ((uint8_t *)cl_vector_get_ptr( + &p_lmx->lid_vec, lid_ho ))[p_lmx->num_ports] ); +} +/* +* PARAMETERS +* p_lmx +* [in] Pointer to an osm_lid_matrix_t object. +* +* lid_ho +* [in] LID (host order) for which to retrieve the shortest hop count. +* +* RETURN VALUES +* Returns the least number of hops for specified lid +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: LID Matrix/osm_lid_matrix_set +* NAME +* osm_lid_matrix_set +* +* DESCRIPTION +* Sets the hop count at the specified LID/Port intersection. +* +* SYNOPSIS +*/ +cl_status_t +osm_lid_matrix_set( + IN osm_lid_matrix_t* const p_lmx, + IN const uint16_t lid_ho, + IN const uint8_t port_num, + IN const uint8_t val ); +/* +* PARAMETERS +* p_lmx +* [in] Pointer to an osm_lid_matrix_t object. +* +* lid_ho +* [in] LID value (host order) to index into the vector. +* +* port_num +* [in] port number index into the vector entry. +* +* val +* [in] value (number of hops) to assign to this entry. +* +* RETURN VALUES +* Returns the hop count at the specified LID/Port intersection. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: LID Matrix/osm_lid_matrix_set_min_lid_size +* NAME +* osm_lid_matrix_set_min_lid_size +* +* DESCRIPTION +* Sets the size of the matrix to at least accomodate the +* specified LID value (host ordered) +* +* SYNOPSIS +*/ +static inline cl_status_t +osm_lid_matrix_set_min_lid_size( + IN osm_lid_matrix_t* const p_lmx, + IN const uint16_t lid_ho ) +{ + return( cl_vector_set_min_size( &p_lmx->lid_vec, lid_ho + 1 ) ); +} +/* +* PARAMETERS +* p_lmx +* [in] Pointer to an osm_lid_matrix_t object. +* +* lid_ho +* [in] Minimum LID value (host order) to accomodate. +* +* RETURN VALUES +* Sets the size of the matrix to at least accomodate the +* specified LID value (host ordered) +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: LID Matrix/osm_lid_matrix_clear +* NAME +* osm_lid_matrix_clear +* +* DESCRIPTION +* Clears a LID Matrix object in anticipation of a rebuild. +* +* SYNOPSIS +*/ +void +osm_lid_matrix_clear( + IN osm_lid_matrix_t* const p_lmx ); +/* +* PARAMETERS +* p_lmx +* [in] Pointer to an osm_lid_matrix_t object to clear. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_MATRIX_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_fwd_rcv.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_fwd_rcv.h new file mode 100644 index 00000000..0a812167 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_fwd_rcv.h @@ -0,0 +1,259 @@ +/* + * 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: + * Declaration of osm_mft_rcv_t. + * This object represents the Multicast Forwarding Table Receiver object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_MFT_RCV_H_ +#define _OSM_MFT_RCV_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/MFT Receiver +* NAME +* MFT Receiver +* +* DESCRIPTION +* The MFT Receiver object encapsulates the information +* needed to receive the MFT attribute from a node. +* +* The MFT Receiver 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: MFT Receiver/osm_mft_rcv_t +* NAME +* osm_mft_rcv_t +* +* DESCRIPTION +* MFT Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_mft_rcv +{ + osm_subn_t *p_subn; + osm_log_t *p_log; + cl_plock_t *p_lock; + +} osm_mft_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* MFT Receiver object +*********/ + +/****f* OpenSM: MFT Receiver/osm_mft_rcv_construct +* NAME +* osm_mft_rcv_construct +* +* DESCRIPTION +* This function constructs a MFT Receiver object. +* +* SYNOPSIS +*/ +void +osm_mft_rcv_construct( + IN osm_mft_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a MFT Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_mft_rcv_init, osm_mft_rcv_destroy +* +* Calling osm_mft_rcv_construct is a prerequisite to calling any other +* method except osm_mft_rcv_init. +* +* SEE ALSO +* MFT Receiver object, osm_mft_rcv_init, +* osm_mft_rcv_destroy +*********/ + +/****f* OpenSM: MFT Receiver/osm_mft_rcv_destroy +* NAME +* osm_mft_rcv_destroy +* +* DESCRIPTION +* The osm_mft_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_mft_rcv_destroy( + IN osm_mft_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* MFT Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_mft_rcv_construct or osm_mft_rcv_init. +* +* SEE ALSO +* MFT Receiver object, osm_mft_rcv_construct, +* osm_mft_rcv_init +*********/ + +/****f* OpenSM: MFT Receiver/osm_mft_rcv_init +* NAME +* osm_mft_rcv_init +* +* DESCRIPTION +* The osm_mft_rcv_init function initializes a +* MFT Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_mft_rcv_init( + IN osm_mft_rcv_t* const p_rcv, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_mft_rcv_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the MFT Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other MFT Receiver methods. +* +* SEE ALSO +* MFT Receiver object, osm_mft_rcv_construct, +* osm_mft_rcv_destroy +*********/ + +/****f* OpenSM: MFT Receiver/osm_mft_rcv_process +* NAME +* osm_mft_rcv_process +* +* DESCRIPTION +* Process the MFT attribute. +* +* SYNOPSIS +*/ +void +osm_mft_rcv_process( + IN const osm_mft_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_mft_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's MFT attribute. +* +* RETURN VALUES +* CL_SUCCESS if the MFT processing was successful. +* +* NOTES +* This function processes a MFT attribute. +* +* SEE ALSO +* MFT Receiver, Node Description Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_MFT_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_fwd_rcv_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_fwd_rcv_ctrl.h new file mode 100644 index 00000000..c664ecb6 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_fwd_rcv_ctrl.h @@ -0,0 +1,235 @@ +/* + * 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: + * Declaration of osm_mft_rcv_ctrl_t. + * This object represents a controller that receives the IBA + * Multicast Forwarding Table attribute from a node (specifically, a + * switch). + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_MFT_RCV_CTRL_H_ +#define _OSM_MFT_RCV_CTRL_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/MFT Receive Controller +* NAME +* MFT Receive Controller +* +* DESCRIPTION +* The MFT Receive Controller object +* encapsulates the information +* needed to receive the Multicast Forwarding Table +* attribute from a node. +* +* The MFT Receive 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: MFT Receive Controller/osm_mft_rcv_ctrl_t +* NAME +* osm_mft_rcv_ctrl_t +* +* DESCRIPTION +* MFT Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_mft_rcv_ctrl +{ + osm_mft_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_mft_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the MFT Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* MFT Receive Controller object +*********/ + +/****f* OpenSM: MFT Receive Controller/osm_mft_rcv_ctrl_construct +* NAME +* osm_mft_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a MFT Receive Controller object. +* +* SYNOPSIS +*/ +void +osm_mft_rcv_ctrl_construct( + IN osm_mft_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a MFT Receive Controller object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_mft_rcv_ctrl_init, osm_mft_rcv_ctrl_destroy +* +* Calling osm_mft_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_mft_rcv_ctrl_init. +* +* SEE ALSO +* MFT Receive Controller object, osm_mft_rcv_ctrl_init, +* osm_mft_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: MFT Receive Controller/osm_mft_rcv_ctrl_destroy +* NAME +* osm_mft_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_mft_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_mft_rcv_ctrl_destroy( + IN osm_mft_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* MFT Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_mft_rcv_ctrl_construct or osm_mft_rcv_ctrl_init. +* +* SEE ALSO +* MFT Receive Controller object, osm_mft_rcv_ctrl_construct, +* osm_mft_rcv_ctrl_init +*********/ + +/****f* OpenSM: MFT Receive Controller/osm_mft_rcv_ctrl_init +* NAME +* osm_mft_rcv_ctrl_init +* +* DESCRIPTION +* The osm_mft_rcv_ctrl_init function initializes a +* MFT Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_mft_rcv_ctrl_init( + IN osm_mft_rcv_ctrl_t* const p_ctrl, + IN osm_mft_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_mft_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_mft_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the MFT Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other MFT Receive Controller methods. +* +* SEE ALSO +* MFT Receive Controller object, osm_mft_rcv_ctrl_construct, +* osm_mft_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* OSM_MFT_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_mgr.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_mgr.h new file mode 100644 index 00000000..c975b96d --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_mgr.h @@ -0,0 +1,339 @@ +/* + * 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: + * Declaration of osm_mcast_mgr_t. + * This object represents the Multicast Manager object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_MCAST_MGR_H_ +#define _OSM_MCAST_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 + +#define OSM_MCAST_MGR_LIST_SIZE_MIN 256 + +/****h* OpenSM/Multicast Manager +* NAME +* Multicast Manager +* +* DESCRIPTION +* The Multicast Manager object encapsulates the information +* needed to control multicast LID forwarding on the subnet. +* +* The Multicast 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 +* +*********/ + +/****s* OpenSM: Multicast Manager/osm_mcast_mgr_t +* NAME +* osm_mcast_mgr_t +* +* DESCRIPTION +* Multicast Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_mcast_mgr +{ + osm_subn_t *p_subn; + osm_req_t *p_req; + osm_log_t *p_log; + cl_plock_t *p_lock; + +} osm_mcast_mgr_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_req +* Pointer to the Requester object sending SMPs. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* Multicast Manager object +*********/ + +/****f* OpenSM: Multicast Manager/osm_mcast_mgr_construct +* NAME +* osm_mcast_mgr_construct +* +* DESCRIPTION +* This function constructs a Multicast Manager object. +* +* SYNOPSIS +*/ +void +osm_mcast_mgr_construct( + IN osm_mcast_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to a Multicast Manager object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows osm_mcast_mgr_destroy +* +* Calling osm_mcast_mgr_construct is a prerequisite to calling any other +* method except osm_mcast_mgr_init. +* +* SEE ALSO +* Multicast Manager object, osm_mcast_mgr_init, +* osm_mcast_mgr_destroy +*********/ + +/****f* OpenSM: Multicast Manager/osm_mcast_mgr_destroy +* NAME +* osm_mcast_mgr_destroy +* +* DESCRIPTION +* The osm_mcast_mgr_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_mcast_mgr_destroy( + IN osm_mcast_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Multicast Manager object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_mcast_mgr_construct or osm_mcast_mgr_init. +* +* SEE ALSO +* Multicast Manager object, osm_mcast_mgr_construct, +* osm_mcast_mgr_init +*********/ + +/****f* OpenSM: Multicast Manager/osm_mcast_mgr_init +* NAME +* osm_mcast_mgr_init +* +* DESCRIPTION +* The osm_mcast_mgr_init function initializes a +* Multicast Manager object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_mcast_mgr_init( + IN osm_mcast_mgr_t* const p_mgr, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_mcast_mgr_t object to initialize. +* +* p_req +* [in] Pointer to the attribute Requester object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the Multicast Manager object was initialized +* successfully. +* +* NOTES +* Allows calling other Multicast Manager methods. +* +* SEE ALSO +* Multicast Manager object, osm_mcast_mgr_construct, +* osm_mcast_mgr_destroy +*********/ + +/****f* OpenSM: Multicast Manager/osm_mcast_mgr_process +* NAME +* osm_mcast_mgr_process +* +* DESCRIPTION +* Process and configure the subnet's multicast forwarding tables. +* +* SYNOPSIS +*/ +osm_signal_t +osm_mcast_mgr_process( + IN osm_mcast_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_mcast_mgr_t object. +* +* RETURN VALUES +* Returns the appropriate signal to the caller: +* OSM_SIGNAL_DONE - operation is complete +* OSM_SIGNAL_DONE_PENDING - local operations are complete, but +* transactions are still pending on the wire. +* +* NOTES +* This function processes the subnet, configuring switch +* multicast forwarding tables. +* +* SEE ALSO +* Multicast Manager, Node Info Response Controller +*********/ + +/****f* OpenSM: Multicast Manager/osm_mcast_mgr_process_mgrp_cb +* NAME +* osm_mcast_mgr_process_mgrp_cb +* +* DESCRIPTION +* Callback entry point for the osm_mcast_mgr_process_mgrp function. +* +* SYNOPSIS +*/ +osm_signal_t +osm_mcast_mgr_process_mgrp_cb( + IN void* const Context1, + IN void* const Context2 ); +/* +* PARAMETERS +* (Context1) p_mgr +* [in] Pointer to an osm_mcast_mgr_t object. +* +* (Context2) p_mgrp +* [in] Pointer to the multicast group to process. +* +* RETURN VALUES +* IB_SUCCESS +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Manager/osm_mcast_mgr_process +* NAME +* osm_mcast_mgr_process_single +* +* DESCRIPTION +* Attempts to add a single port to an existing multicast spanning tree. +* This function can only succeed if the port to be added is connected +* to a switch that is already routing traffic for this multicast group. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_mcast_mgr_process_single( + IN osm_mcast_mgr_t* const p_mgr, + IN const ib_net16_t mlid, + IN const ib_net64_t port_guid, + IN const uint8_t join_state ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_mcast_mgr_t object. +* +* mlid +* [in] Multicast LID of relevent multicast group. +* +* port_guid +* [in] GUID of port to attempt to add to the group. +* +* join_state +* [in] Specifies the join state for this port per the spec. +* +* RETURN VALUES +* IB_SUCCESS +* IB_NOT_DONE +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_MCAST_MGR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_tbl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_tbl.h new file mode 100644 index 00000000..f4adad3c --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcast_tbl.h @@ -0,0 +1,484 @@ +/* + * 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: + * Declaration of osm_mcast_tbl_t. + * This object represents a multicast forwarding table. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#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_fwd_tbl +{ + uint8_t num_ports; + uint8_t max_position; + uint16_t max_block; + int16_t max_block_in_use; + uint16_t num_entries; + uint16_t max_mlid_ho; + uint16_t (*p_mask_tbl)[][IB_MCAST_POSITION_MAX]; +} osm_mcast_tbl_t; +/* +* FIELDS +* num_ports +* The number of ports in the port mask. This value +* is the same as the number of ports on the switch +* +* max_position +* Maximum bit mask position for this table. This value +* is computed from the number of ports on the switch. +* +* max_block +* Maximum block number supported in the table. This value +* is approximately the number of MLID entries divided by the +* number of MLIDs per block +* +* num_entries +* Number of entries in the table (aka number of MLIDs supported). +* +* max_mlid_ho +* Maximum MLID value (host order). +* +* pp_mask_tbl +* Pointer to a two dimensional array of port_masks for this switch. +* The first dimension is MLID, the second dimension is mask position. +* This pointer is null for switches that do not support multicast. +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_init +* NAME +* osm_mcast_tbl_init +* +* DESCRIPTION +* This function initializes a Multicast Forwarding Table object. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_mcast_tbl_init( + IN osm_mcast_tbl_t* const p_tbl, + IN uint8_t const num_ports, + IN uint16_t const capacity ); +/* +* PARAMETERS +* num_ports +* [in] Number of ports in the switch owning this table. +* +* capacity +* [in] The number of MLID entries (starting at 0xC000) supported +* by this switch. +* +* RETURN VALUE +* IB_SUCCESS on success. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_delete +* NAME +* osm_mcast_tbl_delete +* +* DESCRIPTION +* This destroys and deallocates a Multicast Forwarding Table object. +* +* SYNOPSIS +*/ +void +osm_mcast_tbl_delete( + IN osm_mcast_tbl_t** const pp_tbl ); +/* +* PARAMETERS +* pp_tbl +* [in] Pointer a Pointer to the Multicast Forwarding Table object. +* +* RETURN VALUE +* On success, returns a pointer to a new Multicast Forwarding Table object +* of the specified size. +* NULL otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_destroy +* NAME +* osm_mcast_tbl_destroy +* +* DESCRIPTION +* This destroys and deallocates a Multicast Forwarding Table object. +* +* SYNOPSIS +*/ +void +osm_mcast_tbl_destroy( + IN osm_mcast_tbl_t* const p_tbl ); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Multicast Forwarding Table object. +* +* RETURN VALUE +* None +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_set +* NAME +* osm_mcast_tbl_set +* +* DESCRIPTION +* Adds the port to the multicast group. +* +* SYNOPSIS +*/ +void +osm_mcast_tbl_set( + IN osm_mcast_tbl_t* const p_tbl, + IN const uint16_t mlid_ho, + IN const uint8_t port_num ); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Multicast Forwarding Table object. +* +* mlid_ho +* [in] MLID value (host order) for which to set the route. +* +* port_num +* [in] Port to add to the multicast group. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_clear_mlid +* NAME +* osm_mcast_tbl_clear_mlid +* +* DESCRIPTION +* Removes all multicast paths for the specified MLID. +* +* SYNOPSIS +*/ +void +osm_mcast_tbl_clear_mlid( + IN osm_mcast_tbl_t* const p_tbl, + IN const uint16_t mlid_ho ); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Multicast Forwarding Table object. +* +* mlid_ho +* [in] MLID value (host order) for which to clear. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_is_port +* NAME +* osm_mcast_tbl_is_port +* +* DESCRIPTION +* Returns TRUE if the port is in the multicast group. +* +* SYNOPSIS +*/ +boolean_t +osm_mcast_tbl_is_port( + IN const osm_mcast_tbl_t* const p_tbl, + IN const uint16_t mlid_ho, + IN const uint8_t port_num ); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Multicast Forwarding Table object. +* +* mlid_ho +* [in] MLID value (host order). +* +* port_num +* [in] Port number on the switch +* +* RETURN VALUE +* Returns the port that routes the specified LID. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_is_any_port +* NAME +* osm_mcast_tbl_is_any_port +* +* DESCRIPTION +* Returns TRUE if any port is in the multicast group. +* +* SYNOPSIS +*/ +boolean_t +osm_mcast_tbl_is_any_port( + IN const osm_mcast_tbl_t* const p_tbl, + IN const uint16_t mlid_ho ); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Multicast Forwarding Table object. +* +* mlid_ho +* [in] MLID value (host order). +* +* RETURN VALUE +* Returns TRUE if any port is in the multicast group. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_set_block +* NAME +* osm_mcast_tbl_set_block +* +* DESCRIPTION +* Copies the specified block into the Multicast Forwarding Table. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_mcast_tbl_set_block( + IN osm_mcast_tbl_t* const p_tbl, + IN const ib_net16_t* const p_block, + IN const int16_t block_num, + IN const uint8_t position ); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Multicast Forwarding Table object. +* +* p_block +* [in] Pointer to the Forwarding Table block. +* +* block_num +* [in] Block number of this block. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_get_tbl_block +* NAME +* osm_mcast_get_tbl_block +* +* DESCRIPTION +* Retrieve a multicast forwarding table block. +* +* SYNOPSIS +*/ +boolean_t +osm_mcast_tbl_get_block( + IN osm_mcast_tbl_t* const p_tbl, + IN const int16_t block_num, + IN const uint8_t position, + OUT ib_net16_t* const p_block ); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to an osm_mcast_tbl_t object. +* +* p_block +* [in] Pointer to the Forwarding Table block. +* +* block_num +* [in] Block number of this block. +* +* p_block +* [out] Pointer to the 32 entry array to store the +* forwarding table clock specified by block_id. +* +* RETURN VALUES +* Returns true if there are more blocks necessary to +* configure all the MLIDs reachable from this switch. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_get_max_block +* NAME +* osm_mcast_tbl_get_max_block +* +* DESCRIPTION +* Returns the maximum block ID in this table. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_mcast_tbl_get_max_block( + IN osm_mcast_tbl_t* const p_tbl ) +{ + return( p_tbl->max_block ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to an osm_mcast_tbl_t object. +* +* RETURN VALUES +* Returns the maximum block ID in this table. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_get_max_block_in_use +* NAME +* osm_mcast_tbl_get_max_block_in_use +* +* DESCRIPTION +* Returns the maximum block ID in use in this table. +* A value of -1 indicates no blocks are in use. +* +* SYNOPSIS +*/ +static inline int16_t +osm_mcast_tbl_get_max_block_in_use( + IN osm_mcast_tbl_t* const p_tbl ) +{ + return( p_tbl->max_block_in_use ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to an osm_mcast_tbl_t object. +* +* RETURN VALUES +* Returns the maximum block ID in use in this table. +* A value of -1 indicates no blocks are in use. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_get_max_position +* NAME +* osm_mcast_tbl_get_max_position +* +* DESCRIPTION +* Returns the maximum position in this table. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_mcast_tbl_get_max_position( + IN osm_mcast_tbl_t* const p_tbl ) +{ + return( p_tbl->max_position ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to an osm_mcast_tbl_t object. +* +* RETURN VALUES +* Returns the maximum position in this table. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_MCAST_TBL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcm_info.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcm_info.h new file mode 100644 index 00000000..6f6e864c --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcm_info.h @@ -0,0 +1,237 @@ +/* + * 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: + * Declaration of osm_mcm_info_t. + * This object represents a Multicast Forwarding Information object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_MCM_INFO_H_ +#define _OSM_MCM_INFO_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +/****s* OpenSM: Multicast Member Info/osm_mcm_info_t +* NAME +* osm_mcm_info_t +* +* DESCRIPTION +* Multicast Membership Info object. +* This object contains information about a nodes membership +* in a particular multicast group. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_mcm_info +{ + cl_list_item_t list_item; + ib_net16_t mlid; + +} osm_mcm_info_t; +/* +* FIELDS +* list_item +* Linkage structure for cl_qlist. MUST BE FIRST MEMBER! +* +* mlid +* MLID of this multicast group. +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Member Info/osm_mcm_info_construct +* NAME +* osm_mcm_info_construct +* +* DESCRIPTION +* This function constructs a Multicast Member Info object. +* +* SYNOPSIS +*/ +static inline void +osm_mcm_info_construct( + IN osm_mcm_info_t* const p_mcm ) +{ + memset( p_mcm, 0, sizeof(*p_mcm) ); +} +/* +* PARAMETERS +* p_mcm +* [in] Pointer to a Multicast Member Info object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Member Info/osm_mcm_info_destroy +* NAME +* osm_mcm_info_destroy +* +* DESCRIPTION +* The osm_mcm_info_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_mcm_info_destroy( + IN osm_mcm_info_t* const p_mcm ); +/* +* PARAMETERS +* p_mcm +* [in] Pointer to a Multicast Member Info object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Multicast Member Info object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_mtree_construct or +* osm_mtree_init. +* +* SEE ALSO +* Multicast Member Info object, osm_mtree_construct, osm_mtree_init +*********/ + +/****f* OpenSM: Multicast Member Info/osm_mcm_info_init +* NAME +* osm_mcm_info_init +* +* DESCRIPTION +* Initializes a Multicast Member Info object for use. +* +* SYNOPSIS +*/ +void +osm_mcm_info_init( + IN osm_mcm_info_t* const p_mcm, + IN const ib_net16_t mlid ); +/* +* PARAMETERS +* p_mcm +* [in] Pointer to an osm_mcm_info_t object to initialize. +* +* mlid +* [in] MLID value for this multicast group. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Member Info/osm_mcm_info_new +* NAME +* osm_mcm_info_new +* +* DESCRIPTION +* Returns an initialized a Multicast Member Info object for use. +* +* SYNOPSIS +*/ +osm_mcm_info_t* +osm_mcm_info_new( + IN const ib_net16_t mlid ); +/* +* PARAMETERS +* mlid +* [in] MLID value for this multicast group. +* +* RETURN VALUES +* Pointer to an initialized tree node. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Member Info/osm_mcm_info_delete +* NAME +* osm_mcm_info_delete +* +* DESCRIPTION +* Destroys and deallocates the specified object. +* +* SYNOPSIS +*/ +void +osm_mcm_info_delete( + IN osm_mcm_info_t* const p_mcm ); +/* +* PARAMETERS +* p_mcm +* Pointer to the object to destroy. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_MCM_INFO_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcm_port.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcm_port.h new file mode 100644 index 00000000..78232dd3 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mcm_port.h @@ -0,0 +1,269 @@ +/* + * 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: + * 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_MCM_PORT_H_ +#define _OSM_MCM_PORT_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +/****s* OpenSM: MCM Port Object/osm_mcm_port_t +* NAME +* osm_mcm_port_t +* +* DESCRIPTION +* This object represents a particular port as a member of a +* multicast group. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_mcm_port +{ + cl_map_item_t map_item; + ib_gid_t port_gid; + uint8_t scope_state; + boolean_t proxy_join; +} osm_mcm_port_t; +/* +* FIELDS +* map_item +* Map Item for qmap linkage. Must be first element!! +* +* port_gid +* GID of the member port. +* +* scope_state +* ??? +* +* proxy_join +* If FALSE - Join was performed by the endport identified +* by PortGID. If TRUE - Join was performed on behalf of +* the endport identified by PortGID by another port within +* the same partition. +* +* SEE ALSO +* MCM Port Object +*********/ + +/****f* OpenSM: MCM Port Object/osm_mcm_port_construct +* NAME +* osm_mcm_port_construct +* +* DESCRIPTION +* This function constructs a MCM Port object. +* +* SYNOPSIS +*/ +void +osm_mcm_port_construct( + IN osm_mcm_port_t* const p_mcm ); +/* +* PARAMETERS +* p_mcm +* [in] Pointer to a MCM Port Object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_mcm_port_init, osm_mcm_port_destroy. +* +* Calling osm_mcm_port_construct is a prerequisite to calling any other +* method except osm_mcm_port_init. +* +* SEE ALSO +* MCM Port Object, osm_mcm_port_init, osm_mcm_port_destroy +*********/ + +/****f* OpenSM: MCM Port Object/osm_mcm_port_destroy +* NAME +* osm_mcm_port_destroy +* +* DESCRIPTION +* The osm_mcm_port_destroy function destroys a MCM Port Object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_mcm_port_destroy( + IN osm_mcm_port_t* const p_mcm ); +/* +* PARAMETERS +* p_mcm +* [in] Pointer to a MCM Port Object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified MCM Port Object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_mcm_port_construct or osm_mcm_port_init. +* +* SEE ALSO +* MCM Port Object, osm_mcm_port_construct, osm_mcm_port_init +*********/ + +/****f* OpenSM: MCM Port Object/osm_mcm_port_init +* NAME +* osm_mcm_port_init +* +* DESCRIPTION +* The osm_mcm_port_init function initializes a MCM Port Object for use. +* +* SYNOPSIS +*/ +void +osm_mcm_port_init( + IN osm_mcm_port_t* const p_mcm, + IN const ib_gid_t* const p_port_gid, + IN const uint8_t scope_state, + IN const boolean_t proxy_join ); +/* +* PARAMETERS +* p_mcm +* [in] Pointer to an osm_mcm_port_t object to initialize. +* +* p_port_gid +* [in] Pointer to the GID of the port to add to the multicast group. +* +* scope_state +* [in] scope state of the join request +* +* proxy_join +* [in] proxy_join state analyzed from the request +* +* RETURN VALUES +* None. +* +* NOTES +* Allows calling other MCM Port Object methods. +* +* SEE ALSO +* MCM Port Object, osm_mcm_port_construct, osm_mcm_port_destroy, +*********/ + +/****f* OpenSM: MCM Port Object/osm_mcm_port_init +* NAME +* osm_mcm_port_init +* +* DESCRIPTION +* The osm_mcm_port_init function initializes a MCM Port Object for use. +* +* SYNOPSIS +*/ +osm_mcm_port_t* +osm_mcm_port_new( + IN const ib_gid_t* const p_port_gid, + IN const uint8_t scope_state, + IN const boolean_t proxy_join ); +/* +* PARAMETERS +* p_port_gid +* [in] Pointer to the GID of the port to add to the multicast group. +* +* scope_state +* [in] scope state of the join request +* +* proxy_join +* [in] proxy_join state analyzed from the request +* +* RETURN VALUES +* Pointer to the allocated and initialized MCM Port object. +* +* NOTES +* +* SEE ALSO +* MCM Port Object, osm_mcm_port_construct, osm_mcm_port_destroy, +*********/ + +/****f* OpenSM: MCM Port Object/osm_mcm_port_destroy +* NAME +* osm_mcm_port_destroy +* +* DESCRIPTION +* The osm_mcm_port_destroy function destroys and dellallocates an +* MCM Port Object, releasing all resources. +* +* SYNOPSIS +*/ +void +osm_mcm_port_delete( + IN osm_mcm_port_t* const p_mcm ); +/* +* PARAMETERS +* p_mcm +* [in] Pointer to a MCM Port Object to delete. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* MCM Port Object, osm_mcm_port_construct, osm_mcm_port_init +*********/ + +END_C_DECLS + +#endif /* _OSM_MCM_PORT_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_msgdef.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_msgdef.h new file mode 100644 index 00000000..8b591d1a --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_msgdef.h @@ -0,0 +1,208 @@ +/* + * 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: + * Declaration of Dispatcher message values. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#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_REQ +* NAME +* OSM_MSG_REQ +* +* DESCRIPTION +* Initiates a QP0 attribute request. +* +* NOTES +* Sent by: osm_sm_t +* Received by: osm_req_ctrl_t +* Delivery notice: yes +* +***********/ + +/****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 +***********/ + +/****d* OpenSM: Dispatcher Messages/OSM_MSG_NO_SMPS_OUTSTANDING +* NAME +* OSM_MSG_NO_SMPS_OUTSTANDING +* +* DESCRIPTION +* Message indicating that there are no outstanding SMPs on the subnet. +* +* NOTES +* Sent by: osm_mad_ctrl_t +* Received by: osm_state_mgr_ctrl_t +* Delivery notice: no +* +* SOURCE +***********/ +enum +{ + OSM_MSG_REQ = 0, + OSM_MSG_MAD_NODE_INFO, + OSM_MSG_MAD_PORT_INFO, + OSM_MSG_MAD_SWITCH_INFO, + OSM_MSG_MAD_NODE_DESC, + OSM_MSG_NO_SMPS_OUTSTANDING, + 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_MAX +}; + +END_C_DECLS + +#endif /* _OSM_MSGDEF_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mtl_bind.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mtl_bind.h new file mode 100644 index 00000000..4394ff22 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mtl_bind.h @@ -0,0 +1,144 @@ +/* + * 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$ + */ + + +#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-1/ulp/opensm/user/include/opensm/osm_mtree.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mtree.h new file mode 100644 index 00000000..24e4a857 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_mtree.h @@ -0,0 +1,378 @@ +/* + * 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: + * Declaration of osm_mtree_t. + * This object represents multicast spanning tree. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_MTREE_H_ +#define _OSM_MTREE_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 + +#define OSM_MTREE_LEAF ((void*)-1) + +/****h* OpenSM/Multicast Tree +* NAME +* Multicast Tree +* +* DESCRIPTION +* The Multicast Tree object encapsulates the information needed by the +* OpenSM to manage multicast fabric routes. It is a tree structure +* in which each node in the tree represents a switch, and may have a +* varying number of children. +* +* Multicast trees do not contain loops. +* +* The Multicast Tree is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Multicast Tree/osm_mtree_node_t +* NAME +* osm_mtree_node_t +* +* DESCRIPTION +* The MTree Node object encapsulates the information needed by the +* OpenSM for a particular switch in the multicast tree. +* +* The MTree Node object is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_mtree_node +{ + cl_map_item_t map_item; + osm_switch_t *p_sw; + uint8_t max_children; + struct _osm_mtree_node *p_up; + struct _osm_mtree_node *child_array[1]; +} osm_mtree_node_t; +/* +* FIELDS +* map_item +* Linkage for quick map. MUST BE FIRST ELEMENT!!! +* +* p_sw +* Pointer to the switch represented by this tree node. +* +* max_children +* Maximum number of child nodes of this node. Equal to the +* the number of ports on the switch if the switch supports +* multicast. Equal to 1 (default route) if the switch does +* not support multicast. +* +* p_up +* Pointer to the parent of this node. If this pointer is +* NULL, the node is at the root of the tree. +* +* child_array +* Array (indexed by port number) of pointers to the +* child osm_mtree_node_t objects of this tree node, if any. +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Tree/osm_mtree_node_construct +* NAME +* osm_mtree_node_construct +* +* DESCRIPTION +* This function constructs a Multicast Tree Node object. +* +* SYNOPSIS +*/ +static inline void +osm_mtree_node_construct( + IN osm_mtree_node_t* const p_mtn ) +{ + memset( p_mtn, 0, sizeof(*p_mtn) ); +} +/* +* PARAMETERS +* p_mtn +* [in] Pointer to a Multicast Tree Node object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Tree/osm_mtree_node_destroy +* NAME +* osm_mtree_node_destroy +* +* DESCRIPTION +* The osm_mtree_node_destroy function destroys a node, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_mtree_node_destroy( + IN osm_mtree_node_t* const p_mtn ); +/* +* PARAMETERS +* p_mtn +* [in] Pointer to a Multicast Tree Node object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Multicast Tree object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_mtree_construct or +* osm_mtree_init. +* +* SEE ALSO +* Multicast Tree object, osm_mtree_construct, osm_mtree_init +*********/ + +/****f* OpenSM: Multicast Tree/osm_mtree_node_init +* NAME +* osm_mtree_node_init +* +* DESCRIPTION +* Initializes a Multicast Tree Node object for use. +* +* SYNOPSIS +*/ +void +osm_mtree_node_init( + IN osm_mtree_node_t* const p_mtn, + IN const osm_switch_t* const p_sw ); +/* +* PARAMETERS +* p_mtn +* [in] Pointer to an osm_mtree_node_t object to initialize. +* +* p_sw +* [in] Pointer to the switch represented by this node. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Tree/osm_mtree_node_new +* NAME +* osm_mtree_node_new +* +* DESCRIPTION +* Returns an initialized a Multicast Tree object for use. +* +* SYNOPSIS +*/ +osm_mtree_node_t* +osm_mtree_node_new( + IN const osm_switch_t* const p_sw ); +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch represented by this node. +* +* RETURN VALUES +* Pointer to an initialized tree node. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Tree/osm_mtree_destroy +* NAME +* osm_mtree_destroy +* +* DESCRIPTION +* Destroys a Multicast Tree object given by the p_mtn +* +* SYNOPSIS +*/ +void +osm_mtree_destroy( + IN osm_mtree_node_t *p_mtn ); +/* +* PARAMETERS +* p_mtn +* [in] Pointer to an osm_mtree_node_t object to destroy. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Tree/osm_mtree_node_get_max_children +* NAME +* osm_mtree_node_get_max_children +* +* DESCRIPTION +* Returns the number maximum number of children of this node. +* The return value is 1 greater than the highest valid port +* number on the switch. +* +* +* SYNOPSIS +*/ +static inline uint8_t +osm_mtree_node_get_max_children( + IN const osm_mtree_node_t* const p_mtn ) +{ + return( p_mtn->max_children ); +} +/* +* PARAMETERS +* p_mtn +* [in] Pointer to the multicast tree node. +* +* RETURN VALUES +* See description. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Tree/osm_mtree_node_get_child +* NAME +* osm_mtree_node_get_child +* +* DESCRIPTION +* Returns the specified child node of this node. +* +* SYNOPSIS +*/ +static inline osm_mtree_node_t* +osm_mtree_node_get_child( + IN const osm_mtree_node_t* const p_mtn, + IN const uint8_t child ) +{ + CL_ASSERT( child < p_mtn->max_children ); + return( p_mtn->child_array[child] ); +} +/* +* PARAMETERS +* p_mtn +* [in] Pointer to the multicast tree node. +* +* child +* [in] Index of the child to retrieve. +* +* RETURN VALUES +* Returns the specified child node of this node. +* +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Tree/osm_mtree_node_get_switch_ptr +* NAME +* osm_mtree_node_get_switch_ptr +* +* DESCRIPTION +* Returns a pointer to the switch object represented by this tree node. +* +* SYNOPSIS +*/ +static inline osm_switch_t* +osm_mtree_node_get_switch_ptr( + IN const osm_mtree_node_t* const p_mtn ) +{ + return( p_mtn->p_sw ); +} +/* +* PARAMETERS +* p_mtn +* [in] Pointer to the multicast tree node. +* +* child +* [in] Index of the child to retrieve. +* +* RETURN VALUES +* Returns a pointer to the switch object represented by this tree node. +* +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_MTREE_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_multicast.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_multicast.h new file mode 100644 index 00000000..b182d3b7 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_multicast.h @@ -0,0 +1,769 @@ +/* + * 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: + * Declaration of osm_mgrp_t. + * This object represents an IBA Multicast Group. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_MULTICAST_H_ +#define _OSM_MULTICAST_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/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 +* +*********/ + +/****f* IBA Base: OpneSM: Multicast Group/osm_get_mcast_req_type_str +* NAME +* osm_get_mcast_req_type_str +* +* DESCRIPTION +* Returns a string for the specified osm_mcast_req_type_t value. +* +* SYNOPSIS +*/ +const char* +osm_get_mcast_req_type_str( + IN osm_mcast_req_type_t req_type ); +/* +* PARAMETERS +* req_type +* [in] osm_mcast_req_type value +* +* RETURN VALUES +* Pointer to the request type description string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* OpenSM: Multicast Group/osm_mcast_mgr_ctxt_t +* NAME +* osm_mcast_mgr_ctxt_t +* +* DESCRIPTION +* Struct for passing context arguments to the multicast manager. +* +* The osm_mcast_mgr_ctxt_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_mcast_mgr_ctxt +{ + ib_net16_t mlid; + osm_mcast_req_type_t req_type; + ib_net64_t port_guid; +} osm_mcast_mgr_ctxt_t; +/* +* FIELDS +* +* mlid +* The network ordered LID of this Multicast Group (must be >= 0xC000). +* +* req_type +* The type of the request that caused this call +* (multicast create/join/leave). +* +* port_guid +* The port guid of the port that is being added/removed from +* the multicast group due to this call. +* +* SEE ALSO +*********/ + +/****s* OpenSM: Multicast Group/osm_mgrp_t +* NAME +* osm_mgrp_t +* +* DESCRIPTION +* Multicast Group structure. +* +* The osm_mgrp_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_mgrp +{ + cl_map_item_t map_item; + ib_net16_t mlid; + osm_mtree_node_t *p_root; + cl_qmap_t mcm_port_tbl; + ib_member_rec_t mcmember_rec; + boolean_t well_known; + boolean_t to_be_deleted; + uint32_t last_change_id; + uint32_t last_tree_id; +} osm_mgrp_t; +/* +* FIELDS +* map_item +* Map Item for qmap linkage. Must be first element!! +* +* mlid +* The network ordered LID of this Multicast Group (must be +* >= 0xC000). +* +* p_root +* Pointer to the root "tree node" in the single spanning tree +* for this multicast group. The nodes of the tree represent +* switches. Member ports are not represented in the tree. +* +* mcm_port_tbl +* Table (sorted by port GUID) of osm_mcm_port_t objects +* representing the member ports of this multicast group. +* +* mcmember_rec +* Hold the parameters of the Multicast Group. +* +* well_known +* Indicates that this is the wellknow multicast group which +* is created during the initialization of SM/SA and will be +* present even if there are no ports for this group +* +* to_be_deleted +* Since groups are deleted only after re-route we need to +* track the fact the group is about to be deleted so we can +* track the fact a new join is actually a create request. +* +* last_change_id +* a counter for the number of changes applied to the group. +* This counter shuold be incremented on any modification +* to the group: joining or leaving of ports. +* +* last_tree_id +* the last change id used for building the current tree. +* +* SEE ALSO +*********/ + +/****f* OpenSM: Vendor API/osm_mgrp_func_t +* NAME +* osm_mgrp_func_t +* +* DESCRIPTION +* Callback for the osm_mgrp_apply_func function. +* The callback function must not modify the tree linkage. +* +* SYNOPSIS +*/ +typedef void (*osm_mgrp_func_t)( + IN const osm_mgrp_t* const p_mgrp, + IN const osm_mtree_node_t* const p_mtn, + IN void* context ); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to the multicast group object. +* +* p_mtn +* [in] Pointer to the multicast tree node. +* +* context +* [in] User context. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_construct +* NAME +* osm_mgrp_construct +* +* DESCRIPTION +* This function constructs a Multicast Group. +* +* SYNOPSIS +*/ +void +osm_mgrp_construct( + IN osm_mgrp_t* const p_mgrp ); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to a Multicast Group to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_mgrp_init, osm_mgrp_destroy. +* +* Calling osm_mgrp_construct is a prerequisite to calling any other +* method except osm_mgrp_init. +* +* SEE ALSO +* Multicast Group, osm_mgrp_init, osm_mgrp_destroy +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_destroy +* NAME +* osm_mgrp_destroy +* +* DESCRIPTION +* The osm_mgrp_destroy function destroys a Multicast Group, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_mgrp_destroy( + IN osm_mgrp_t* const p_mgrp ); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to a Muticast Group to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Multicast Group. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_mgrp_construct or +* osm_mgrp_init. +* +* SEE ALSO +* Multicast Group, osm_mgrp_construct, osm_mgrp_init +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_init +* NAME +* osm_mgrp_init +* +* DESCRIPTION +* The osm_mgrp_init function initializes a Multicast Group for use. +* +* SYNOPSIS +*/ +void +osm_mgrp_init( + IN osm_mgrp_t* const p_mgrp, + IN const ib_net16_t mlid ); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object to initialize. +* +* mlid +* [in] Multicast LID for this multicast group. +* +* RETURN VALUES +* None. +* +* NOTES +* Allows calling other Multicast Group methods. +* +* SEE ALSO +* Multicast Group, osm_mgrp_construct, osm_mgrp_destroy, +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_new +* NAME +* osm_mgrp_new +* +* DESCRIPTION +* Allocates and initializes a Multicast Group for use. +* +* SYNOPSIS +*/ +osm_mgrp_t* +osm_mgrp_new( + IN const ib_net16_t mlid ); +/* +* PARAMETERS +* mlid +* [in] Multicast LID for this multicast group. +* +* RETURN VALUES +* IB_SUCCESS if initialization was successful. +* +* NOTES +* Allows calling other Multicast Group methods. +* +* SEE ALSO +* Multicast Group, osm_mgrp_construct, osm_mgrp_destroy, +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_delete +* NAME +* osm_mgrp_delete +* +* DESCRIPTION +* Destroys and de-allocates a Multicast Group. +* +* SYNOPSIS +*/ +void +osm_mgrp_delete( + IN osm_mgrp_t* const p_mgrp ); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Multicast Group, osm_mgrp_construct, osm_mgrp_destroy, +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_is_guid +* NAME +* osm_mgrp_is_guid +* +* DESCRIPTION +* Indicates if the specified port GUID is a member of the Multicast Group. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_mgrp_is_guid( + IN const osm_mgrp_t* const p_mgrp, + IN const ib_net64_t port_guid ) +{ + return( cl_qmap_get( &p_mgrp->mcm_port_tbl, port_guid ) != + cl_qmap_end( &p_mgrp->mcm_port_tbl ) ); +} +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* port_guid +* [in] Port GUID. +* +* RETURN VALUES +* TRUE if the port GUID is a member of the group, +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Multicast Group +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_is_empty +* NAME +* osm_mgrp_is_empty +* +* DESCRIPTION +* Indicates if the multicast group has any member ports. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_mgrp_is_empty( + IN const osm_mgrp_t* const p_mgrp ) +{ + return( cl_qmap_count( &p_mgrp->mcm_port_tbl ) == 0 ); +} +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* RETURN VALUES +* TRUE if there are no ports in the multicast group. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Multicast Group +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_get_mlid +* NAME +* osm_mgrp_get_mlid +* +* DESCRIPTION +* The osm_mgrp_get_mlid function returns the multicast LID of this group. +* +* SYNOPSIS +*/ +static inline ib_net16_t +osm_mgrp_get_mlid( + IN const osm_mgrp_t* const p_mgrp ) +{ + return( p_mgrp->mlid ); +} +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* RETURN VALUES +* MLID of the Multicast Group. +* +* NOTES +* +* SEE ALSO +* Multicast Group +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_add_port +* NAME +* osm_mgrp_add_port +* +* DESCRIPTION +* Adds a port to the multicast group. +* +* SYNOPSIS +*/ +osm_mcm_port_t* +osm_mgrp_add_port( + IN osm_mgrp_t* const p_mgrp, + IN const ib_gid_t* const p_port_gid, + IN const uint8_t join_state, + IN boolean_t proxy_join); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object to initialize. +* +* p_port_gid +* [in] Pointer to the GID of the port to add to the multicast group. +* +* join_state +* [in] The join state for this port in the group. +* +* RETURN VALUES +* IB_SUCCESS +* IB_INSUFFICIENT_MEMORY +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_is_port_present +* NAME +* osm_mgrp_is_port_present +* +* DESCRIPTION +* checks a port from the multicast group. +* +* SYNOPSIS +*/ + +boolean_t +osm_mgrp_is_port_present( + IN const osm_mgrp_t* const p_mgrp, + IN const ib_net64_t port_guid, + OUT osm_mcm_port_t ** const pp_mcm_port); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* port_guid +* [in] Port guid of the departing port. +* +* pp_mcm_port +* [out] Pointer to a pointer to osm_mcm_port_t +* Updated to the member on success or NULLed +* +* RETURN VALUES +* TRUE if port present +* FALSE if port is not present. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_remove_port +* NAME +* osm_mgrp_remove_port +* +* DESCRIPTION +* Removes a port from the multicast group. +* +* SYNOPSIS +*/ +void +osm_mgrp_remove_port( + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_mgrp_t* const p_mgrp, + IN const ib_net64_t port_guid ); +/* +* PARAMETERS +* +* p_subn +* [in] Pointer to the subnet object +* +* p_log +* [in] The log object pointer +* +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* port_guid +* [in] Port guid of the departing port. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_get_root_switch +* NAME +* osm_mgrp_get_root_switch +* +* DESCRIPTION +* Returns the "root" switch of this multicast group. The root switch +* is at the trunk of the multicast single spanning tree. +* +* SYNOPSIS +*/ +static inline osm_switch_t* +osm_mgrp_get_root_switch( + IN const osm_mgrp_t* const p_mgrp ) +{ + if( p_mgrp->p_root ) + return( p_mgrp->p_root->p_sw ); + else + return( NULL ); +} +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* RETURN VALUES +* Returns the "root" switch of this multicast group. The root switch +* is at the trunk of the multicast single spanning tree. +* +* NOTES +* +* SEE ALSO +* Multicast Group +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_compute_avg_hops +* NAME +* osm_mgrp_compute_avg_hops +* +* DESCRIPTION +* Returns the average number of hops from the given to switch +* to all member of a multicast group. +* +* SYNOPSIS +*/ +float +osm_mgrp_compute_avg_hops( + const osm_mgrp_t* const p_mgrp, + const osm_switch_t* const p_sw ); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* p_sw +* [in] Pointer to the switch from which to measure. +* +* RETURN VALUES +* Returns the average number of hops from the given to switch +* to all member of a multicast group. +* +* NOTES +* +* SEE ALSO +* Multicast Group +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_apply_func +* NAME +* osm_mgrp_apply_func +* +* DESCRIPTION +* Calls the specified function for each element in the tree. +* Elements are passed to the callback function in no particular order. +* +* SYNOPSIS +*/ +void +osm_mgrp_apply_func( + const osm_mgrp_t* const p_mgrp, + osm_mgrp_func_t p_func, + void* context ); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* p_func +* [in] Pointer to the users callback function. +* +* context +* [in] User context passed to the callback function. +* +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Multicast Group +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_send_delete_notice +* NAME +* osm_mgrp_send_delete_notice +* +* DESCRIPTION +* Sends a notice that the given multicast group is now deleted. +* +* SYNOPSIS +*/ +void +osm_mgrp_send_delete_notice( + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_mgrp_t *p_mgrp ); +/* +* PARAMETERS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_log +* Pointer to the log object. +* +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Multicast Group +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_send_create_notice +* NAME +* osm_mgrp_send_create_notice +* +* DESCRIPTION +* Sends a notice that the given multicast group is now created. +* +* SYNOPSIS +*/ +void +osm_mgrp_send_create_notice( + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_mgrp_t *p_mgrp ); +/* +* PARAMETERS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_log +* Pointer to the log object. +* +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Multicast Group +*********/ + +END_C_DECLS + +#endif /* _OSM_MULTICAST_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node.h new file mode 100644 index 00000000..db249543 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node.h @@ -0,0 +1,957 @@ +/* + * 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: + * Declaration of osm_node_t. + * This object represents an IBA node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#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; + 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. +* +* 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_destroy +* NAME +* osm_node_destroy +* +* DESCRIPTION +* The osm_node_destroy function destroys a node, releasing +* all resources. +* +* SYNOPSIS +*/void +osm_node_destroy( + IN osm_node_t *p_node ); +/* +* PARAMETERS +* p_node +* [in] Pointer a Node object to destroy. +* +* 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_delete +* NAME +* osm_node_delete +* +* DESCRIPTION +* The osm_node_delete function destroys a node, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_node_delete( + IN OUT osm_node_t** const p_node ); +/* +* PARAMETERS +* p_node +* [in][out] Pointer to a Pointer a Node object to destroy. +* On return, the pointer to set to NULL. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Node object. +* This function should only be called after a call to osm_node_new. +* +* SEE ALSO +* Node object, osm_node_new +*********/ + +/****f* OpenSM: Node/osm_node_new +* NAME +* osm_node_new +* +* DESCRIPTION +* The osm_node_new function initializes a Node object for use. +* +* SYNOPSIS +*/ +osm_node_t* +osm_node_new( + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_madw +* [in] Pointer to a osm_madw_t object containing a mad with +* the node's NodeInfo attribute. The caller may discard the +* osm_madw_t structure after calling osm_node_new. +* +* RETURN VALUES +* On success, a pointer to the new initialized osm_node_t structure. +* NULL otherwise. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_is_lid +* NAME +* osm_node_is_lid +* +* DESCRIPTION +* Indicates if the specified LID belongs to this node. +* +* SYNOPSIS +*/ +boolean_t osm_node_is_lid( + IN const osm_node_t* const p_node, + IN const uint16_t lid ); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* lid +* [in] LID value. +* +* RETURN VALUES +* TRUE if the specified LID belongs to the node, +* FALSE 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 const osm_node_t* const p_node, + IN const uint32_t port_num ) +{ + + CL_ASSERT( port_num < p_node->physp_tbl_size ); + return( (osm_physp_t*)&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_any_physp_ptr +* NAME +* osm_node_get_any_physp_ptr +* +* DESCRIPTION +* Returns a pointer to any valid physical port object associated +* with this node. This operation is mostly meaningful for switches, +* in which case all the Physical Ports share the same GUID. +* +* SYNOPSIS +*/ +static inline osm_physp_t* +osm_node_get_any_physp_ptr( + IN const osm_node_t* const p_node ) +{ + CL_ASSERT( p_node ); + return( (osm_physp_t*)&p_node->physp_table[ + ib_node_info_get_local_port_num( &p_node->node_info )] ); +} +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* RETURN VALUES +* Returns a pointer to any valid physical port object associated +* with this node. This operation is mostly meaningful for switches, +* in which case all the Physical Ports share the same GUID. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_any_path +* NAME +* osm_node_get_any_path +* +* DESCRIPTION +* Returns a pointer to the physical port object at the +* specified local port number. +* +* SYNOPSIS +*/ +static inline osm_dr_path_t* +osm_node_get_any_dr_path_ptr( + IN const osm_node_t* const p_node ) +{ + CL_ASSERT( p_node ); + return( osm_physp_get_dr_path_ptr( &p_node->physp_table[ + ib_node_info_get_local_port_num( &p_node->node_info )] ) ); +} +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Local port number. +* +* RETURN VALUES +* Returns a pointer to the physical port object at the +* specified local port number. +* A return value of zero means the port number was out of range. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_type +* NAME +* osm_node_get_type +* +* DESCRIPTION +* Returns the type of this node. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_node_get_type( + IN const osm_node_t* const p_node ) +{ + return( p_node->node_info.node_type ); +} +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* RETURN VALUES +* Returns the IBA defined type of this node. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_num_physp +* NAME +* osm_node_get_num_physp +* +* DESCRIPTION +* Returns the type of this node. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_node_get_num_physp( + IN const osm_node_t* const p_node ) +{ + return( (uint8_t)p_node->physp_tbl_size ); +} +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* RETURN VALUES +* Returns the IBA defined type of this node. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_remote_node +* NAME +* osm_node_get_remote_node +* +* DESCRIPTION +* Returns a pointer to the node on the other end of the +* specified port. +* Returns NULL if no remote node exists. +* +* SYNOPSIS +*/ +osm_node_t* +osm_node_get_remote_node( + IN const osm_node_t* const p_node, + IN const uint8_t port_num, + OUT uint8_t *p_remote_port_num ); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Port number in p_node through which to get the remote node. +* +* p_remote_port_num +* [out] Port number in the remote's node through which this +* link exists. The caller may specify NULL for this pointer +* if the port number isn't needed. +* +* RETURN VALUES +* Returns a pointer to the node on the other end of the +* specified port. +* Returns NULL if no remote node exists. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_base_lid +* NAME +* osm_node_get_base_lid +* +* DESCRIPTION +* Returns the LID value of the specified port on this node. +* +* SYNOPSIS +*/ +static inline ib_net16_t +osm_node_get_base_lid( + IN const osm_node_t* const p_node, + IN const uint32_t port_num ) +{ + CL_ASSERT( port_num < p_node->physp_tbl_size ); + return( osm_physp_get_base_lid( &p_node->physp_table[port_num] ) ); +} +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Local port number. +* +* RETURN VALUES +* Returns a pointer to the physical port object at the +* specified local port number. +* A return value of zero means the port number was out of range. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_remote_base_lid +* NAME +* osm_node_get_remote_base_lid +* +* DESCRIPTION +* Returns the base LID value of the port on the other side +* of the wire from the specified port on this node. +* +* SYNOPSIS +*/ +ib_net16_t +osm_node_get_remote_base_lid( + IN const osm_node_t* const p_node, + IN const uint32_t port_num ); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Local port number. +* +* RETURN VALUES +* Returns a pointer to the physical port object at the +* specified local port number. +* A return value of zero means the port number was out of range. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_remote_type +* NAME +* osm_node_get_remote_type +* +* DESCRIPTION +* Returns the type of the node on the other side +* of the wire from the specified port on this node. +* The remote node must exist. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_node_get_remote_type( + IN const osm_node_t* const p_node, + IN const uint8_t port_num ) +{ + osm_node_t *p_remote_node; + + p_remote_node = osm_node_get_remote_node( p_node, port_num, NULL ); + CL_ASSERT( p_remote_node ); + return( osm_node_get_type( p_remote_node ) ); +} +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Local port number. +* +* RETURN VALUES +* Returns the type of the node on the other side +* of the wire from the specified port on this node. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_lmc +* NAME +* osm_node_get_lmc +* +* DESCRIPTION +* Returns the LMC value of the specified port on this node. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_node_get_lmc( + IN const osm_node_t* const p_node, + IN const uint32_t port_num ) +{ + CL_ASSERT( port_num < p_node->physp_tbl_size ); + return( osm_physp_get_lmc( &p_node->physp_table[port_num] ) ); +} +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Local port number. +* +* RETURN VALUES +* Returns the LMC value of the specified port on this node. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_init_physp +* NAME +* osm_node_init_physp +* +* DESCRIPTION +* Initializes a physical port for the given node. +* +* SYNOPSIS +*/ +void +osm_node_init_physp( + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* p_madw +* [in] Pointer to a osm_madw_t object containing a mad with +* the node's NodeInfo attribute as discovered through the +* Physical Port to add to the node. The caller may discard the +* osm_madw_t structure after calling osm_node_new. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Node object, Physical Port object. +*********/ + +/****f* OpenSM: Node/osm_node_discovery_count_get +* NAME +* osm_node_discovery_count_get +* +* DESCRIPTION +* Returns a pointer to the physical port object at the +* specified local port number. +* +* SYNOPSIS +*/ +static inline uint32_t +osm_node_discovery_count_get( + IN const osm_node_t* const p_node ) +{ + return( p_node->discovery_count ); +} +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* RETURN VALUES +* Returns the discovery count for this node. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_discovery_count_reset +* NAME +* osm_node_discovery_count_reset +* +* DESCRIPTION +* Resets the discovery count for this node to zero. +* This operation should be performed at the start of a sweep. +* +* SYNOPSIS +*/ +static inline void +osm_node_discovery_count_reset( + IN osm_node_t* const p_node ) +{ + p_node->discovery_count = 0; +} +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_discovery_count_inc +* NAME +* osm_node_discovery_count_inc +* +* DESCRIPTION +* Increments the discovery count for this node. +* +* SYNOPSIS +*/ +static inline void +osm_node_discovery_count_inc( + IN osm_node_t* const p_node ) +{ + p_node->discovery_count++; +} +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_node_guid +* NAME +* osm_node_get_node_guid +* +* DESCRIPTION +* Returns the node GUID of this node. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_node_get_node_guid( + IN const osm_node_t* const p_node ) +{ + return( p_node->node_info.node_guid ); +} +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* RETURN VALUES +* Returns the node GUID of this node. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_link +* NAME +* osm_node_link +* +* DESCRIPTION +* Logically connects a node to another node through the specified port. +* +* SYNOPSIS +*/ +void +osm_node_link( + IN osm_node_t* const p_node, + IN const uint8_t port_num, + IN osm_node_t* const p_remote_node, + IN const uint8_t remote_port_num ); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Port number in p_node through which to create the link. +* +* p_remote_node +* [in] Pointer to the remote port object. +* +* remote_port_num +* [in] Port number in the remote's node through which to +* create this link. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_unlink +* NAME +* osm_node_unlink +* +* DESCRIPTION +* Logically disconnects a node from another node through +* the specified port. +* +* SYNOPSIS +*/ +void +osm_node_unlink( + IN osm_node_t* const p_node, + IN const uint8_t port_num, + IN osm_node_t* const p_remote_node, + IN const uint8_t remote_port_num ); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Port number in p_node through which to unlink. +* +* p_remote_node +* [in] Pointer to the remote port object. +* +* remote_port_num +* [in] Port number in the remote's node through which to unlink. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_link_exists +* NAME +* osm_node_link_exists +* +* DESCRIPTION +* Return TRUE if a link exists between the specified nodes on +* the specified ports. +* Returns FALSE otherwise. +* +* SYNOPSIS +*/ +boolean_t +osm_node_link_exists( + IN osm_node_t* const p_node, + IN const uint8_t port_num, + IN osm_node_t* const p_remote_node, + IN const uint8_t remote_port_num ); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Port number in p_node through which to check the link. +* +* p_remote_node +* [in] Pointer to the remote port object. +* +* remote_port_num +* [in] Port number in the remote's node through which to +* check this link. +* +* RETURN VALUES +* Return TRUE if a link exists between the specified nodes on +* the specified ports. +* Returns FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_has_any_link +* NAME +* osm_node_has_any_link +* +* DESCRIPTION +* Return TRUE if a any link exists from the specified nodes on +* the specified port. +* Returns FALSE otherwise. +* +* SYNOPSIS +*/ +boolean_t +osm_node_has_any_link( + IN osm_node_t* const p_node, + IN const uint8_t port_num ); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Port number in p_node through which to check the link. +* +* RETURN VALUES +* Return TRUE if a any link exists from the specified nodes on +* the specified port. +* Returns FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_link_has_valid_ports +* NAME +* osm_node_link_has_valid_ports +* +* DESCRIPTION +* Return TRUE if both ports in the link are valid (initialized). +* Returns FALSE otherwise. +* +* SYNOPSIS +*/ +boolean_t +osm_node_link_has_valid_ports( + IN osm_node_t* const p_node, + IN const uint8_t port_num, + IN osm_node_t* const p_remote_node, + IN const uint8_t remote_port_num ); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Port number in p_node through which to check the link. +* +* RETURN VALUES +* Return TRUE if both ports in the link are valid (initialized). +* Returns FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +END_C_DECLS + +#endif /* _OSM_NODE_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_desc_rcv.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_desc_rcv.h new file mode 100644 index 00000000..6e48cd27 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_desc_rcv.h @@ -0,0 +1,256 @@ +/* + * 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: + * Declaration of osm_nd_rcv_t. + * This object represents the NodeInfo Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_ND_RCV_H_ +#define _OSM_ND_RCV_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/Node Description Receiver +* NAME +* Node Description Receiver +* +* DESCRIPTION +* The Node Description Receiver object encapsulates the information +* needed to receive the NodeInfo attribute from a node. +* +* The Node Description Receiver 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: Node Description Receiver/osm_nd_rcv_t +* NAME +* osm_nd_rcv_t +* +* DESCRIPTION +* Node Description Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_nd_rcv +{ + osm_subn_t *p_subn; + osm_log_t *p_log; + cl_plock_t *p_lock; + +} osm_nd_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* Node Description Receiver object +*********/ + +/****f* OpenSM: Node Description Receiver/osm_nd_rcv_construct +* NAME +* osm_nd_rcv_construct +* +* DESCRIPTION +* This function constructs a Node Description Receiver object. +* +* SYNOPSIS +*/ +void osm_nd_rcv_construct( + IN osm_nd_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a Node Description Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_nd_rcv_init, osm_nd_rcv_destroy +* +* Calling osm_nd_rcv_construct is a prerequisite to calling any other +* method except osm_nd_rcv_init. +* +* SEE ALSO +* Node Description Receiver object, osm_nd_rcv_init, +* osm_nd_rcv_destroy +*********/ + +/****f* OpenSM: Node Description Receiver/osm_nd_rcv_destroy +* NAME +* osm_nd_rcv_destroy +* +* DESCRIPTION +* The osm_nd_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_nd_rcv_destroy( + IN osm_nd_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Node Description Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_nd_rcv_construct or osm_nd_rcv_init. +* +* SEE ALSO +* Node Description Receiver object, osm_nd_rcv_construct, +* osm_nd_rcv_init +*********/ + +/****f* OpenSM: Node Description Receiver/osm_nd_rcv_init +* NAME +* osm_nd_rcv_init +* +* DESCRIPTION +* The osm_nd_rcv_init function initializes a +* Node Description Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_nd_rcv_init( + IN osm_nd_rcv_t* const p_rcv, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_nd_rcv_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the Node Description Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other Node Description Receiver methods. +* +* SEE ALSO +* Node Description Receiver object, osm_nd_rcv_construct, +* osm_nd_rcv_destroy +*********/ + +/****f* OpenSM: Node Description Receiver/osm_nd_rcv_process +* NAME +* osm_nd_rcv_process +* +* DESCRIPTION +* Process the NodeInfo attribute. +* +* SYNOPSIS +*/ +void osm_nd_rcv_process( + IN const osm_nd_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_nd_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's NodeInfo attribute. +* +* RETURN VALUES +* CL_SUCCESS if the NodeInfo processing was successful. +* +* NOTES +* This function processes a NodeInfo attribute. +* +* SEE ALSO +* Node Description Receiver, Node Description Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_ND_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_desc_rcv_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_desc_rcv_ctrl.h new file mode 100644 index 00000000..d838a60c --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_desc_rcv_ctrl.h @@ -0,0 +1,232 @@ +/* + * 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: + * Declaration of osm_nd_rcv_ctrl_t. + * This object represents a controller that receives the IBA NodeDescription + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_ND_RCV_CTRL_H_ +#define _OSM_ND_RCV_CTRL_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/Node Description Receive Controller +* NAME +* Node Description Receive Controller +* +* DESCRIPTION +* The Node Description Receive Controller object encapsulates the information +* needed to receive the NodeDescription attribute from a node. +* +* The Node Description Receive 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: Node Description Receive Controller/osm_nd_rcv_ctrl_t +* NAME +* osm_nd_rcv_ctrl_t +* +* DESCRIPTION +* Node Description Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_nd_rcv_ctrl +{ + osm_nd_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_nd_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the Node Description Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Node Description Receive Controller object +*********/ + +/****f* OpenSM: Node Description Receive Controller/osm_nd_rcv_ctrl_construct +* NAME +* osm_nd_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Node Description Receive Controller object. +* +* SYNOPSIS +*/ +void +osm_nd_rcv_ctrl_construct( + IN osm_nd_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Node Description Receive Controller object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_nd_rcv_ctrl_init, osm_nd_rcv_ctrl_destroy +* +* Calling osm_nd_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_nd_rcv_ctrl_init. +* +* SEE ALSO +* Node Description Receive Controller object, osm_nd_rcv_ctrl_init, +* osm_nd_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: Node Description Receive Controller/osm_nd_rcv_ctrl_destroy +* NAME +* osm_nd_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_nd_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_nd_rcv_ctrl_destroy( + IN osm_nd_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Node Description Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_nd_rcv_ctrl_construct or osm_nd_rcv_ctrl_init. +* +* SEE ALSO +* Node Description Receive Controller object, osm_nd_rcv_ctrl_construct, +* osm_nd_rcv_ctrl_init +*********/ + +/****f* OpenSM: Node Description Receive Controller/osm_nd_rcv_ctrl_init +* NAME +* osm_nd_rcv_ctrl_init +* +* DESCRIPTION +* The osm_nd_rcv_ctrl_init function initializes a +* Node Description Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_nd_rcv_ctrl_init( + IN osm_nd_rcv_ctrl_t* const p_ctrl, + IN osm_nd_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_nd_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_nd_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Node Description Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Node Description Receive Controller methods. +* +* SEE ALSO +* Node Description Receive Controller object, osm_nd_rcv_ctrl_construct, +* osm_nd_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* OSM_ND_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_info_rcv.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_info_rcv.h new file mode 100644 index 00000000..ca202fd9 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_info_rcv.h @@ -0,0 +1,305 @@ +/* + * 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: + * Declaration of osm_ni_rcv_t. + * This object represents the NodeInfo Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_NI_RCV_H_ +#define _OSM_NI_RCV_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/Node Info Receiver +* NAME +* Node Info Receiver +* +* DESCRIPTION +* The Node Info Receiver object encapsulates the information +* needed to receive the NodeInfo attribute from a node. +* +* The Node Info Receiver 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: Node Info Receiver/osm_ni_rcv_t +* NAME +* osm_ni_rcv_t +* +* DESCRIPTION +* Node Info Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_ni_rcv +{ + osm_subn_t *p_subn; + osm_req_t *p_gen_req; + osm_log_t *p_log; + osm_state_mgr_t *p_state_mgr; + cl_plock_t *p_lock; + +} osm_ni_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_gen_req_ctrl +* Pointer to the generic request controller. +* +* p_log +* Pointer to the log object. +* +* p_state_mgr +* Pointer to the State Manager object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* Node Info Receiver object +*********/ + +/****f* OpenSM: Node Info Receiver/osm_ni_rcv_construct +* NAME +* osm_ni_rcv_construct +* +* DESCRIPTION +* This function constructs a Node Info Receiver object. +* +* SYNOPSIS +*/ +void osm_ni_rcv_construct( + IN osm_ni_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Node Info Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_ni_rcv_init, osm_ni_rcv_destroy, +* and osm_ni_rcv_is_inited. +* +* Calling osm_ni_rcv_construct is a prerequisite to calling any other +* method except osm_ni_rcv_init. +* +* SEE ALSO +* Node Info Receiver object, osm_ni_rcv_init, +* osm_ni_rcv_destroy, osm_ni_rcv_is_inited +*********/ + +/****f* OpenSM: Node Info Receiver/osm_ni_rcv_destroy +* NAME +* osm_ni_rcv_destroy +* +* DESCRIPTION +* The osm_ni_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_ni_rcv_destroy( + IN osm_ni_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Node Info Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_ni_rcv_construct or osm_ni_rcv_init. +* +* SEE ALSO +* Node Info Receiver object, osm_ni_rcv_construct, +* osm_ni_rcv_init +*********/ + +/****f* OpenSM: Node Info Receiver/osm_ni_rcv_init +* NAME +* osm_ni_rcv_init +* +* DESCRIPTION +* The osm_ni_rcv_init function initializes a +* Node Info Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_ni_rcv_init( + IN osm_ni_rcv_t* const p_ctrl, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_state_mgr_t* const p_state_mgr, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_ni_rcv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_state_mgr +* [in] Pointer to the State Manager object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the Node Info Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other Node Info Receiver methods. +* +* SEE ALSO +* Node Info Receiver object, osm_ni_rcv_construct, +* osm_ni_rcv_destroy, osm_ni_rcv_is_inited +*********/ + +/****f* OpenSM: Node Info Receiver/osm_ni_rcv_is_inited +* NAME +* osm_ni_rcv_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_ni_rcv_init. +* +* SYNOPSIS +*/ +boolean_t osm_ni_rcv_is_inited( + IN const osm_ni_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_ni_rcv_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_ni_rcv_construct or osm_ni_rcv_init must be +* called before using this function. +* +* SEE ALSO +* Node Info Receiver object, osm_ni_rcv_construct, +* osm_ni_rcv_init +*********/ + +/****f* OpenSM: Node Info Receiver/osm_ni_rcv_process +* NAME +* osm_ni_rcv_process +* +* DESCRIPTION +* Process the NodeInfo attribute. +* +* SYNOPSIS +*/ +void osm_ni_rcv_process( + IN const osm_ni_rcv_t* const p_ctrl, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_ni_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's NodeInfo attribute. +* +* RETURN VALUES +* CL_SUCCESS if the NodeInfo processing was successful. +* +* NOTES +* This function processes a NodeInfo attribute. +* +* SEE ALSO +* Node Info Receiver, Node Info Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_NI_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_info_rcv_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_info_rcv_ctrl.h new file mode 100644 index 00000000..72b1f671 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_node_info_rcv_ctrl.h @@ -0,0 +1,261 @@ +/* + * 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: + * Declaration of osm_ni_rcv_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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_NI_RCV_CTRL_H_ +#define _OSM_NI_RCV_CTRL_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/Node Info Receive Controller +* NAME +* Node Info Receive Controller +* +* DESCRIPTION +* The Node Info Receive Controller object encapsulates +* the information needed to receive the NodeInfo attribute from a node. +* +* The Node Info Receive 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: Node Info Receive Controller/osm_ni_rcv_ctrl_t +* NAME +* osm_ni_rcv_ctrl_t +* +* DESCRIPTION +* Node Info Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_ni_rcv_ctrl +{ + osm_ni_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_ni_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the Node Info Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Node Info Receive Controller object +* Node Info Receiver object +*********/ + +/****f* OpenSM: Node Info Receive Controller/osm_ni_rcv_ctrl_construct +* NAME +* osm_ni_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Node Info Receive Controller object. +* +* SYNOPSIS +*/ +void osm_ni_rcv_ctrl_construct( + IN osm_ni_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Node Info Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_ni_rcv_ctrl_init, osm_ni_rcv_ctrl_destroy, +* and osm_ni_rcv_ctrl_is_inited. +* +* Calling osm_ni_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_ni_rcv_ctrl_init. +* +* SEE ALSO +* Node Info Receive Controller object, osm_ni_rcv_ctrl_init, +* osm_ni_rcv_ctrl_destroy, osm_ni_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Node Info Receive Controller/osm_ni_rcv_ctrl_destroy +* NAME +* osm_ni_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_ni_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_ni_rcv_ctrl_destroy( + IN osm_ni_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Node Info Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_ni_rcv_ctrl_construct or osm_ni_rcv_ctrl_init. +* +* SEE ALSO +* Node Info Receive Controller object, osm_ni_rcv_ctrl_construct, +* osm_ni_rcv_ctrl_init +*********/ + +/****f* OpenSM: Node Info Receive Controller/osm_ni_rcv_ctrl_init +* NAME +* osm_ni_rcv_ctrl_init +* +* DESCRIPTION +* The osm_ni_rcv_ctrl_init function initializes a +* Node Info Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_ni_rcv_ctrl_init( + IN osm_ni_rcv_ctrl_t* const p_ctrl, + IN osm_ni_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_ni_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_ni_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Node Info Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Node Info Receive Controller methods. +* +* SEE ALSO +* Node Info Receive Controller object, osm_ni_rcv_ctrl_construct, +* osm_ni_rcv_ctrl_destroy, osm_ni_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Node Info Receive Controller/osm_ni_rcv_ctrl_is_inited +* NAME +* osm_ni_rcv_ctrl_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_ni_rcv_ctrl_init. +* +* SYNOPSIS +*/ +boolean_t osm_ni_rcv_ctrl_is_inited( + IN const osm_ni_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_ni_rcv_ctrl_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_ni_rcv_ctrl_construct or osm_ni_rcv_ctrl_init must be +* called before using this function. +* +* SEE ALSO +* Node Info Receive Controller object, osm_ni_rcv_ctrl_construct, +* osm_ni_rcv_ctrl_init +*********/ + +END_C_DECLS + +#endif /* _OSM_NI_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_opensm.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_opensm.h new file mode 100644 index 00000000..9f20488a --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_opensm.h @@ -0,0 +1,440 @@ +/* + * 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: + * Declaration of osm_opensm_t. + * This object represents the OpenSM super object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +#ifndef _OSM_OPENSM_H_ +#define _OSM_OPENSM_H_ + +#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 +* +*********/ + +/****s* OpenSM: OpenSM/osm_routing_engine +* NAME +* struct osm_routing_engine +* +* DESCRIPTION +* OpenSM routing engine module definition. +* NOTES +* routing engine structure - yet limited by ucast_fdb_assign and +* ucast_build_fwd_tables (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); +}; +/* +* 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. +*/ + +/****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_t +{ + osm_subn_t subn; + osm_sm_t sm; + osm_sa_t sa; + 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; + osm_stats_t stats; +} osm_opensm_t; +/* +* FIELDS +* 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 +* Routing engine; will be initialized then used. +* +* stats +* Open SM statistics block +* +* SEE ALSO +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_construct +* NAME +* osm_opensm_construct +* +* DESCRIPTION +* This function constructs an OpenSM object. +* +* SYNOPSIS +*/ +void osm_opensm_construct( + IN osm_opensm_t* const p_osm ); +/* +* PARAMETERS +* p_osm +* [in] Pointer to a OpenSM object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_opensm_init, osm_opensm_destroy +* +* Calling osm_opensm_construct is a prerequisite to calling any other +* method except osm_opensm_init. +* +* SEE ALSO +* SM object, osm_opensm_init, osm_opensm_destroy +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_destroy +* NAME +* osm_opensm_destroy +* +* DESCRIPTION +* The osm_opensm_destroy function destroys an SM, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_opensm_destroy( + IN osm_opensm_t* const p_osm ); +/* +* PARAMETERS +* p_osm +* [in] Pointer to a OpenSM object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified OpenSM object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_opensm_construct or +* osm_opensm_init. +* +* SEE ALSO +* SM object, osm_opensm_construct, osm_opensm_init +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_init +* NAME +* osm_opensm_init +* +* DESCRIPTION +* The osm_opensm_init function initializes a OpenSM object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_opensm_init( + IN osm_opensm_t* const p_osm, + IN const osm_subn_opt_t* const p_opt ); +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object to initialize. +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* RETURN VALUES +* IB_SUCCESS if the OpenSM object was initialized successfully. +* +* NOTES +* Allows calling other OpenSM methods. +* +* SEE ALSO +* SM object, osm_opensm_construct, osm_opensm_destroy +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_sweep +* NAME +* osm_opensm_sweep +* +* DESCRIPTION +* Initiates a subnet sweep. +* +* SYNOPSIS +*/ +static inline void +osm_opensm_sweep( + IN osm_opensm_t* const p_osm ) +{ + osm_sm_sweep( &p_osm->sm ); +} +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object on which to +* initiate a sweep. +* +* RETURN VALUES +* None +* +* NOTES +* If the OpenSM object is not bound to a port, this function +* does nothing. +* +* SEE ALSO +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_set_log_flags +* NAME +* osm_opensm_set_log_flags +* +* DESCRIPTION +* Sets the log level. +* +* SYNOPSIS +*/ +static inline void +osm_opensm_set_log_flags( + IN osm_opensm_t* const p_osm, + IN const osm_log_level_t log_flags ) +{ + osm_log_set_level( &p_osm->log, log_flags ); +} +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object. +* +* log_flags +* [in] Log level flags to set. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_bind +* NAME +* osm_opensm_bind +* +* DESCRIPTION +* Binds the opensm object to a port guid. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_opensm_bind( + IN osm_opensm_t* const p_osm, + IN const ib_net64_t guid ); +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object to bind. +* +* guid +* [in] Local port GUID with which to bind. +* +* RETURN VALUES +* None +* +* NOTES +* A given opensm object can only be bound to one port at a time. +* +* SEE ALSO +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_wait_for_subnet_up +* NAME +* osm_opensm_wait_for_subnet_up +* +* DESCRIPTION +* Blocks the calling thread until the subnet is up. +* +* SYNOPSIS +*/ +static inline cl_status_t +osm_opensm_wait_for_subnet_up( + IN osm_opensm_t* const p_osm, + IN uint32_t const wait_us, + IN boolean_t const interruptible ) +{ + return( osm_sm_wait_for_subnet_up( &p_osm->sm, wait_us, interruptible ) ); +} +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object. +* +* wait_us +* [in] Number of microseconds to wait. +* +* interruptible +* [in] Indicates whether the wait operation can be interrupted +* by external signals. +* +* RETURN VALUES +* CL_SUCCESS if the wait operation succeeded in response to the event +* being set. +* +* CL_TIMEOUT if the specified time period elapses. +* +* CL_NOT_DONE if the wait was interrupted by an external signal. +* +* CL_ERROR if the wait operation failed. +* +* NOTES +* +* SEE ALSO +*********/ + +/****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-1/ulp/opensm/user/include/opensm/osm_partition.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_partition.h new file mode 100644 index 00000000..0076a349 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_partition.h @@ -0,0 +1,256 @@ +/* + * 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: + * Declaration of osm_prtn_t. + * This object represents an IBA Partition. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_PARTITION_H_ +#define _OSM_PARTITION_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +/****h* OpenSM/Partition +* NAME +* Partition +* +* DESCRIPTION +* The Partition object encapsulates the information needed by the +* OpenSM to manage Partitions. The OpenSM allocates one Partition +* object per Partition in the IBA subnet. +* +* The Partition is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Partition/osm_prtn_t +* NAME +* osm_prtn_t +* +* DESCRIPTION +* Partition structure. +* +* The osm_prtn_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_prtn +{ + cl_map_item_t map_item; + uint16_t pkey; + uint8_t sl; + cl_map_t full_guid_tbl; + cl_map_t part_guid_tbl; + char name[32]; +} osm_prtn_t; +/* +* FIELDS +* map_item +* Linkage structure for cl_qmap. MUST BE FIRST MEMBER! +* +* pkey +* The IBA defined P_KEY of this Partition. +* +* sl +* The Service Level (SL) associated with this Partiton. +* +* full_guid_tbl +* Container of pointers to all Port objects in the Partition +* with full membership, indexed by port GUID. +* +* part_guid_tbl +* Container of pointers to all Port objects in the Partition +* with limited membership, indexed by port GUID. +* +* name +* Name of the Partition as specified in partition +* configuration. +* +* SEE ALSO +* Partition +*********/ + +/****f* OpenSM: Partition/osm_prtn_delete +* NAME +* osm_prtn_delete +* +* DESCRIPTION +* This function destroys and deallocates a Partition object. +* +* SYNOPSIS +*/ +void osm_prtn_delete( + IN OUT osm_prtn_t** const pp_prtn ); +/* +* PARAMETERS +* pp_prtn +* [in][out] Pointer to a pointer to a Partition object to +* delete. On return, this pointer is NULL. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Partition object. +* +* SEE ALSO +* Partition, osm_prtn_new +*********/ + +/****f* OpenSM: Partition/osm_prtn_new +* NAME +* osm_prtn_new +* +* DESCRIPTION +* This function allocates and initializes a Partition object. +* +* SYNOPSIS +*/ +osm_prtn_t* osm_prtn_new( + IN const char *name, + IN const uint16_t pkey ); +/* +* PARAMETERS +* name +* [in] Partition name string +* +* pkey +* [in] Partition P_Key value +* +* RETURN VALUE +* Pointer to the initialize Partition object. +* +* NOTES +* Allows calling other partition methods. +* +* SEE ALSO +* Partition +*********/ + +/****f* OpenSM: Partition/osm_prtn_is_guid +* NAME +* osm_prtn_is_guid +* +* DESCRIPTION +* Indicates if a port is a member of the partition. +* +* SYNOPSIS +*/ +static inline +boolean_t osm_prtn_is_guid( + IN const osm_prtn_t* const p_prtn, + IN const ib_net64_t guid ) +{ + return (cl_map_get(&p_prtn->full_guid_tbl, guid) != NULL) || + (cl_map_get(&p_prtn->part_guid_tbl, guid) != NULL); +} +/* +* PARAMETERS +* p_prtn +* [in] Pointer to an osm_prtn_t object. +* +* guid +* [in] Port GUID. +* +* RETURN VALUES +* TRUE if the specified port GUID is a member of the partition, +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Partition/osm_prtn_make_partitions +* NAME +* osm_prtn_make_partitions +* +* DESCRIPTION +* Makes all partitions in subnet. +* +* SYNOPSIS +*/ +ib_api_status_t osm_prtn_make_partitions( + IN osm_log_t * const p_log, + IN osm_subn_t * const p_subn); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to subnet object. +* +* RETURN VALUES +* IB_SUCCESS value on success. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_PARTITION_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_path.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_path.h new file mode 100644 index 00000000..3cc435a7 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_path.h @@ -0,0 +1,267 @@ +/* + * 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$ + */ + + +#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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +/****h* OpenSM/DR Path +* NAME +* DR Path +* +* DESCRIPTION +* The DR Path structure encapsulates a directed route through the subnet. +* +* This structure allows direct access to member variables. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: DR Path/osm_dr_path_t +* NAME +* osm_dr_path_t +* +* DESCRIPTION +* Directed Route structure. +* +* This structure allows direct access to member variables. +* +* SYNOPSIS +*/ +typedef struct _osm_dr_path +{ + osm_bind_handle_t h_bind; + uint8_t hop_count; + uint8_t path[IB_SUBNET_PATH_HOPS_MAX]; + +} osm_dr_path_t; +/* +* FIELDS +* h_bind +* Bind handle for port to which this path applies. +* +* hop_count +* The number of hops in this path. +* +* path +* The array of port numbers that comprise this path. +* +* SEE ALSO +* DR Path structure +*********/ +/****f* OpenSM: DR Path/osm_dr_path_construct +* NAME +* osm_dr_path_construct +* +* DESCRIPTION +* This function constructs a directed route path object. +* +* SYNOPSIS +*/ +static inline void +osm_dr_path_construct( + IN osm_dr_path_t* const p_path ) +{ + /* The first location in the path array is reserved. */ + memset( p_path, 0, sizeof(*p_path) ); + p_path->h_bind = OSM_BIND_INVALID_HANDLE; +} + +/* +* PARAMETERS +* p_path +* [in] Pointer to a directed route path object to initialize. +* +* h_bind +* [in] Bind handle for the port on which this path applies. +* +* hop_count +* [in] Hop count needed to reach this node. +* +* path +* [in] Directed route path to reach this node. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: DR Path/osm_dr_path_init +* NAME +* osm_dr_path_init +* +* DESCRIPTION +* This function initializes a directed route path object. +* +* SYNOPSIS +*/ +static inline void +osm_dr_path_init( + IN osm_dr_path_t* const p_path, + IN const osm_bind_handle_t h_bind, + IN const uint8_t hop_count, + IN const uint8_t path[IB_SUBNET_PATH_HOPS_MAX] ) +{ + /* The first location in the path array is reserved. */ + CL_ASSERT( path[0] == 0 ); + CL_ASSERT( hop_count < IB_SUBNET_PATH_HOPS_MAX ); + p_path->h_bind = h_bind; + p_path->hop_count = hop_count; + memcpy( p_path->path, path, IB_SUBNET_PATH_HOPS_MAX ); +} + +/* +* PARAMETERS +* p_path +* [in] Pointer to a directed route path object to initialize. +* +* h_bind +* [in] Bind handle for the port on which this path applies. +* +* hop_count +* [in] Hop count needed to reach this node. +* +* path +* [in] Directed route path to reach this node. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ +/****f* OpenSM: DR Path/osm_dr_path_extend +* NAME +* osm_dr_path_extend +* +* DESCRIPTION +* Adds a new hop to a path. +* +* SYNOPSIS +*/ +static inline void +osm_dr_path_extend( + IN osm_dr_path_t* const p_path, + IN const uint8_t port_num ) +{ + p_path->hop_count++; + CL_ASSERT( p_path->hop_count < IB_SUBNET_PATH_HOPS_MAX ); + /* + Location 0 in the path array is reserved per IB spec. + */ + p_path->path[p_path->hop_count] = port_num; +} + +/* +* PARAMETERS +* p_path +* [in] Pointer to a directed route path object to initialize. +* +* port_num +* [in] Additional port to add to the DR path. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: DR Path/osm_dr_path_get_bind_handle +* NAME +* osm_dr_path_get_bind_handle +* +* DESCRIPTION +* Gets the bind handle from a path. +* +* SYNOPSIS +*/ +static inline osm_bind_handle_t +osm_dr_path_get_bind_handle( + IN const osm_dr_path_t* const p_path ) +{ + return( p_path->h_bind ); +} + +/* +* PARAMETERS +* p_path +* [in] Pointer to a directed route path object to initialize. +* +* port_num +* [in] Additional port to add to the DR path. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_PATH_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey.h new file mode 100644 index 00000000..ef8771c4 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey.h @@ -0,0 +1,755 @@ +/* + * 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$ + */ + + +#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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.1 $ + */ + +/****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_pkey_tbl +{ + cl_ptr_vector_t blocks; + cl_ptr_vector_t new_blocks; + cl_map_t keys; + cl_qlist_t pending; + uint16_t used_blocks; + uint16_t max_blocks; +} osm_pkey_tbl_t; +/* +* FIELDS +* blocks +* The IBA defined blocks of pkey values, updated from the subnet +* +* new_blocks +* The blocks of pkey values, will be used for updates by SM +* +* keys +* A set holding all keys +* +* pending +* A list of osm_pending_pkey structs that is temporarily set by +* the pkey mgr and used during pkey mgr algorithm only +* +* used_blocks +* Tracks the number of blocks having non-zero pkeys +* +* max_blocks +* The maximal number of blocks this partition table might hold +* this value is based on node_info (for port 0 or CA) or +* switch_info updated on receiving the node_info or switch_info +* GetResp +* +* NOTES +* 'blocks' vector should be used to store pkey values obtained from +* the port and SM pkey manager should not change it directly, for this +* purpose 'new_blocks' should be used. +* +* The only pkey values stored in 'blocks' vector will be mapped with +* 'keys' map +* +*********/ + +/****s* OpenSM: osm_pending_pkey_t +* NAME +* osm_pending_pkey_t +* +* DESCRIPTION +* This objects stores temporary information on pkeys, their target block, +* and index during the pkey manager operation +* +* SYNOPSIS +*/ +typedef struct _osm_pending_pkey { + cl_list_item_t list_item; + uint16_t pkey; + uint16_t block; + uint8_t index; + boolean_t is_new; +} osm_pending_pkey_t; +/* +* FIELDS +* pkey +* The actual P_Key +* +* block +* The block index based on the previous table extracted from the +* device +* +* index +* The index of the pkey within the block +* +* is_new +* TRUE for new P_Keys such that the block and index are invalid +* in that case +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_construct +* NAME +* osm_pkey_tbl_construct +* +* DESCRIPTION +* Constructs the PKey table object +* +* SYNOPSIS +*/ +void osm_pkey_tbl_construct( + IN osm_pkey_tbl_t *p_pkey_tbl); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_init +* NAME +* osm_pkey_tbl_init +* +* DESCRIPTION +* Inits the PKey table object +* +* SYNOPSIS +*/ +ib_api_status_t +osm_pkey_tbl_init( + IN osm_pkey_tbl_t *p_pkey_tbl); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_destroy +* NAME +* osm_pkey_tbl_destroy +* +* DESCRIPTION +* Destroys the PKey table object +* +* SYNOPSIS +*/ +void osm_pkey_tbl_destroy( + IN osm_pkey_tbl_t *p_pkey_tbl); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_get_num_blocks +* NAME +* osm_pkey_get_num_blocks +* +* DESCRIPTION +* Obtain the number of blocks in IB PKey table +* +* SYNOPSIS +*/ +static inline uint16_t +osm_pkey_tbl_get_num_blocks( + IN const osm_pkey_tbl_t *p_pkey_tbl ) +{ + return((uint16_t)(cl_ptr_vector_get_size( &p_pkey_tbl->blocks ))); +} +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* RETURN VALUES +* The IB pkey table of that pkey table element +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_block_get +* NAME +* osm_pkey_tbl_block_get +* +* DESCRIPTION +* Obtain the pointer to the IB PKey table block stored in the object +* +* SYNOPSIS +*/ +static inline ib_pkey_table_t *osm_pkey_tbl_block_get( + const osm_pkey_tbl_t *p_pkey_tbl, uint16_t block) +{ + return( (block < cl_ptr_vector_get_size(&p_pkey_tbl->blocks)) ? + cl_ptr_vector_get(&p_pkey_tbl->blocks, block) : NULL ); +}; +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* block +* [in] The lock number to get +* +* RETURN VALUES +* The IB pkey table of that pkey table element +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_new_block_get +* NAME +* osm_pkey_tbl_new_block_get +* +* DESCRIPTION +* The same as above but for new block +* +* SYNOPSIS +*/ +static inline ib_pkey_table_t *osm_pkey_tbl_new_block_get( + const osm_pkey_tbl_t *p_pkey_tbl, uint16_t block) +{ + return (block < cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks)) ? + cl_ptr_vector_get(&p_pkey_tbl->new_blocks, block) : NULL; +}; + +/****f* OpenSM: osm_pkey_tbl_set_new_entry +* NAME +* osm_pkey_tbl_set_new_entry +* +* DESCRIPTION +* Stores the given pkey in the "new" blocks array and update +* the "map" to show that on the "old" blocks +* +* SYNOPSIS +*/ +ib_api_status_t +osm_pkey_tbl_set_new_entry( + IN osm_pkey_tbl_t *p_pkey_tbl, + IN uint16_t block_idx, + IN uint8_t pkey_idx, + IN uint16_t pkey); +/* +* p_pkey_tbl +* [in] Pointer to the PKey table +* +* block_idx +* [in] The block index to use +* +* pkey_idx +* [in] The index within the block +* +* pkey +* [in] PKey to store +* +* RETURN VALUES +* IB_SUCCESS if OK +* IB_ERROR if failed +* +*********/ + +/****f* OpenSM: osm_pkey_find_next_free_entry +* NAME +* osm_pkey_find_next_free_entry +* +* DESCRIPTION +* Find the next free entry in the PKey table starting at the given +* index and block number. The user should increment pkey_idx before +* next call +* Inspect the "new" blocks array for empty space. +* +* SYNOPSIS +*/ +boolean_t +osm_pkey_find_next_free_entry( + IN osm_pkey_tbl_t *p_pkey_tbl, + OUT uint16_t *p_block_idx, + OUT uint8_t *p_pkey_idx); +/* +* p_pkey_tbl +* [in] Pointer to the PKey table +* +* p_block_idx +* [out] The block index to use +* +* p_pkey_idx +* [out] The index within the block to use +* +* RETURN VALUES +* TRUE if found +* FALSE if did not find +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_init_new_blocks +* NAME +* osm_pkey_tbl_init_new_blocks +* +* DESCRIPTION +* Initializes new_blocks vector content (allocate and clear) +* +* SYNOPSIS +*/ +void osm_pkey_tbl_init_new_blocks( + const osm_pkey_tbl_t *p_pkey_tbl); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_get_block_and_idx +* NAME +* osm_pkey_tbl_get_block_and_idx +* +* DESCRIPTION +* Set the block index and pkey index the given +* pkey is found in. Return IB_NOT_FOUND if could +* not find it, IB_SUCCESS if OK +* +* SYNOPSIS +*/ +ib_api_status_t +osm_pkey_tbl_get_block_and_idx( + IN osm_pkey_tbl_t *p_pkey_tbl, + IN uint16_t *p_pkey, + OUT uint16_t *block_idx, + OUT uint8_t *pkey_index); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* p_pkey +* [in] Pointer to the P_Key entry searched +* +* p_block_idx +* [out] Pointer to the block index to be updated +* +* p_pkey_idx +* [out] Pointer to the pkey index (in the block) to be updated +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_set +* NAME +* osm_pkey_tbl_set +* +* DESCRIPTION +* Set the PKey table block provided in the PKey object. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_pkey_tbl_set( + IN osm_pkey_tbl_t *p_pkey_tbl, + IN uint16_t block, + IN ib_pkey_table_t *p_tbl); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* block +* [in] The block number to set +* +* p_tbl +* [in] The IB PKey block to copy to the object +* +* RETURN VALUES +* IB_SUCCESS or IB_ERROR +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_physp_share_this_pkey +* NAME +* osm_physp_share_this_pkey +* +* DESCRIPTION +* Checks if the given physical ports share the specified pkey. +* +* SYNOPSIS +*/ +boolean_t osm_physp_share_this_pkey( + IN const struct _osm_physp * const p_physp1, + IN const struct _osm_physp * const p_physp2, + IN const ib_net16_t pkey); +/* +* PARAMETERS +* +* p_physp1 +* [in] Pointer to an osm_physp_t object. +* +* p_physp2 +* [in] Pointer to an osm_physp_t object. +* +* pkey +* [in] value of P_Key to check. +* +* RETURN VALUES +* Returns TRUE if the two ports are matching. +* FALSE otherwise. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_physp_find_common_pkey +* NAME +* osm_physp_find_common_pkey +* +* DESCRIPTION +* Returns first matching P_Key values for specified physical ports. +* +* SYNOPSIS +*/ +ib_net16_t osm_physp_find_common_pkey( + IN const struct _osm_physp * const p_physp1, + IN const struct _osm_physp * const p_physp2 ); +/* +* PARAMETERS +* +* p_physp1 +* [in] Pointer to an osm_physp_t object. +* +* p_physp2 +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns value of first shared P_Key or INVALID P_Key (0x0) if not +* found. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_physp_share_pkey +* NAME +* osm_physp_share_pkey +* +* DESCRIPTION +* Checks if the given physical ports share a pkey. +* The meaning P_Key matching: +* 10.9.3 : +* In the following, let M_P_Key(Message P_Key) be the P_Key in the incoming +* packet and E_P_Key(Endnode P_Key) be the P_Key it is being compared against +* in the packet's destination endnode. +* +* If: +* * neither M_P_Key nor E_P_Key are the invalid P_Key +* * and the low-order 15 bits of the M_P_Key match the low order 15 +* bits of the E_P_Key +* * and the high order bit(membership type) of both the M_P_Key and +* E_P_Key are not both 0 (i.e., both are not Limited members of +* the partition) +* +* then the P_Keys are said to match. +* +* SYNOPSIS +*/ +boolean_t osm_physp_share_pkey( + IN osm_log_t* p_log, + IN const struct _osm_physp* const p_physp_1, + IN const struct _osm_physp* const p_physp_2 ); + +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_physp_1 +* [in] Pointer to an osm_physp_t object. +* +* p_physp_2 +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns TRUE if the 2 physical ports are matching. +* FALSE otherwise. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_port_share_pkey +* NAME +* osm_port_share_pkey +* +* DESCRIPTION +* Checks if the given ports (on their default physical port) share a pkey. +* The meaning P_Key matching: +* 10.9.3 : +* In the following, let M_P_Key(Message P_Key) be the P_Key in the incoming +* packet and E_P_Key(Endnode P_Key) be the P_Key it is being compared against +* in the packet's destination endnode. +* +* If: +* * neither M_P_Key nor E_P_Key are the invalid P_Key +* * and the low-order 15 bits of the M_P_Key match the low order 15 +* bits of the E_P_Key +* * and the high order bit(membership type) of both the M_P_Key and +* E_P_Key are not both 0 (i.e., both are not Limited members of +* the partition) +* +* then the P_Keys are said to match. +* +* SYNOPSIS +*/ +boolean_t osm_port_share_pkey( + IN osm_log_t* p_log, + IN const struct _osm_port* const p_port_1, + IN const struct _osm_port* const p_port_2 ); + +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_port_1 +* [in] Pointer to an osm_port_t object. +* +* p_port_2 +* [in] Pointer to an osm_port_t object. +* +* RETURN VALUES +* Returns TRUE if the 2 ports are matching. +* FALSE otherwise. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_lid_share_pkey +* NAME +* osm_lid_share_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_lid_share_pkey( + IN osm_log_t* p_log, + IN const struct _osm_subn* const p_subn, + IN const ib_net16_t lid1, + IN const uint8_t port_num1, + IN const ib_net16_t lid2, + IN const uint8_t port_num2 ); + +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to the subnet object for accessing of the options. +* +* lid1 +* [in] lid number of first port. +* +* port_num1 +* [in] port number of first port. +* +* lid2 +* [in] lid number of second port. +* +* port_num2 +* [in] port number of second port. +* +* RETURN VALUES +* Returns TRUE if the 2 physical ports that belong to these lids/port_numbers +* are matching. FALSE otherwise. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_physp_has_pkey +* NAME +* osm_physp_has_pkey +* +* DESCRIPTION +* Checks if the given lids and port_numbers share a pkey. +* The meaning P_Key matching: +* 10.9.3 : +* In the following, let M_P_Key(Message P_Key) be the P_Key in the incoming +* packet and E_P_Key(Endnode P_Key) be the P_Key it is being compared against +* in the packet's destination endnode. +* +* If: +* * neither M_P_Key nor E_P_Key are the invalid P_Key +* * and the low-order 15 bits of the M_P_Key match the low order 15 +* bits of the E_P_Key +* * and the high order bit(membership type) of both the M_P_Key and +* E_P_Key are not both 0 (i.e., both are not Limited members of +* the partition) +* +* then the P_Keys are said to match. +* +* SYNOPSIS +*/ +boolean_t osm_physp_has_pkey( + IN osm_log_t* p_log, + IN const ib_net16_t pkey, + IN const struct _osm_physp* const p_physp ); + +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* pkey +* [in] pkey number to look for. +* +* p_physp +* [in] Pointer to osm_physp_t object. +* +* RETURN VALUES +* Returns TRUE if the p_physp has the pkey given. False otherwise. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_get_tables +* NAME +* osm_pkey_get_tables +* +* DESCRIPTION +* Sends a request for getting the pkey tables of the given physp. +* +* SYNOPSIS +*/ +void osm_pkey_get_tables( + IN osm_log_t *p_log, + IN osm_req_t *p_req, + IN osm_subn_t* const p_subn, + IN struct _osm_node* const p_node, + IN struct _osm_physp* const p_physp ); + +/* +* PARAMETERS +* p_log +* [in] Pointer to osm_log object. +* +* p_req +* [in] Pointer to osm_req object. +* +* p_subn +* [in] Pointer to osm_subn object. +* +* p_node +* [in] Pointer to osm_node object. +* +* p_physp +* [in] Pointer to osm_physp_t object. +* +* RETURN VALUES +* None +* +* NOTES +* +*********/ + +END_C_DECLS + +#endif /* _OSM_PKEY_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey_mgr.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey_mgr.h new file mode 100644 index 00000000..b750503c --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey_mgr.h @@ -0,0 +1,90 @@ +/* + * 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: + * Prototype for osm_pkey_mgr_process() function + * This is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_PKEY_MGR_H_ +#define _OSM_PKEY_MGR_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +/****f* OpenSM: P_Key Manager/osm_pkey_mgr_process +* NAME +* osm_pkey_mgr_process +* +* DESCRIPTION +* This function enforces the pkey rules on the SM DB. +* +* SYNOPSIS +*/ +osm_signal_t +osm_pkey_mgr_process( + IN osm_opensm_t *p_osm ); +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_PKEY_MGR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey_rcv.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey_rcv.h new file mode 100644 index 00000000..5099e0e3 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey_rcv.h @@ -0,0 +1,253 @@ +/* + * 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$ + */ + + +#ifndef _OSM_PKEY_RCV_H_ +#define _OSM_PKEY_RCV_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/P_Key Receiver +* NAME +* P_Key Receiver +* +* DESCRIPTION +* The P_Key Receiver object encapsulates the information +* needed to set or get the vl arbitration attribute from a port. +* +* The P_Key Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Yael Kalka, Mellanox +* +*********/ + +/****s* OpenSM: P_Key Receiver/osm_pkey_rcv_t +* NAME +* osm_pkey_rcv_t +* +* DESCRIPTION +* P_Key Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_pkey_rcv +{ + osm_subn_t *p_subn; + osm_req_t *p_req; + osm_log_t *p_log; + cl_plock_t *p_lock; + +} osm_pkey_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_req +* Pointer to the generic attribute request object. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* P_Key Receiver object +*********/ + +/****f* OpenSM: P_Key Receiver/osm_pkey_rcv_construct +* NAME +* osm_pkey_rcv_construct +* +* DESCRIPTION +* This function constructs a P_Key Receiver object. +* +* SYNOPSIS +*/ +void osm_pkey_rcv_construct( + IN osm_pkey_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a P_Key Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_pkey_rcv_destroy +* +* Calling osm_pkey_rcv_construct is a prerequisite to calling any other +* method except osm_pkey_rcv_init. +* +* SEE ALSO +* P_Key Receiver object, osm_pkey_rcv_init, +* osm_pkey_rcv_destroy +*********/ + +/****f* OpenSM: P_Key Receiver/osm_pkey_rcv_destroy +* NAME +* osm_pkey_rcv_destroy +* +* DESCRIPTION +* The osm_pkey_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_pkey_rcv_destroy( + IN osm_pkey_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* P_Key Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_pkey_rcv_construct or osm_pkey_rcv_init. +* +* SEE ALSO +* P_Key Receiver object, osm_pkey_rcv_construct, +* osm_pkey_rcv_init +*********/ + +/****f* OpenSM: P_Key Receiver/osm_pkey_rcv_init +* NAME +* osm_pkey_rcv_init +* +* DESCRIPTION +* The osm_pkey_rcv_init function initializes a +* P_Key Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_pkey_rcv_init( + IN osm_pkey_rcv_t* const p_ctrl, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_pkey_rcv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the P_Key Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other P_Key Receiver methods. +* +* SEE ALSO +* P_Key Receiver object, osm_pkey_rcv_construct, +* osm_pkey_rcv_destroy +*********/ + +/****f* OpenSM: P_Key Receiver/osm_pkey_rcv_process +* NAME +* osm_pkey_rcv_process +* +* DESCRIPTION +* Process the vl arbitration attribute. +* +* SYNOPSIS +*/ +void osm_pkey_rcv_process( + IN const osm_pkey_rcv_t* const p_ctrl, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_pkey_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's SLtoVL attribute. +* +* RETURN VALUES +* CL_SUCCESS if the SLtoVL processing was successful. +* +* NOTES +* This function processes a SLtoVL attribute. +* +* SEE ALSO +* P_Key Receiver, P_Key Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_PKEY_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey_rcv_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey_rcv_ctrl.h new file mode 100644 index 00000000..20700d36 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_pkey_rcv_ctrl.h @@ -0,0 +1,248 @@ +/* + * 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$ + */ + + +#ifndef _OSM_PKEY_RCV_CTRL_H_ +#define _OSM_PKEY_RCV_CTRL_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/P_Key Table Receive Controller +* NAME +* P_Key Receive Controller +* +* DESCRIPTION +* The P_Key Receive Controller object encapsulates +* the information needed to get or set P_Key table of a port. +* +* The P_Key Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Yael Kalka, Mellanox +* +*********/ + +/****s* OpenSM: P_Key Receive Controller/osm_pkey_rcv_ctrl_t +* NAME +* osm_pkey_rcv_ctrl_t +* +* DESCRIPTION +* P_Key Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_pkey_rcv_ctrl +{ + osm_pkey_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_pkey_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the P_Key Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* P_Key Receive Controller object +* P_Key Receiver object +*********/ + +/****f* OpenSM: P_Key Receive Controller/osm_pkey_rcv_ctrl_construct +* NAME +* osm_pkey_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a P_Key Receive Controller object. +* +* SYNOPSIS +*/ +void osm_pkey_rcv_ctrl_construct( + IN osm_pkey_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a P_Key Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_pkey_rcv_ctrl_init, osm_pkey_rcv_ctrl_destroy, +* and osm_pkey_rcv_ctrl_is_inited. +* +* Calling osm_pkey_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_pkey_rcv_ctrl_init. +* +* SEE ALSO +* P_Key Receive Controller object, osm_pkey_rcv_ctrl_init, +* osm_pkey_rcv_ctrl_destroy, osm_pkey_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: P_Key Receive Controller/osm_pkey_rcv_ctrl_destroy +* NAME +* osm_pkey_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_pkey_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_pkey_rcv_ctrl_destroy( + IN osm_pkey_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* P_Key Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_pkey_rcv_ctrl_construct or osm_pkey_rcv_ctrl_init. +* +* SEE ALSO +* P_Key Receive Controller object, osm_pkey_rcv_ctrl_construct, +* osm_pkey_rcv_ctrl_init +*********/ + +/****f* OpenSM: P_Key Receive Controller/osm_pkey_rcv_ctrl_init +* NAME +* osm_pkey_rcv_ctrl_init +* +* DESCRIPTION +* The osm_pkey_rcv_ctrl_init function initializes a +* P_Key Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_pkey_rcv_ctrl_init( + IN osm_pkey_rcv_ctrl_t* const p_ctrl, + IN osm_pkey_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_pkey_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_pkey_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the P_Key Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other P_Key Receive Controller methods. +* +* SEE ALSO +* P_Key Receive Controller object, osm_pkey_rcv_ctrl_construct, +* osm_pkey_rcv_ctrl_destroy, osm_pkey_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: P_Key Receive Controller/osm_pkey_rcv_ctrl_is_inited +* NAME +* osm_pkey_rcv_ctrl_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_pkey_rcv_ctrl_init. +* +* SYNOPSIS +*/ +boolean_t osm_pkey_rcv_ctrl_is_inited( + IN const osm_pkey_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_pkey_rcv_ctrl_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_pkey_rcv_ctrl_construct or osm_pkey_rcv_ctrl_init must be +* called before using this function. +* +* SEE ALSO +* P_Key Receive Controller object, osm_pkey_rcv_ctrl_construct, +* osm_pkey_rcv_ctrl_init +*********/ + +END_C_DECLS + +#endif /* _OSM_PKEY_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port.h new file mode 100644 index 00000000..b72b16d0 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port.h @@ -0,0 +1,2122 @@ +/* + * 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: + * Declaration of port related objects. + * These objects comprise an IBA port. + * These objects are part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.8 $ + */ + +#ifndef _OSM_PORT_H_ +#define _OSM_PORT_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 + +/* + Forward references. +*/ +struct _osm_port; +struct _osm_node; + +/****h* OpenSM/Physical Port +* NAME +* Physical Port +* +* DESCRIPTION +* The Physical Port object encapsulates the information needed by the +* OpenSM to manage physical ports. The OpenSM allocates one Physical Port +* per physical port in the IBA subnet. +* +* In a switch, one multiple Physical Port objects share the same port GUID. +* In an end-point, Physical Ports do not share GUID values. +* +* The Physical Port is not thread safe, thus callers must provide +* serialization. +* +* These objects should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Physical Port/osm_physp_t +* NAME +* osm_physp_t +* +* DESCRIPTION +* This object represents a physical port on a switch, router or end-point. +* +* The osm_physp_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_physp +{ + ib_port_info_t port_info; + ib_net64_t port_guid; + uint8_t port_num; + struct _osm_node *p_node; + struct _osm_physp *p_remote_physp; + boolean_t healthy; + 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; + boolean_t got_set_resp; +} 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. +* +* 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). +* On switches have an entry for every other input port (inc SMA=0). +* On CAs only one per port. +* +* got_set_resp +* Marks whether or not we got a PortInfoSetResp from this port or not. +* This is used for minimizing the number of PortInfoSet requests sent. +* If we already got a set response from this port, then we will +* send a PortInfoSet only if the values we are updating are +* different than the ones on the port. If the haven't gotten a set +* response - then we want to send the request anyways - since +* every we need at least one PortInfoSet request for every port +* (by a new SM). +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_construct +* NAME +* osm_physp_construct +* +* DESCRIPTION +* Constructs a Physical Port. +* +* SYNOPSIS +*/ +void +osm_physp_construct( + IN osm_physp_t* const p_physp ); +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object to initialize. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_init +* NAME +* osm_physp_init +* +* DESCRIPTION +* Initializes a Physical Port for use. +* +* SYNOPSIS +*/ +void +osm_physp_init( + IN osm_physp_t* const p_physp, + IN const ib_net64_t port_guid, + IN const uint8_t port_num, + IN const struct _osm_node* const p_node, + IN const osm_bind_handle_t h_bind, + IN const uint8_t hop_count, + IN const uint8_t* const p_initial_path ); +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object to initialize. +* +* port_guid +* [in] GUID value of this port. Switch ports all share +* the same value. +* Caller should use 0 if the guid is unknown. +* +* port_num +* [in] The port number of this port. +* +* p_node +* [in] Pointer to the parent Node object of this Physical Port. +* +* h_bind +* [in] Bind handle on which this port is accessed. +* Caller should use OSM_INVALID_BIND_HANDLE if the bind +* handle to this port is unknown. +* +* hop_count +* [in] Directed route hop count to reach this port. +* Caller should use 0 if the hop count is unknown. +* +* p_initial_path +* [in] Pointer to the directed route path to reach this node. +* Caller should use NULL if the path is unknown. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Port/void osm_physp_destroy +* NAME +* osm_physp_destroy +* +* DESCRIPTION +* This function destroys a Port object. +* +* SYNOPSIS +*/ +void +osm_physp_destroy( + IN osm_physp_t* const p_physp ); +/* +* PARAMETERS +* p_port +* [in] Pointer to a PhysPort object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified PhysPort object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_physp_construct or +* osm_physp_init. +* +* SEE ALSO +* Port, osm_port_init, osm_port_destroy +*********/ + +/****f* OpenSM: Physical Port/osm_physp_is_valid +* NAME +* osm_physp_is_valid +* +* DESCRIPTION +* Returns TRUE if the Physical Port has been successfully initialized. +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_physp_is_valid( + IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( p_physp ); + return( p_physp->port_guid != 0 ); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns TRUE if the Physical Port has been successfully initialized. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_is_healthy +* NAME +* osm_physp_is_healthy +* +* DESCRIPTION +* Returns TRUE if the Physical Port has been maked as healthy +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_physp_is_healthy( + IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( p_physp ); + return( p_physp->healthy ); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns TRUE if the Physical Port has been maked as healthy +* FALSE otherwise. +* All physical ports are initialized as "healthy" but may be marked +* otherwise if a received trap claims otherwise. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_link_is_healthy +* NAME +* osm_link_is_healthy +* +* DESCRIPTION +* Returns TRUE if the link given by the physical port is health, +* and FALSE otherwise. Link is healthy if both its physical ports are +* healthy +* +* SYNOPSIS +*/ +boolean_t +osm_link_is_healthy( + IN const osm_physp_t* const p_physp ); +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* TRUE if both physical ports on the link are healthy, and FALSE otherwise. +* All physical ports are initialized as "healthy" but may be marked +* otherwise if a received trap claiming otherwise. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_set_health +* NAME +* osm_physp_set_health +* +* DESCRIPTION +* Sets the port health flag. TRUE means the port is healthy and +* should be used for packet routing. FALSE means it should be avoided. +* +* SYNOPSIS +*/ +static inline void +osm_physp_set_health( + IN osm_physp_t* const p_physp, + IN boolean_t is_healthy ) +{ + CL_ASSERT( p_physp ); + p_physp->healthy = is_healthy; +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* is_healthy +* [in] The health value to be assigned to the port. +* TRUE if the Physical Port should been maked as healthy +* FALSE otherwise. +* +* RETURN VALUES +* NONE +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_set_port_info +* NAME +* osm_physp_set_port_info +* +* DESCRIPTION +* Copies the PortInfo attribute into the Physical Port object +* based on the PortState. +* +* SYNOPSIS +*/ +static inline void +osm_physp_set_port_info( + IN osm_physp_t* const p_physp, + IN const ib_port_info_t* const p_pi ) +{ + CL_ASSERT( p_pi ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + + if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN) + { + /* If PortState is down, only copy PortState */ + /* and PortPhysicalState per C14-24-2.1 */ + ib_port_info_set_port_state(&p_physp->port_info, IB_LINK_DOWN); + ib_port_info_set_port_phys_state( + ib_port_info_get_port_phys_state(p_pi), &p_physp->port_info); + } + else + { + p_physp->port_info = *p_pi; + } +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* p_pi +* [in] Pointer to the IBA defined PortInfo at this port number. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_trim_base_lid_to_valid_range +* NAME +* osm_physp_trim_base_lid_to_valid_range +* +* DESCRIPTION +* Validates the base LID in the Physical Port object +* and resets it if the base LID is invalid. +* +* SYNOPSIS +*/ +static inline ib_net16_t +osm_physp_trim_base_lid_to_valid_range( + IN osm_physp_t* const p_physp ) +{ + ib_net16_t orig_lid = 0; + + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + if ( ( cl_ntoh16( p_physp->port_info.base_lid ) > IB_LID_UCAST_END_HO ) || + ( cl_ntoh16( p_physp->port_info.base_lid ) < IB_LID_UCAST_START_HO ) ) + { + orig_lid = p_physp->port_info.base_lid; + p_physp->port_info.base_lid = 0; + } + return orig_lid; +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns 0 if the base LID in the Physical port object is valid. +* Returns original invalid LID otherwise. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_set_pkey_tbl +* NAME +* osm_physp_set_pkey_tbl +* +* DESCRIPTION +* Copies the P_Key table into the Physical Port object. +* +* SYNOPSIS +*/ +void +osm_physp_set_pkey_tbl( IN osm_log_t* p_log, + IN const osm_subn_t* p_subn, + IN osm_physp_t* const p_physp, + IN ib_pkey_table_t *p_pkey_tbl, + IN uint16_t block_num ); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to the subnet data structure. +* +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* p_pkey_tbl +* [in] Pointer to the IBA defined P_Key table for this port +* number. +* +* block_num +* [in] The part of the P_Key table as defined in the IBA +* (valid values 0-2047, and is further limited by the +* partitionCap). +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_pkey_tbl +* NAME +* osm_physp_get_pkey_tbl +* +* DESCRIPTION +* Returns a pointer to the P_Key table object of the Physical Port object. +* +* SYNOPSIS +*/ +static inline const osm_pkey_tbl_t * +osm_physp_get_pkey_tbl( IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + /* + (14.2.5.7) - the block number valid values are 0-2047, and are further + limited by the size of the P_Key table specified by the PartitionCap on the node. + */ + return( &p_physp->pkeys ); +}; +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* The pointer to the P_Key table object. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_mod_pkey_tbl +* NAME +* osm_physp_get_mod_pkey_tbl +* +* DESCRIPTION +* Returns a NON CONST pointer to the P_Key table object of the Physical Port object. +* +* SYNOPSIS +*/ +static inline osm_pkey_tbl_t * +osm_physp_get_mod_pkey_tbl( IN osm_physp_t* const p_physp ) +{ + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + /* + (14.2.5.7) - the block number valid values are 0-2047, and are further + limited by the size of the P_Key table specified by the PartitionCap on the node. + */ + return( &p_physp->pkeys ); +}; +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* The pointer to the P_Key table object. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_set_slvl_tbl +* NAME +* osm_physp_set_slvl_tbl +* +* DESCRIPTION +* Copies the SLtoVL attribute into the Physical Port object. +* +* SYNOPSIS +*/ +static inline void +osm_physp_set_slvl_tbl( IN osm_physp_t* const p_physp, + IN ib_slvl_table_t *p_slvl_tbl, + IN uint8_t in_port_num ) +{ + ib_slvl_table_t *p_tbl; + + CL_ASSERT( p_slvl_tbl ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + p_tbl = cl_ptr_vector_get(&p_physp->slvl_by_port, in_port_num); + *p_tbl = *p_slvl_tbl; +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* p_slvl_tbl +* [in] Pointer to the IBA defined SLtoVL map table for this port number. +* +* in_port_num +* [in] Input Port Number for this SLtoVL. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_slvl_tbl +* NAME +* osm_physp_get_slvl_tbl +* +* DESCRIPTION +* Returns a pointer to the SLtoVL attribute of the Physical Port object. +* +* SYNOPSIS +*/ +static inline ib_slvl_table_t * +osm_physp_get_slvl_tbl( IN const osm_physp_t* const p_physp, + IN uint8_t in_port_num ) +{ + ib_slvl_table_t *p_tbl; + + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + p_tbl = cl_ptr_vector_get(&p_physp->slvl_by_port, in_port_num); + return(p_tbl); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* in_port_num +* [in] Input Port Number for this SLtoVL. +* +* RETURN VALUES +* The pointer to the slvl table +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_set_vla_tbl +* NAME +* osm_physp_set_vla_tbl +* +* DESCRIPTION +* Copies the VL Arbitration attribute into the Physical Port object. +* +* SYNOPSIS +*/ +static inline void +osm_physp_set_vla_tbl( IN osm_physp_t* const p_physp, + IN ib_vl_arb_table_t *p_vla_tbl, + IN uint8_t block_num ) +{ + CL_ASSERT( p_vla_tbl ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + CL_ASSERT( (1 <= block_num) && (block_num <= 4)); + p_physp->vl_arb[block_num - 1] = *p_vla_tbl; +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* p_vla_tbl +* [in] Pointer to the IBA defined VL Arbitration table for this port number. +* +* block_num +* [in] The part of the VL arbitration as defined in the IBA +* (valid values 1-4) +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_vla_tbl +* NAME +* osm_physp_get_vla_tbl +* +* DESCRIPTION +* Returns a pointer to the VL Arbitration table of the Physical Port object. +* +* SYNOPSIS +*/ +static inline ib_vl_arb_table_t * +osm_physp_get_vla_tbl( IN osm_physp_t* const p_physp, + IN uint8_t block_num ) +{ + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + CL_ASSERT( (1 <= block_num) && (block_num <= 4)); + return(& (p_physp->vl_arb[block_num - 1])); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* block_num +* [in] The part of the VL arbitration as defined in the IBA +* (valid values 1-4) +* +* RETURN VALUES +* The pointer to the VL Arbitration table +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_remote +* NAME +* osm_physp_get_remote +* +* DESCRIPTION +* Returns a pointer to the Physical Port on the other side the wire. +* +* SYNOPSIS +*/ +static inline osm_physp_t* +osm_physp_get_remote( + IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + return( p_physp->p_remote_physp ); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns a pointer to the Physical Port on the other side of +* the wire. A return value of NULL means there is no link at this port. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_port_guid +* NAME +* osm_physp_get_port_guid +* +* DESCRIPTION +* Returns the port guid of this physical port. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_physp_get_port_guid( + IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + return( p_physp->port_guid ); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns the port guid of this physical port. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_subnet_prefix +* NAME +* osm_physp_get_subnet_prefix +* +* DESCRIPTION +* Returns the subnet prefix for this physical port. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_physp_get_subnet_prefix( + IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + return( p_physp->port_info.subnet_prefix ); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns the subnet prefix for this physical port. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_link_exists +* NAME +* osm_physp_link_exists +* +* DESCRIPTION +* Returns TRUE if the Physical Port has a link to the specified port. +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_physp_link_exists( + IN const osm_physp_t* const p_physp, + IN const osm_physp_t* const p_remote_physp ) +{ + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + CL_ASSERT( p_remote_physp ); + CL_ASSERT( osm_physp_is_valid( p_remote_physp ) ); + return( (p_physp->p_remote_physp == p_remote_physp ) && + (p_remote_physp->p_remote_physp == p_physp ) ); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* p_remote_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns TRUE if the Physical Port has a link to another port. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_link +* NAME +* osm_physp_link +* +* DESCRIPTION +* Sets the pointers to the Physical Ports on the other side the wire. +* +* SYNOPSIS +*/ +static inline void +osm_physp_link( + IN osm_physp_t* const p_physp, + IN osm_physp_t* const p_remote_physp ) +{ + CL_ASSERT( p_physp ); + CL_ASSERT( p_remote_physp ); + p_physp->p_remote_physp = p_remote_physp; + p_remote_physp->p_remote_physp = p_physp; +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object to link. +* +* p_remote_physp +* [in] Pointer to the adjacent osm_physp_t object to link. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_unlink +* NAME +* osm_physp_unlink +* +* DESCRIPTION +* Clears the pointers to the Physical Port on the other side the wire. +* +* SYNOPSIS +*/ +static inline void +osm_physp_unlink( + IN osm_physp_t* const p_physp, + IN osm_physp_t* const p_remote_physp ) +{ + CL_ASSERT( p_physp ); + CL_ASSERT( p_remote_physp ); + CL_ASSERT( osm_physp_link_exists( p_physp, p_remote_physp ) ); + p_physp->p_remote_physp = NULL; + p_remote_physp->p_remote_physp = NULL; +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object to link. +* +* p_remote_physp +* [in] Pointer to the adjacent osm_physp_t object to link. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_has_any_link +* NAME +* osm_physp_has_any_link +* +* DESCRIPTION +* Returns TRUE if the Physical Port has a link to another port. +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_physp_has_any_link( + IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( p_physp ); + if( osm_physp_is_valid( p_physp ) ) + return( p_physp->p_remote_physp != NULL ); + else + return( FALSE ); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns TRUE if the Physical Port has a link to another port. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_port_num +* NAME +* osm_physp_get_port_num +* +* DESCRIPTION +* Returns the local port number of this Physical Port. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_physp_get_port_num( + IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + return( p_physp->port_num ); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns the local port number of this Physical Port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_port_info_ptr +* NAME +* osm_physp_get_port_info_ptr +* +* DESCRIPTION +* Returns a pointer to the PortInfo attribute for this port. +* +* SYNOPSIS +*/ +static inline ib_port_info_t* +osm_physp_get_port_info_ptr( + IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + return( (ib_port_info_t*)&p_physp->port_info ); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns a pointer to the PortInfo attribute for this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_node_ptr +* NAME +* osm_physp_get_node_ptr +* +* DESCRIPTION +* Returns a pointer to the parent Node object for this port. +* +* SYNOPSIS +*/ +static inline struct _osm_node* +osm_physp_get_node_ptr( + IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + return( (struct _osm_node*)p_physp->p_node ); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns a pointer to the parent Node object for this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_port_state +* NAME +* osm_physp_get_port_state +* +* DESCRIPTION +* Returns the port state of this Physical Port. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_physp_get_port_state( + IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + return( ib_port_info_get_port_state( &p_physp->port_info )); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns the local port number of this Physical Port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_base_lid +* NAME +* osm_physp_get_base_lid +* +* DESCRIPTION +* Returns the base lid of this Physical Port. +* +* SYNOPSIS +*/ +static inline ib_net16_t +osm_physp_get_base_lid( + IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + return( p_physp->port_info.base_lid ); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns the base lid of this Physical Port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_lmc +* NAME +* osm_physp_get_lmc +* +* DESCRIPTION +* Returns the LMC value of this Physical Port. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_physp_get_lmc( + IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + return( ib_port_info_get_lmc( &p_physp->port_info ) ); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns the LMC value of this Physical Port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_dr_path_ptr +* NAME +* osm_physp_get_dr_path_ptr +* +* DESCRIPTION +* Returns a pointer to the directed route path for this port. +* +* SYNOPSIS +*/ +static inline osm_dr_path_t* +osm_physp_get_dr_path_ptr( + IN const osm_physp_t* const p_physp ) +{ + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + return( (osm_dr_path_t*)&p_physp->dr_path ); +} +/* +* PARAMETERS +* p_physp +* [in] Pointer to a Physical Port object. +* +* RETURN VALUES +* Returns a pointer to the directed route path for this port. +* +* NOTES +* +* SEE ALSO +* Physical Port object +*********/ + +/****h* OpenSM/Port +* NAME +* Port +* +* DESCRIPTION +* The Port object encapsulates the information needed by the +* OpenSM to manage ports. The OpenSM allocates one Port object +* per port in the IBA subnet. +* +* Each Port object is associated with a single port GUID. A Port object +* contains 1 or more Physical Port objects. An end point node has +* one Physical Port per Port. A switch node has more than +* one Physical Port per Port. +* +* The Port object is not thread safe, thus callers must provide +* serialization. +* +* These objects should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****d* OpenSM: Port/osm_port_lid_category_t +* NAME +* osm_port_lid_category_t +* +* DESCRIPTION +* Enumerated values for LID disposition. +* +* SYNOPSIS +*/ +typedef enum _osm_port_lid_category +{ + OSM_PORT_LID_ASSIGNED = 0, + OSM_PORT_LID_UNASSIGNED, + OSM_PORT_LID_CONFLICT, + OSM_PORT_LID_FOREIGN, + +} osm_port_lid_category_t; +/* +* FIELDS +* OSM_PORT_LID_ASSIGNED +* Indicates the Port has a known LID value. +* +* OSM_PORT_LID_UNASSIGNED +* Indicates the Port does not have a LID value. +* +* OSM_PORT_LID_CONFLICT +* Indicates the Port's LID conflicts with an assigned LID. +* +* OSM_PORT_LID_FOREIGN +* Indicates the Port has a LID value not currently known in +* in the OpenSM LID database. +* +* SEE ALSO +* Port +*********/ + +/****s* OpenSM: Port/osm_port_t +* NAME +* osm_port_t +* +* DESCRIPTION +* This object represents a logical port on a switch, router or end-point. +* +* The osm_port_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_port +{ + cl_map_item_t map_item; + struct _osm_node *p_node; + ib_net64_t guid; + uint32_t discovery_count; + uint8_t default_port_num; + uint8_t physp_tbl_size; + cl_qlist_t mcm_list; + osm_physp_t *tbl[1]; +} osm_port_t; +/* +* FIELDS +* map_item +* Linkage structure for cl_qmap. MUST BE FIRST MEMBER! +* +* 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. +* +* default_port_num +* Index of the physical port used when physical characteristics +* contained in the Physical Port are needed. +* +* physp_tbl_size +* Number of physical ports associated with this logical port. +* +* mcm_list +* Multicast member list +* +* tbl +* Array of pointers to Physical Port objects contained by this node. +* MUST BE LAST ELEMENT SINCE IT CAN GROW !!! +* +* SEE ALSO +* Port, Physical Port, Physical Port Table +*********/ + +/****f* OpenSM: Port/osm_port_construct +* NAME +* osm_port_construct +* +* DESCRIPTION +* This function constructs a Port object. +* +* SYNOPSIS +*/ +static inline void +osm_port_construct( + IN osm_port_t* const p_port ) +{ + memset( p_port, 0, sizeof(*p_port) ); + cl_qlist_init( &p_port->mcm_list ); +} +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_port_init, and osm_port_destroy. +* +* Calling osm_port_construct is a prerequisite to calling any other +* method except osm_port_init. +* +* SEE ALSO +* Port, osm_port_init, osm_port_destroy +*********/ + +/****f* OpenSM: Port/osm_port_destroy +* NAME +* osm_port_destroy +* +* DESCRIPTION +* This function destroys a Port object. +* +* SYNOPSIS +*/ +void +osm_port_destroy( + IN osm_port_t* const p_port ); +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Port object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_port_construct +* or osm_port_init. +* +* SEE ALSO +* Port, osm_port_init, osm_port_destroy +*********/ + +/****f* OpenSM: Port/osm_port_delete +* NAME +* osm_port_delete +* +* DESCRIPTION +* This function destroys and deallocates a Port object. +* +* SYNOPSIS +*/ +inline static void +osm_port_delete( + IN OUT osm_port_t** const pp_port ) +{ + osm_port_destroy( *pp_port ); + free( *pp_port ); + *pp_port = NULL; +} +/* +* 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, osm_port_init, osm_port_destroy +*********/ + +/****f* OpenSM: Port/osm_port_init +* NAME +* osm_port_init +* +* DESCRIPTION +* This function initializes a Port object. +* +* SYNOPSIS +*/ +void +osm_port_init( + IN osm_port_t* const p_port, + IN const ib_node_info_t* p_ni, + IN const struct _osm_node* const p_parent_node ); +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object to initialize. +* +* 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 +* None. +* +* NOTES +* Allows calling other port methods. +* +* 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 const struct _osm_node* const p_parent_node ); +/* +* PARAMETERS +* p_ni +* [in] Pointer to the NodeInfo attribute relavent for this port. +* +* p_parent_node +* [in] Pointer to the initialized parent osm_node_t object +* that owns this port. +* +* RETURN VALUE +* Pointer to the initialize Port object. +* +* NOTES +* Allows calling other port methods. +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_get_base_lid +* NAME +* osm_port_get_base_lid +* +* DESCRIPTION +* Gets the base LID of a port. +* +* SYNOPSIS +*/ +static inline ib_net16_t +osm_port_get_base_lid( + IN const osm_port_t* const p_port ) +{ + const osm_physp_t* const p_physp = p_port->tbl[p_port->default_port_num]; + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + return( osm_physp_get_base_lid( p_physp )); +} +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object. +* +* RETURN VALUE +* Base LID of the port. +* If the return value is 0, then this port has no assigned LID. +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_get_lmc +* NAME +* osm_port_get_lmc +* +* DESCRIPTION +* Gets the LMC value of a port. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_port_get_lmc( + IN const osm_port_t* const p_port ) +{ + const osm_physp_t* const p_physp = p_port->tbl[p_port->default_port_num]; + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + return( osm_physp_get_lmc( p_physp )); +} +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object. +* +* RETURN VALUE +* Gets the LMC value of a port. +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_get_guid +* NAME +* osm_port_get_guid +* +* DESCRIPTION +* Gets the GUID of a port. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_port_get_guid( + IN const osm_port_t* const p_port ) +{ + return( p_port->guid ); +} +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object. +* +* RETURN VALUE +* Manufacturer assigned GUID of the port. +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_get_num_physp +* NAME +* osm_port_get_num_physp +* +* DESCRIPTION +* Returns the number of Physical Port objects associated with this port. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_port_get_num_physp( + IN const osm_port_t* const p_port ) +{ + return( p_port->physp_tbl_size ); +} +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object. +* +* RETURN VALUE +* Returns the number of Physical Port objects associated with this port. +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_get_phys_ptr +* NAME +* osm_port_get_phys_ptr +* +* DESCRIPTION +* Gets the pointer to the specified Physical Port object. +* +* SYNOPSIS +*/ +static inline osm_physp_t* +osm_port_get_phys_ptr( + IN const osm_port_t* const p_port, + IN const uint8_t port_num ) +{ + CL_ASSERT( port_num < p_port->physp_tbl_size ); + return( p_port->tbl[port_num] ); +} +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object. +* +* port_num +* [in] Number of physical port for which to return the +* osm_physp_t object. If this port is on an HCA, then +* this value is ignored. +* +* RETURN VALUE +* Pointer to the Physical Port object. +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_get_default_phys_ptr +* NAME +* osm_port_get_default_phys_ptr +* +* DESCRIPTION +* Gets the pointer to the default Physical Port object. +* This call should only be used for non-switch ports in which there +* is a one-for-one mapping of port to physp. +* +* SYNOPSIS +*/ +static inline +osm_physp_t* +osm_port_get_default_phys_ptr( + IN const osm_port_t* const p_port ) +{ + CL_ASSERT( p_port->tbl[p_port->default_port_num] ); + CL_ASSERT( osm_physp_is_valid( p_port->tbl[p_port->default_port_num] ) ); + return( p_port->tbl[p_port->default_port_num] ); +} +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object. +* +* RETURN VALUE +* Pointer to the Physical Port object. +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_get_parent_node +* NAME +* osm_port_get_parent_node +* +* DESCRIPTION +* Gets the pointer to the this port's Node object. +* +* SYNOPSIS +*/ +static inline struct _osm_node* +osm_port_get_parent_node( + IN const osm_port_t* const p_port ) +{ + return( p_port->p_node ); +} +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object. +* +* port_num +* [in] Number of physical port for which to return the +* osm_physp_t object. +* +* RETURN VALUE +* Pointer to the Physical Port object. +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_get_lid_range_ho +* NAME +* osm_port_get_lid_range_ho +* +* DESCRIPTION +* Returns the HOST ORDER lid min and max values for this port, +* based on the lmc value. +* +* SYNOPSIS +*/ +void +osm_port_get_lid_range_ho( + IN const osm_port_t* const p_port, + OUT uint16_t* const p_min_lid, + OUT uint16_t* const p_max_lid ); +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object. +* +* p_min_lid +* [out] Pointer to the minimum LID value occupied by this port. +* +* p_max_lid +* [out] Pointer to the maximum LID value occupied by this port. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_get_port_by_base_lid +* NAME +* osm_get_port_by_base_lid +* +* DESCRIPTION +* Returns a status on whether a Port was able to be +* determined based on the LID supplied and if so, return the Port. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_get_port_by_base_lid( + IN const osm_subn_t* const p_subn, + IN const ib_net16_t lid, + IN OUT const osm_port_t** const pp_port ); +/* +* PARAMETERS +* p_subn +* [in] Pointer to the subnet data structure. +* +* lid +* [in] LID requested. +* +* pp_port +* [in][out] Pointer to pointer to Port object. +* +* RETURN VALUES +* IB_SUCCESS +* IB_NOT_FOUND +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_add_new_physp +* NAME +* osm_port_add_new_physp +* +* DESCRIPTION +* Adds a new physical port to the logical collection owned by the Port. +* Physical Ports added here must share the same GUID as the Port. +* +* SYNOPSIS +*/ +void +osm_port_add_new_physp( + IN osm_port_t* const p_port, + IN const uint8_t port_num ); +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object. +* +* port_num +* [in] Port number to add. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_discovery_count_reset +* NAME +* osm_port_discovery_count_reset +* +* DESCRIPTION +* Resets the discovery count for this Port to zero. +* This operation should be performed at the start of a sweep. +* +* SYNOPSIS +*/ +static inline void +osm_port_discovery_count_reset( + IN osm_port_t* const p_port ) +{ + p_port->discovery_count = 0; +} +/* +* PARAMETERS +* p_port +* [in] Pointer to an osm_port_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Port object +*********/ + +/****f* OpenSM: Port/osm_port_discovery_count_get +* NAME +* osm_port_discovery_count_get +* +* DESCRIPTION +* Returns the number of times this port has been discovered +* since the last time the discovery count was reset. +* +* SYNOPSIS +*/ +static inline uint32_t +osm_port_discovery_count_get( + IN const osm_port_t* const p_port ) +{ + return( p_port->discovery_count ); +} +/* +* PARAMETERS +* p_port +* [in] Pointer to an osm_port_t object. +* +* RETURN VALUES +* Returns the number of times this port has been discovered +* since the last time the discovery count was reset. +* +* NOTES +* +* SEE ALSO +* Port object +*********/ + +/****f* OpenSM: Port/osm_port_discovery_count_inc +* NAME +* osm_port_discovery_count_inc +* +* DESCRIPTION +* Increments the discovery count for this Port. +* +* SYNOPSIS +*/ +static inline void +osm_port_discovery_count_inc( + IN osm_port_t* const p_port ) +{ + p_port->discovery_count++; +} +/* +* PARAMETERS +* p_port +* [in] Pointer to an osm_port_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Port object +*********/ + +/****f* OpenSM: Port/osm_port_add_mgrp +* NAME +* osm_port_add_mgrp +* +* DESCRIPTION +* Logically connects a port to a multicast group. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_port_add_mgrp( + IN osm_port_t* const p_port, + IN const ib_net16_t mlid ); +/* +* PARAMETERS +* p_port +* [in] Pointer to an osm_port_t object. +* +* mlid +* [in] MLID of the multicast group. +* +* RETURN VALUES +* IB_SUCCESS +* IB_INSUFFICIENT_MEMORY +* +* NOTES +* +* SEE ALSO +* Port object +*********/ + +/****f* OpenSM: Port/osm_port_remove_mgrp +* NAME +* osm_port_remove_mgrp +* +* DESCRIPTION +* Logically disconnects a port from a multicast group. +* +* SYNOPSIS +*/ +void +osm_port_remove_mgrp( + IN osm_port_t* const p_port, + IN const ib_net16_t mlid ); +/* +* PARAMETERS +* p_port +* [in] Pointer to an osm_port_t object. +* +* mlid +* [in] MLID of the multicast group. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Port object +*********/ + +/****f* OpenSM: Port/osm_port_remove_all_mgrp +* NAME +* osm_port_remove_all_mgrp +* +* DESCRIPTION +* Logically disconnects a port from all its multicast groups. +* +* SYNOPSIS +*/ +void +osm_port_remove_all_mgrp( + IN osm_port_t* const p_port ); +/* +* PARAMETERS +* p_port +* [in] Pointer to an osm_port_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Port object +*********/ + +/****f* OpenSM: Physical Port/osm_physp_calc_link_mtu +* NAME +* osm_physp_calc_link_mtu +* +* DESCRIPTION +* Calculate the Port MTU based on current and remote +* physical ports MTU CAP values. +* +* SYNOPSIS +*/ +uint8_t +osm_physp_calc_link_mtu( + IN osm_log_t* p_log, + IN const osm_physp_t* p_physp ); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* The MTU of the link to be used. +* +* NOTES +* +* SEE ALSO +* PhysPort object +*********/ + +/****f* OpenSM: Physical Port/osm_physp_calc_link_op_vls +* NAME +* osm_physp_calc_link_op_vls +* +* DESCRIPTION +* Calculate the Port OP_VLS based on current and remote +* physical ports VL CAP values. Allowing user option for a max limit. +* +* SYNOPSIS +*/ +uint8_t +osm_physp_calc_link_op_vls( + IN osm_log_t* p_log, + IN const osm_subn_t * p_subn, + IN const osm_physp_t* p_physp ); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to the subnet object for accessing of the options. +* +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* The OP_VLS of the link to be used. +* +* NOTES +* +* SEE ALSO +* PhysPort object +*********/ + +/****f* OpenSM: Physical Port/osm_physp_replace_dr_path_with_alternate_dr_path +* NAME +* osm_physp_replace_dr_path_with_alternate_dr_path +* +* DESCRIPTION +* Replace the direct route path for the given phys port with an +* alternate path going through forien set of phys port. +* +* SYNOPSIS +*/void +osm_physp_replace_dr_path_with_alternate_dr_path( + IN osm_log_t *p_log, + IN osm_subn_t const *p_subn, + IN osm_physp_t const *p_physp, + IN osm_bind_handle_t *h_bind ); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to the subnet object for accessing of the options. +* +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* h_bind +* [in] Pointer to osm_bind_handle_t object. +* +* RETURN VALUES +* NONE +* +* NOTES +* +* SEE ALSO +* PhysPort object +*********/ + +END_C_DECLS + +#endif /* _OSM_PORT_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port_info_rcv.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port_info_rcv.h new file mode 100644 index 00000000..67b2a164 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port_info_rcv.h @@ -0,0 +1,274 @@ +/* + * 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: + * Declaration of osm_pi_rcv_t. + * This object represents the PortInfo Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_PI_RCV_H_ +#define _OSM_PI_RCV_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 Info Receiver +* NAME +* Port Info Receiver +* +* DESCRIPTION +* The Port Info Receiver object encapsulates the information +* needed to receive the PortInfo attribute from a node. +* +* The Port Info Receiver 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: Port Info Receiver/osm_pi_rcv_t +* NAME +* osm_pi_rcv_t +* +* DESCRIPTION +* Port Info Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_pi_rcv +{ + osm_subn_t *p_subn; + osm_req_t *p_req; + osm_log_t *p_log; + osm_state_mgr_t *p_state_mgr; + cl_plock_t *p_lock; +} osm_pi_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_req +* Pointer to the generic attribute request object. +* +* p_log +* Pointer to the log object. +* +* p_state_mgr +* Pointer to the State Manager object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* Port Info Receiver object +*********/ + +/****f* OpenSM: Port Info Receiver/osm_pi_rcv_construct +* NAME +* osm_pi_rcv_construct +* +* DESCRIPTION +* This function constructs a Port Info Receiver object. +* +* SYNOPSIS +*/ +void osm_pi_rcv_construct( + IN osm_pi_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Port Info Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_pi_rcv_destroy +* +* Calling osm_pi_rcv_construct is a prerequisite to calling any other +* method except osm_pi_rcv_init. +* +* SEE ALSO +* Port Info Receiver object, osm_pi_rcv_init, +* osm_pi_rcv_destroy +*********/ + +/****f* OpenSM: Port Info Receiver/osm_pi_rcv_destroy +* NAME +* osm_pi_rcv_destroy +* +* DESCRIPTION +* The osm_pi_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_pi_rcv_destroy( + IN osm_pi_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Port Info Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_pi_rcv_construct or osm_pi_rcv_init. +* +* SEE ALSO +* Port Info Receiver object, osm_pi_rcv_construct, +* osm_pi_rcv_init +*********/ + +/****f* OpenSM: Port Info Receiver/osm_pi_rcv_init +* NAME +* osm_pi_rcv_init +* +* DESCRIPTION +* The osm_pi_rcv_init function initializes a +* Port Info Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_pi_rcv_init( + IN osm_pi_rcv_t* const p_ctrl, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_state_mgr_t* const p_state_mgr, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_pi_rcv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_state_mgr +* [in] Pointer to the state manager object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the Port Info Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other Port Info Receiver methods. +* +* SEE ALSO +* Port Info Receiver object, osm_pi_rcv_construct, +* osm_pi_rcv_destroy +*********/ + +/****f* OpenSM: Port Info Receiver/osm_pi_rcv_process +* NAME +* osm_pi_rcv_process +* +* DESCRIPTION +* Process the PortInfo attribute. +* +* SYNOPSIS +*/ +void osm_pi_rcv_process( + IN const osm_pi_rcv_t* const p_ctrl, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_pi_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's PortInfo attribute. +* +* RETURN VALUES +* None. +* +* NOTES +* This function processes a PortInfo attribute. +* +* SEE ALSO +* Port Info Receiver, Port Info Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_PI_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port_info_rcv_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port_info_rcv_ctrl.h new file mode 100644 index 00000000..47bf31ea --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port_info_rcv_ctrl.h @@ -0,0 +1,261 @@ +/* + * 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: + * Declaration of osm_pi_rcv_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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_PI_RCV_CTRL_H_ +#define _OSM_PI_RCV_CTRL_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/Port Info Receive Controller +* NAME +* Port Info Receive Controller +* +* DESCRIPTION +* The Port Info Receive Controller object encapsulates +* the information needed to receive the NodeInfo attribute from a node. +* +* The Port Info Receive 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: Port Info Receive Controller/osm_pi_rcv_ctrl_t +* NAME +* osm_pi_rcv_ctrl_t +* +* DESCRIPTION +* Port Info Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_pi_rcv_ctrl +{ + osm_pi_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_pi_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the Port Info Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Port Info Receive Controller object +* Port Info Receiver object +*********/ + +/****f* OpenSM: Port Info Receive Controller/osm_pi_rcv_ctrl_construct +* NAME +* osm_pi_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Port Info Receive Controller object. +* +* SYNOPSIS +*/ +void osm_pi_rcv_ctrl_construct( + IN osm_pi_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Port Info Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_pi_rcv_ctrl_init, osm_pi_rcv_ctrl_destroy, +* and osm_pi_rcv_ctrl_is_inited. +* +* Calling osm_pi_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_pi_rcv_ctrl_init. +* +* SEE ALSO +* Port Info Receive Controller object, osm_pi_rcv_ctrl_init, +* osm_pi_rcv_ctrl_destroy, osm_pi_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Port Info Receive Controller/osm_pi_rcv_ctrl_destroy +* NAME +* osm_pi_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_pi_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_pi_rcv_ctrl_destroy( + IN osm_pi_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Port Info Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_pi_rcv_ctrl_construct or osm_pi_rcv_ctrl_init. +* +* SEE ALSO +* Port Info Receive Controller object, osm_pi_rcv_ctrl_construct, +* osm_pi_rcv_ctrl_init +*********/ + +/****f* OpenSM: Port Info Receive Controller/osm_pi_rcv_ctrl_init +* NAME +* osm_pi_rcv_ctrl_init +* +* DESCRIPTION +* The osm_pi_rcv_ctrl_init function initializes a +* Port Info Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_pi_rcv_ctrl_init( + IN osm_pi_rcv_ctrl_t* const p_ctrl, + IN osm_pi_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_pi_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_pi_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Port Info Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Port Info Receive Controller methods. +* +* SEE ALSO +* Port Info Receive Controller object, osm_pi_rcv_ctrl_construct, +* osm_pi_rcv_ctrl_destroy, osm_pi_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Port Info Receive Controller/osm_pi_rcv_ctrl_is_inited +* NAME +* osm_pi_rcv_ctrl_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_pi_rcv_ctrl_init. +* +* SYNOPSIS +*/ +boolean_t osm_pi_rcv_ctrl_is_inited( + IN const osm_pi_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_pi_rcv_ctrl_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_pi_rcv_ctrl_construct or osm_pi_rcv_ctrl_init must be +* called before using this function. +* +* SEE ALSO +* Port Info Receive Controller object, osm_pi_rcv_ctrl_construct, +* osm_pi_rcv_ctrl_init +*********/ + +END_C_DECLS + +#endif /* _OSM_PI_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port_profile.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port_profile.h new file mode 100644 index 00000000..7e516426 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_port_profile.h @@ -0,0 +1,291 @@ +/* + * 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: + * 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#ifndef _OSM_PORT_PROFILE_H_ +#define _OSM_PORT_PROFILE_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/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 +*********/ + +/****f* OpenSM: Port Profile/osm_port_prof_construct +* NAME +* osm_port_prof_construct +* +* DESCRIPTION +* +* +* SYNOPSIS +*/ +static inline void +osm_port_prof_construct( + IN osm_port_profile_t* const p_prof ) +{ + CL_ASSERT( p_prof ); + memset( p_prof, 0, sizeof(*p_prof) ); +} +/* +* PARAMETERS +* p_prof +* [in] Pointer to the Port Profile object to construct. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Port Profile/osm_port_prof_path_count_inc +* NAME +* osm_port_prof_path_count_inc +* +* DESCRIPTION +* Increments the count of the number of paths going through this port. +* +* +* SYNOPSIS +*/ +static inline void +osm_port_prof_path_count_inc( + IN osm_port_profile_t* const p_prof ) +{ + CL_ASSERT( p_prof ); + p_prof->num_paths++; +} +/* +* PARAMETERS +* p_pro +* [in] Pointer to the Port Profile object. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Port Profile/osm_port_prof_path_count_get +* NAME +* osm_port_prof_path_count_get +* +* DESCRIPTION +* Returns the count of the number of paths going through this port. +* +* SYNOPSIS +*/ +static inline uint32_t +osm_port_prof_path_count_get( + IN const osm_port_profile_t* const p_prof ) +{ + return( p_prof->num_paths ); +} +/* +* PARAMETERS +* p_pro +* [in] Pointer to the Port Profile object. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Port Profile Opt/osm_port_prof_is_ignored_port +* NAME +* osm_port_prof_is_ignored_port +* +* DESCRIPTION +* Check to see if this port is to be ignored in path counting. +* This is done by examining the optional list of port_prof_ignore_guids. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_port_prof_is_ignored_port( + IN const osm_subn_t *p_subn, + IN uint64_t port_guid, + IN uint8_t port_num ) +{ + const cl_map_t *p_map = &(p_subn->opt.port_prof_ignore_guids); + const void *p_obj = cl_map_get(p_map, port_guid); + size_t res; + + // HACK: we currently support ignoring ports 0 - 31 + if (p_obj != NULL) { + res = (size_t)p_obj & (size_t)(1 << port_num); + return (res != 0); + } + return FALSE; +} +/* +* PARAMETERS +* p_subn +* [in] Pointer to the OSM Subnet object. +* +* port_guid +* [in] The port guid +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Port Profile Opt/osm_port_prof_set_ignored_port +* NAME +* osm_port_prof_set_ignored_port +* +* DESCRIPTION +* Set the ignored property of the port. +* +* SYNOPSIS +*/ +static inline void +osm_port_prof_set_ignored_port( + IN osm_subn_t *p_subn, + IN uint64_t port_guid, + IN uint8_t port_num ) +{ + cl_map_t *p_map = &(p_subn->opt.port_prof_ignore_guids); + const void *p_obj = cl_map_get(p_map, port_guid); + size_t value = 0; + + // HACK: we currently support ignoring ports 0 - 31 + CL_ASSERT(port_num < 32); + + if (p_obj != NULL) { + value = (size_t)p_obj; + } + + value = value | ((size_t)1 << port_num); //size_t will be 64 bit length in Win2003_64 + cl_map_insert(&(p_subn->opt.port_prof_ignore_guids), + port_guid, + (void *)value); +} +/* +* PARAMETERS +* p_subn +* [in] Pointer to the OSM Subnet object. +* +* port_guid +* [in] The port guid +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_PORT_PROFILE_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_rand_fwd_tbl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_rand_fwd_tbl.h new file mode 100644 index 00000000..bc362adc --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_rand_fwd_tbl.h @@ -0,0 +1,354 @@ +/* + * 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: + * Declaration of osm_switch_t. + * This object represents an IBA switch. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_RAND_FWD_TBL_H_ +#define _OSM_RAND_FWD_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 + +/****h* OpenSM/Random Forwarding Table +* NAME +* Random Forwarding Table +* +* DESCRIPTION +* The Random Forwarding Table objects encapsulate the information +* needed by the OpenSM to manage random forwarding tables. The OpenSM +* allocates one Random Forwarding Table object per switch in the +* IBA subnet, if that switch uses a random forwarding table. +* +* The Random Forwarding Table objects are not thread safe, thus +* callers must provide serialization. +* +* ** RANDOM FORWARDING TABLES ARE NOT SUPPORTED IN THE CURRENT VERSION ** +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Forwarding Table/osm_rand_fwd_tbl_t +* NAME +* osm_rand_fwd_tbl_t +* +* DESCRIPTION +* Random Forwarding Table structure. +* +* THIS OBJECT IS PLACE HOLDER. SUPPORT FOR SWITCHES WITH +* RANDOM FORWARDING TABLES HAS NOT BEEN IMPLEMENTED YET. +* +* SYNOPSIS +*/ +typedef struct _osm_rand_fwd_tbl +{ + /* PLACE HOLDER STRUCTURE ONLY!! */ + uint32_t size; +} osm_rand_fwd_tbl_t; +/* +* FIELDS +* RANDOM FORWARDING TABLES ARE NOT SUPPORTED YET!! +* +* SEE ALSO +* Forwarding Table object, Random Forwarding Table object. +*********/ + +/****f* OpenSM: Forwarding Table/osm_rand_tbl_delete +* NAME +* osm_rand_tbl_delete +* +* DESCRIPTION +* This destroys and deallocates a Random Forwarding Table object. +* +* SYNOPSIS +*/ +static inline void +osm_rand_tbl_delete( + IN osm_rand_fwd_tbl_t** const pp_tbl ) +{ + /* + TO DO - This is a place holder function only! + */ + free( *pp_tbl ); + *pp_tbl = NULL; +} +/* +* PARAMETERS +* pp_tbl +* [in] Pointer a Pointer to the Random Forwarding Table object. +* +* RETURN VALUE +* On success, returns a pointer to a new Linear Forwarding Table object +* of the specified size. +* NULL otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_rand_fwd_tbl_set +* NAME +* osm_rand_fwd_tbl_set +* +* DESCRIPTION +* Sets the port to route the specified LID. +* +* SYNOPSIS +*/ +static inline void +osm_rand_fwd_tbl_set( + IN osm_rand_fwd_tbl_t* const p_tbl, + IN const uint16_t lid_ho, + IN const uint8_t port ) +{ + /* Random forwarding tables not supported yet. */ + UNUSED_PARAM( p_tbl ); + UNUSED_PARAM( lid_ho ); + UNUSED_PARAM( port ); + CL_ASSERT( FALSE ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Random Forwarding Table object. +* +* lid_ho +* [in] LID value (host order) for which to set the route. +* +* port +* [in] Port to route the specified LID value. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_rand_fwd_tbl_set_block +* NAME +* osm_rand_fwd_tbl_set_block +* +* DESCRIPTION +* Copies the specified block into the Random Forwarding Table. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +osm_rand_fwd_tbl_set_block( + IN osm_rand_fwd_tbl_t* const p_tbl, + IN const uint8_t* const p_block, + IN const uint32_t block_num ) +{ + /* Random forwarding tables not supported yet. */ + UNUSED_PARAM( p_tbl ); + UNUSED_PARAM( p_block ); + UNUSED_PARAM( block_num ); + CL_ASSERT( FALSE ); + return( IB_ERROR ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Random 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_rand_fwd_tbl_get +* NAME +* osm_rand_fwd_tbl_get +* +* DESCRIPTION +* Returns the port that routes the specified LID. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_rand_fwd_tbl_get( + IN const osm_rand_fwd_tbl_t* const p_tbl, + IN const uint16_t lid_ho ) +{ + CL_ASSERT( FALSE ); + UNUSED_PARAM( p_tbl ); + UNUSED_PARAM( lid_ho ); + + return( OSM_NO_PATH ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Linear Forwarding Table object. +* +* lid_ho +* [in] LID value (host order) for which to get the route. +* +* RETURN VALUE +* Returns the port that routes the specified LID. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_rand_fwd_tbl_get_lids_per_block +* NAME +* osm_rand_fwd_tbl_get_lids_per_block +* +* DESCRIPTION +* Returns the number of LIDs per LID block. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_rand_fwd_tbl_get_lids_per_block( + IN const osm_rand_fwd_tbl_t* const p_tbl ) +{ + UNUSED_PARAM( p_tbl ); + return( 16 ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* RETURN VALUE +* Returns the number of LIDs per LID block. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_rand_fwd_tbl_get_max_block_id_in_use +* NAME +* osm_rand_fwd_tbl_get_max_block_id_in_use +* +* DESCRIPTION +* Returns the maximum block ID in actual use by the forwarding table. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_rand_fwd_tbl_get_max_block_id_in_use( + IN const osm_rand_fwd_tbl_t* const p_tbl, + IN const uint16_t lid_top_ho ) +{ + UNUSED_PARAM( p_tbl ); + UNUSED_PARAM( lid_top_ho ); + CL_ASSERT( FALSE ); + return( 0 ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* RETURN VALUE +* Returns the maximum block ID in actual use by the forwarding table. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_rand_fwd_tbl_get_size +* NAME +* osm_rand_fwd_tbl_get_size +* +* DESCRIPTION +* Returns the number of entries available in the forwarding table. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_rand_fwd_tbl_get_size( + IN const osm_rand_fwd_tbl_t* const p_tbl ) +{ + UNUSED_PARAM( p_tbl ); + CL_ASSERT( FALSE ); + return( 0 ); +} +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Forwarding Table object. +* +* RETURN VALUE +* Returns the number of entries available in the forwarding table. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_RAND_FWD_TBL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_remote_sm.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_remote_sm.h new file mode 100644 index 00000000..da4b6f71 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_remote_sm.h @@ -0,0 +1,212 @@ +/* + * 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: + * Declaration of osm_sm_t, osm_remote_sm_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_REMOTE_SM_H_ +#define _OSM_REMOTE_SM_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/Remote SM +* NAME +* Remote SM +* +* DESCRIPTION +* The Remote SM object encapsulates the information tracked for +* other SM ports on the subnet. +* +* The Remote SM object is thread safe. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Remote SM/osm_remote_sm_t +* NAME +* osm_remote_sm_t +* +* DESCRIPTION +* Remote Subnet Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_remote_sm +{ + cl_map_item_t map_item; + const osm_port_t *p_port; + ib_sm_info_t smi; +} osm_remote_sm_t; +/* +* FIELDS +* map_item +* Linkage for the cl_qmap container. MUST BE FIRST ELEMENT!! +* p_port +* Pointer to the port object for this SM. +* +* smi +* The SMInfo attribute for this SM. +* +* SEE ALSO +*********/ + +/****f* OpenSM: SM/osm_remote_sm_construct +* NAME +* osm_remote_sm_construct +* +* DESCRIPTION +* This function constructs an Remote SM object. +* +* SYNOPSIS +*/ +void +osm_remote_sm_construct( + IN osm_remote_sm_t* const p_sm ); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an Remote SM object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_remote_sm_init, osm_remote_sm_destroy +* +* Calling osm_remote_sm_construct is a prerequisite to calling any other +* method except osm_remote_sm_init. +* +* SEE ALSO +* SM object, osm_remote_sm_init, osm_remote_sm_destroy +*********/ + +/****f* OpenSM: SM/osm_remote_sm_destroy +* NAME +* osm_remote_sm_destroy +* +* DESCRIPTION +* The osm_remote_sm_destroy function destroys an SM, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_remote_sm_destroy( + IN osm_remote_sm_t* const p_sm ); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an Remote SM object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Remote SM object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_remote_sm_construct or osm_remote_sm_init. +* +* SEE ALSO +* Remote SM object, osm_remote_sm_construct, osm_remote_sm_init +*********/ + +/****f* OpenSM: SM/osm_remote_sm_init +* NAME +* osm_remote_sm_init +* +* DESCRIPTION +* The osm_remote_sm_init function initializes an Remote SM object for use. +* +* SYNOPSIS +*/ +void +osm_remote_sm_init( + IN osm_remote_sm_t* const p_sm, + IN const osm_port_t* const p_port, + IN const ib_sm_info_t* const p_smi ); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_remote_sm_t object to initialize. +* +* p_port +* [in] Pointer to the Remote SM's port object. +* +* p_smi +* [in] Pointer to the SMInfo attribute for this SM. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* Allows calling other Remote SM methods. +* +* SEE ALSO +* Remote SM object, osm_remote_sm_construct, osm_remote_sm_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_REMOTE_SM_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_req.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_req.h new file mode 100644 index 00000000..aed298c1 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_req.h @@ -0,0 +1,354 @@ +/* + * 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: + * Declaration of osm_req_t. + * This object represents an object that genericly requests + * attributes from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_REQ_H_ +#define _OSM_REQ_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/Generic Requester +* NAME +* Generic Requester +* +* DESCRIPTION +* The Generic Requester object encapsulates the information +* needed to request an attribute from a node. +* +* The Generic Requester 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: Generic Requester/osm_req_t +* NAME +* osm_req_t +* +* DESCRIPTION +* Generic Requester structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_req +{ + osm_mad_pool_t *p_pool; + osm_vl15_t *p_vl15; + osm_log_t *p_log; + osm_subn_t *p_subn; + atomic32_t *p_sm_trans_id; + +} osm_req_t; +/* +* FIELDS +* p_pool +* Pointer to the MAD pool. +* +* p_vl15 +* Pointer to the VL15 interface. +* +* p_log +* Pointer to the log object. +* +* p_subn +* Pointer to the subnet object. +* +* SEE ALSO +* Generic Requester object +*********/ + +/****f* OpenSM: Generic Requester/osm_req_construct +* NAME +* osm_req_construct +* +* DESCRIPTION +* This function constructs a Generic Requester object. +* +* SYNOPSIS +*/ +void +osm_req_construct( + IN osm_req_t* const p_req ); +/* +* PARAMETERS +* p_req +* [in] Pointer to a Generic Requester object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_req_init, and osm_req_destroy. +* +* Calling osm_req_construct is a prerequisite to calling any other +* method except osm_req_init. +* +* SEE ALSO +* Generic Requester object, osm_req_init, +* osm_req_destroy +*********/ + +/****f* OpenSM: Generic Requester/osm_req_destroy +* NAME +* osm_req_destroy +* +* DESCRIPTION +* The osm_req_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_req_destroy( + IN osm_req_t* const p_req ); +/* +* PARAMETERS +* p_req +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Generic Requester object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_req_construct or osm_req_init. +* +* SEE ALSO +* Generic Requester object, osm_req_construct, +* osm_req_init +*********/ + +/****f* OpenSM: Generic Requester/osm_req_init +* NAME +* osm_req_init +* +* DESCRIPTION +* The osm_req_init function initializes a +* Generic Requester object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_req_init( + IN osm_req_t* const p_req, + IN osm_mad_pool_t* const p_pool, + IN osm_vl15_t* const p_vl15, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN atomic32_t* const p_sm_trans_id ); +/* +* PARAMETERS +* p_req +* [in] Pointer to an osm_req_t object to initialize. +* +* p_mad_pool +* [in] Pointer to the MAD pool. +* +* p_vl15 +* [in] Pointer to the VL15 interface. +* +* p_subn +* [in] Pointer to the subnet object. +* +* p_log +* [in] Pointer to the log object. +* +* p_sm_trans_id +* [in] Pointer to the atomic SM transaction ID. +* +* RETURN VALUES +* IB_SUCCESS if the Generic Requester object was initialized +* successfully. +* +* NOTES +* Allows calling other Generic Requester methods. +* +* SEE ALSO +* Generic Requester object, osm_req_construct, +* osm_req_destroy +*********/ + +/****f* OpenSM: Generic Requester/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 const osm_req_t* const p_req, + IN const osm_dr_path_t* const p_path, + IN const uint16_t attr_id, + IN const uint32_t attr_mod, + IN const cl_disp_msgid_t err_msg, + IN const osm_madw_context_t* const p_context ); +/* +* PARAMETERS +* p_req +* [in] Pointer to an osm_req_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. +* +* SEE ALSO +* Generic Requester +*********/ +/****f* OpenSM: Generic Requester/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 const osm_req_t* const p_req, + IN const osm_dr_path_t* const p_path, + IN const uint8_t* const p_payload, + IN const size_t payload_size, + IN const uint16_t attr_id, + IN const uint32_t attr_mod, + IN const cl_disp_msgid_t err_msg, + IN const osm_madw_context_t* const p_context ); +/* +* PARAMETERS +* p_req +* [in] Pointer to an osm_req_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. +* +* SEE ALSO +* Generic Requester +*********/ + +END_C_DECLS + +#endif /* _OSM_REQ_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_req_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_req_ctrl.h new file mode 100644 index 00000000..1113d056 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_req_ctrl.h @@ -0,0 +1,228 @@ +/* + * 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: + * Declaration of osm_req_ctrl_t. + * This object represents a controller that calls the + * generic requester object to retrieve attributes from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_REQ_CTRL_H_ +#define _OSM_REQ_CTRL_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/Generic Request Controller +* NAME +* Generic Request Controller +* +* DESCRIPTION +* The Generic Request Controller object encapsulates the information +* needed to request an attribute from a node. +* +* The Generic Request 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: Generic Request Controller/osm_req_ctrl_t +* NAME +* osm_req_ctrl_t +* +* DESCRIPTION +* Generic Request Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_req_ctrl +{ + osm_req_t *p_req; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_req_ctrl_t; +/* +* FIELDS +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Generic Request Controller object +*********/ + +/****f* OpenSM: Generic Request Controller/osm_req_ctrl_construct +* NAME +* osm_req_ctrl_construct +* +* DESCRIPTION +* This function constructs a Generic Request Controller object. +* +* SYNOPSIS +*/ +void +osm_req_ctrl_construct( + IN osm_req_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Generic Request Controller object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_req_ctrl_init, and osm_req_ctrl_destroy. +* +* Calling osm_req_ctrl_construct is a prerequisite to calling any other +* method except osm_req_ctrl_init. +* +* SEE ALSO +* Generic Request Controller object, osm_req_ctrl_init, +* osm_req_ctrl_destroy +*********/ + +/****f* OpenSM: Generic Request Controller/osm_req_ctrl_destroy +* NAME +* osm_req_ctrl_destroy +* +* DESCRIPTION +* The osm_req_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_req_ctrl_destroy( + IN osm_req_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Generic Request Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_req_ctrl_construct or osm_req_ctrl_init. +* +* SEE ALSO +* Generic Request Controller object, osm_req_ctrl_construct, +* osm_req_ctrl_init +*********/ + +/****f* OpenSM: Generic Request Controller/osm_req_ctrl_init +* NAME +* osm_req_ctrl_init +* +* DESCRIPTION +* The osm_req_ctrl_init function initializes a +* Generic Request Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_req_ctrl_init( + IN osm_req_ctrl_t* const p_ctrl, + IN osm_req_t* const p_req, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_req_ctrl_t object to initialize. +* +* p_req +* [in] Pointer to a Generic Requester object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Generic Request Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Generic Request Controller methods. +* +* SEE ALSO +* Generic Request Controller object, osm_req_ctrl_construct, +* Generic Requester object, osm_req_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_REQ_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_resp.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_resp.h new file mode 100644 index 00000000..9a5977a0 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_resp.h @@ -0,0 +1,279 @@ +/* + * 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: + * Declaration of osm_resp_t. + * This object represents an object that genericly requests + * attributes from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_RESP_H_ +#define _OSM_RESP_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/Generic Responder +* NAME +* Generic Responder +* +* DESCRIPTION +* The Generic Responder object encapsulates the information +* needed to respond to an attribute from a node. +* +* The Generic Responder 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: Generic Responder/osm_resp_t +* NAME +* osm_resp_t +* +* DESCRIPTION +* Generic Responder structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_resp +{ + osm_mad_pool_t *p_pool; + osm_vl15_t *p_vl15; + osm_log_t *p_log; + osm_subn_t *p_subn; + +} osm_resp_t; +/* +* FIELDS +* p_pool +* Pointer to the MAD pool. +* +* p_vl15 +* Pointer to the VL15 interface. +* +* p_log +* Pointer to the log object. +* +* p_subn +* Pointer to the subnet object. +* +* SEE ALSO +* Generic Responder object +*********/ + +/****f* OpenSM: Generic Responder/osm_resp_construct +* NAME +* osm_resp_construct +* +* DESCRIPTION +* This function constructs a Generic Responder object. +* +* SYNOPSIS +*/ +void +osm_resp_construct( + IN osm_resp_t* const p_resp ); +/* +* PARAMETERS +* p_resp +* [in] Pointer to a Generic Responder object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_resp_init, osm_resp_destroy +* +* Calling osm_resp_construct is a prerequisite to calling any other +* method except osm_resp_init. +* +* SEE ALSO +* Generic Responder object, osm_resp_init, +* osm_resp_destroy +*********/ + +/****f* OpenSM: Generic Responder/osm_resp_destroy +* NAME +* osm_resp_destroy +* +* DESCRIPTION +* The osm_resp_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_resp_destroy( + IN osm_resp_t* const p_resp ); +/* +* PARAMETERS +* p_resp +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Generic Responder object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_resp_construct or osm_resp_init. +* +* SEE ALSO +* Generic Responder object, osm_resp_construct, +* osm_resp_init +*********/ + +/****f* OpenSM: Generic Responder/osm_resp_init +* NAME +* osm_resp_init +* +* DESCRIPTION +* The osm_resp_init function initializes a +* Generic Responder object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_resp_init( + IN osm_resp_t* const p_resp, + IN osm_mad_pool_t* const p_pool, + IN osm_vl15_t* const p_vl15, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log ); +/* +* PARAMETERS +* p_resp +* [in] Pointer to an osm_resp_t object to initialize. +* +* p_mad_pool +* [in] Pointer to the MAD pool. +* +* p_vl15 +* [in] Pointer to the VL15 interface. +* +* p_subn +* [in] Pointer to the subnet object. +* +* p_log +* [in] Pointer to the log object. +* +* RETURN VALUES +* IB_SUCCESS if the Generic Responder object was initialized +* successfully. +* +* NOTES +* Allows calling other Generic Responder methods. +* +* SEE ALSO +* Generic Responder object, osm_resp_construct, +* osm_resp_destroy +*********/ + +/****f* OpenSM: Generic Responder/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 const osm_resp_t* const p_resp, + IN const osm_madw_t* const p_req_madw, + IN const ib_net16_t status, + IN const uint8_t* const p_payload ); +/* +* PARAMETERS +* p_resp +* [in] Pointer to an osm_resp_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper object for the requesting MAD +* to which this response is generated. +* +* status +* [in] Status for this response. +* +* p_payload +* [in] Pointer to the payload of the response MAD. +* +* RETURN VALUES +* IB_SUCCESS if the response was successful. +* +* NOTES +* +* SEE ALSO +* Generic Responder +*********/ + +END_C_DECLS + +#endif /* _OSM_RESP_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_router.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_router.h new file mode 100644 index 00000000..91b04166 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_router.h @@ -0,0 +1,323 @@ +/* + * 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: + * Declaration of osm_router_t. + * This object represents an IBA router. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#ifndef _OSM_ROUTER_H_ +#define _OSM_ROUTER_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/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_construct +* NAME +* osm_router_construct +* +* DESCRIPTION +* This function constructs a Router object. +* +* SYNOPSIS +*/ +void +osm_router_construct( + IN osm_router_t* const p_rtr ); +/* +* PARAMETERS +* p_rtr +* [in] Pointer to a Router object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_router_init, and osm_router_destroy. +* +* Calling osm_router_construct is a prerequisite to calling any other +* method except osm_router_init. +* +* SEE ALSO +* Router object, osm_router_init, osm_router_destroy +*********/ + +/****f* OpenSM: Router/osm_router_destroy +* NAME +* osm_router_destroy +* +* DESCRIPTION +* The osm_router_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_router_destroy( + IN osm_router_t* const p_rtr ); +/* +* PARAMETERS +* p_rtr +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* None. +* +* NOTES +* Performs any necessary cleanup of the specified object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_router_construct +* or osm_router_init. +* +* SEE ALSO +* Router object, osm_router_construct, osm_router_init +*********/ + +/****f* OpenSM: Router/osm_router_destroy +* NAME +* osm_router_destroy +* +* DESCRIPTION +* Destroys and deallocates the object. +* +* SYNOPSIS +*/ +void +osm_router_delete( + IN OUT osm_router_t** const pp_rtr ); +/* +* PARAMETERS +* p_rtr +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +* Router object, osm_router_construct, osm_router_init +*********/ + +/****f* OpenSM: Router/osm_router_init +* NAME +* osm_router_init +* +* DESCRIPTION +* The osm_router_init function initializes a Router object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_router_init( + IN osm_router_t* const p_rtr, + IN osm_port_t* const p_port ); +/* +* PARAMETERS +* p_rtr +* [in] Pointer to an osm_router_t object to initialize. +* +* p_port +* [in] Pointer to the port object of this router +* +* RETURN VALUES +* IB_SUCCESS if the Router object was initialized successfully. +* +* NOTES +* Allows calling other node methods. +* +* SEE ALSO +* Router object, osm_router_construct, osm_router_destroy +*********/ + +/****f* OpenSM: Router/osm_router_new +* NAME +* osm_router_new +* +* DESCRIPTION +* The osm_router_init function initializes a Router object for use. +* +* SYNOPSIS +*/ +osm_router_t* +osm_router_new( + IN osm_port_t* const p_port ); +/* +* PARAMETERS +* p_node +* [in] Pointer to the node object of this router +* +* RETURN VALUES +* Pointer to the new initialized router object. +* +* NOTES +* +* SEE ALSO +* Router object, osm_router_construct, osm_router_destroy, +*********/ + +/****f* OpenSM: Router/osm_router_get_port_ptr +* NAME +* osm_router_get_port_ptr +* +* DESCRIPTION +* Returns a pointer to the Port object for this router. +* +* SYNOPSIS +*/ +static inline osm_port_t* +osm_router_get_port_ptr( + IN const osm_router_t* const p_rtr ) +{ + return( p_rtr->p_port ); +} +/* +* PARAMETERS +* p_rtr +* [in] Pointer to an osm_router_t object. +* +* RETURN VALUES +* Returns a pointer to the Port object for this router. +* +* NOTES +* +* SEE ALSO +* Router object +*********/ + +/****f* OpenSM: Router/osm_router_get_node_ptr +* NAME +* osm_router_get_node_ptr +* +* DESCRIPTION +* Returns a pointer to the Node object for this router. +* +* SYNOPSIS +*/ +static inline osm_node_t* +osm_router_get_node_ptr( + IN const osm_router_t* const p_rtr ) +{ + return( p_rtr->p_port->p_node ); +} +/* +* PARAMETERS +* p_rtr +* [in] Pointer to an osm_router_t object. +* +* RETURN VALUES +* Returns a pointer to the Node object for this router. +* +* NOTES +* +* SEE ALSO +* Router object +*********/ + +END_C_DECLS + +#endif /* _OSM_ROUTER_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa.h new file mode 100644 index 00000000..de0f64d0 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa.h @@ -0,0 +1,500 @@ +/* + * 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: + * Declaration of osm_sa_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +#ifndef _OSM_SA_H_ +#define _OSM_SA_H_ + +#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 + +#ifdef __cplusplus +# define 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_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; + osm_sa_resp_t resp; + osm_cpi_rcv_t cpi_rcv; + osm_cpi_rcv_ctrl_t cpi_rcv_ctrl; + osm_nr_rcv_t nr_rcv; + osm_nr_rcv_ctrl_t nr_rcv_ctrl; + osm_pir_rcv_t pir_rcv; + osm_pir_rcv_ctrl_t pir_rcv_ctrl; + osm_gir_rcv_t gir_rcv; + osm_gir_rcv_ctrl_t gir_rcv_ctrl; + osm_lr_rcv_t lr_rcv; + osm_lr_rcv_ctrl_t lr_rcv_ctrl; + osm_pr_rcv_t pr_rcv; + osm_pr_rcv_ctrl_t pr_rcv_ctrl; + osm_smir_rcv_t smir_rcv; + osm_smir_ctrl_t smir_ctrl; + osm_mcmr_recv_t mcmr_rcv; + osm_mcmr_rcv_ctrl_t mcmr_rcv_ctlr; + osm_sr_rcv_t sr_rcv; + osm_sr_rcv_ctrl_t sr_rcv_ctrl; +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + osm_mpr_rcv_t mpr_rcv; + osm_mpr_rcv_ctrl_t mpr_rcv_ctrl; +#endif + + /* InformInfo Receiver */ + osm_infr_rcv_t infr_rcv; + osm_infr_rcv_ctrl_t infr_rcv_ctrl; + + /* VL Arbitrartion Query */ + osm_vlarb_rec_rcv_t vlarb_rec_rcv; + osm_vlarb_rec_rcv_ctrl_t vlarb_rec_rcv_ctrl; + + /* SLtoVL Map Query */ + osm_slvl_rec_rcv_t slvl_rec_rcv; + osm_slvl_rec_rcv_ctrl_t slvl_rec_rcv_ctrl; + + /* P_Key table Query */ + osm_pkey_rec_rcv_t pkey_rec_rcv; + osm_pkey_rec_rcv_ctrl_t pkey_rec_rcv_ctrl; + + /* LinearForwardingTable Query */ + osm_lftr_rcv_t lftr_rcv; + osm_lftr_rcv_ctrl_t lftr_rcv_ctrl; + + /* SwitchInfo Query */ + osm_sir_rcv_t sir_rcv; + osm_sir_rcv_ctrl_t sir_rcv_ctrl; + + /* MulticastForwardingTable Query */ + osm_mftr_rcv_t mftr_rcv; + osm_mftr_rcv_ctrl_t mftr_rcv_ctrl; +} osm_sa_t; +/* +* FIELDS +* state +* State of this SA 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 +* +* resp +* Response object +* +* nr +* +* nr_ctrl +* +* pir_rcv +* +* pir_rcv_ctrl +* +* lr +* +* lr_ctrl +* +* pr +* +* pr_ctrl +* +* smir +* +* smir_ctrl +* +* SEE ALSO +* SM object +*********/ + +/****f* OpenSM: SA/osm_sa_construct +* NAME +* osm_sa_construct +* +* DESCRIPTION +* This function constructs an SA object. +* +* SYNOPSIS +*/ +void osm_sa_construct( + IN osm_sa_t* const p_sa ); +/* +* PARAMETERS +* p_sa +* [in] Pointer to a SA object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sa_init, osm_sa_destroy, and osm_sa_is_inited. +* +* 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, osm_sa_is_inited +*********/ + +/****f* OpenSM: SA/osm_sa_shutdown +* NAME +* osm_sa_shutdown +* +* DESCRIPTION +* The osm_sa_shutdown function shutdowns an SA, unregistering from all +* dispatcher messages and unbinding the QP1 mad service +* +* SYNOPSIS +*/ +void osm_sa_shutdown( + IN osm_sa_t* const p_sa ); +/* +* PARAMETERS +* p_sa +* [in] Pointer to a SA object to shutdown. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* SA object, osm_sa_construct, osm_sa_init +*********/ + +/****f* OpenSM: SA/osm_sa_destroy +* NAME +* osm_sa_destroy +* +* DESCRIPTION +* The osm_sa_destroy function destroys an SA, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_sa_destroy( + IN osm_sa_t* const p_sa ); +/* +* PARAMETERS +* p_sa +* [in] Pointer to a SA object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified SA object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_sa_construct or +* osm_sa_init. +* +* SEE ALSO +* SA object, osm_sa_construct, osm_sa_init +*********/ + +/****f* OpenSM: SA/osm_sa_init +* NAME +* osm_sa_init +* +* DESCRIPTION +* The osm_sa_init function initializes a SA object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_sa_init( + IN osm_sm_t* const p_sm, + IN osm_sa_t* const p_sa, + IN osm_subn_t* const p_subn, + IN osm_vendor_t* const p_vendor, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_log_t* const p_log, + IN osm_stats_t* const p_stats, + IN cl_dispatcher_t* const p_disp, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_sa +* [in] Pointer to an osm_sa_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_vendor +* [in] Pointer to the vendor specific interfaces object. +* +* p_mad_pool +* [in] Pointer to the MAD pool. +* +* p_log +* [in] Pointer to the log object. +* +* p_stats +* [in] Pointer to the statistics object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the SA object was initialized successfully. +* +* NOTES +* Allows calling other SA methods. +* +* SEE ALSO +* SA object, osm_sa_construct, osm_sa_destroy, +* osm_sa_is_inited +*********/ + +/****f* OpenSM: SA/osm_sa_is_inited +* NAME +* osm_sa_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_sa_init. +* +* SYNOPSIS +*/ +boolean_t osm_sa_is_inited( + IN const osm_sa_t* const p_sa ); +/* +* PARAMETERS +* p_sa +* [in] Pointer to an osm_sa_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_sa_construct or osm_sa_init must be called before using +* this function. +* +* SEE ALSO +* SA object, osm_sa_construct, osm_sa_init +*********/ + +/****f* OpenSM: SA/osm_sa_bind +* NAME +* osm_sa_bind +* +* DESCRIPTION +* Binds the SA object to a port guid. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sa_bind( + IN osm_sa_t* const p_sa, + IN const ib_net64_t port_guid ); +/* +* PARAMETERS +* p_sa +* [in] Pointer to an osm_sa_t object to bind. +* +* port_guid +* [in] Local port GUID with which to bind. +* +* +* RETURN VALUES +* None +* +* NOTES +* A given SA object can only be bound to one port at a time. +* +* SEE ALSO +*********/ + +struct _osm_opensm_t; +/****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_t *p_osm); +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object. +* +* RETURN VALUES +* None +* +*********/ + +/****f* OpenSM: SA/osm_sa_db_file_load +* NAME +* osm_sa_db_file_load +* +* DESCRIPTION +* Loads SA DB from the file. +* +* SYNOPSIS +*/ +int osm_sa_db_file_load(struct _osm_opensm_t *p_osm); +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object. +* +* RETURN VALUES +* 0 on success, other value on failure. +* +*********/ + +END_C_DECLS + +#endif /* _OSM_SA_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_class_port_info.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_class_port_info.h new file mode 100644 index 00000000..3869dbce --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_class_port_info.h @@ -0,0 +1,269 @@ +/* + * 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: + * Declaration of osm_cpi_rcv_t. + * This object represents the ClassPortInfo Receiver object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.2 $ + */ + +#ifndef _OSM_CPI_H_ +#define _OSM_CPI_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/ClassPort Info Receiver +* NAME +* ClassPort Info Receiver +* +* DESCRIPTION +* The ClassPort Info Receiver object encapsulates the information +* needed to receive the ClassPortInfo request from a node. +* +* The ClassPort Info Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ + +/****s* OpenSM: ClassPort Info Receiver/osm_cpi_rcv_t +* NAME +* osm_cpi_rcv_t +* +* DESCRIPTION +* ClassPort Info Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_cpi_rcv +{ + osm_subn_t *p_subn; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + cl_plock_t *p_lock; + +} osm_cpi_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_gen_req_ctrl +* Pointer to the generic request controller. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* ClassPort Info Receiver object +*********/ + +/****f* OpenSM: ClassPort Info Receiver/osm_cpi_rcv_construct +* NAME +* osm_cpi_rcv_construct +* +* DESCRIPTION +* This function constructs a ClassPort Info Receiver object. +* +* SYNOPSIS +*/ +void +osm_cpi_rcv_construct( + IN osm_cpi_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a ClassPort Info Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_cpi_rcv_init, osm_cpi_rcv_destroy +* +* Calling osm_cpi_rcv_construct is a prerequisite to calling any other +* method except osm_cpi_rcv_init. +* +* SEE ALSO +* ClassPort Info Receiver object, osm_cpi_rcv_init, osm_cpi_rcv_destroy +*********/ + +/****f* OpenSM: ClassPort Info Receiver/osm_cpi_rcv_destroy +* NAME +* osm_cpi_rcv_destroy +* +* DESCRIPTION +* The osm_cpi_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_cpi_rcv_destroy( + IN osm_cpi_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* ClassPort Info Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_cpi_rcv_construct or osm_cpi_rcv_init. +* +* SEE ALSO +* ClassPort Info Receiver object, osm_cpi_rcv_construct, +* osm_cpi_rcv_init +*********/ + +/****f* OpenSM: ClassPort Info Receiver/osm_cpi_rcv_init +* NAME +* osm_cpi_rcv_init +* +* DESCRIPTION +* The osm_cpi_rcv_init function initializes a +* ClassPort Info Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_cpi_rcv_init( + IN osm_cpi_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_cpi_rcv_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the ClassPort Info Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other ClassPort Info Receiver methods. +* +* SEE ALSO +* ClassPort Info Receiver object, osm_cpi_rcv_construct, +* osm_cpi_rcv_destroy +*********/ + +/****f* OpenSM: ClassPort Info Receiver/osm_cpi_rcv_process +* NAME +* osm_cpi_rcv_process +* +* DESCRIPTION +* Process the ClassPortInfo request. +* +* SYNOPSIS +*/ +void +osm_cpi_rcv_process( + IN osm_cpi_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_cpi_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the ClassPortInfo attribute. +* +* RETURN VALUES +* IB_SUCCESS if the ClassPortInfo processing was successful. +* +* NOTES +* This function processes a ClassPortInfo attribute. +* +* SEE ALSO +* ClassPort Info Receiver, ClassPort Info Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_CPI_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_class_port_info_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_class_port_info_ctrl.h new file mode 100644 index 00000000..58c3c91d --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_class_port_info_ctrl.h @@ -0,0 +1,261 @@ +/* + * 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: + * Declaration of osm_cpi_rcv_ctrl_t. + * This object represents a controller that receives the IBA ClassPortInfo + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.2 $ + */ + +#ifndef _OSM_CPICTRL_H_ +#define _OSM_CPICTRL_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/Class Port Info Receive Controller +* NAME +* Class Port Info Receive Controller +* +* DESCRIPTION +* The Class Port Info Receive Controller object encapsulates +* the information requested by the ClassPortInfo attribute. +* +* The ClassPortInfo Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ + +/****s* OpenSM: ClassPort Info Receive Controller/osm_cpi_rcv_ctrl_t +* NAME +* osm_cpi_rcv_ctrl_t +* +* DESCRIPTION +* ClassPort Info Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_cpi_rcv_ctrl +{ + osm_cpi_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_cpi_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the ClassPort Info Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Class Port Info Receive Controller object +* Class Port Info Receiver object +*********/ + +/****f* OpenSM: Class Port Info Receive Controller/osm_cpi_rcv_ctrl_construct +* NAME +* osm_cpi_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Class Port Info Receive Controller object. +* +* SYNOPSIS +*/ +void osm_cpi_rcv_ctrl_construct( + IN osm_cpi_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Class Port Info Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_cpi_rcv_ctrl_init, osm_cpi_rcv_ctrl_destroy, +* and osm_cpi_rcv_ctrl_is_inited. +* +* Calling osm_cpi_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_cpi_rcv_ctrl_init. +* +* SEE ALSO +* Class Port Info Receive Controller object, osm_cpi_rcv_ctrl_init, +* osm_cpi_rcv_ctrl_destroy, osm_cpi_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Class Port Info Receive Controller/osm_cpi_rcv_ctrl_destroy +* NAME +* osm_cpi_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_cpi_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_cpi_rcv_ctrl_destroy( + IN osm_cpi_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Class Port Info Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_cpi_rcv_ctrl_construct or osm_cpi_rcv_ctrl_init. +* +* SEE ALSO +* Class Port Info Receive Controller object, osm_cpi_rcv_ctrl_construct, +* osm_cpi_rcv_ctrl_init +*********/ + +/****f* OpenSM: Class Port Info Receive Controller/osm_cpi_rcv_ctrl_init +* NAME +* osm_cpi_rcv_ctrl_init +* +* DESCRIPTION +* The osm_cpi_rcv_ctrl_init function initializes a +* Class Port Info Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_cpi_rcv_ctrl_init( + IN osm_cpi_rcv_ctrl_t* const p_ctrl, + IN osm_cpi_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_cpi_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_cpi_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Class Port Info Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Class Port Info Receive Controller methods. +* +* SEE ALSO +* Class Port Info Receive Controller object, osm_cpi_rcv_ctrl_construct, +* osm_cpi_rcv_ctrl_destroy, osm_cpi_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Class Port Info Receive Controller/osm_cpi_rcv_ctrl_is_inited +* NAME +* osm_cpi_rcv_ctrl_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_cpi_rcv_ctrl_init. +* +* SYNOPSIS +*/ +boolean_t osm_cpi_rcv_ctrl_is_inited( + IN const osm_cpi_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_cpi_rcv_ctrl_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_cpi_rcv_ctrl_construct or osm_cpi_rcv_ctrl_init must be +* called before using this function. +* +* SEE ALSO +* Class Port Info Receive Controller object, osm_cpi_rcv_ctrl_construct, +* osm_cpi_rcv_ctrl_init +*********/ + +END_C_DECLS + +#endif /* _OSM_CPICTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_guidinfo_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_guidinfo_record.h new file mode 100644 index 00000000..d9bd48e3 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_guidinfo_record.h @@ -0,0 +1,279 @@ +/* + * 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: + * Declaration of osm_gir_rcv_t. + * This object represents the GUIDInfo Record Receiver object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#ifndef _OSM_GIR_RCV_H_ +#define _OSM_GIR_RCV_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/GUIDInfo Record Receiver +* NAME +* GUIDInfo Record Receiver +* +* DESCRIPTION +* The GUIDInfo Record Receiver object encapsulates the information +* needed to receive the GUIDInfoRecord attribute from a node. +* +* The GUIDInfo Record Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Hal Rosenstock, Voltaire +* +*********/ + +/****s* OpenSM: GUIDInfo Record Receiver/osm_gir_rcv_t +* NAME +* osm_gir_rcv_t +* +* DESCRIPTION +* GUIDInfo Record Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_gir_rcv +{ + const osm_subn_t *p_subn; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + cl_plock_t *p_lock; + cl_qlock_pool_t pool; + +} osm_gir_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_resp +* Pointer to the SA responder. +* +* p_mad_pool +* Pointer to the mad pool. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* pool +* Pool of linkable GUIDInfo Record objects used to generate +* the query response. +* +* SEE ALSO +* +*********/ + +/****f* OpenSM: GUIDInfo Record Receiver/osm_gir_rcv_construct +* NAME +* osm_gir_rcv_construct +* +* DESCRIPTION +* This function constructs a GUIDInfo Record Receiver object. +* +* SYNOPSIS +*/ +void +osm_gir_rcv_construct( + IN osm_gir_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a GUIDInfo Record Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_gir_rcv_init, osm_gir_rcv_destroy +* +* Calling osm_gir_rcv_construct is a prerequisite to calling any other +* method except osm_gir_rcv_init. +* +* SEE ALSO +* GUIDInfo Record Receiver object, osm_gir_rcv_init, +* osm_gir_rcv_destroy +*********/ + +/****f* OpenSM: GUIDInfo Record Receiver/osm_gir_rcv_destroy +* NAME +* osm_gir_rcv_destroy +* +* DESCRIPTION +* The osm_gir_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_gir_rcv_destroy( + IN osm_gir_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* GUIDInfo Record Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_gir_rcv_construct or osm_gir_rcv_init. +* +* SEE ALSO +* GUIDInfo Record Receiver object, osm_gir_rcv_construct, +* osm_gir_rcv_init +*********/ + +/****f* OpenSM: GUIDInfo Record Receiver/osm_gir_rcv_init +* NAME +* osm_gir_rcv_init +* +* DESCRIPTION +* The osm_gir_rcv_init function initializes a +* GUIDInfo Record Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_gir_rcv_init( + IN osm_gir_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN const osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_gir_rcv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the GUIDInfo Record Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other GUIDInfo Record Receiver methods. +* +* SEE ALSO +* GUIDInfo Record Receiver object, osm_gir_rcv_construct, +* osm_gir_rcv_destroy +*********/ + +/****f* OpenSM: GUIDInfo Record Receiver/osm_gir_rcv_process +* NAME +* osm_gir_rcv_process +* +* DESCRIPTION +* Process the GUIDInfoRecord attribute. +* +* SYNOPSIS +*/ +void +osm_gir_rcv_process( + IN osm_gir_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_gir_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's GUIDInfoRecord attribute. +* +* RETURN VALUES +* CL_SUCCESS if the GUIDInfoRecord processing was successful. +* +* NOTES +* This function processes a GUIDInfoRecord attribute. +* +* SEE ALSO +* GUIDInfo Record Receiver, GUIDInfo Record Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_GIR_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_guidinfo_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_guidinfo_record_ctrl.h new file mode 100644 index 00000000..f92b5a71 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_guidinfo_record_ctrl.h @@ -0,0 +1,230 @@ +/* + * 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: + * Declaration of osm_sa_gir_rec_rcv_ctrl_t. + * This object represents a controller that receives the IBA GUID Info + * record query from SA client. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#ifndef _OSM_GIR_CTRL_H_ +#define _OSM_GIR_CTRL_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/GUID Info Record Receive Controller +* NAME +* GUID Info Record Receive Controller +* +* DESCRIPTION +* The GUID Info Record Receive Controller object encapsulates +* the information needed to handle GUID Info record query from SA client. +* +* The GUID Info Record Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Hal Rosenstock, Voltaire +* +*********/ + +/****s* OpenSM: GUID Info Record Receive Controller/osm_gir_rcv_ctrl_t +* NAME +* osm_gir_rcv_ctrl_t +* +* DESCRIPTION +* GUID Info Record Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_gir_rcv_ctrl +{ + osm_gir_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_gir_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the GUID Info Record Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* GUID Info Record Receive Controller object +* GUID Info Record Receiver object +*********/ + +/****f* OpenSM: GUID Info Record Receive Controller/osm_gir_rec_rcv_ctrl_construct +* NAME +* osm_gir_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a GUID Info Record Receive Controller object. +* +* SYNOPSIS +*/ +void osm_gir_rcv_ctrl_construct( + IN osm_gir_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a GUID Info Record Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_gir_rcv_ctrl_init, osm_gir_rcv_ctrl_destroy +* +* Calling osm_gir_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_gir_rcv_ctrl_init. +* +* SEE ALSO +* GUID Info Record Receive Controller object, osm_gir_rcv_ctrl_init, +* osm_gir_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: GUID Info Record Receive Controller/osm_gir_rcv_ctrl_destroy +* NAME +* osm_gir_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_gir_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_gir_rcv_ctrl_destroy( + IN osm_gir_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* GUIDInfo Record Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_gir_rcv_ctrl_construct or osm_gir_rcv_ctrl_init. +* +* SEE ALSO +* GUIDInfo Record Receive Controller object, osm_gir_rcv_ctrl_construct, +* osm_gir_rcv_ctrl_init +*********/ + +/****f* OpenSM: GUID Info Record Receive Controller/osm_gir_rcv_ctrl_init +* NAME +* osm_gir_rcv_ctrl_init +* +* DESCRIPTION +* The osm_gir_rcv_ctrl_init function initializes a +* GUID Info Record Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_gir_rcv_ctrl_init( + IN osm_gir_rcv_ctrl_t* const p_ctrl, + IN osm_gir_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_gir_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_gir_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the GUID Info Record Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other GUID Info Record Receive Controller methods. +* +* SEE ALSO +* GUID Info Record Receive Controller object, osm_gir_rcv_ctrl_construct, +* osm_gir_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_GIR_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_informinfo.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_informinfo.h new file mode 100644 index 00000000..ac12208e --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_informinfo.h @@ -0,0 +1,299 @@ +/* + * 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: + * Declaration of osm_infr_rcv_t. + * This object represents the InformInfoRecord Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#ifndef _OSM_SA_INFR_H_ +#define _OSM_SA_INFR_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/InformInfo Receiver +* NAME +* InformInfo Receiver +* +* DESCRIPTION +* The InformInfo Receiver object encapsulates the information +* needed to receive the InformInfo request from a node. +* +* The InformInfo Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ + +/****s* OpenSM: InformInfo Receiver/osm_infr_rcv_t +* NAME +* osm_infr_rcv_t +* +* DESCRIPTION +* InformInfo Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_infr_rcv +{ + osm_subn_t *p_subn; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + cl_plock_t *p_lock; + cl_qlock_pool_t pool; +} osm_infr_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_resp +* Pointer to the osm_sa_resp_t object. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* pool +* Pool of linkable InformInfo Record objects used to +* generate the query response. +* +* SEE ALSO +* InformInfo Receiver object +*********/ + +/****f* OpenSM: InformInfo Receiver/osm_infr_rcv_construct +* NAME +* osm_infr_rcv_construct +* +* DESCRIPTION +* This function constructs a InformInfo Receiver object. +* +* SYNOPSIS +*/ +void +osm_infr_rcv_construct( + IN osm_infr_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a InformInfo Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_infr_rcv_init, osm_infr_rcv_destroy +* +* Calling osm_infr_rcv_construct is a prerequisite to calling any other +* method except osm_infr_rcv_init. +* +* SEE ALSO +* InformInfo Receiver object, osm_infr_rcv_init, osm_infr_rcv_destroy +*********/ + +/****f* OpenSM: InformInfo Receiver/osm_infr_rcv_destroy +* NAME +* osm_infr_rcv_destroy +* +* DESCRIPTION +* The osm_infr_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_infr_rcv_destroy( + IN osm_infr_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* InformInfo Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_infr_rcv_construct or osm_infr_rcv_init. +* +* SEE ALSO +* InformInfo Receiver object, osm_infr_rcv_construct, +* osm_infr_rcv_init +*********/ + +/****f* OpenSM: InformInfo Receiver/osm_infr_rcv_init +* NAME +* osm_infr_rcv_init +* +* DESCRIPTION +* The osm_infr_rcv_init function initializes a +* InformInfo Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_infr_rcv_init( + IN osm_infr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_infr_rcv_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the InformInfo Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other InformInfo Receiver methods. +* +* SEE ALSO +* InformInfo Receiver object, osm_infr_rcv_construct, +* osm_infr_rcv_destroy +*********/ + +/****f* OpenSM: InformInfo Receiver/osm_infr_rcv_process +* NAME +* osm_infr_rcv_process +* +* DESCRIPTION +* Process the InformInfo request. +* +* SYNOPSIS +*/ +void +osm_infr_rcv_process( + IN osm_infr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_infr_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's InformInfo attribute. +* NOTES +* This function processes a InformInfo attribute. +* +* SEE ALSO +* InformInfo Receiver +*********/ + +/****f* OpenSM: InformInfo Record Receiver/osm_infir_rcv_process +* NAME +* osm_infir_rcv_process +* +* DESCRIPTION +* Process the InformInfo Record request. +* +* SYNOPSIS +*/ +void +osm_infir_rcv_process( + IN osm_infr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_infr_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's InformInfo Record attribute. +* NOTES +* This function processes a InformInfo Record attribute. +* +* SEE ALSO +* InformInfo Receiver +*********/ + +END_C_DECLS + +#endif /* _OSM_SA_INFR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_informinfo_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_informinfo_ctrl.h new file mode 100644 index 00000000..4c23bd90 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_informinfo_ctrl.h @@ -0,0 +1,261 @@ +/* + * 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: + * Declaration of osm_infr_rcv_ctrl_t. + * This object represents a controller that receives the IBA InfromInfo + * Set method attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#ifndef _OSM_INFR_RCV_CTRL_H_ +#define _OSM_INFR_RCV_CTRL_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/InformInfo Receive Controller +* NAME +* InformInfo Receive Controller +* +* DESCRIPTION +* The InformInfo Receive Controller object encapsulates +* the information needed to receive the InformInfo attribute from a node. +* +* The InformInfo Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ + +/****s* OpenSM: InformInfo Receive Controller/osm_infr_rcv_ctrl_t +* NAME +* osm_infr_rcv_ctrl_t +* +* DESCRIPTION +* InformInfo Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_infr_rcv_ctrl +{ + osm_infr_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + cl_disp_reg_handle_t h_disp2; +} osm_infr_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the InformInfo Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* InformInfo Receive Controller object +* InformInfo Receiver object +*********/ + +/****f* OpenSM: InformInfo Receive Controller/osm_infr_rcv_ctrl_construct +* NAME +* osm_infr_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a InformInfo Receive Controller object. +* +* SYNOPSIS +*/ +void osm_infr_rcv_ctrl_construct( + IN osm_infr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a InformInfo Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_infr_rcv_ctrl_init, osm_infr_rcv_ctrl_destroy, +* and osm_infr_rcv_ctrl_is_inited. +* +* Calling osm_infr_rcv_ctrl_construct is a prerequisite to calling any +* other method except osm_infr_rcv_ctrl_init. +* +* SEE ALSO +* InformInfo Receive Controller object, osm_infr_rcv_ctrl_init, +* osm_infr_rcv_ctrl_destroy, osm_infr_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: InformInfo Receive Controller/osm_infr_rcv_ctrl_destroy +* NAME +* osm_infr_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_infr_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_infr_rcv_ctrl_destroy( + IN osm_infr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* InformInfo Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_infr_rcv_ctrl_construct or osm_infr_rcv_ctrl_init. +* +* SEE ALSO +* InformInfo Receive Controller object, osm_infr_rcv_ctrl_construct, +* osm_infr_rcv_ctrl_init +*********/ + +/****f* OpenSM: InformInfo Receive Controller/osm_infr_rcv_ctrl_init +* NAME +* osm_infr_rcv_ctrl_init +* +* DESCRIPTION +* The osm_infr_rcv_ctrl_init function initializes a +* InformInfo Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_infr_rcv_ctrl_init( + IN osm_infr_rcv_ctrl_t* const p_ctrl, + IN osm_infr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_infr_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_infr_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the InformInfo Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other InformInfo Receive Controller methods. +* +* SEE ALSO +* InformInfo Receive Controller object, osm_infr_rcv_ctrl_construct, +* osm_infr_rcv_ctrl_destroy, osm_infr_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: InformInfo Receive Controller/osm_infr_rcv_ctrl_is_inited +* NAME +* osm_infr_rcv_ctrl_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_infr_rcv_ctrl_init. +* +* SYNOPSIS +*/ +boolean_t osm_infr_rcv_ctrl_is_inited( + IN const osm_infr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_infr_rcv_ctrl_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_infr_rcv_ctrl_construct or osm_infr_rcv_ctrl_init must be +* called before using this function. +* +* SEE ALSO +* InformInfo Receive Controller object, osm_infr_rcv_ctrl_construct, +* osm_infr_rcv_ctrl_init +*********/ + +END_C_DECLS + +#endif /* _OSM_INFR_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_lft_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_lft_record.h new file mode 100644 index 00000000..6b543e66 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_lft_record.h @@ -0,0 +1,281 @@ +/* + * 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: + * Declaration of osm_lftr_rcv_t. + * This object represents the LinearForwardingTable Receiver object. + * attribute from a switch node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_LFTR_H_ +#define _OSM_LFTR_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/Linear Forwarding Table Receiver +* NAME +* Linear Forwarding Table Receiver +* +* DESCRIPTION +* The Linear Forwarding Table Receiver object encapsulates the information +* needed to receive the LinearForwardingTable attribute from a switch node. +* +* The Linear Forwarding Table Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox Technologies LTD +* +*********/ + +/****s* OpenSM: Linear Forwarding Table Receiver/osm_lftr_rcv_t +* NAME +* osm_lftr_rcv_t +* +* DESCRIPTION +* Linear Forwarding Table Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_lft +{ + osm_subn_t* p_subn; + osm_stats_t* p_stats; + osm_sa_resp_t* p_resp; + osm_mad_pool_t* p_mad_pool; + osm_log_t* p_log; + cl_plock_t* p_lock; + cl_qlock_pool_t pool; +} osm_lftr_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_stats +* Pointer to the statistics. +* +* p_resp +* Pointer to the SA responder. +* +* p_mad_pool +* Pointer to the mad pool. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* pool +* Pool of linkable Linear Forwarding Table Record objects used to +* generate the query response. +* +* SEE ALSO +* Linear Forwarding Table Receiver object +*********/ + +/****f* OpenSM: Linear Forwarding Table Receiver/osm_lftr_rcv_construct +* NAME +* osm_lftr_rcv_construct +* +* DESCRIPTION +* This function constructs a Linear Forwarding Table Receiver object. +* +* SYNOPSIS +*/ +void osm_lftr_rcv_construct( + IN osm_lftr_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Linear Forwarding Table Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_lftr_rcv_init, osm_lftr_rcv_destroy +* +* Calling osm_lftr_rcv_construct is a prerequisite to calling any other +* method except osm_lftr_rcv_init. +* +* SEE ALSO +* Linear Forwarding Table Receiver object, osm_lftr_rcv_init, +* osm_lftr_rcv_destroy +*********/ + +/****f* OpenSM: Linear Forwarding Table Receiver/osm_lftr_rcv_destroy +* NAME +* osm_lftr_rcv_destroy +* +* DESCRIPTION +* The osm_lftr_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_lftr_rcv_destroy( + IN osm_lftr_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Linear Forwarding Table Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_lftr_rcv_construct or osm_lftr_rcv_init. +* +* SEE ALSO +* Linear Forwarding Table Receiver object, osm_lftr_rcv_construct, +* osm_lftr_rcv_init +*********/ + +/****f* OpenSM: Linear Forwarding Table Receiver/osm_lftr_rcv_init +* NAME +* osm_lftr_rcv_init +* +* DESCRIPTION +* The osm_lftr_rcv_init function initializes a +* Linear Forwarding Table Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_lftr_rcv_init( + IN osm_lftr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_lftr_rcv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the Linear Forwarding Table Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other Linear Forwarding Table Receiver methods. +* +* SEE ALSO +* Linear Forwarding Table Receiver object, osm_lftr_rcv_construct, +* osm_lftr_rcv_destroy +*********/ + +/****f* OpenSM: Linear Forwarding Table Receiver/osm_lftr_rcv_process +* NAME +* osm_lftr_rcv_process +* +* DESCRIPTION +* Process the LinearForwardingTable attribute. +* +* SYNOPSIS +*/ +void osm_lftr_rcv_process( + IN osm_lftr_rcv_t* const p_ctrl, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_lftr_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the switch node's LinearForwardingTable attribute. +* +* RETURN VALUES +* CL_SUCCESS if the LinearForwardingTable processing was successful. +* +* NOTES +* This function processes a LinearForwardingTable attribute. +* +* SEE ALSO +* Linear Forwarding Table Receiver, Linear Forwarding Table Response +* Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_LFTR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_lft_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_lft_record_ctrl.h new file mode 100644 index 00000000..1dd3a837 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_lft_record_ctrl.h @@ -0,0 +1,233 @@ +/* + * 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: + * Declaration of osm_lftr_rcv_ctrl_t. + * This object represents a controller that receives the IBA + * LinearForwardingTable attribute from a switch. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_LFTR_RCV_CTRL_H_ +#define _OSM_LFTR_RCV_CTRL_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/Linear Forwarding Table Receive Controller +* NAME +* Linear Forwarding Table Record Receive Controller +* +* DESCRIPTION +* The Linear Forwarding Table Receive Controller object encapsulates +* the information needed to receive the LinearFowardingTable attribute +* from a switch node. +* +* The Linear Forwarding Table Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox Technologies LTD +* +*********/ + +/****s* OpenSM: Linear Forwarding Table Receive Controller/osm_lftr_rcv_ctrl_t +* NAME +* osm_lftr_rcv_ctrl_t +* +* DESCRIPTION +* Linear Forwarding Table Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_lftr_rcv_ctrl +{ + osm_lftr_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_lftr_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the Linear Forwarding Table Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Linear Forwarding Table Receive Controller object +* Linear Forwarding Table Receiver object +*********/ + +/****f* OpenSM: Linear Forwarding Table Receive Controller/osm_lftr_rcv_ctrl_construct +* NAME +* osm_lftr_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Linear Forwarding Table Receive +* Controller object. +* +* SYNOPSIS +*/ +void osm_lftr_rcv_ctrl_construct( + IN osm_lftr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Linear Forwarding Table Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_lftr_rcv_ctrl_init, osm_lftr_rcv_ctrl_destroy +* +* Calling osm_lftr_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_lftr_rcv_ctrl_init. +* +* SEE ALSO +* Linear Forwarding Table Receive Controller object, osm_lftr_rcv_ctrl_init, +* osm_lftr_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: Linear Forwarding Table Receive Controller/osm_lftr_rcv_ctrl_destroy +* NAME +* osm_lftr_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_lftr_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_lftr_rcv_ctrl_destroy( + IN osm_lftr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Linear Forwarding Table Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_lftr_rcv_ctrl_construct or osm_lftr_rcv_ctrl_init. +* +* SEE ALSO +* Linear Forwarding Table Receive Controller object, osm_lftr_rcv_ctrl_construct, +* osm_lftr_rcv_ctrl_init +*********/ + +/****f* OpenSM: Linear Forwarding Table Receive Controller/osm_lftr_rcv_ctrl_init +* NAME +* osm_lftr_rcv_ctrl_init +* +* DESCRIPTION +* The osm_lftr_rcv_ctrl_init function initializes a +* Linear Forwarding Table Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_lftr_rcv_ctrl_init( + IN osm_lftr_rcv_ctrl_t* const p_ctrl, + IN osm_lftr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_lftr_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_lftr_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Linear Forwarding Table Receive Controller object +* was initialized successfully. +* +* NOTES +* Allows calling other Linear Forwarding Table Receive Controller methods. +* +* SEE ALSO +* Linear Forwarding Table Receive Controller object, +* osm_lftr_rcv_ctrl_construct, osm_lftr_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_LFTR_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_link_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_link_record.h new file mode 100644 index 00000000..5c9b291c --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_link_record.h @@ -0,0 +1,276 @@ +/* + * 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: + * Declaration of osm_lr_rcv_t. + * This object represents the Link Record Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_LR_RCV_H_ +#define _OSM_LR_RCV_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/Link Record Receiver +* NAME +* Link Record Receiver +* +* DESCRIPTION +* The Link Record Receiver object encapsulates the information +* needed to receive the Link Record attribute from a node. +* +* The Link Record Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Ranjit Pandit, Intel +* +*********/ + +/****s* OpenSM: Link Record Receiver/osm_lr_rcv_t +* NAME +* osm_lr_rcv_t +* +* DESCRIPTION +* Link Record Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_lr_rcv +{ + osm_subn_t *p_subn; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + cl_plock_t *p_lock; + cl_qlock_pool_t lr_pool; + +} osm_lr_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_resp +* Pointer to the SA responder. +* +* p_mad_pool +* Pointer to the mad pool. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* lr_pool +* Pool of link record objects used to generate the query response. +* +* SEE ALSO +*********/ + +/****f* OpenSM: Link Record Receiver/osm_lr_rcv_construct +* NAME +* osm_lr_rcv_construct +* +* DESCRIPTION +* This function constructs a Link Record Receiver object. +* +* SYNOPSIS +*/ +void +osm_lr_rcv_construct( + IN osm_lr_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a Link Record Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_lr_rcv_init, osm_lr_rcv_destroy +* +* Calling osm_lr_rcv_construct is a prerequisite to calling any other +* method except osm_lr_rcv_init. +* +* SEE ALSO +* Link Record Receiver object, osm_lr_rcv_init, osm_lr_rcv_destroy +*********/ + +/****f* OpenSM: Link Record Receiver/osm_lr_rcv_destroy +* NAME +* osm_lr_rcv_destroy +* +* DESCRIPTION +* The osm_lr_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_lr_rcv_destroy( + IN osm_lr_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Link Record Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_lr_rcv_construct or osm_lr_rcv_init. +* +* SEE ALSO +* Link Record Receiver object, osm_lr_rcv_construct, +* osm_lr_rcv_init +*********/ + +/****f* OpenSM: Link Record Receiver/osm_lr_rcv_init +* NAME +* osm_lr_rcv_init +* +* DESCRIPTION +* The osm_lr_rcv_init function initializes a +* Link Record Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_lr_rcv_init( + IN osm_lr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_lr_rcv_t object to initialize. +* +* p_resp +* [in] Pointer to the SA Responder object. +* +* p_mad_pool +* [in] Pointer to the mad pool. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the Link Record Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other Link Record Receiver methods. +* +* SEE ALSO +* Link Record Receiver object, osm_lr_rcv_construct, osm_lr_rcv_destroy +*********/ + +/****f* OpenSM: Link Record Receiver/osm_lr_rcv_process +* NAME +* osm_lr_rcv_process +* +* DESCRIPTION +* Process the Link Record attribute. +* +* SYNOPSIS +*/ +void osm_lr_rcv_process( + IN osm_lr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_lr_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's Link Record attribute. +* +* NOTES +* This function processes a Link Record attribute. +* +* SEE ALSO +* Link Record Receiver, Link Record Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_LR_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_link_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_link_record_ctrl.h new file mode 100644 index 00000000..2c9355d3 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_link_record_ctrl.h @@ -0,0 +1,261 @@ +/* + * 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: + * Declaration of osm_lr_rcv_ctrl_t. + * This object represents a controller that receives the IBA Link Record + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_LR_CTRL_H_ +#define _OSM_LR_CTRL_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/Link Record Receive Controller +* NAME +* Link Record Receive Controller +* +* DESCRIPTION +* The Link Record Receive Controller object encapsulates +* the information needed to receive the LinkRecord attribute from a node. +* +* The Link Record Receive 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 +* +*********/ + +/****s* OpenSM: Link Record Receive Controller/osm_lr_rcv_ctrl_t +* NAME +* osm_lr_rcv_ctrl_t +* +* DESCRIPTION +* Link Record Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_lr_rcv_ctrl +{ + osm_lr_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_lr_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the Link Record Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Link Record Receive Controller object +* Link Record Receiver object +*********/ + +/****f* OpenSM: Link Record Receive Controller/osm_lr_rcv_ctrl_construct +* NAME +* osm_lr_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Link Record Receive Controller object. +* +* SYNOPSIS +*/ +void osm_lr_rcv_ctrl_construct( + IN osm_lr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Link Record Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_lr_rcv_ctrl_init, osm_lr_rcv_ctrl_destroy, +* and osm_lr_rcv_ctrl_is_inited. +* +* Calling osm_lr_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_lr_rcv_ctrl_init. +* +* SEE ALSO +* Link Record Receive Controller object, osm_lr_rcv_ctrl_init, +* osm_lr_rcv_ctrl_destroy, osm_lr_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Link Record Receive Controller/osm_lr_rcv_ctrl_destroy +* NAME +* osm_lr_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_lr_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_lr_rcv_ctrl_destroy( + IN osm_lr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Link Record Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_lr_rcv_ctrl_construct or osm_lr_rcv_ctrl_init. +* +* SEE ALSO +* Link Record Receive Controller object, osm_lr_rcv_ctrl_construct, +* osm_lr_rcv_ctrl_init +*********/ + +/****f* OpenSM: Link Record Receive Controller/osm_lr_rcv_ctrl_init +* NAME +* osm_lr_rcv_ctrl_init +* +* DESCRIPTION +* The osm_lr_rcv_ctrl_init function initializes a +* Link Record Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_lr_rcv_ctrl_init( + IN osm_lr_rcv_ctrl_t* const p_ctrl, + IN osm_lr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_lr_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_lr_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Link Record Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Link Record Receive Controller methods. +* +* SEE ALSO +* Link Record Receive Controller object, osm_lr_rcv_ctrl_construct, +* osm_lr_rcv_ctrl_destroy, osm_lr_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Link Record Receive Controller/osm_lr_rcv_ctrl_is_inited +* NAME +* osm_lr_rcv_ctrl_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_lr_rcv_ctrl_init. +* +* SYNOPSIS +*/ +boolean_t osm_lr_rcv_ctrl_is_inited( + IN const osm_lr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_lr_rcv_ctrl_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_lr_rcv_ctrl_construct or osm_lr_rcv_ctrl_init must be +* called before using this function. +* +* SEE ALSO +* Link Record Receive Controller object, osm_lr_rcv_ctrl_construct, +* osm_lr_rcv_ctrl_init +*********/ + +END_C_DECLS + +#endif /* _OSM_LR_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mad_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mad_ctrl.h new file mode 100644 index 00000000..378618e5 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mad_ctrl.h @@ -0,0 +1,352 @@ +/* + * 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: + * 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_SA_MAD_CTRL_H_ +#define _OSM_SA_MAD_CTRL_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/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 +* +*********/ + +/****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 +{ + 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_resp_t *p_resp; +} osm_sa_mad_ctrl_t; +/* +* FIELDS +* 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. +* +* p_resp +* Pointer to the SA response manager +* +* SEE ALSO +* SA MAD Controller object +* SA MADr object +*********/ + +/****f* OpenSM: SA MAD Controller/osm_sa_mad_ctrl_construct +* NAME +* osm_sa_mad_ctrl_construct +* +* DESCRIPTION +* This function constructs a SA MAD Controller object. +* +* SYNOPSIS +*/ +void osm_sa_mad_ctrl_construct( + IN osm_sa_mad_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a SA MAD Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sa_mad_ctrl_init, and osm_sa_mad_ctrl_destroy. +* +* Calling osm_sa_mad_ctrl_construct is a prerequisite to calling any other +* method except osm_sa_mad_ctrl_init. +* +* SEE ALSO +* SA MAD Controller object, osm_sa_mad_ctrl_init, +* osm_sa_mad_ctrl_destroy +*********/ + +/****f* OpenSM: SA MAD Controller/osm_sa_mad_ctrl_destroy +* NAME +* osm_sa_mad_ctrl_destroy +* +* DESCRIPTION +* The osm_sa_mad_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_sa_mad_ctrl_destroy( + IN osm_sa_mad_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* SA MAD Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_sa_mad_ctrl_construct or osm_sa_mad_ctrl_init. +* +* SEE ALSO +* SA MAD Controller object, osm_sa_mad_ctrl_construct, +* osm_sa_mad_ctrl_init +*********/ + +/****f* OpenSM: SA MAD Controller/osm_sa_mad_ctrl_init +* NAME +* osm_sa_mad_ctrl_init +* +* DESCRIPTION +* The osm_sa_mad_ctrl_init function initializes a +* SA MAD Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_sa_mad_ctrl_init( + IN osm_sa_mad_ctrl_t* const p_ctrl, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_vendor_t* const p_vendor, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_stats_t* const p_stats, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sa_mad_ctrl_t object to initialize. +* +* p_resp +* [in] Pointer to the response SA manager object +* +* p_mad_pool +* [in] Pointer to the MAD pool. +* +* p_vendor +* [in] Pointer to the vendor specific interfaces object. +* +* p_log +* [in] Pointer to the log object. +* +* p_stats +* [in] Pointer to the OpenSM stastics block. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* IB_SUCCESS if the SA MAD Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other SA MAD Controller methods. +* +* SEE ALSO +* SA MAD Controller object, osm_sa_mad_ctrl_construct, +* osm_sa_mad_ctrl_destroy +*********/ + +/****f* OpenSM: SA/osm_sa_mad_ctrl_bind +* NAME +* osm_sa_mad_ctrl_bind +* +* DESCRIPTION +* Binds the SA MAD Controller object to a port guid. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sa_mad_ctrl_bind( + IN osm_sa_mad_ctrl_t* const p_ctrl, + IN const ib_net64_t port_guid ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sa_mad_ctrl_t object to initialize. +* +* port_guid +* [in] Local port GUID with which to bind. +* +* +* RETURN VALUES +* None +* +* NOTES +* A given SA MAD Controller object can only be bound to one +* port at a time. +* +* SEE ALSO +*********/ + +/****f* OpenSM: SA/osm_sa_mad_ctrl_unbind +* NAME +* osm_sa_mad_ctrl_unbind +* +* DESCRIPTION +* Un-Binds the SA MAD Controller object from the IB port +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sa_mad_ctrl_unbind( + IN osm_sa_mad_ctrl_t* const p_ctrl); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sa_mad_ctrl_t object to initialize. +* +* RETURN VALUES +* None +* +* NOTES +* A given SA MAD Controller should be previously bound to IB +* port. +* +* SEE ALSO +*********/ + +/****f* OpenSM: SA/osm_sa_mad_ctrl_get_bind_handle +* NAME +* osm_sa_mad_ctrl_get_bind_handle +* +* DESCRIPTION +* Returns the bind handle. +* +* SYNOPSIS +*/ +static inline osm_bind_handle_t +osm_sa_mad_ctrl_get_bind_handle( + IN const osm_sa_mad_ctrl_t* const p_ctrl ) +{ + return( p_ctrl->h_bind ); +} +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sa_mad_ctrl_t object. +* +* RETURN VALUES +* Returns the bind handle, which may be OSM_BIND_INVALID_HANDLE +* if no port has been bound. +* +* NOTES +* A given SA MAD Controller object can only be bound to one +* port at a time. +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_SA_MAD_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mcmember_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mcmember_record.h new file mode 100644 index 00000000..7603f76b --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mcmember_record.h @@ -0,0 +1,420 @@ +/* + * 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: + * Declaration of osm_mcmr_recv_t. + * This object represents the MCMemberRecord Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#ifndef _OSM_MCMR_H_ +#define _OSM_MCMR_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/MCMember Receiver +* NAME +* MCMember Receiver +* +* DESCRIPTION +* The MCMember Receiver object encapsulates the information +* needed to receive the MCMemberRecord attribute from a node. +* +* The MCMember Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Anil Keshavamurthy, Intel +* +*********/ + +/****s* OpenSM: MCMember Receiver/osm_mcmr_recv_t +* NAME +* osm_mcmr_recv_t +* +* DESCRIPTION +* MCMember Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ + + +typedef struct _osm_mcmr +{ + osm_subn_t *p_subn; + osm_sm_t *p_sm; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + cl_plock_t *p_lock; + uint16_t mlid_ho; + cl_qlock_pool_t pool; +} osm_mcmr_recv_t; + + +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_gen_req_ctrl +* Pointer to the generic request controller. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* MCMember Receiver object +*********/ + +/****f* OpenSM: MCMember Receiver/osm_mcmr_rcv_construct +* NAME +* osm_mcmr_rcv_construct +* +* DESCRIPTION +* This function constructs a MCMember Receiver object. +* +* SYNOPSIS +*/ +void osm_mcmr_rcv_construct( + IN osm_mcmr_recv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a MCMember Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_mcmr_rcv_init, osm_mcmr_rcv_destroy +* +* Calling osm_mcmr_rcv_construct is a prerequisite to calling any other +* method except osm_mcmr_init. +* +* SEE ALSO +* MCMember Receiver object, osm_mcmr_init, +* osm_mcmr_rcv_destroy +*********/ + +/****f* OpenSM: MCMember Receiver/osm_mcmr_rcv_destroy +* NAME +* osm_mcmr_rcv_destroy +* +* DESCRIPTION +* The osm_mcmr_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_mcmr_rcv_destroy( + IN osm_mcmr_recv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* MCMember Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_mcmr_rcv_construct or osm_mcmr_init. +* +* SEE ALSO +* MCMember Receiver object, osm_mcmr_rcv_construct, +* osm_mcmr_init +*********/ + +/****f* OpenSM: MCMember Receiver/osm_mcmr_rcv_init +* NAME +* osm_mcmr_init +* +* DESCRIPTION +* The osm_mcmr_init function initializes a +* MCMember Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_mcmr_rcv_init( + IN osm_sm_t * const p_sm, + IN osm_mcmr_recv_t* const p_ctrl, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_sm +* [in] pointer to osm_sm_t object +* p_ctrl +* [in] Pointer to an osm_mcmr_recv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the MCMember Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other MCMember Receiver methods. +* +* SEE ALSO +* MCMember Receiver object, osm_mcmr_rcv_construct, +* osm_mcmr_rcv_destroy +*********/ + +/****f* OpenSM: MCMember Receiver/osm_mcmr_rcv_process +* NAME +* osm_mcmr_rcv_process +* +* DESCRIPTION +* Process the MCMemberRecord attribute. +* +* SYNOPSIS +*/ +void osm_mcmr_rcv_process( + IN osm_mcmr_recv_t* const p_ctrl, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_mcmr_recv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's MCMemberRecord attribute. +* +* RETURN VALUES +* CL_SUCCESS if the MCMemberRecord processing was successful. +* +* NOTES +* This function processes a MCMemberRecord attribute. +* +* SEE ALSO +* MCMember Receiver, MCMember Response Controller +*********/ + + + +/****f* OpenSM: MC Member Record Receiver/osm_mcmr_rcv_create_new_mgrp +* NAME +* osm_mcmr_rcv_create_new_mgrp +* +* DESCRIPTION +* Create new Multicast group +* +* SYNOPSIS +*/ + +ib_api_status_t +osm_mcmr_rcv_create_new_mgrp( + IN osm_mcmr_recv_t* const p_mcmr, + IN uint64_t comp_mask, + IN const ib_member_rec_t* const p_recvd_mcmember_rec, + IN const osm_physp_t* const p_req_physp, + OUT osm_mgrp_t **pp_mgrp); +/* +* PARAMETERS +* p_mcmr +* [in] Pointer to an osm_mcmr_recv_t object. +* p_recvd_mcmember_rec +* [in] Received Multicast member record +* +* p_req_physp +* [in] The requesting osm_physp_t object. +* NULL if the creation is without a requesting port (e.g - ipoib known mcgroups) +* +* pp_mgrp +* [out] pointer the osm_mgrp_t object +* +* RETURN VALUES +* IB_SUCCESS, IB_ERROR +* +* NOTES +* +* +* SEE ALSO +* +*********/ + +/****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_mcmr_recv_t* const p_mcmr, + IN uint64_t comp_mask, + IN ib_member_rec_t* const p_recvd_mcmember_rec, + OUT osm_mgrp_t **pp_mgrp); +/* +* PARAMETERS +* p_mcmr +* [in] Pointer to an osm_mcmr_recv_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 +* +* NOTES +* +* +* SEE ALSO +* +*********/ + +#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) + +/****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 +/***********/ + +/* Scope component definitions from IBA 1.2 (Table 3 p. 146) */ +#define MC_SCOPE_LINK_LOCAL 0x2 +#define MC_SCOPE_SITE_LOCAL 0x5 +#define MC_SCOPE_ORG_LOCAL 0x8 +#define MC_SCOPE_GLOBAL 0xE + +/****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 MC_SCOPE_LINK_LOCAL +/***********/ + +/* JoinState definitions from IBA 1.2 */ +#define MC_FULL_MEMBER 0x1 +#define MC_NON_MEMBER 0x2 +#define MC_SENDONLY_NON_MEMBER 0x4 + +END_C_DECLS + +#endif /* _OSM_MCMR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mcmember_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mcmember_record_ctrl.h new file mode 100644 index 00000000..22c5606b --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mcmember_record_ctrl.h @@ -0,0 +1,262 @@ +/* + * 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: + * Declaration of osm_mcmr_rcv_ctrl_t. + * This object represents a controller that receives the IBA MCMemberRecord + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + + +#ifndef _OSM_MCMRCTRL_H +#define _OSM_MCMRCTRL_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/MCMember Receive Controller +* NAME +* MCMember Receive Controller +* +* DESCRIPTION +* The MCMember Receive Controller object encapsulates +* the information needed to receive the MCMemberRecord attribute from a node. +* +* The MCMember Receive 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 +* +*********/ + +/****s* OpenSM: MCMember Receive Controller/osm_mcmr_rcv_ctrl_t +* NAME +* osm_mcmr_rcv_ctrl_t +* +* DESCRIPTION +* MCMember Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_mcmr_rcv_ctrl +{ + osm_mcmr_recv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_mcmr_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the MCMember Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* MCMember Receive Controller object +* MCMember Receiver object +*********/ + +/****f* OpenSM: MCMember Receive Controller/osm_mcmr_rcv_ctrl_construct +* NAME +* osm_mcmr_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a MCMember Receive Controller object. +* +* SYNOPSIS +*/ +void osm_mcmr_rcv_ctrl_construct( + IN osm_mcmr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a MCMember Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_mcmr_rcv_ctrl_init, osm_mcmr_rcv_ctrl_destroy, +* and osm_mcmr_ctrl_is_inited. +* +* Calling osm_mcmr_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_mcmr_rcv_ctrl_init. +* +* SEE ALSO +* MCMember Receive Controller object, osm_mcmr_rcv_ctrl_init, +* osm_mcmr_rcv_ctrl_destroy, osm_mcmr_ctrl_is_inited +*********/ + +/****f* OpenSM: MCMember Receive Controller/osm_mcmr_rcv_ctrl_destroy +* NAME +* osm_mcmr_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_mcmr_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_mcmr_rcv_ctrl_destroy( + IN osm_mcmr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* MCMember Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_mcmr_rcv_ctrl_construct or osm_mcmr_rcv_ctrl_init. +* +* SEE ALSO +* MCMember Receive Controller object, osm_mcmr_rcv_ctrl_construct, +* osm_mcmr_rcv_ctrl_init +*********/ + +/****f* OpenSM: MCMember Receive Controller/osm_mcmr_rcv_ctrl_init +* NAME +* osm_mcmr_rcv_ctrl_init +* +* DESCRIPTION +* The osm_mcmr_rcv_ctrl_init function initializes a +* MCMember Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_mcmr_rcv_ctrl_init( + IN osm_mcmr_rcv_ctrl_t* const p_ctrl, + IN osm_mcmr_recv_t* const p_mcmr, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_mcmr_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_mcmr_recv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the MCMember Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other MCMember Receive Controller methods. +* +* SEE ALSO +* MCMember Receive Controller object, osm_mcmr_rcv_ctrl_construct, +* osm_mcmr_rcv_ctrl_destroy, osm_mcmr_ctrl_is_inited +*********/ + +/****f* OpenSM: MCMember Receive Controller/osm_mcmr_ctrl_is_inited +* NAME +* osm_mcmr_ctrl_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_mcmr_rcv_ctrl_init. +* +* SYNOPSIS +*/ +boolean_t osm_mcmr_ctrl_is_inited( + IN const osm_mcmr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_mcmr_rcv_ctrl_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_mcmr_rcv_ctrl_construct or osm_mcmr_rcv_ctrl_init must be +* called before using this function. +* +* SEE ALSO +* MCMember Receive Controller object, osm_mcmr_rcv_ctrl_construct, +* osm_mcmr_rcv_ctrl_init +*********/ + +END_C_DECLS + +#endif /* _OSM_MCMRCTRL_H */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mft_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mft_record.h new file mode 100644 index 00000000..a4e42483 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mft_record.h @@ -0,0 +1,280 @@ +/* + * 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: + * Declaration of osm_mftr_rcv_t. + * This object represents the MulticastForwardingTable Receiver object. + * attribute from a switch node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#ifndef _OSM_MFTR_H_ +#define _OSM_MFTR_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/Multicast Forwarding Table Receiver +* NAME +* Multicast Forwarding Table Receiver +* +* DESCRIPTION +* The Multicast Forwarding Table Receiver object encapsulates the information +* needed to receive the MulticastForwardingTable attribute from a switch node. +* +* The Multicast Forwarding Table Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Hal Rosenstock, Voltaire +* +*********/ + +/****s* OpenSM: Multicast Forwarding Table Receiver/osm_mftr_rcv_t +* NAME +* osm_mftr_rcv_t +* +* DESCRIPTION +* Multicast Forwarding Table Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_mft +{ + osm_subn_t* p_subn; + osm_stats_t* p_stats; + osm_sa_resp_t* p_resp; + osm_mad_pool_t* p_mad_pool; + osm_log_t* p_log; + cl_plock_t* p_lock; + cl_qlock_pool_t pool; +} osm_mftr_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_stats +* Pointer to the statistics. +* +* p_resp +* Pointer to the SA responder. +* +* p_mad_pool +* Pointer to the mad pool. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* pool +* Pool of linkable Multicast Forwarding Table Record objects used to +* generate the query response. +* +* SEE ALSO +* Multicast Forwarding Table Receiver object +*********/ + +/****f* OpenSM: Multicast Forwarding Table Receiver/osm_mftr_rcv_construct +* NAME +* osm_mftr_rcv_construct +* +* DESCRIPTION +* This function constructs a Multicast Forwarding Table Receiver object. +* +* SYNOPSIS +*/ +void osm_mftr_rcv_construct( + IN osm_mftr_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Multicast Forwarding Table Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_mftr_rcv_init, osm_mftr_rcv_destroy +* +* Calling osm_mftr_rcv_construct is a prerequisite to calling any other +* method except osm_mftr_rcv_init. +* +* SEE ALSO +* Multicast Forwarding Table Receiver object, osm_mftr_rcv_init, +* osm_mftr_rcv_destroy +*********/ + +/****f* OpenSM: Multicast Forwarding Table Receiver/osm_mftr_rcv_destroy +* NAME +* osm_mftr_rcv_destroy +* +* DESCRIPTION +* The osm_mftr_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_mftr_rcv_destroy( + IN osm_mftr_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Multicast Forwarding Table Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_mftr_rcv_construct or osm_mftr_rcv_init. +* +* SEE ALSO +* Multicast Forwarding Table Receiver object, osm_mftr_rcv_construct, +* osm_mftr_rcv_init +*********/ + +/****f* OpenSM: Multicast Forwarding Table Receiver/osm_mftr_rcv_init +* NAME +* osm_mftr_rcv_init +* +* DESCRIPTION +* The osm_mftr_rcv_init function initializes a +* Multicast Forwarding Table Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_mftr_rcv_init( + IN osm_mftr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_mftr_rcv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the Multicast Forwarding Table Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other Multicast Forwarding Table Receiver methods. +* +* SEE ALSO +* Multicast Forwarding Table Receiver object, osm_mftr_rcv_construct, +* osm_mftr_rcv_destroy +*********/ + +/****f* OpenSM: Multicast Forwarding Table Receiver/osm_mftr_rcv_process +* NAME +* osm_mftr_rcv_process +* +* DESCRIPTION +* Process the MulticastForwardingTable attribute. +* +* SYNOPSIS +*/ +void osm_mftr_rcv_process( + IN osm_mftr_rcv_t* const p_ctrl, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_mftr_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the switch node's MulticastForwardingTable attribute. +* +* RETURN VALUES +* CL_SUCCESS if the MulticastForwardingTable processing was successful. +* +* NOTES +* This function processes a MulticastForwardingTable attribute. +* +* SEE ALSO +* Multicast Forwarding Table Receiver, Multicast Forwarding Table Response +* Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_MFTR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mft_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mft_record_ctrl.h new file mode 100644 index 00000000..8f815ff5 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_mft_record_ctrl.h @@ -0,0 +1,231 @@ +/* + * 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: + * Declaration of osm_mftr_rcv_ctrl_t. + * This object represents a controller that receives the IBA + * MulticastForwardingTable attribute from a switch. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#ifndef _OSM_MFTR_RCV_CTRL_H_ +#define _OSM_MFTR_RCV_CTRL_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/Multicast Forwarding Table Receive Controller +* NAME +* Multicast Forwarding Table Record Receive Controller +* +* DESCRIPTION +* The Multicast Forwarding Table Receive Controller object encapsulates +* the information needed to receive the MulticastFowardingTable attribute +* from a switch node. +* +* The Multicast Forwarding Table Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Hal Rosenstock, Voltaire +* +*********/ + +/****s* OpenSM: Multicast Forwarding Table Receive Controller/osm_mftr_rcv_ctrl_t +* NAME +* osm_mftr_rcv_ctrl_t +* +* DESCRIPTION +* Multicast Forwarding Table Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_mftr_rcv_ctrl +{ + osm_mftr_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; +} osm_mftr_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the Multicast Forwarding Table Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Multicast Forwarding Table Receive Controller object +* Multicast Forwarding Table Receiver object +*********/ + +/****f* OpenSM: Multicast Forwarding Table Receive Controller/osm_mftr_rcv_ctrl_construct +* NAME +* osm_mftr_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Multicast Forwarding Table Receive +* Controller object. +* +* SYNOPSIS +*/ +void osm_mftr_rcv_ctrl_construct( + IN osm_mftr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Multicast Forwarding Table Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_mftr_rcv_ctrl_init, osm_mftr_rcv_ctrl_destroy +* +* Calling osm_mftr_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_mftr_rcv_ctrl_init. +* +* SEE ALSO +* Multicast Forwarding Table Receive Controller object, osm_mftr_rcv_ctrl_init, +* osm_mftr_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: Multicast Forwarding Table Receive Controller/osm_mftr_rcv_ctrl_destroy +* NAME +* osm_mftr_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_mftr_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_mftr_rcv_ctrl_destroy( + IN osm_mftr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Multicast Forwarding Table Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_mftr_rcv_ctrl_construct or osm_mftr_rcv_ctrl_init. +* +* SEE ALSO +* Multicast Forwarding Table Receive Controller object, osm_mftr_rcv_ctrl_construct, +* osm_mftr_rcv_ctrl_init +*********/ + +/****f* OpenSM: Multicast Forwarding Table Receive Controller/osm_mftr_rcv_ctrl_init +* NAME +* osm_mftr_rcv_ctrl_init +* +* DESCRIPTION +* The osm_mftr_rcv_ctrl_init function initializes a +* Multicast Forwarding Table Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_mftr_rcv_ctrl_init( + IN osm_mftr_rcv_ctrl_t* const p_ctrl, + IN osm_mftr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_mftr_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_mftr_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Multicast Forwarding Table Receive Controller object +* was initialized successfully. +* +* NOTES +* Allows calling other Multicast Forwarding Table Receive Controller methods. +* +* SEE ALSO +* Multicast Forwarding Table Receive Controller object, +* osm_mftr_rcv_ctrl_construct, osm_mftr_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_MFTR_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_multipath_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_multipath_record.h new file mode 100644 index 00000000..b55cfb09 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_multipath_record.h @@ -0,0 +1,273 @@ +/* + * 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: + * Declaration of osm_mpr_rcv_t. + * This object represents the MultiPathRecord Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#ifndef _OSM_MPR_RCV_H_ +#define _OSM_MPR_RCV_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/MultiPath Record Receiver +* NAME +* MultiPath Record Receiver +* +* DESCRIPTION +* The MultiPath Record Receiver object encapsulates the information +* needed to receive the PathRecord request from a node. +* +* The MultiPath Record Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Hal Rosenstock, Voltaire +* +*********/ + +/****s* OpenSM: MultiPath Record Receiver/osm_mpr_rcv_t +* NAME +* osm_mpr_rcv_t +* +* DESCRIPTION +* MultiPath Record Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_mpr_rcv +{ + osm_subn_t *p_subn; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + cl_plock_t *p_lock; + cl_qlock_pool_t pr_pool; +} osm_mpr_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_gen_req_ctrl +* Pointer to the generic request controller. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* pr_pool +* Pool of multipath record objects used to generate query responses. +* +* SEE ALSO +* MultiPath Record Receiver object +*********/ + +/****f* OpenSM: MultiPath Record Receiver/osm_mpr_rcv_construct +* NAME +* osm_mpr_rcv_construct +* +* DESCRIPTION +* This function constructs a MultiPath Record Receiver object. +* +* SYNOPSIS +*/ +void +osm_mpr_rcv_construct( + IN osm_mpr_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a MultiPath Record Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_mpr_rcv_init, osm_mpr_rcv_destroy +* +* Calling osm_mpr_rcv_construct is a prerequisite to calling any other +* method except osm_mpr_rcv_init. +* +* SEE ALSO +* MultiPath Record Receiver object, osm_mpr_rcv_init, osm_mpr_rcv_destroy +*********/ + +/****f* OpenSM: MultiPath Record Receiver/osm_mpr_rcv_destroy +* NAME +* osm_mpr_rcv_destroy +* +* DESCRIPTION +* The osm_mpr_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_mpr_rcv_destroy( + IN osm_mpr_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* MultiPath Record Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_mpr_rcv_construct or osm_mpr_rcv_init. +* +* SEE ALSO +* MultiPath Record Receiver object, osm_mpr_rcv_construct, +* osm_mpr_rcv_init +*********/ + +/****f* OpenSM: MultiPath Record Receiver/osm_mpr_rcv_init +* NAME +* osm_mpr_rcv_init +* +* DESCRIPTION +* The osm_mpr_rcv_init function initializes a +* MultiPath Record Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_mpr_rcv_init( + IN osm_mpr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_mpr_rcv_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the MultiPath Record Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other MultiPath Record Receiver methods. +* +* SEE ALSO +* MultiPath Record Receiver object, osm_mpr_rcv_construct, +* osm_mpr_rcv_destroy +*********/ + +/****f* OpenSM: MultiPath Record Receiver/osm_mpr_rcv_process +* NAME +* osm_mpr_rcv_process +* +* DESCRIPTION +* Process the MultiPathRecord request. +* +* SYNOPSIS +*/ +void +osm_mpr_rcv_process( + IN osm_mpr_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_mpr_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's MultiPathRecord attribute. +* +* RETURN VALUES +* IB_SUCCESS if the MultiPathRecord processing was successful. +* +* NOTES +* This function processes a MultiPathRecord attribute. +* +* SEE ALSO +* MultiPath Record Receiver, Node Info Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_MPR_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_multipath_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_multipath_record_ctrl.h new file mode 100644 index 00000000..090dc9e8 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_multipath_record_ctrl.h @@ -0,0 +1,260 @@ +/* + * 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: + * Declaration of osm_mpr_rcv_ctrl_t. + * This object represents a controller that receives the IBA + * MultiPathRecord attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#ifndef _OSM_MPRCTRL_H_ +#define _OSM_MPRCTRL_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/MultiPath Record Receive Controller +* NAME +* MultiPath Record Receive Controller +* +* DESCRIPTION +* The MultiPath Record Receive Controller object encapsulates +* the information needed to receive the MultiPathRecord attribute from a node. +* +* The MultiPath record Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Hal Rosenstock, Voltaire +* +*********/ + +/****s* OpenSM: MultiPath Record Receive Controller/osm_mpr_rcv_ctrl_t +* NAME +* osm_mpr_rcv_ctrl_t +* +* DESCRIPTION +* MultiPath Record Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_mpr_rcv_ctrl +{ + osm_mpr_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_mpr_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the MultiPath Record Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* MultiPath Record Receive Controller object +* MultiPath Record Receiver object +*********/ + +/****f* OpenSM: MultiPath Record Receive Controller/osm_pr_rcv_ctrl_construct +* NAME +* osm_mpr_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a MultiPath Record Receive Controller object. +* +* SYNOPSIS +*/ +void osm_mpr_rcv_ctrl_construct( + IN osm_mpr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a MultiPath Record Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_mpr_rcv_ctrl_init, osm_mpr_rcv_ctrl_destroy, +* and osm_mpr_rcv_ctrl_is_inited. +* +* Calling osm_mpr_rcv_ctrl_construct is a prerequisite to calling any +* other method except osm_mpr_rcv_ctrl_init. +* +* SEE ALSO +* MultiPath Record Receive Controller object, osm_mpr_rcv_ctrl_init, +* osm_mpr_rcv_ctrl_destroy, osm_mpr_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: MultiPath Record Receive Controller/osm_mpr_rcv_ctrl_destroy +* NAME +* osm_mpr_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_mpr_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_mpr_rcv_ctrl_destroy( + IN osm_mpr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* MultiPath Record Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_mpr_rcv_ctrl_construct or osm_mpr_rcv_ctrl_init. +* +* SEE ALSO +* MultiPath Record Receive Controller object, osm_mpr_rcv_ctrl_construct, +* osm_mpr_rcv_ctrl_init +*********/ + +/****f* OpenSM: MultiPath Record Receive Controller/osm_mpr_rcv_ctrl_init +* NAME +* osm_mpr_rcv_ctrl_init +* +* DESCRIPTION +* The osm_mpr_rcv_ctrl_init function initializes a +* MultiPath Record Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_mpr_rcv_ctrl_init( + IN osm_mpr_rcv_ctrl_t* const p_ctrl, + IN osm_mpr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_mpr_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_mpr_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the MultiPath Record Receive Controller object was +* initialized successfully. +* +* NOTES +* Allows calling other MultiPath Record Receive Controller methods. +* +* SEE ALSO +* MultiPath Record Receive Controller object, osm_pr_rcv_ctrl_construct, +* osm_mpr_rcv_ctrl_destroy, osm_mpr_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: MultiPath Record Receive Controller/osm_mpr_rcv_ctrl_is_inited +* NAME +* osm_mpr_rcv_ctrl_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_mpr_rcv_ctrl_init. +* +* SYNOPSIS +*/ +boolean_t osm_mpr_rcv_ctrl_is_inited( + IN const osm_mpr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_mpr_rcv_ctrl_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_mpr_rcv_ctrl_construct or osm_mpr_rcv_ctrl_init must be +* called before using this function. +* +* SEE ALSO +* MultiPath Record Receive Controller object, osm_mpr_rcv_ctrl_construct, +* osm_mpr_rcv_ctrl_init +*********/ + +END_C_DECLS + +#endif /* _OSM_MPRCTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_node_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_node_record.h new file mode 100644 index 00000000..6af9e2bc --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_node_record.h @@ -0,0 +1,275 @@ +/* + * 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: + * Declaration of osm_nr_rcv_t. + * This object represents the NodeRecord Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_NR_H_ +#define _OSM_NR_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/Node Record Receiver +* NAME +* Node Record Receiver +* +* DESCRIPTION +* The Node Record Receiver object encapsulates the information +* needed to receive the NodeRecord attribute from a node. +* +* The Node record Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Anil S Keshavamurthy, Intel +* +*********/ + +/****s* OpenSM: Node Record Receiver/osm_nr_rcv_t +* NAME +* osm_nr_rcv_t +* +* DESCRIPTION +* Node Record Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_nr_recv +{ + const osm_subn_t *p_subn; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + cl_plock_t *p_lock; + cl_qlock_pool_t pool; + +} osm_nr_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_resp +* Pointer to the SA responder. +* +* p_mad_pool +* Pointer to the mad pool. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* pool +* Pool of linkable node record objects used to generate +* the query response. +* +* SEE ALSO +* +*********/ + +/****f* OpenSM: Node Record Receiver/osm_nr_rcv_construct +* NAME +* osm_nr_rcv_construct +* +* DESCRIPTION +* This function constructs a Node Record Receiver object. +* +* SYNOPSIS +*/ +void osm_nr_rcv_construct( + IN osm_nr_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a Node Record Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_nr_rcv_init, osm_nr_rcv_destroy +* +* Calling osm_nr_rcv_construct is a prerequisite to calling any other +* method except osm_nr_rcv_init. +* +* SEE ALSO +* Node Record Receiver object, osm_nr_rcv_init, osm_lr_rcv_destroy +*********/ + +/****f* OpenSM: Node Record Receiver/osm_nr_rcv_destroy +* NAME +* osm_nr_rcv_destroy +* +* DESCRIPTION +* The osm_nr_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_nr_rcv_destroy( + IN osm_nr_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Node Record Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_nr_rcv_construct or osm_nr_rcv_init. +* +* SEE ALSO +* Node Record Receiver object, osm_nr_rcv_construct, +* osm_nr_rcv_init +*********/ + +/****f* OpenSM: Node Record Receiver/osm_nr_rcv_init +* NAME +* osm_nr_rcv_init +* +* DESCRIPTION +* The osm_nr_rcv_init function initializes a +* Node Record Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_nr_rcv_init( + IN osm_nr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN const osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_nr_rcv_t object to initialize. +* +* p_resp +* [in] Pointer to the SA Responder object. +* +* p_mad_pool +* [in] Pointer to the mad pool. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the Node Record Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other Link Record Receiver methods. +* +* SEE ALSO +* Node Record Receiver object, osm_nr_rcv_construct, osm_nr_rcv_destroy +*********/ + + +/****f* OpenSM: Node Record Receiver/osm_nr_rcv_process +* NAME +* osm_nr_rcv_process +* +* DESCRIPTION +* Process the NodeRecord attribute. +* +* SYNOPSIS +*/ +void osm_nr_rcv_process( + IN osm_nr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_nr_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's NodeRecord attribute. +* +* NOTES +* This function processes a NodeRecord attribute. +* +* SEE ALSO +* Node Record Receiver, Node Record Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_NR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_node_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_node_record_ctrl.h new file mode 100644 index 00000000..681e20ff --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_node_record_ctrl.h @@ -0,0 +1,231 @@ +/* + * 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: + * Declaration of osm_nr_rcv_ctrl_t. + * This object represents a controller that receives the IBA NodeInfo + * record from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_NR_CTRL_H_ +#define _OSM_NR_CTRL_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/Node Record Receive Controller +* NAME +* Node Record Receive Controller +* +* DESCRIPTION +* The Node Record Receive Controller object encapsulates +* the information needed to receive the NodeInfo attribute from a node. +* +* The Node Record Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Anil S Keshavamurthy, Intel +* +*********/ + +/****s* OpenSM: Node Record Receive Controller/osm_nr_rcv_ctrl_t +* NAME +* osm_nr_rcv_ctrl_t +* +* DESCRIPTION +* Node Record Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_nr_ctrl +{ + osm_nr_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_nr_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the Node Record Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Node Record Receive Controller object +* Node Record Receiver object +*********/ + +/****f* OpenSM: Node Record Receive Controller/osm_nr_rcv_ctrl_construct +* NAME +* osm_nr_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Node Record Receive Controller object. +* +* SYNOPSIS +*/ +void osm_nr_rcv_ctrl_construct( + IN osm_nr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Node Record Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_nr_rcv_ctrl_init, osm_nr_rcv_ctrl_destroy, +* +* Calling osm_nr_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_nr_rcv_ctrl_init. +* +* SEE ALSO +* Node Record Receive Controller object, osm_nr_rcv_ctrl_init, +* osm_nr_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: Node Record Receive Controller/osm_nr_rcv_ctrl_destroy +* NAME +* osm_nr_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_nr_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_nr_rcv_ctrl_destroy( + IN osm_nr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Node Record Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_nr_rcv_ctrl_construct or osm_nr_rcv_ctrl_init. +* +* SEE ALSO +* Node Record Receive Controller object, osm_nr_rcv_ctrl_construct, +* osm_nr_rcv_ctrl_init +*********/ + +/****f* OpenSM: Node Record Receive Controller/osm_nr_rcv_ctrl_init +* NAME +* osm_nr_rcv_ctrl_init +* +* DESCRIPTION +* The osm_nr_rcv_ctrl_init function initializes a +* Node Record Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_nr_rcv_ctrl_init( + IN osm_nr_rcv_ctrl_t* const p_ctrl, + IN osm_nr_rcv_t* const p_nr, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_nr_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_nr_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Node Record Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Node Record Receive Controller methods. +* +* SEE ALSO +* Node Record Receive Controller object, osm_nr_rcv_ctrl_construct, +* osm_nr_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_NR_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_path_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_path_record.h new file mode 100644 index 00000000..30a6289e --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_path_record.h @@ -0,0 +1,274 @@ +/* + * 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: + * Declaration of osm_pr_rcv_t. + * This object represents the PathRecord Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_PR_H_ +#define _OSM_PR_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/Path Record Receiver +* NAME +* Path Record Receiver +* +* DESCRIPTION +* The Path Record Receiver object encapsulates the information +* needed to receive the PathRecord request from a node. +* +* The Path Record Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Ranjit Pandit, Intel +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Path Record Receiver/osm_pr_rcv_t +* NAME +* osm_pr_rcv_t +* +* DESCRIPTION +* Path Record Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_pr_rcv +{ + osm_subn_t *p_subn; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + cl_plock_t *p_lock; + cl_qlock_pool_t pr_pool; +} osm_pr_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_gen_req_ctrl +* Pointer to the generic request controller. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* pr_pool +* Pool of path record objects used to generate query responses. +* +* SEE ALSO +* Path Record Receiver object +*********/ + +/****f* OpenSM: Path Record Receiver/osm_pr_rcv_construct +* NAME +* osm_pr_rcv_construct +* +* DESCRIPTION +* This function constructs a Path Record Receiver object. +* +* SYNOPSIS +*/ +void +osm_pr_rcv_construct( + IN osm_pr_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a Path Record Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_pr_rcv_init, osm_pr_rcv_destroy +* +* Calling osm_pr_rcv_construct is a prerequisite to calling any other +* method except osm_pr_rcv_init. +* +* SEE ALSO +* Path Record Receiver object, osm_pr_rcv_init, osm_pr_rcv_destroy +*********/ + +/****f* OpenSM: Path Record Receiver/osm_pr_rcv_destroy +* NAME +* osm_pr_rcv_destroy +* +* DESCRIPTION +* The osm_pr_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_pr_rcv_destroy( + IN osm_pr_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Path Record Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_pr_rcv_construct or osm_pr_rcv_init. +* +* SEE ALSO +* Path Record Receiver object, osm_pr_rcv_construct, +* osm_pr_rcv_init +*********/ + +/****f* OpenSM: Path Record Receiver/osm_pr_rcv_init +* NAME +* osm_pr_rcv_init +* +* DESCRIPTION +* The osm_pr_rcv_init function initializes a +* Path Record Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_pr_rcv_init( + IN osm_pr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_pr_rcv_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the Path Record Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other Path Record Receiver methods. +* +* SEE ALSO +* Path Record Receiver object, osm_pr_rcv_construct, +* osm_pr_rcv_destroy +*********/ + +/****f* OpenSM: Path Record Receiver/osm_pr_rcv_process +* NAME +* osm_pr_rcv_process +* +* DESCRIPTION +* Process the PathRecord request. +* +* SYNOPSIS +*/ +void +osm_pr_rcv_process( + IN osm_pr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_pr_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's PathRecord attribute. +* +* RETURN VALUES +* IB_SUCCESS if the PathRecord processing was successful. +* +* NOTES +* This function processes a PathRecord attribute. +* +* SEE ALSO +* Path Record Receiver, Path Record Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_PR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_path_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_path_record_ctrl.h new file mode 100644 index 00000000..1b7f9052 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_path_record_ctrl.h @@ -0,0 +1,261 @@ +/* + * 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: + * Declaration of osm_pr_rcv_ctrl_t. + * This object represents a controller that receives the IBA PathRecord + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_PRCTRL_H_ +#define _OSM_PRCTRL_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/Path Record Receive Controller +* NAME +* Path Record Receive Controller +* +* DESCRIPTION +* The Path Record Receive Controller object encapsulates +* the information needed to receive the PathRecord attribute from a node. +* +* The Path record Receive 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 +* +*********/ + +/****s* OpenSM: Path Record Receive Controller/osm_pr_rcv_ctrl_t +* NAME +* osm_pr_rcv_ctrl_t +* +* DESCRIPTION +* Path Record Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_pr_rcv_ctrl +{ + osm_pr_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_pr_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the Path Record Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Path Record Receive Controller object +* Path Record Receiver object +*********/ + +/****f* OpenSM: Path Record Receive Controller/osm_pr_rcv_ctrl_construct +* NAME +* osm_pr_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Path Record Receive Controller object. +* +* SYNOPSIS +*/ +void osm_pr_rcv_ctrl_construct( + IN osm_pr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Path Record Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_pr_rcv_ctrl_init, osm_pr_rcv_ctrl_destroy, +* and osm_pr_rcv_ctrl_is_inited. +* +* Calling osm_pr_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_pr_rcv_ctrl_init. +* +* SEE ALSO +* Path Record Receive Controller object, osm_pr_rcv_ctrl_init, +* osm_pr_rcv_ctrl_destroy, osm_pr_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Path Record Receive Controller/osm_pr_rcv_ctrl_destroy +* NAME +* osm_pr_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_pr_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_pr_rcv_ctrl_destroy( + IN osm_pr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Path Record Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_pr_rcv_ctrl_construct or osm_pr_rcv_ctrl_init. +* +* SEE ALSO +* Path Record Receive Controller object, osm_pr_rcv_ctrl_construct, +* osm_pr_rcv_ctrl_init +*********/ + +/****f* OpenSM: Path Record Receive Controller/osm_pr_rcv_ctrl_init +* NAME +* osm_pr_rcv_ctrl_init +* +* DESCRIPTION +* The osm_pr_rcv_ctrl_init function initializes a +* Path Record Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_pr_rcv_ctrl_init( + IN osm_pr_rcv_ctrl_t* const p_ctrl, + IN osm_pr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_pr_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_pr_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Path Record Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Path Record Receive Controller methods. +* +* SEE ALSO +* Path Record Receive Controller object, osm_pr_rcv_ctrl_construct, +* osm_pr_rcv_ctrl_destroy, osm_pr_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Path Record Receive Controller/osm_pr_rcv_ctrl_is_inited +* NAME +* osm_pr_rcv_ctrl_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_pr_rcv_ctrl_init. +* +* SYNOPSIS +*/ +boolean_t osm_pr_rcv_ctrl_is_inited( + IN const osm_pr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_pr_rcv_ctrl_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_pr_rcv_ctrl_construct or osm_pr_rcv_ctrl_init must be +* called before using this function. +* +* SEE ALSO +* Path Record Receive Controller object, osm_pr_rcv_ctrl_construct, +* osm_pr_rcv_ctrl_init +*********/ + +END_C_DECLS + +#endif /* _OSM_PRCTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_pkey_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_pkey_record.h new file mode 100644 index 00000000..a3c016bc --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_pkey_record.h @@ -0,0 +1,268 @@ +/* + * 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$ + */ + + +#ifndef _OSM_PKEY_REC_RCV_H_ +#define _OSM_PKEY_REC_RCV_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/P_Key Record Receiver +* NAME +* P_Key Record Receiver +* +* DESCRIPTION +* The P_Key Record Receiver object encapsulates the information +* needed to handle P_Key Record query from a SA. +* +* The P_Key Record Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Yael Kalka, Mellanox +* +*********/ + +/****s* OpenSM: P_Key Record Receiver/osm_pkey_rec_rcv_t +* NAME +* osm_pkey_rec_rcv_t +* +* DESCRIPTION +* P_Key Record Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_pkey_rec_rcv +{ + const osm_subn_t *p_subn; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + cl_plock_t *p_lock; + cl_qlock_pool_t pool; + +} osm_pkey_rec_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_resp +* Pointer to the SA responder. +* +* p_mad_pool +* Pointer to the mad pool. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* pool +* Pool of linkable P_Key Record objects used to generate +* the query response. +* +* SEE ALSO +* +*********/ + +/****f* OpenSM: P_Key Record Receiver/osm_vlarb_rec_rcv_construct +* NAME +* osm_pkey_rec_rcv_construct +* +* DESCRIPTION +* This function constructs a P_Key Record Receiver object. +* +* SYNOPSIS +*/ +void +osm_pkey_rec_rcv_construct( + IN osm_pkey_rec_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a P_Key Record Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_pkey_rec_rcv_init, osm_pkey_rec_rcv_destroy +* +* Calling osm_pkey_rec_rcv_construct is a prerequisite to calling any other +* method except osm_pkey_rec_rcv_init. +* +* SEE ALSO +* P_Key Record Receiver object, osm_pkey_rec_rcv_init, +* osm_pkey_rec_rcv_destroy +*********/ + +/****f* OpenSM: P_Key Record Receiver/osm_pkey_rec_rcv_destroy +* NAME +* osm_pkey_rec_rcv_destroy +* +* DESCRIPTION +* The osm_pkey_rec_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_pkey_rec_rcv_destroy( + IN osm_pkey_rec_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* P_Key Record Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_pkey_rec_rcv_construct or osm_pkey_rec_rcv_init. +* +* SEE ALSO +* P_Key Record Receiver object, osm_pkey_rec_rcv_construct, +* osm_pkey_rec_rcv_init +*********/ + +/****f* OpenSM: P_Key Record Receiver/osm_pkey_rec_rcv_init +* NAME +* osm_pkey_rec_rcv_init +* +* DESCRIPTION +* The osm_pkey_rec_rcv_init function initializes a +* P_Key Record Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_pkey_rec_rcv_init( + IN osm_pkey_rec_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN const osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_pkey_rec_rcv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the P_Key Record Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other P_Key Record Receiver methods. +* +* SEE ALSO +* P_Key Record Receiver object, osm_pkey_rec_rcv_construct, +* osm_pkey_rec_rcv_destroy +*********/ + +/****f* OpenSM: P_Key Record Receiver/osm_pkey_rec_rcv_process +* NAME +* osm_pkey_rec_rcv_process +* +* DESCRIPTION +* Process the P_Key Table Query . +* +* SYNOPSIS +*/ +void +osm_pkey_rec_rcv_process( + IN osm_pkey_rec_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_pkey_rec_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the P_Key Record Query attribute. +* +* RETURN VALUES +* CL_SUCCESS if the Query processing was successful. +* +* NOTES +* This function processes a SA P_Key Record attribute. +* +* SEE ALSO +* P_Key Record Receiver, P_Key Record Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_PKEY_REC_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_pkey_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_pkey_record_ctrl.h new file mode 100644 index 00000000..3c861b20 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_pkey_record_ctrl.h @@ -0,0 +1,218 @@ +/* + * 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$ + */ + + +#ifndef _OSM_PKEY_REC_CTRL_H_ +#define _OSM_PKEY_REC_CTRL_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/P_Key Record Receive Controller +* NAME +* P_Key Record Receive Controller +* +* DESCRIPTION +* The P_Key Record Receive Controller object encapsulates +* the information needed to handle P_Key record query from SA client. +* +* The P_Key Record Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Yael Kalka, Mellanox +* +*********/ + +/****s* OpenSM: P_Key Record Receive Controller/osm_pkey_rec_rcv_ctrl_t +* NAME +* osm_pkey_rec_rcv_ctrl_t +* +* DESCRIPTION +* P_Key Record Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_pkey_rec_rcv_ctrl +{ + osm_pkey_rec_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_pkey_rec_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the P_Key Record Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* P_Key Record Receive Controller object +* P_Key Record Receiver object +*********/ + +/****f* OpenSM: P_Key Record Receive Controller/osm_pkey_rec_rcv_ctrl_construct +* NAME +* osm_pkey_rec_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a P_Key Record Receive Controller object. +* +* SYNOPSIS +*/ +void osm_pkey_rec_rcv_ctrl_construct( + IN osm_pkey_rec_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a P_Key Record Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_pkey_rec_rcv_ctrl_init, osm_pkey_rec_rcv_ctrl_destroy +* +* Calling osm_pkey_rec_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_pkey_rec_rcv_ctrl_init. +* +* SEE ALSO +* P_Key Record Receive Controller object, osm_pkey_rec_rcv_ctrl_init, +* osm_pkey_rec_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: P_Key Record Receive Controller/osm_pkey_rec_rcv_ctrl_destroy +* NAME +* osm_pkey_rec_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_pkey_rec_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_pkey_rec_rcv_ctrl_destroy( + IN osm_pkey_rec_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* P_Key Record Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_pkey_rec_rcv_ctrl_construct or osm_pkey_rec_rcv_ctrl_init. +* +* SEE ALSO +* P_Key Record Receive Controller object, osm_pkey_rec_rcv_ctrl_construct, +* osm_pkey_rec_rcv_ctrl_init +*********/ + +/****f* OpenSM: P_Key Record Receive Controller/osm_pkey_rec_rcv_ctrl_init +* NAME +* osm_pkey_rec_rcv_ctrl_init +* +* DESCRIPTION +* The osm_pkey_rec_rcv_ctrl_init function initializes a +* P_Key Record Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_pkey_rec_rcv_ctrl_init( + IN osm_pkey_rec_rcv_ctrl_t* const p_ctrl, + IN osm_pkey_rec_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_pkey_rec_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_pkey_rec_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the P_Key Record Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other P_Key Record Receive Controller methods. +* +* SEE ALSO +* P_Key Record Receive Controller object, osm_pkey_rec_rcv_ctrl_construct, +* osm_pkey_rec_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_PKEY_REC_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_portinfo_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_portinfo_record.h new file mode 100644 index 00000000..242d52eb --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_portinfo_record.h @@ -0,0 +1,280 @@ +/* + * 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: + * Declaration of osm_pir_rcv_t. + * This object represents the PortInfo Record Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_PIR_RCV_H_ +#define _OSM_PIR_RCV_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/PortInfo Record Receiver +* NAME +* PortInfo Record Receiver +* +* DESCRIPTION +* The PortInfo Record Receiver object encapsulates the information +* needed to receive the PortInfoRecord attribute from a node. +* +* The PortInfo Record Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Ranjit Pandit, Intel +* +*********/ + +/****s* OpenSM: PortInfo Record Receiver/osm_pir_rcv_t +* NAME +* osm_pir_rcv_t +* +* DESCRIPTION +* PortInfo Record Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_pir_rcv +{ + osm_subn_t *p_subn; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + cl_plock_t *p_lock; + cl_qlock_pool_t pool; +} osm_pir_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_resp +* Pointer to the SA responder. +* +* p_mad_pool +* Pointer to the mad pool. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* pool +* Pool of linkable PortInfo Record objects used to generate +* the query response. +* +* SEE ALSO +* +*********/ + +/****f* OpenSM: PortInfo Record Receiver/osm_pir_rcv_construct +* NAME +* osm_pir_rcv_construct +* +* DESCRIPTION +* This function constructs a PortInfo Record Receiver object. +* +* SYNOPSIS +*/ +void +osm_pir_rcv_construct( + IN osm_pir_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a PortInfo Record Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_pir_rcv_init, osm_pir_rcv_destroy +* +* Calling osm_pir_rcv_construct is a prerequisite to calling any other +* method except osm_pir_rcv_init. +* +* SEE ALSO +* PortInfo Record Receiver object, osm_pir_rcv_init, +* osm_pir_rcv_destroy +*********/ + +/****f* OpenSM: PortInfo Record Receiver/osm_pir_rcv_destroy +* NAME +* osm_pir_rcv_destroy +* +* DESCRIPTION +* The osm_pir_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_pir_rcv_destroy( + IN osm_pir_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* PortInfo Record Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_pir_rcv_construct or osm_pir_rcv_init. +* +* SEE ALSO +* PortInfo Record Receiver object, osm_pir_rcv_construct, +* osm_pir_rcv_init +*********/ + +/****f* OpenSM: PortInfo Record Receiver/osm_pir_rcv_init +* NAME +* osm_pir_rcv_init +* +* DESCRIPTION +* The osm_pir_rcv_init function initializes a +* PortInfo Record Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_pir_rcv_init( + IN osm_pir_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_pir_rcv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the PortInfo Record Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other PortInfo Record Receiver methods. +* +* SEE ALSO +* PortInfo Record Receiver object, osm_pir_rcv_construct, +* osm_pir_rcv_destroy +*********/ + +/****f* OpenSM: PortInfo Record Receiver/osm_pir_rcv_process +* NAME +* osm_pir_rcv_process +* +* DESCRIPTION +* Process the PortInfoRecord attribute. +* +* SYNOPSIS +*/ +void +osm_pir_rcv_process( + IN osm_pir_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_pir_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's PortInfoRecord attribute. +* +* RETURN VALUES +* CL_SUCCESS if the PortInfoRecord processing was successful. +* +* NOTES +* This function processes a PortInfoRecord attribute. +* +* SEE ALSO +* PortInfo Record Receiver, PortInfo Record Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_PIR_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_portinfo_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_portinfo_record_ctrl.h new file mode 100644 index 00000000..a8ee2b80 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_portinfo_record_ctrl.h @@ -0,0 +1,231 @@ +/* + * 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: + * Declaration of osm_pir_rcv_ctrl_t. + * This object represents a controller that receives the IBA PortInfo + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_PIR_CTRL_H_ +#define _OSM_PIR_CTRL_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/PortInfo Record Receive Controller +* NAME +* PortInfo Record Receive Controller +* +* DESCRIPTION +* The PortInfo Record Receive Controller object encapsulates +* the information needed to receive the PortInfo attribute from a node. +* +* The PortInfo Record Receive 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 +* +*********/ + +/****s* OpenSM: PortInfo Record Receive Controller/osm_pir_rcv_ctrl_t +* NAME +* osm_pir_rcv_ctrl_t +* +* DESCRIPTION +* PortInfo Record Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_pir_rcv_ctrl +{ + osm_pir_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_pir_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the PortInfo Record Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* PortInfo Record Receive Controller object +* PortInfo Record Receiver object +*********/ + +/****f* OpenSM: PortInfo Record Receive Controller/osm_pir_rcv_ctrl_construct +* NAME +* osm_pir_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a PortInfo Record Receive Controller object. +* +* SYNOPSIS +*/ +void osm_pir_rcv_ctrl_construct( + IN osm_pir_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a PortInfo Record Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_pir_rcv_ctrl_init, osm_pir_rcv_ctrl_destroy +* +* Calling osm_pir_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_pir_rcv_ctrl_init. +* +* SEE ALSO +* PortInfo Record Receive Controller object, osm_pir_rcv_ctrl_init, +* osm_pir_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: PortInfo Record Receive Controller/osm_pir_rcv_ctrl_destroy +* NAME +* osm_pir_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_pir_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_pir_rcv_ctrl_destroy( + IN osm_pir_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* PortInfo Record Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_pir_rcv_ctrl_construct or osm_pir_rcv_ctrl_init. +* +* SEE ALSO +* PortInfo Record Receive Controller object, osm_pir_rcv_ctrl_construct, +* osm_pir_rcv_ctrl_init +*********/ + +/****f* OpenSM: PortInfo Record Receive Controller/osm_pir_rcv_ctrl_init +* NAME +* osm_pir_rcv_ctrl_init +* +* DESCRIPTION +* The osm_pir_rcv_ctrl_init function initializes a +* PortInfo Record Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_pir_rcv_ctrl_init( + IN osm_pir_rcv_ctrl_t* const p_ctrl, + IN osm_pir_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_pir_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_pir_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the PortInfo Record Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other PortInfo Record Receive Controller methods. +* +* SEE ALSO +* PortInfo Record Receive Controller object, osm_pir_rcv_ctrl_construct, +* osm_pir_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_PIR_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_response.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_response.h new file mode 100644 index 00000000..7d691609 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_response.h @@ -0,0 +1,255 @@ +/* + * 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: + * Declaration of osm_sa_resp_t. + * This object represents an object that responds to SA queries. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_SA_RESP_H_ +#define _OSM_SA_RESP_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/SA Response +* NAME +* SA Response +* +* DESCRIPTION +* The SA Response object encapsulates the information +* needed to respond to an SA query. +* +* The SA Response object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Ranjit Pandit, Intel +* Steve King, Intel +* +*********/ + +/****s* OpenSM: SA Response/osm_sa_resp_t +* NAME +* osm_sa_resp_t +* +* DESCRIPTION +* SA Response structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_sa_resp +{ + osm_mad_pool_t *p_pool; + osm_log_t *p_log; +} osm_sa_resp_t; +/* +* FIELDS +* p_pool +* Pointer to the MAD pool. +* +* SEE ALSO +* SA Response object +*********/ + +/****f* OpenSM: SA Response/osm_sa_resp_construct +* NAME +* osm_sa_resp_construct +* +* DESCRIPTION +* This function constructs a SA Response object. +* +* SYNOPSIS +*/ +void +osm_sa_resp_construct( + IN osm_sa_resp_t* const p_resp ); +/* +* PARAMETERS +* p_resp +* [in] Pointer to a SA Response object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sa_resp_init, and osm_sa_resp_destroy. +* +* Calling osm_sa_resp_construct is a prerequisite to calling any other +* method except osm_sa_resp_init. +* +* SEE ALSO +* SA Response object, osm_sa_resp_init, +* osm_sa_resp_destroy +*********/ + +/****f* OpenSM: SA Response/osm_sa_resp_destroy +* NAME +* osm_sa_resp_destroy +* +* DESCRIPTION +* The osm_sa_resp_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_sa_resp_destroy( + IN osm_sa_resp_t* const p_resp ); +/* +* PARAMETERS +* p_resp +* [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 Response object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_sa_resp_construct or osm_sa_resp_init. +* +* SEE ALSO +* SA Response object, osm_sa_resp_construct, +* osm_sa_resp_init +*********/ + +/****f* OpenSM: SA Response/osm_sa_resp_init +* NAME +* osm_sa_resp_init +* +* DESCRIPTION +* The osm_sa_resp_init function initializes a +* SA Response object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sa_resp_init( + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_pool, + IN osm_log_t* const p_log ); +/* +* PARAMETERS +* p_resp +* [in] Pointer to an osm_sa_resp_t object to initialize. +* +* 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. +* +* RETURN VALUES +* IB_SUCCESS if the SA Response object was initialized +* successfully. +* +* NOTES +* Allows calling other SA Response methods. +* +* SEE ALSO +* SA Response object, osm_sa_resp_construct, +* osm_sa_resp_destroy +*********/ + +/****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_resp_t* const p_resp, + IN const osm_madw_t* const p_madw, + IN const ib_net16_t sa_status ); +/* +* PARAMETERS +* p_resp +* [in] Pointer to an osm_sa_resp_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. +* +* NOTES +* Allows calling other SA Response methods. +* +* SEE ALSO +* SA Response object, osm_sa_resp_construct, +* osm_sa_resp_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_SA_RESP_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_service_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_service_record.h new file mode 100644 index 00000000..baa15fae --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_service_record.h @@ -0,0 +1,298 @@ +/* + * 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: + * Declaration of osm_sr_rcv_t. + * This object represents the ServiceRecord Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_SR_H_ +#define _OSM_SR_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/Service Record Receiver +* NAME +* Service Record Receiver +* +* DESCRIPTION +* The Service Record Receiver object encapsulates the information +* needed to receive the ServiceRecord request from a node. +* +* The Service Record Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Anil S Keshavamurthy +* +*********/ + +/****s* OpenSM: Service Record Receiver/osm_sr_rcv_t +* NAME +* osm_sr_rcv_t +* +* DESCRIPTION +* Service Record Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_sr_rcv +{ + osm_subn_t *p_subn; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + cl_plock_t *p_lock; + cl_qlock_pool_t sr_pool; + cl_timer_t sr_timer; + +} osm_sr_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_resp +* Pointer to the osm_sa_resp_t object. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* sr_pool +* Pool of Service Record objects used to generate query responses. +* +* SEE ALSO +* Service Record Receiver object +*********/ + +/****f* OpenSM: Service Record Receiver/osm_sr_rcv_construct +* NAME +* osm_sr_rcv_construct +* +* DESCRIPTION +* This function constructs a Service Record Receiver object. +* +* SYNOPSIS +*/ +void +osm_sr_rcv_construct( + IN osm_sr_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a Service Record Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sr_rcv_init, osm_sr_rcv_destroy +* +* Calling osm_sr_rcv_construct is a prerequisite to calling any other +* method except osm_sr_rcv_init. +* +* SEE ALSO +* Service Record Receiver object, osm_sr_rcv_init, osm_sr_rcv_destroy +*********/ + +/****f* OpenSM: Service Record Receiver/osm_sr_rcv_destroy +* NAME +* osm_sr_rcv_destroy +* +* DESCRIPTION +* The osm_sr_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_sr_rcv_destroy( + IN osm_sr_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Service Record Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_sr_rcv_construct or osm_sr_rcv_init. +* +* SEE ALSO +* Service Record Receiver object, osm_sr_rcv_construct, +* osm_sr_rcv_init +*********/ + +/****f* OpenSM: Service Record Receiver/osm_sr_rcv_init +* NAME +* osm_sr_rcv_init +* +* DESCRIPTION +* The osm_sr_rcv_init function initializes a +* Service Record Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sr_rcv_init( + IN osm_sr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_sr_rcv_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the Service Record Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other Service Record Receiver methods. +* +* SEE ALSO +* Service Record Receiver object, osm_sr_rcv_construct, +* osm_sr_rcv_destroy +*********/ + +/****f* OpenSM: Service Record Receiver/osm_sr_rcv_process +* NAME +* osm_sr_rcv_process +* +* DESCRIPTION +* Process the ServiceRecord request. +* +* SYNOPSIS +*/ +void +osm_sr_rcv_process( + IN osm_sr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_sr_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's ServiceRecord attribute. +* NOTES +* This function processes a ServiceRecord attribute. +* +* SEE ALSO +* Service Record Receiver +*********/ + +/****f* OpenSM: Service Record Receiver/osm_sr_rcv_lease_cb +* NAME +* osm_sr_rcv_lease_cb +* +* DESCRIPTION +* Timer Callback function which is executed to check the lease period +* expiration +* +* SYNOPSIS +*/ + +void +osm_sr_rcv_lease_cb( + IN void* context ); +/* +* PARAMETERS +* context +* [in] Pointer to osm_sa_db_t object. +* +* NOTES +* This function processes a ServiceRecord attribute. +* +* SEE ALSO +* Service Record Receiver +*********/ + +END_C_DECLS + +#endif /* _OSM_SR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_service_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_service_record_ctrl.h new file mode 100644 index 00000000..f784090e --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_service_record_ctrl.h @@ -0,0 +1,230 @@ +/* + * 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: + * Declaration of osm_sr_rcv_ctrl_t. + * This object represents a controller that receives the IBA Service + * record attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_SRCTRL_H_ +#define _OSM_SRCTRL_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/Service Record Receive Controller +* NAME +* Service Record Receive Controller +* +* DESCRIPTION +* The Service Record Receive Controller object encapsulates +* the information needed to receive the Service Record attribute from a node. +* +* The Service Record Receive Controller object is thread safe. +* +* 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 Receive Controller/osm_sr_rcv_ctrl_t +* NAME +* osm_sr_rcv_ctrl_t +* +* DESCRIPTION +* Service Record Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_sr_rcv_ctrl +{ + osm_sr_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_sr_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the Service Record Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Service Record Receiver object +*********/ + +/****f* OpenSM: Service Record Receive Controller/osm_sr_rcv_ctrl_construct +* NAME +* osm_sr_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Service Record Receive Controller object. +* +* SYNOPSIS +*/ +void osm_sr_rcv_ctrl_construct( + IN osm_sr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Service Record Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sr_rcv_ctrl_init, osm_sr_rcv_ctrl_destroy, +* +* Calling osm_sr_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_psr_rcv_ctrl_init. +* +* SEE ALSO +* Service Record Receive Controller object, osm_sr_rcv_ctrl_init, +* osm_sr_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: Service Record Receive Controller/osm_sr_rcv_ctrl_destroy +* NAME +* osm_sr_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_sr_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_sr_rcv_ctrl_destroy( + IN osm_sr_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Service Record Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_sr_rcv_ctrl_construct or osm_sr_rcv_ctrl_init. +* +* SEE ALSO +* Service Record Receive Controller object, osm_sr_rcv_ctrl_construct, +* osm_sr_rcv_ctrl_init +*********/ + +/****f* OpenSM: Service Record Receive Controller/osm_sr_rcv_ctrl_init +* NAME +* osm_sr_rcv_ctrl_init +* +* DESCRIPTION +* The osm_sr_rcv_ctrl_init function initializes a +* Service Record Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_sr_rcv_ctrl_init( + IN osm_sr_rcv_ctrl_t* const p_ctrl, + IN osm_sr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sr_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_sr_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* IB_SUCCESS if the osm_sr_rcv_t Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Service Record Receive Controller methods. +* +* SEE ALSO +* Service Record Receive Controller object, osm_sr_rcv_ctrl_construct, +* osm_sr_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_SRCTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_slvl_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_slvl_record.h new file mode 100644 index 00000000..3f1abfff --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_slvl_record.h @@ -0,0 +1,281 @@ +/* + * 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: + * Declaration of osm_slvl_rec_rcv_t. + * This object represents the SLtoVL Mapping Table Receiver object. + * attribute from a SA query. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#ifndef _OSM_SLVL_REC_RCV_H_ +#define _OSM_SLVL_REC_RCV_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/SLtoVL Mapping Record Receiver +* NAME +* SLtoVL Mapping Record Receiver +* +* DESCRIPTION +* The SLtoVL Mapping Record Receiver object encapsulates the information +* needed to handle SLtoVL Mapping Record query from a SA. +* +* The SLtoVL Mapping Record Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ + +/****s* OpenSM: SLtoVL Mapping Record Receiver/osm_slvl_rec_rcv_t +* NAME +* osm_slvl_rec_rcv_t +* +* DESCRIPTION +* SLtoVL Mapping Record Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_slvl_rec_rcv +{ + const osm_subn_t *p_subn; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + cl_plock_t *p_lock; + cl_qlock_pool_t pool; + +} osm_slvl_rec_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_resp +* Pointer to the SA responder. +* +* p_mad_pool +* Pointer to the mad pool. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* pool +* Pool of linkable SLtoVL Mapping Record objects used to generate +* the query response. +* +* SEE ALSO +* +*********/ + +/****f* OpenSM: SLtoVL Mapping Record Receiver/osm_slvl_rec_rcv_construct +* NAME +* osm_slvl_rec_rcv_construct +* +* DESCRIPTION +* This function constructs a SLtoVL Mapping Record Receiver object. +* +* SYNOPSIS +*/ +void +osm_slvl_rec_rcv_construct( + IN osm_slvl_rec_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a SLtoVL Mapping Record Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_slvl_rec_rcv_init, osm_slvl_rec_rcv_destroy +* +* Calling osm_slvl_rec_rcv_construct is a prerequisite to calling any other +* method except osm_slvl_rec_rcv_init. +* +* SEE ALSO +* SLtoVL Mapping Record Receiver object, osm_slvl_rec_rcv_init, +* osm_slvl_rec_rcv_destroy +*********/ + +/****f* OpenSM: SLtoVL Mapping Record Receiver/osm_slvl_rec_rcv_destroy +* NAME +* osm_slvl_rec_rcv_destroy +* +* DESCRIPTION +* The osm_slvl_rec_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_slvl_rec_rcv_destroy( + IN osm_slvl_rec_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* SLtoVL Mapping Record Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_slvl_rec_rcv_construct or osm_slvl_rec_rcv_init. +* +* SEE ALSO +* SLtoVL Mapping Record Receiver object, osm_slvl_rec_rcv_construct, +* osm_slvl_rec_rcv_init +*********/ + +/****f* OpenSM: SLtoVL Mapping Record Receiver/osm_slvl_rec_rcv_init +* NAME +* osm_slvl_rec_rcv_init +* +* DESCRIPTION +* The osm_slvl_rec_rcv_init function initializes a +* SLtoVL Mapping Record Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_slvl_rec_rcv_init( + IN osm_slvl_rec_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN const osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_slvl_rec_rcv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the SLtoVL Mapping Record Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other SLtoVL Mapping Record Receiver methods. +* +* SEE ALSO +* SLtoVL Mapping Record Receiver object, osm_slvl_rec_rcv_construct, +* osm_slvl_rec_rcv_destroy +*********/ + +/****f* OpenSM: SLtoVL Mapping Record Receiver/osm_slvl_rec_rcv_process +* NAME +* osm_slvl_rec_rcv_process +* +* DESCRIPTION +* Process the SLtoVL Map Table Query . +* +* SYNOPSIS +*/ +void +osm_slvl_rec_rcv_process( + IN osm_slvl_rec_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_slvl_rec_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the SLtoVL Map Record Query attribute. +* +* RETURN VALUES +* CL_SUCCESS if the Query processing was successful. +* +* NOTES +* This function processes a SA SLtoVL Map Record attribute. +* +* SEE ALSO +* SLtoVL Mapping Record Receiver, SLtoVL Mapping Record Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_SLVL_REC_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_slvl_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_slvl_record_ctrl.h new file mode 100644 index 00000000..ae02bba1 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_slvl_record_ctrl.h @@ -0,0 +1,231 @@ +/* + * 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: + * Declaration of osm_sa_slvl_rec_rcv_ctrl_t. + * This object represents a controller that receives the IBA VL Arbitration + * record query from SA client. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#ifndef _OSM_SLVL_REC_CTRL_H_ +#define _OSM_SLVL_REC_CTRL_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/SLtoVL Record Receive Controller +* NAME +* SLtoVL Record Receive Controller +* +* DESCRIPTION +* The SLtoVL Mapping Record Receive Controller object encapsulates +* the information needed to handle SLtoVL Mapping record query from SA client. +* +* The SLtoVL Mapping Record Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ + +/****s* OpenSM: SLtoVL Mapping Record Receive Controller/osm_slvl_rec_rcv_ctrl_t +* NAME +* osm_slvl_rec_rcv_ctrl_t +* +* DESCRIPTION +* SLtoVL Mapping Record Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_slvl_rec_rcv_ctrl +{ + osm_slvl_rec_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_slvl_rec_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the SLtoVL Mapping Record Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* SLtoVL Mapping Record Receive Controller object +* SLtoVL Mapping Record Receiver object +*********/ + +/****f* OpenSM: SLtoVL Mapping Record Receive Controller/osm_slvl_rec_rcv_ctrl_construct +* NAME +* osm_slvl_rec_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a SLtoVL Mapping Record Receive Controller object. +* +* SYNOPSIS +*/ +void osm_slvl_rec_rcv_ctrl_construct( + IN osm_slvl_rec_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a SLtoVL Mapping Record Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_slvl_rec_rcv_ctrl_init, osm_slvl_rec_rcv_ctrl_destroy +* +* Calling osm_slvl_rec_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_slvl_rec_rcv_ctrl_init. +* +* SEE ALSO +* SLtoVL Mapping Record Receive Controller object, osm_slvl_rec_rcv_ctrl_init, +* osm_slvl_rec_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: SLtoVL Mapping Record Receive Controller/osm_slvl_rec_rcv_ctrl_destroy +* NAME +* osm_slvl_rec_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_slvl_rec_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_slvl_rec_rcv_ctrl_destroy( + IN osm_slvl_rec_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* SLtoVL Mapping Record Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_slvl_rec_rcv_ctrl_construct or osm_slvl_rec_rcv_ctrl_init. +* +* SEE ALSO +* SLtoVL Mapping Record Receive Controller object, osm_slvl_rec_rcv_ctrl_construct, +* osm_slvl_rec_rcv_ctrl_init +*********/ + +/****f* OpenSM: SLtoVL Mapping Record Receive Controller/osm_slvl_rec_rcv_ctrl_init +* NAME +* osm_slvl_rec_rcv_ctrl_init +* +* DESCRIPTION +* The osm_slvl_rec_rcv_ctrl_init function initializes a +* SLtoVL Mapping Record Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_slvl_rec_rcv_ctrl_init( + IN osm_slvl_rec_rcv_ctrl_t* const p_ctrl, + IN osm_slvl_rec_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_slvl_rec_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_slvl_rec_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the SLtoVL Mapping Record Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other SLtoVL Mapping Record Receive Controller methods. +* +* SEE ALSO +* SLtoVL Mapping Record Receive Controller object, osm_slvl_rec_rcv_ctrl_construct, +* osm_slvl_rec_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_SLVL_REC_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sminfo_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sminfo_record.h new file mode 100644 index 00000000..d9dabcb3 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sminfo_record.h @@ -0,0 +1,262 @@ +/* + * 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: + * Declaration of osm_smir_rcv_t. + * This object represents the SMInfo Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_SMIR_H_ +#define _OSM_SMIR_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/SM Info Receiver +* NAME +* SM Info Receiver +* +* DESCRIPTION +* The SM Info Receiver object encapsulates the information +* needed to receive the SMInfoRecord attribute from a node. +* +* The SM Info Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Ranjit Pandit, Intel +* +*********/ +/****s* OpenSM: SM Info Receiver/osm_smir_rcv_t +* NAME +* osm_smir_rcv_t +* +* DESCRIPTION +* SM Info Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_smir +{ + osm_subn_t* p_subn; + osm_stats_t* p_stats; + osm_sa_resp_t* p_resp; + osm_mad_pool_t* p_mad_pool; + osm_log_t* p_log; + cl_plock_t* p_lock; + cl_qlock_pool_t pool; +} osm_smir_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* SEE ALSO +* SM Info Receiver object +*********/ + +/****f* OpenSM: SM Info Receiver/osm_smir_rcv_construct +* NAME +* osm_smir_rcv_construct +* +* DESCRIPTION +* This function constructs a SM Info Receiver object. +* +* SYNOPSIS +*/ +void osm_smir_rcv_construct( + IN osm_smir_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a SM Info Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_smir_rcv_init, osm_smir_rcv_destroy +* +* Calling osm_smir_rcv_construct is a prerequisite to calling any other +* method except osm_smir_rcv_init. +* +* SEE ALSO +* SM Info Receiver object, osm_smir_rcv_init, osm_smir_rcv_destroy +*********/ + +/****f* OpenSM: SM Info Receiver/osm_smir_rcv_destroy +* NAME +* osm_smir_rcv_destroy +* +* DESCRIPTION +* The osm_smir_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_smir_rcv_destroy( + IN osm_smir_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* SM Info Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_smir_rcv_construct or osm_smir_rcv_init. +* +* SEE ALSO +* SM Info Receiver object, osm_smir_rcv_construct, +* osm_smir_rcv_init +*********/ + +/****f* OpenSM: SM Info Receiver/osm_smir_rcv_init +* NAME +* osm_smir_rcv_init +* +* DESCRIPTION +* The osm_smir_rcv_init function initializes a +* SM Info Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_smir_rcv_init( + IN osm_smir_rcv_t* const p_ctrl, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_stats_t* const p_stats, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_smir_rcv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_stats +* [in] Pointer to the Statistics object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the SM Info Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other SM Info Receiver methods. +* +* SEE ALSO +* SM Info Receiver object, osm_smir_rcv_construct, osm_smir_rcv_destroy +*********/ + +/****f* OpenSM: SM Info Receiver/osm_smir_rcv_process +* NAME +* osm_smir_rcv_process +* +* DESCRIPTION +* Process the SMInfoRecord attribute. +* +* SYNOPSIS +*/ +void osm_smir_rcv_process( + IN osm_smir_rcv_t* const p_ctrl, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_smir_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's SMInfoRecord attribute. +* +* RETURN VALUES +* CL_SUCCESS if the SMInfoRecord processing was successful. +* +* NOTES +* This function processes a SMInfoRecord attribute. +* +* SEE ALSO +* SM Info Receiver, SM Info Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_SMIR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sminfo_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sminfo_record_ctrl.h new file mode 100644 index 00000000..28aae4dd --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sminfo_record_ctrl.h @@ -0,0 +1,231 @@ +/* + * 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: + * Declaration of osm_smir_ctrl_t. + * This object represents a controller that receives the IBA SMInfo + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_SMIR_CTRL_H_ +#define _OSM_SMIR_CTRL_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/SM Info Receive Controller +* NAME +* SM Info Receive Controller +* +* DESCRIPTION +* The SM Info Receive Controller object encapsulates +* the information needed to receive the SMInfo attribute from a node. +* +* The SM Info Receive 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 +* +*********/ + +/****s* OpenSM: SM Info Receive Controller/osm_smir_ctrl_t +* NAME +* osm_smir_ctrl_t +* +* DESCRIPTION +* SM Info Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_smir_ctrl +{ + osm_smir_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_smir_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the SM Info Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* SM Info Receive Controller object +* SM Info Receiver object +*********/ + +/****f* OpenSM: SM Info Receive Controller/osm_smir_ctrl_construct +* NAME +* osm_smir_ctrl_construct +* +* DESCRIPTION +* This function constructs a SM Info Receive Controller object. +* +* SYNOPSIS +*/ +void osm_smir_ctrl_construct( + IN osm_smir_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a SM Info Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_smir_ctrl_init, osm_smir_ctrl_destroy +* +* Calling osm_smir_ctrl_construct is a prerequisite to calling any other +* method except osm_smir_ctrl_init. +* +* SEE ALSO +* SM Info Receive Controller object, osm_smir_ctrl_init, +* osm_smir_ctrl_destroy +*********/ + +/****f* OpenSM: SM Info Receive Controller/osm_smir_ctrl_destroy +* NAME +* osm_smir_ctrl_destroy +* +* DESCRIPTION +* The osm_smir_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_smir_ctrl_destroy( + IN osm_smir_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* SM Info Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_smir_ctrl_construct or osm_smir_ctrl_init. +* +* SEE ALSO +* SM Info Receive Controller object, osm_smir_ctrl_construct, +* osm_smir_ctrl_init +*********/ + +/****f* OpenSM: SM Info Receive Controller/osm_smir_ctrl_init +* NAME +* osm_smir_ctrl_init +* +* DESCRIPTION +* The osm_smir_ctrl_init function initializes a +* SM Info Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_smir_ctrl_init( + IN osm_smir_ctrl_t* const p_ctrl, + IN osm_smir_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_smir_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_smir_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the SM Info Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other SM Info Receive Controller methods. +* +* SEE ALSO +* SM Info Receive Controller object, osm_smir_ctrl_construct, +* osm_smir_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_SMIR_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sw_info_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sw_info_record.h new file mode 100644 index 00000000..e8cf0bb0 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sw_info_record.h @@ -0,0 +1,306 @@ +/* + * 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: + * Declaration of osm_sir_rcv_t. + * This object represents the SwitchInfo Receiver object. + * attribute from a switch node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#ifndef _OSM_SIR_RCV_H_ +#define _OSM_SIR_RCV_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/Switch Info Receiver +* NAME +* Switch Info Receiver +* +* DESCRIPTION +* The Switch Info Receiver object encapsulates the information +* needed to receive the SwitchInfo attribute from a switch node. +* +* The Switch Info Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Hal Rosenstock, Voltaire +* +*********/ + +/****s* OpenSM: Switch Info Receiver/osm_sir_rcv_t +* NAME +* osm_sir_rcv_t +* +* DESCRIPTION +* Switch Info Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_sir_rcv +{ + osm_subn_t *p_subn; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + osm_req_t *p_req; + osm_state_mgr_t *p_state_mgr; + cl_plock_t *p_lock; + cl_qlock_pool_t pool; +} osm_sir_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_log +* Pointer to the log object. +* +* p_req +* Pointer to the Request object. +* +* p_state_mgr +* Pointer to the State Manager object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* Switch Info Receiver object +*********/ + +/****f* OpenSM: Switch Info Receiver/osm_sir_rcv_construct +* NAME +* osm_sir_rcv_construct +* +* DESCRIPTION +* This function constructs a Switch Info Receiver object. +* +* SYNOPSIS +*/ +void osm_sir_rcv_construct( + IN osm_sir_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Switch Info Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sir_rcv_init, osm_sir_rcv_destroy, +* and osm_sir_rcv_is_inited. +* +* Calling osm_sir_rcv_construct is a prerequisite to calling any other +* method except osm_sir_rcv_init. +* +* SEE ALSO +* Switch Info Receiver object, osm_sir_rcv_init, +* osm_sir_rcv_destroy, osm_sir_rcv_is_inited +*********/ + +/****f* OpenSM: Switch Info Receiver/osm_sir_rcv_destroy +* NAME +* osm_sir_rcv_destroy +* +* DESCRIPTION +* The osm_sir_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_sir_rcv_destroy( + IN osm_sir_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Switch Info Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_sir_rcv_construct or osm_sir_rcv_init. +* +* SEE ALSO +* Switch Info Receiver object, osm_sir_rcv_construct, +* osm_sir_rcv_init +*********/ + +/****f* OpenSM: Switch Info Receiver/osm_sir_rcv_init +* NAME +* osm_sir_rcv_init +* +* DESCRIPTION +* The osm_sir_rcv_init function initializes a +* Switch Info Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_sir_rcv_init( + IN osm_sir_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_sir_rcv_t object to initialize. +* +* p_resp +* [in] Pointer to the SA Responder object. +* +* p_mad_pool +* [in] Pointer to the mad pool. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the Switch Info Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other Switch Info Receiver methods. +* +* SEE ALSO +* Switch Info Receiver object, osm_sir_rcv_construct, +* osm_sir_rcv_destroy, osm_sir_rcv_is_inited +*********/ + +/****f* OpenSM: Switch Info Receiver/osm_sir_rcv_is_inited +* NAME +* osm_sir_rcv_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_sir_rcv_init. +* +* SYNOPSIS +*/ +boolean_t osm_sir_rcv_is_inited( + IN const osm_sir_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sir_rcv_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_sir_rcv_construct or osm_sir_rcv_init must be +* called before using this function. +* +* SEE ALSO +* Switch Info Receiver object, osm_sir_rcv_construct, +* osm_sir_rcv_init +*********/ + +/****f* OpenSM: Switch Info Receiver/osm_sir_rcv_process +* NAME +* osm_sir_rcv_process +* +* DESCRIPTION +* Process the SwitchInfo attribute. +* +* SYNOPSIS +*/ +void osm_sir_rcv_process( + IN osm_sir_rcv_t* const p_ctrl, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sir_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's SwitchInfo attribute. +* +* RETURN VALUES +* CL_SUCCESS if the SwitchInfo processing was successful. +* +* NOTES +* This function processes a SwitchInfo attribute. +* +* SEE ALSO +* Switch Info Receiver, Switch Info Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_SIR_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sw_info_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sw_info_record_ctrl.h new file mode 100644 index 00000000..86b9674f --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_sw_info_record_ctrl.h @@ -0,0 +1,259 @@ +/* + * 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: + * Declaration of osm_sir_rcv_ctrl_t. + * This object represents a controller that receives the IBA SwitchInfo + * attribute from a switch node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#ifndef _OSM_SIR_RCV_CTRL_H_ +#define _OSM_SIR_RCV_CTRL_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/Switch Info Receive Controller +* NAME +* Switch Info Receive Controller +* +* DESCRIPTION +* The Switch Info Receive Controller object encapsulates the information +* needed to receive the SwitchInfo attribute from a switch node. +* +* The Switch Info Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Hal Rosenstock, Voltaire +* +*********/ + +/****s* OpenSM: Switch Info Receive Controller/osm_sir_rcv_ctrl_t +* NAME +* osm_sir_rcv_ctrl_t +* +* DESCRIPTION +* Switch Info Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_sir_rcv_ctrl +{ + osm_sir_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; +} osm_sir_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the Switch Info Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Switch Info Receive Controller object +* Switch Info Receiver object +*********/ + +/****f* OpenSM: Switch Info Receive Controller/osm_sir_rcv_ctrl_construct +* NAME +* osm_sir_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Switch Info Receive Controller object. +* +* SYNOPSIS +*/ +void osm_sir_rcv_ctrl_construct( + IN osm_sir_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Switch Info Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sir_rcv_ctrl_init, osm_sir_rcv_ctrl_destroy, +* and osm_sir_rcv_ctrl_is_inited. +* +* Calling osm_sir_rcv_ctrl_construct is a prerequisite to calling any +* other method except osm_sir_rcv_ctrl_init. +* +* SEE ALSO +* Switch Info Receive Controller object, osm_sir_rcv_ctrl_init, +* osm_sir_rcv_ctrl_destroy, osm_sir_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Switch Info Receive Controller/osm_sir_rcv_ctrl_destroy +* NAME +* osm_sir_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_sir_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_sir_rcv_ctrl_destroy( + IN osm_sir_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Switch Info Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_sir_rcv_ctrl_construct or osm_sir_rcv_ctrl_init. +* +* SEE ALSO +* Switch Info Receive Controller object, osm_sir_rcv_ctrl_construct, +* osm_sir_rcv_ctrl_init +*********/ + +/****f* OpenSM: Switch Info Receive Controller/osm_sir_rcv_ctrl_init +* NAME +* osm_sir_rcv_ctrl_init +* +* DESCRIPTION +* The osm_sir_rcv_ctrl_init function initializes a +* Switch Info Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_sir_rcv_ctrl_init( + IN osm_sir_rcv_ctrl_t* const p_ctrl, + IN osm_sir_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sir_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_sir_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Switch Info Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Switch Info Receive Controller methods. +* +* SEE ALSO +* Switch Info Receive Controller object, osm_sir_rcv_ctrl_construct, +* osm_sir_rcv_ctrl_destroy, osm_sir_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Switch Info Receive Controller/osm_sir_rcv_ctrl_is_inited +* NAME +* osm_sir_rcv_ctrl_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_sir_rcv_ctrl_init. +* +* SYNOPSIS +*/ +boolean_t osm_sir_rcv_ctrl_is_inited( + IN const osm_sir_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sir_rcv_ctrl_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_sir_rcv_ctrl_construct or osm_sir_rcv_ctrl_init must be +* called before using this function. +* +* SEE ALSO +* Switch Info Receive Controller object, osm_sir_rcv_ctrl_construct, +* osm_sir_rcv_ctrl_init +*********/ + +END_C_DECLS + +#endif /* _OSM_SIR_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_vlarb_record.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_vlarb_record.h new file mode 100644 index 00000000..c5f3766e --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_vlarb_record.h @@ -0,0 +1,280 @@ +/* + * 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: + * Declaration of osm_vlarb_rec_rcv_t. + * This object represents the VLArbitration Record Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#ifndef _OSM_VLARB_REC_RCV_H_ +#define _OSM_VLARB_REC_RCV_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/VLArbitration Record Receiver +* NAME +* VLArbitration Record Receiver +* +* DESCRIPTION +* The VLArbitration Record Receiver object encapsulates the information +* needed to handle VL Arbitration Record query from a SA. +* +* The VLArbitration Record Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ + +/****s* OpenSM: VLArbitration Record Receiver/osm_vlarb_rec_rcv_t +* NAME +* osm_vlarb_rec_rcv_t +* +* DESCRIPTION +* VLArbitration Record Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_vlarb_rec_rcv +{ + const osm_subn_t *p_subn; + osm_sa_resp_t *p_resp; + osm_mad_pool_t *p_mad_pool; + osm_log_t *p_log; + cl_plock_t *p_lock; + cl_qlock_pool_t pool; +} osm_vlarb_rec_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_resp +* Pointer to the SA responder. +* +* p_mad_pool +* Pointer to the mad pool. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* pool +* Pool of linkable VLArbitration Record objects used to generate +* the query response. +* +* SEE ALSO +* +*********/ + +/****f* OpenSM: VLArbitration Record Receiver/osm_vlarb_rec_rcv_construct +* NAME +* osm_vlarb_rec_rcv_construct +* +* DESCRIPTION +* This function constructs a VLArbitration Record Receiver object. +* +* SYNOPSIS +*/ +void +osm_vlarb_rec_rcv_construct( + IN osm_vlarb_rec_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a VLArbitration Record Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_vlarb_rec_rcv_init, osm_vlarb_rec_rcv_destroy +* +* Calling osm_vlarb_rec_rcv_construct is a prerequisite to calling any other +* method except osm_vlarb_rec_rcv_init. +* +* SEE ALSO +* VLArbitration Record Receiver object, osm_vlarb_rec_rcv_init, +* osm_vlarb_rec_rcv_destroy +*********/ + +/****f* OpenSM: VLArbitration Record Receiver/osm_vlarb_rec_rcv_destroy +* NAME +* osm_vlarb_rec_rcv_destroy +* +* DESCRIPTION +* The osm_vlarb_rec_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_vlarb_rec_rcv_destroy( + IN osm_vlarb_rec_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* VLArbitration Record Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_vlarb_rec_rcv_construct or osm_vlarb_rec_rcv_init. +* +* SEE ALSO +* VLArbitration Record Receiver object, osm_vlarb_rec_rcv_construct, +* osm_vlarb_rec_rcv_init +*********/ + +/****f* OpenSM: VLArbitration Record Receiver/osm_vlarb_rec_rcv_init +* NAME +* osm_vlarb_rec_rcv_init +* +* DESCRIPTION +* The osm_vlarb_rec_rcv_init function initializes a +* VLArbitration Record Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_vlarb_rec_rcv_init( + IN osm_vlarb_rec_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN const osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_vlarb_rec_rcv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the VLArbitration Record Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other VLArbitration Record Receiver methods. +* +* SEE ALSO +* VLArbitration Record Receiver object, osm_vlarb_rec_rcv_construct, +* osm_vlarb_rec_rcv_destroy +*********/ + +/****f* OpenSM: VLArbitration Record Receiver/osm_vlarb_rec_rcv_process +* NAME +* osm_vlarb_rec_rcv_process +* +* DESCRIPTION +* Process the VL Arbitration Table Query . +* +* SYNOPSIS +*/ +void +osm_vlarb_rec_rcv_process( + IN osm_vlarb_rec_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_vlarb_rec_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the VL Arbitration Record Query attribute. +* +* RETURN VALUES +* CL_SUCCESS if the Query processing was successful. +* +* NOTES +* This function processes a SA VL Arbitration Record attribute. +* +* SEE ALSO +* VLArbitration Record Receiver, VLArbitration Record Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_VLARB_REC_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_vlarb_record_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_vlarb_record_ctrl.h new file mode 100644 index 00000000..3cc07568 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sa_vlarb_record_ctrl.h @@ -0,0 +1,231 @@ +/* + * 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: + * Declaration of osm_sa_vlarb_rec_rcv_ctrl_t. + * This object represents a controller that receives the IBA VL Arbitration + * record query from SA client. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#ifndef _OSM_VLARB_REC_CTRL_H_ +#define _OSM_VLARB_REC_CTRL_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/VLArbitration Record Receive Controller +* NAME +* VLArbitration Record Receive Controller +* +* DESCRIPTION +* The VLArbitration Record Receive Controller object encapsulates +* the information needed to handle VLArbitration record query from SA client. +* +* The VLArbitration Record Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ + +/****s* OpenSM: VLArbitration Record Receive Controller/osm_vlarb_rec_rcv_ctrl_t +* NAME +* osm_vlarb_rec_rcv_ctrl_t +* +* DESCRIPTION +* VLArbitration Record Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_vlarb_rec_rcv_ctrl +{ + osm_vlarb_rec_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_vlarb_rec_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the VLArbitration Record Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* VLArbitration Record Receive Controller object +* VLArbitration Record Receiver object +*********/ + +/****f* OpenSM: VLArbitration Record Receive Controller/osm_vlarb_rec_rcv_ctrl_construct +* NAME +* osm_vlarb_rec_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a VLArbitration Record Receive Controller object. +* +* SYNOPSIS +*/ +void osm_vlarb_rec_rcv_ctrl_construct( + IN osm_vlarb_rec_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a VLArbitration Record Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_vlarb_rec_rcv_ctrl_init, osm_vlarb_rec_rcv_ctrl_destroy +* +* Calling osm_vlarb_rec_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_vlarb_rec_rcv_ctrl_init. +* +* SEE ALSO +* VLArbitration Record Receive Controller object, osm_vlarb_rec_rcv_ctrl_init, +* osm_vlarb_rec_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: VLArbitration Record Receive Controller/osm_vlarb_rec_rcv_ctrl_destroy +* NAME +* osm_vlarb_rec_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_vlarb_rec_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_vlarb_rec_rcv_ctrl_destroy( + IN osm_vlarb_rec_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* VLArbitration Record Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_vlarb_rec_rcv_ctrl_construct or osm_vlarb_rec_rcv_ctrl_init. +* +* SEE ALSO +* VLArbitration Record Receive Controller object, osm_vlarb_rec_rcv_ctrl_construct, +* osm_vlarb_rec_rcv_ctrl_init +*********/ + +/****f* OpenSM: VLArbitration Record Receive Controller/osm_vlarb_rec_rcv_ctrl_init +* NAME +* osm_vlarb_rec_rcv_ctrl_init +* +* DESCRIPTION +* The osm_vlarb_rec_rcv_ctrl_init function initializes a +* VLArbitration Record Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_vlarb_rec_rcv_ctrl_init( + IN osm_vlarb_rec_rcv_ctrl_t* const p_ctrl, + IN osm_vlarb_rec_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_vlarb_rec_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_vlarb_rec_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the VLArbitration Record Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other VLArbitration Record Receive Controller methods. +* +* SEE ALSO +* VLArbitration Record Receive Controller object, osm_vlarb_rec_rcv_ctrl_construct, +* osm_vlarb_rec_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_VLARB_REC_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_service.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_service.h new file mode 100644 index 00000000..7c09a4f6 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_service.h @@ -0,0 +1,241 @@ +/* + * 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$ + */ + + +#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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#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_t +{ + 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_construct, osm_svcr_destroy +*********/ + + +/****f* OpenSM: Service Record/osm_svcr_init +* NAME +* osm_svcr_new +* +* DESCRIPTION +* Initializes the osm_svcr_t structure. +* +* SYNOPSIS +*/ +void +osm_svcr_init( + IN osm_svcr_t* const p_svcr, + IN const ib_service_record_t *p_svc_rec ); +/* +* PARAMETERS +* p_svc_rec +* [in] Pointer to osm_svcr_t structure +* p_svc_rec +* [in] Pointer to the ib_service_record_t +* +* SEE ALSO +* Service Record, osm_svcr_construct, osm_svcr_destroy +*********/ + +/****f* OpenSM: Service Record/osm_svcr_construct +* NAME +* osm_svcr_construct +* +* DESCRIPTION +* Constructs the osm_svcr_t structure. +* +* SYNOPSIS +*/ +void +osm_svcr_construct( + IN osm_svcr_t* const p_svcr ); +/* +* PARAMETERS +* p_svc_rec +* [in] Pointer to osm_svcr_t structure +* +* SEE ALSO +* Service Record, osm_svcr_construct, osm_svcr_destroy +*********/ + +/****f* OpenSM: Service Record/osm_svcr_destroy +* NAME +* osm_svcr_destroy +* +* DESCRIPTION +* Constructs the osm_svcr_t structure. +* +* SYNOPSIS +*/ +void +osm_svcr_destroy( + IN osm_svcr_t* const p_svcr ); +/* +* PARAMETERS +* p_svc_rec +* [in] Pointer to osm_svcr_t structure +* +* SEE ALSO +* Service Record, osm_svcr_construct, osm_svcr_destroy +*********/ + + + +osm_svcr_t* +osm_svcr_get_by_rid( + IN osm_subn_t const *p_subn, + IN osm_log_t *p_log, + IN ib_service_record_t* const p_svc_rec ); + +void +osm_svcr_insert_to_db( + IN osm_subn_t *p_subn, + IN osm_log_t *p_log, + IN osm_svcr_t *p_svcr); +void +osm_svcr_remove_from_db( + IN osm_subn_t *p_subn, + IN osm_log_t *p_log, + IN osm_svcr_t *p_svcr); + + +END_C_DECLS + +#endif /* _OSM_SVCR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_slvl_map_rcv.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_slvl_map_rcv.h new file mode 100644 index 00000000..9ab13bf7 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_slvl_map_rcv.h @@ -0,0 +1,265 @@ +/* + * 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: + * Declaration of osm_slvl_rcv_t. + * This object represents the SLtoVL Map Receiver object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#ifndef _OSM_SLVL_RCV_H_ +#define _OSM_SLVL_RCV_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/Slvl Map Receiver +* NAME +* Slvl Map Receiver +* +* DESCRIPTION +* The Slvl Map Receiver object encapsulates the information +* needed to set or get the SLtoVL map attribute from a port. +* +* The Slvl Map Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ + +/****s* OpenSM: Slvl Map Receiver/osm_slvl_rcv_t +* NAME +* osm_slvl_rcv_t +* +* DESCRIPTION +* Slvl Map Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_slvl_rcv +{ + osm_subn_t *p_subn; + osm_req_t *p_req; + osm_log_t *p_log; + cl_plock_t *p_lock; + +} osm_slvl_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_req +* Pointer to the generic attribute request object. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* Slvl Map Receiver object +*********/ + +/****f* OpenSM: Slvl Map Receiver/osm_slvl_rcv_construct +* NAME +* osm_slvl_rcv_construct +* +* DESCRIPTION +* This function constructs a Slvl Map Receiver object. +* +* SYNOPSIS +*/ +void osm_slvl_rcv_construct( + IN osm_slvl_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Slvl Map Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_slvl_rcv_destroy +* +* Calling osm_slvl_rcv_construct is a prerequisite to calling any other +* method except osm_slvl_rcv_init. +* +* SEE ALSO +* Slvl Map Receiver object, osm_slvl_rcv_init, +* osm_slvl_rcv_destroy +*********/ + +/****f* OpenSM: Slvl Map Receiver/osm_slvl_rcv_destroy +* NAME +* osm_slvl_rcv_destroy +* +* DESCRIPTION +* The osm_slvl_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_slvl_rcv_destroy( + IN osm_slvl_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Slvl Map Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_slvl_rcv_construct or osm_slvl_rcv_init. +* +* SEE ALSO +* Slvl Map Receiver object, osm_slvl_rcv_construct, +* osm_slvl_rcv_init +*********/ + +/****f* OpenSM: Slvl Map Receiver/osm_slvl_rcv_init +* NAME +* osm_slvl_rcv_init +* +* DESCRIPTION +* The osm_slvl_rcv_init function initializes a +* Slvl Map Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_slvl_rcv_init( + IN osm_slvl_rcv_t* const p_ctrl, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_slvl_rcv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the Slvl Map Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other Slvl Map Receiver methods. +* +* SEE ALSO +* Slvl Map Receiver object, osm_slvl_rcv_construct, +* osm_slvl_rcv_destroy +*********/ + +/****f* OpenSM: Slvl Map Receiver/osm_slvl_rcv_process +* NAME +* osm_slvl_rcv_process +* +* DESCRIPTION +* Process the SLtoVL map attribute. +* +* SYNOPSIS +*/ +void osm_slvl_rcv_process( + IN const osm_slvl_rcv_t* const p_ctrl, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_slvl_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's SLtoVL attribute. +* +* RETURN VALUES +* CL_SUCCESS if the SLtoVL processing was successful. +* +* NOTES +* This function processes a SLtoVL attribute. +* +* SEE ALSO +* Slvl Map Receiver, Slvl Map Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_SLVL_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_slvl_map_rcv_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_slvl_map_rcv_ctrl.h new file mode 100644 index 00000000..26f4776f --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_slvl_map_rcv_ctrl.h @@ -0,0 +1,261 @@ +/* + * 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: + * Declaration of osm_pi_rcv_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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#ifndef _OSM_SLVL_RCV_CTRL_H_ +#define _OSM_SLVL_RCV_CTRL_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/SltoVL Map Table Receive Controller +* NAME +* Slvl Map Receive Controller +* +* DESCRIPTION +* The Slvl Map Receive Controller object encapsulates +* the information needed to get or set SLtoVL Map of a port. +* +* The Slvl Map Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ + +/****s* OpenSM: Slvl Map Receive Controller/osm_slvl_rcv_ctrl_t +* NAME +* osm_slvl_rcv_ctrl_t +* +* DESCRIPTION +* Slvl Map Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_slvl_rcv_ctrl +{ + osm_slvl_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_slvl_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the Slvl Map Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Slvl Map Receive Controller object +* Slvl Map Receiver object +*********/ + +/****f* OpenSM: Slvl Map Receive Controller/osm_slvl_rcv_ctrl_construct +* NAME +* osm_slvl_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Slvl Map Receive Controller object. +* +* SYNOPSIS +*/ +void osm_slvl_rcv_ctrl_construct( + IN osm_slvl_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Slvl Map Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_slvl_rcv_ctrl_init, osm_slvl_rcv_ctrl_destroy, +* and osm_slvl_rcv_ctrl_is_inited. +* +* Calling osm_slvl_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_slvl_rcv_ctrl_init. +* +* SEE ALSO +* Slvl Map Receive Controller object, osm_slvl_rcv_ctrl_init, +* osm_slvl_rcv_ctrl_destroy, osm_slvl_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Slvl Map Receive Controller/osm_slvl_rcv_ctrl_destroy +* NAME +* osm_slvl_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_slvl_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_slvl_rcv_ctrl_destroy( + IN osm_slvl_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Slvl Map Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_slvl_rcv_ctrl_construct or osm_slvl_rcv_ctrl_init. +* +* SEE ALSO +* Slvl Map Receive Controller object, osm_slvl_rcv_ctrl_construct, +* osm_slvl_rcv_ctrl_init +*********/ + +/****f* OpenSM: Slvl Map Receive Controller/osm_slvl_rcv_ctrl_init +* NAME +* osm_slvl_rcv_ctrl_init +* +* DESCRIPTION +* The osm_slvl_rcv_ctrl_init function initializes a +* Slvl Map Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_slvl_rcv_ctrl_init( + IN osm_slvl_rcv_ctrl_t* const p_ctrl, + IN osm_slvl_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_slvl_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_slvl_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Slvl Map Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Slvl Map Receive Controller methods. +* +* SEE ALSO +* Slvl Map Receive Controller object, osm_slvl_rcv_ctrl_construct, +* osm_slvl_rcv_ctrl_destroy, osm_slvl_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Slvl Map Receive Controller/osm_slvl_rcv_ctrl_is_inited +* NAME +* osm_slvl_rcv_ctrl_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_slvl_rcv_ctrl_init. +* +* SYNOPSIS +*/ +boolean_t osm_slvl_rcv_ctrl_is_inited( + IN const osm_slvl_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_slvl_rcv_ctrl_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_slvl_rcv_ctrl_construct or osm_slvl_rcv_ctrl_init must be +* called before using this function. +* +* SEE ALSO +* Slvl Map Receive Controller object, osm_slvl_rcv_ctrl_construct, +* osm_slvl_rcv_ctrl_init +*********/ + +END_C_DECLS + +#endif /* _OSM_SLVL_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sm.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sm.h new file mode 100644 index 00000000..07025554 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sm.h @@ -0,0 +1,566 @@ +/* + * 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: + * Declaration of osm_sm_t, osm_other_sm_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#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 +#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; + cl_event_t signal; + cl_event_t subnet_up_event; + cl_thread_t sweeper; + 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; + osm_req_t req; + osm_req_ctrl_t req_ctrl; + osm_resp_t resp; + osm_ni_rcv_t ni_rcv; + osm_ni_rcv_ctrl_t ni_rcv_ctrl; + osm_pi_rcv_t pi_rcv; + osm_pi_rcv_ctrl_t pi_rcv_ctrl; + osm_nd_rcv_t nd_rcv; + osm_nd_rcv_ctrl_t nd_rcv_ctrl; + osm_sm_mad_ctrl_t mad_ctrl; + osm_si_rcv_t si_rcv; + osm_si_rcv_ctrl_t si_rcv_ctrl; + osm_state_mgr_ctrl_t state_mgr_ctrl; + osm_lid_mgr_t lid_mgr; + osm_ucast_mgr_t ucast_mgr; + osm_link_mgr_t link_mgr; + osm_state_mgr_t state_mgr; + osm_drop_mgr_t drop_mgr; + osm_lft_rcv_t lft_rcv; + osm_lft_rcv_ctrl_t lft_rcv_ctrl; + osm_mft_rcv_t mft_rcv; + osm_mft_rcv_ctrl_t mft_rcv_ctrl; + osm_sweep_fail_ctrl_t sweep_fail_ctrl; + osm_sminfo_rcv_t sm_info_rcv; + osm_sminfo_rcv_ctrl_t sm_info_rcv_ctrl; + osm_trap_rcv_t trap_rcv; + osm_trap_rcv_ctrl_t trap_rcv_ctrl; + osm_sm_state_mgr_t sm_state_mgr; + osm_mcast_mgr_t mcast_mgr; + osm_slvl_rcv_t slvl_rcv; + osm_slvl_rcv_ctrl_t slvl_rcv_ctrl; + osm_vla_rcv_t vla_rcv; + osm_vla_rcv_ctrl_t vla_rcv_ctrl; + osm_pkey_rcv_t pkey_rcv; + osm_pkey_rcv_ctrl_t pkey_rcv_ctrl; +} 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. +* +* req +* Generic MAD attribute requester. +* +* req_ctrl +* Controller for the generic requester. +* +* resp +* MAD attribute responder. +* +* nd_rcv_ctrl +* Node Description Receive Controller. +* +* ni_rcv_ctrl +* Node Info Receive Controller. +* +* pi_rcv_ctrl +* Port Info Receive Controller. +* +* si_rcv_ctrl +* Switch Info Receive Controller. +* +* nd_rcv_ctrl +* Node Description Receive Controller. +* +* mad_ctrl +* MAD Controller. +* +* smi_get_ctrl +* SM Info Get Controller. +* +* p_disp +* Pointer to the Dispatcher. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* SM object +*********/ + +/****f* OpenSM: SM/osm_sm_construct +* NAME +* osm_sm_construct +* +* DESCRIPTION +* This function constructs an SM object. +* +* SYNOPSIS +*/ +void +osm_sm_construct( + IN osm_sm_t* const p_sm ); +/* +* PARAMETERS +* p_sm +* [in] Pointer to a SM object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sm_init, osm_sm_destroy +* +* Calling osm_sm_construct is a prerequisite to calling any other +* method except osm_sm_init. +* +* SEE ALSO +* SM object, osm_sm_init, osm_sm_destroy +*********/ + +/****f* OpenSM: SM/osm_sm_shutdown +* NAME +* osm_sm_shutdown +* +* DESCRIPTION +* The osm_sm_shutdown function shutdowns an SM, stopping the sweeper +* and unregistering all messages from the dispatcher +* +* SYNOPSIS +*/ +void +osm_sm_shutdown( + IN osm_sm_t* const p_sm ); +/* +* PARAMETERS +* p_sm +* [in] Pointer to a SM object to shutdown. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* SM object, osm_sm_construct, osm_sm_init +*********/ + +/****f* OpenSM: SM/osm_sm_destroy +* NAME +* osm_sm_destroy +* +* DESCRIPTION +* The osm_sm_destroy function destroys an SM, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_sm_destroy( + IN osm_sm_t* const p_sm ); +/* +* PARAMETERS +* p_sm +* [in] Pointer to a SM object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified SM object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_sm_construct or +* osm_sm_init. +* +* SEE ALSO +* SM object, osm_sm_construct, osm_sm_init +*********/ + +/****f* OpenSM: SM/osm_sm_init +* NAME +* osm_sm_init +* +* DESCRIPTION +* The osm_sm_init function initializes a SM object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sm_init( + IN osm_sm_t* const p_sm, + IN osm_subn_t* const p_subn, + IN osm_db_t* const p_db, + IN osm_vendor_t* const p_vendor, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_vl15_t* const p_vl15, + IN osm_log_t* const p_log, + IN osm_stats_t* const p_stats, + IN cl_dispatcher_t* const p_disp, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_sm_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_vendor +* [in] Pointer to the vendor specific interfaces object. +* +* p_mad_pool +* [in] Pointer to the MAD pool. +* +* p_vl15 +* [in] Pointer to the VL15 interface. +* +* p_log +* [in] Pointer to the log object. +* +* p_stats +* [in] Pointer to the statistics object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the SM object was initialized successfully. +* +* NOTES +* Allows calling other SM methods. +* +* SEE ALSO +* SM object, osm_sm_construct, osm_sm_destroy +*********/ + +/****f* OpenSM: SM/osm_sm_sweep +* NAME +* osm_sm_sweep +* +* DESCRIPTION +* Initiates a subnet sweep. +* +* SYNOPSIS +*/ +void +osm_sm_sweep( + IN osm_sm_t* const p_sm ); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_sm_t object. +* +* RETURN VALUES +* IB_SUCCESS if the sweep completed successfully. +* +* NOTES +* +* SEE ALSO +* SM object +*********/ + +/****f* OpenSM: SM/osm_sm_bind +* NAME +* osm_sm_bind +* +* DESCRIPTION +* Binds the sm object to a port guid. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sm_bind( + IN osm_sm_t* const p_sm, + IN const ib_net64_t port_guid ); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_sm_t object to bind. +* +* port_guid +* [in] Local port GUID with which to bind. +* +* +* RETURN VALUES +* None +* +* NOTES +* A given SM object can only be bound to one port at a time. +* +* SEE ALSO +*********/ + +/****f* OpenSM: SM/osm_sm_mcgrp_join +* NAME +* osm_sm_mcgrp_join +* +* DESCRIPTION +* Adds a port to the multicast group. Creates the multicast group +* if necessary. +* +* This function is called by the SA. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sm_mcgrp_join( + IN osm_sm_t* const p_sm, + IN const ib_net16_t mlid, + IN const ib_net64_t port_guid, + IN osm_mcast_req_type_t req_type ); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_sm_t object. +* +* mlid +* [in] Multicast LID +* +* port_guid +* [in] Port GUID to add to the group. +* +* req_type +* [in] Type of the MC request that caused this join +* (MC create/join). +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: SM/osm_sm_mcgrp_leave +* NAME +* osm_sm_mcgrp_leave +* +* DESCRIPTION +* Removes a port from the multicast group. +* +* This function is called by the SA. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sm_mcgrp_leave( + IN osm_sm_t* const p_sm, + IN const ib_net16_t mlid, + IN const ib_net64_t port_guid ); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_sm_t object. +* +* mlid +* [in] Multicast LID +* +* port_guid +* [in] Port GUID to remove from the group. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: OpenSM/osm_sm_wait_for_subnet_up +* NAME +* osm_sm_wait_for_subnet_up +* +* DESCRIPTION +* Blocks the calling thread until the subnet is up. +* +* SYNOPSIS +*/ +static inline cl_status_t +osm_sm_wait_for_subnet_up( + IN osm_sm_t* const p_sm, + IN uint32_t const wait_us, + IN boolean_t const interruptible ) +{ + return( cl_event_wait_on( &p_sm->subnet_up_event, + wait_us, interruptible ) ); +} +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_sm_t object. +* +* wait_us +* [in] Number of microseconds to wait. +* +* interruptible +* [in] Indicates whether the wait operation can be interrupted +* by external signals. +* +* RETURN VALUES +* CL_SUCCESS if the wait operation succeeded in response to the event +* being set. +* +* CL_TIMEOUT if the specified time period elapses. +* +* CL_NOT_DONE if the wait was interrupted by an external signal. +* +* CL_ERROR if the wait operation failed. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_SM_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sm_mad_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sm_mad_ctrl.h new file mode 100644 index 00000000..ffba2c75 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sm_mad_ctrl.h @@ -0,0 +1,339 @@ +/* + * 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: + * 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_SM_MAD_CTRL_H_ +#define _OSM_SM_MAD_CTRL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +/****h* OpenSM/SM MAD Controller +* NAME +* SM MAD Controller +* +* DESCRIPTION +* The SM MAD Controller object encapsulates +* the information needed to receive MADs from the transport layer. +* +* The SM MAD Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: SM MAD Controller/osm_sm_mad_ctrl_t +* NAME +* osm_sm_mad_ctrl_t +* +* DESCRIPTION +* SM MAD Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_sm_mad_ctrl +{ + osm_log_t *p_log; + osm_subn_t *p_subn; + osm_mad_pool_t *p_mad_pool; + osm_vl15_t *p_vl15; + osm_vendor_t *p_vendor; + osm_bind_handle_t h_bind; + cl_plock_t *p_lock; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + osm_stats_t *p_stats; + +} osm_sm_mad_ctrl_t; +/* +* FIELDS +* p_log +* Pointer to the log object. +* +* p_subn +* Pointer to the subnet object. +* +* p_mad_pool +* Pointer to the MAD pool. +* +* p_vendor +* Pointer to the vendor specific interfaces object. +* +* h_bind +* Bind handle returned by the transport layer. +* +* p_lock +* Pointer to the serializing lock. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* p_stats +* Pointer to the OpenSM statistics block. +* +* SEE ALSO +* SM MAD Controller object +* SM MADr object +*********/ + +/****f* OpenSM: SM MAD Controller/osm_sm_mad_ctrl_construct +* NAME +* osm_sm_mad_ctrl_construct +* +* DESCRIPTION +* This function constructs a SM MAD Controller object. +* +* SYNOPSIS +*/ +void +osm_sm_mad_ctrl_construct( + IN osm_sm_mad_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a SM MAD Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sm_mad_ctrl_init, and osm_sm_mad_ctrl_destroy. +* +* Calling osm_sm_mad_ctrl_construct is a prerequisite to calling any other +* method except osm_sm_mad_ctrl_init. +* +* SEE ALSO +* SM MAD Controller object, osm_sm_mad_ctrl_init, +* osm_sm_mad_ctrl_destroy +*********/ + +/****f* OpenSM: SM MAD Controller/osm_sm_mad_ctrl_destroy +* NAME +* osm_sm_mad_ctrl_destroy +* +* DESCRIPTION +* The osm_sm_mad_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_sm_mad_ctrl_destroy( + IN osm_sm_mad_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* SM MAD Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_sm_mad_ctrl_construct or osm_sm_mad_ctrl_init. +* +* SEE ALSO +* SM MAD Controller object, osm_sm_mad_ctrl_construct, +* osm_sm_mad_ctrl_init +*********/ + +/****f* OpenSM: SM MAD Controller/osm_sm_mad_ctrl_init +* NAME +* osm_sm_mad_ctrl_init +* +* DESCRIPTION +* The osm_sm_mad_ctrl_init function initializes a +* SM MAD Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sm_mad_ctrl_init( + IN osm_sm_mad_ctrl_t* const p_ctrl, + IN osm_subn_t* const p_subn, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_vl15_t* const p_vl15, + IN osm_vendor_t* const p_vendor, + IN osm_log_t* const p_log, + IN osm_stats_t* const p_stats, + IN cl_plock_t* const p_lock, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sm_mad_ctrl_t object to initialize. +* +* p_mad_pool +* [in] Pointer to the MAD pool. +* +* p_vl15 +* [in] Pointer to the VL15 interface object. +* +* p_vendor +* [in] Pointer to the vendor specific interfaces object. +* +* p_log +* [in] Pointer to the log object. +* +* p_stats +* [in] Pointer to the OpenSM stastics block. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* IB_SUCCESS if the SM MAD Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other SM MAD Controller methods. +* +* SEE ALSO +* SM MAD Controller object, osm_sm_mad_ctrl_construct, +* osm_sm_mad_ctrl_destroy +*********/ + +/****f* OpenSM: SM/osm_sm_mad_ctrl_bind +* NAME +* osm_sm_mad_ctrl_bind +* +* DESCRIPTION +* Binds the SM MAD Controller object to a port guid. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sm_mad_ctrl_bind( + IN osm_sm_mad_ctrl_t* const p_ctrl, + IN const ib_net64_t port_guid ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sm_mad_ctrl_t object to initialize. +* +* port_guid +* [in] Local port GUID with which to bind. +* +* +* RETURN VALUES +* None +* +* NOTES +* A given SM MAD Controller object can only be bound to one +* port at a time. +* +* SEE ALSO +*********/ + +/****f* OpenSM: SM/osm_sm_mad_ctrl_get_bind_handle +* NAME +* osm_sm_mad_ctrl_get_bind_handle +* +* DESCRIPTION +* Returns the bind handle. +* +* SYNOPSIS +*/ +static inline osm_bind_handle_t +osm_sm_mad_ctrl_get_bind_handle( + IN const osm_sm_mad_ctrl_t* const p_ctrl ) +{ + return( p_ctrl->h_bind ); +} +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sm_mad_ctrl_t object. +* +* RETURN VALUES +* Returns the bind handle, which may be OSM_BIND_INVALID_HANDLE +* if no port has been bound. +* +* NOTES +* A given SM MAD Controller object can only be bound to one +* port at a time. +* +* SEE ALSO +*********/ + +END_C_DECLS + +#endif /* _OSM_SM_MAD_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sm_state_mgr.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sm_state_mgr.h new file mode 100644 index 00000000..2d8282a9 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sm_state_mgr.h @@ -0,0 +1,353 @@ +/* + * 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: + * Declaration of osm_sm_state_mgr_t. + * This object represents the SM State Manager object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.2 $ + */ + +#ifndef _OSM_SM_STATE_MGR_H_ +#define _OSM_SM_STATE_MGR_H_ + +#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 State Manager +* NAME +* SM State Manager +* +* DESCRIPTION +* The SM State Manager object encapsulates the information +* needed to control the state of the SM. +* +* The SM State Manager object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Yael Kalka, Mellanox +* +*********/ + +/****s* OpenSM: SM State Manager/osm_sm_state_mgr_t +* NAME +* osm_sm_state_mgr_t +* +* DESCRIPTION +* SM State Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_sm_state_mgr +{ + cl_spinlock_t state_lock; + cl_timer_t polling_timer; + uint32_t retry_number; + ib_net64_t master_guid; + osm_state_mgr_t* p_state_mgr; + osm_subn_t* p_subn; + osm_req_t* p_req; + osm_log_t* p_log; + osm_remote_sm_t* p_polling_sm; +} osm_sm_state_mgr_t; + +/* +* FIELDS +* state_lock +* Spinlock guarding the state and processes. +* +* retry_number +* Used on Standby state - to count the number of retries +* of queries to the master SM. +* +* polling_timer +* Timer for polling +* +* p_state_mgr +* Point to the state manager object +* +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_req +* Pointer to the generic attribute request object. +* +* p_log +* Pointer to the log object. +* +* p_polling_sm +* Pointer to a osm_remote_sm_t object. When our SM needs +* to poll on a remote sm, this will be the pointer of the +* polled SM. +* +* SEE ALSO +* SM State Manager object +*********/ + + +/****f* OpenSM: SM State Manager/osm_sm_state_mgr_construct +* NAME +* osm_sm_state_mgr_construct +* +* DESCRIPTION +* This function constructs a SM State Manager object. +* +* SYNOPSIS +*/ +void +osm_sm_state_mgr_construct( + IN osm_sm_state_mgr_t* const p_sm_mgr ); +/* +* PARAMETERS +* p_sm_mgr +* [in] Pointer to a SM State Manager object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows osm_sm_state_mgr_destroy +* +* Calling osm_sm_state_mgr_construct is a prerequisite to calling any other +* method except osm_sm_state_mgr_init. +* +* SEE ALSO +* SM State Manager object, osm_sm_state_mgr_init, +* osm_sm_state_mgr_destroy +*********/ + +/****f* OpenSM: SM State Manager/osm_sm_state_mgr_destroy +* NAME +* osm_sm_state_mgr_destroy +* +* DESCRIPTION +* The osm_sm_state_mgr_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_sm_state_mgr_destroy( + IN osm_sm_state_mgr_t* const p_sm_mgr ); +/* +* PARAMETERS +* p_sm_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 +* SM State Manager object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_sm_state_mgr_construct or osm_sm_state_mgr_init. +* +* SEE ALSO +* SM State Manager object, osm_sm_state_mgr_construct, +* osm_sm_state_mgr_init +*********/ + +/****f* OpenSM: SM State Manager/osm_sm_state_mgr_init +* NAME +* osm_sm_state_mgr_init +* +* DESCRIPTION +* The osm_sm_state_mgr_init function initializes a +* SM State Manager object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sm_state_mgr_init( + IN osm_sm_state_mgr_t* const p_sm_mgr, + IN osm_state_mgr_t* const p_state_mgr, + IN osm_subn_t* const p_subn, + IN osm_req_t* const p_req, + IN osm_log_t* const p_log ); +/* +* PARAMETERS +* p_sm_mgr +* [in] Pointer to an osm_sm_state_mgr_t object to initialize. +* +* +* p_state_mgr +* [in] Pointer to the State Manager object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_log +* [in] Pointer to the log object. +* +* RETURN VALUES +* IB_SUCCESS if the SM State Manager object was initialized +* successfully. +* +* NOTES +* Allows calling other SM State Manager methods. +* +* SEE ALSO +* SM State Manager object, osm_sm_state_mgr_construct, +* osm_sm_state_mgr_destroy +*********/ + +/****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_state_mgr_t* const p_sm_mgr, + IN osm_sm_signal_t signal ); +/* +* PARAMETERS +* p_sm_mgr +* [in] Pointer to an osm_sm_state_mgr_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_state_mgr_t* const p_sm_mgr ); +/* +* PARAMETERS +* p_sm_mgr +* [in] Pointer to an osm_sm_state_mgr_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_state_mgr_t* const p_sm_mgr, + IN osm_sm_signal_t signal ); +/* +* PARAMETERS +* p_sm_mgr +* [in] Pointer to an osm_sm_state_mgr_t object. +* +* signal +* [in] Signal to the state SM engine. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* State Manager +*********/ + +END_C_DECLS + +#endif /* _OSM_SM_STATE_MGR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sminfo_rcv.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sminfo_rcv.h new file mode 100644 index 00000000..51b5f985 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sminfo_rcv.h @@ -0,0 +1,291 @@ +/* + * 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: + * Declaration of osm_sminfo_rcv_t. + * This object represents the SMInfo Receiver object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_SMINFO_RCV_H_ +#define _OSM_SMINFO_RCV_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/SMInfo Receiver +* NAME +* SMInfo Receiver +* +* DESCRIPTION +* The SMInfo Receiver object encapsulates the information +* needed to receive the SMInfo attribute from a node. +* +* The SMInfo Receiver 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: SMInfo Receiver/osm_sminfo_rcv_t +* NAME +* osm_sminfo_rcv_t +* +* DESCRIPTION +* SMInfo Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_sminfo_rcv +{ + osm_subn_t *p_subn; + osm_stats_t *p_stats; + osm_log_t *p_log; + osm_resp_t *p_resp; + osm_state_mgr_t *p_state_mgr; + struct _osm_sm_state_mgr *p_sm_state_mgr; + cl_plock_t *p_lock; + +} osm_sminfo_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_stats +* Pointer to the OpenSM statistics block. +* +* p_log +* Pointer to the log object. +* +* p_resp +* Pointer to the generic MAD responder object. +* +* p_state_mgr +* Pointer to the State Manager object. +* +* p_sm_state_mgr +* Pointer to the SM State Manager object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* SMInfo Receiver object +*********/ + +/****f* OpenSM: SMInfo Receiver/osm_sminfo_rcv_construct +* NAME +* osm_sminfo_rcv_construct +* +* DESCRIPTION +* This function constructs a SMInfo Receiver object. +* +* SYNOPSIS +*/ +void osm_sminfo_rcv_construct( + IN osm_sminfo_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a SMInfo Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sminfo_rcv_init, osm_sminfo_rcv_destroy +* +* Calling osm_sminfo_rcv_construct is a prerequisite to calling any other +* method except osm_sminfo_rcv_init. +* +* SEE ALSO +* SMInfo Receiver object, osm_sminfo_rcv_init, +* osm_sminfo_rcv_destroy +*********/ + +/****f* OpenSM: SMInfo Receiver/osm_sminfo_rcv_destroy +* NAME +* osm_sminfo_rcv_destroy +* +* DESCRIPTION +* The osm_sminfo_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_sminfo_rcv_destroy( + IN osm_sminfo_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* SMInfo Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_sminfo_rcv_construct or osm_sminfo_rcv_init. +* +* SEE ALSO +* SMInfo Receiver object, osm_sminfo_rcv_construct, +* osm_sminfo_rcv_init +*********/ + +/****f* OpenSM: SMInfo Receiver/osm_sminfo_rcv_init +* NAME +* osm_sminfo_rcv_init +* +* DESCRIPTION +* The osm_sminfo_rcv_init function initializes a +* SMInfo Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_sminfo_rcv_init( + IN osm_sminfo_rcv_t* const p_rcv, + IN osm_subn_t* const p_subn, + IN osm_stats_t* const p_stats, + IN osm_resp_t* const p_resp, + IN osm_log_t* const p_log, + IN osm_state_mgr_t* const p_state_mgr, + IN struct _osm_sm_state_mgr* const p_sm_state_mgr, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_sminfo_rcv_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_stats +* [in] Pointer to the OpenSM statistics block. +* +* p_resp +* [in] Pointer to the generic MAD Responder object. +* +* p_log +* [in] Pointer to the log object. +* +* p_state_mgr +* [in] Pointer to the State Manager object. +* +* p_sm_state_mgr +* [in] Pointer to the SM State Manager object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the SMInfo Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other SMInfo Receiver methods. +* +* SEE ALSO +* SMInfo Receiver object, osm_sminfo_rcv_construct, +* osm_sminfo_rcv_destroy +*********/ + +/****f* OpenSM: SMInfo Receiver/osm_sminfo_rcv_process +* NAME +* osm_sminfo_rcv_process +* +* DESCRIPTION +* Process the SMInfo attribute. +* +* SYNOPSIS +*/ +void osm_sminfo_rcv_process( + IN const osm_sminfo_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_sminfo_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's SMInfo attribute. +* +* RETURN VALUES +* IB_SUCCESS if the SMInfo processing was successful. +* +* NOTES +* This function processes a SMInfo attribute. +* +* SEE ALSO +* SMInfo Receiver, SMInfo Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_SMINFO_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sminfo_rcv_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sminfo_rcv_ctrl.h new file mode 100644 index 00000000..08d5dd0b --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sminfo_rcv_ctrl.h @@ -0,0 +1,232 @@ +/* + * 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: + * Declaration of osm_sminfo_rcv_ctrl_t. + * This object represents a controller that receives the IBA SMInfo + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_SMINFO_RCV_CTRL_H_ +#define _OSM_SMINFO_RCV_CTRL_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/SMInfo Receive Controller +* NAME +* SMInfo Receive Controller +* +* DESCRIPTION +* The SMInfo Receive Controller object encapsulates the information +* needed to receive the SMInfo attribute from a node. +* +* The SMInfo Receive 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: SMInfo Receive Controller/osm_sminfo_rcv_ctrl_t +* NAME +* osm_sminfo_rcv_ctrl_t +* +* DESCRIPTION +* SMInfo Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_sminfo_rcv_ctrl +{ + osm_sminfo_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_sminfo_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the SMInfo Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* SMInfo Receive Controller object +*********/ + +/****f* OpenSM: SMInfo Receive Controller/osm_sminfo_rcv_ctrl_construct +* NAME +* osm_sminfo_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a SMInfo Receive Controller object. +* +* SYNOPSIS +*/ +void +osm_sminfo_rcv_ctrl_construct( + IN osm_sminfo_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a SMInfo Receive Controller object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sminfo_rcv_ctrl_init, osm_sminfo_rcv_ctrl_destroy +* +* Calling osm_sminfo_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_sminfo_rcv_ctrl_init. +* +* SEE ALSO +* SMInfo Receive Controller object, osm_sminfo_rcv_ctrl_init, +* osm_sminfo_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: SMInfo Receive Controller/osm_sminfo_rcv_ctrl_destroy +* NAME +* osm_sminfo_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_sminfo_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_sminfo_rcv_ctrl_destroy( + IN osm_sminfo_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* SMInfo Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_sminfo_rcv_ctrl_construct or osm_sminfo_rcv_ctrl_init. +* +* SEE ALSO +* SMInfo Receive Controller object, osm_sminfo_rcv_ctrl_construct, +* osm_sminfo_rcv_ctrl_init +*********/ + +/****f* OpenSM: SMInfo Receive Controller/osm_sminfo_rcv_ctrl_init +* NAME +* osm_sminfo_rcv_ctrl_init +* +* DESCRIPTION +* The osm_sminfo_rcv_ctrl_init function initializes a +* SMInfo Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sminfo_rcv_ctrl_init( + IN osm_sminfo_rcv_ctrl_t* const p_ctrl, + IN osm_sminfo_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sminfo_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_sminfo_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* IB_SUCCESS if the SMInfo Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other SMInfo Receive Controller methods. +* +* SEE ALSO +* SMInfo Receive Controller object, osm_sminfo_rcv_ctrl_construct, +* osm_sminfo_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* OSM_SMINFO_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_state_mgr.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_state_mgr.h new file mode 100644 index 00000000..7e701796 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_state_mgr.h @@ -0,0 +1,518 @@ +/* + * 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: + * Declaration of osm_state_mgr_t. + * This object represents the State Manager object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#ifndef _OSM_STATE_MGR_H_ +#define _OSM_STATE_MGR_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/State Manager +* NAME +* State Manager +* +* DESCRIPTION +* The State Manager object encapsulates the information +* needed to control subnet sweeps and configuration. +* +* The State 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 +* +*********/ + +/****s* OpenSM: State Manager/osm_state_mgr_t +* NAME +* osm_state_mgr_t +* +* DESCRIPTION +* State Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_state_mgr +{ + osm_subn_t *p_subn; + osm_log_t *p_log; + osm_lid_mgr_t *p_lid_mgr; + osm_ucast_mgr_t *p_ucast_mgr; + osm_mcast_mgr_t *p_mcast_mgr; + osm_link_mgr_t *p_link_mgr; + osm_drop_mgr_t *p_drop_mgr; + osm_req_t *p_req; + osm_stats_t *p_stats; + struct _osm_sm_state_mgr *p_sm_state_mgr; + const osm_sm_mad_ctrl_t *p_mad_ctrl; + cl_spinlock_t state_lock; + cl_spinlock_t idle_lock; + cl_qlist_t idle_time_list; + cl_plock_t *p_lock; + cl_event_t *p_subnet_up_event; + osm_sm_state_t state; + osm_state_mgr_mode_t state_step_mode; + osm_signal_t next_stage_signal; +} osm_state_mgr_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_log +* Pointer to the log object. +* +* p_lid_mgr +* Pointer to the LID Manager object. +* +* p_ucast_mgr +* Pointer to the Unicast Manager object. +* +* p_mcast_mgr +* Pointer to the Multicast Manager object. +* +* p_link_mgr +* Pointer to the Link Manager object. +* +* p_drop_mgr +* Pointer to the Drop Manager object. +* +* p_req +* Pointer to the Requester object sending SMPs. +* +* p_stats +* Pointer to the OpenSM statistics block. +* +* p_sm_state_mgr +* Pointer to the SM state mgr object. +* +* p_mad_ctrl +* Pointer to the SM's MAD Controller object. +* +* state_lock +* Spinlock guarding the state and processes. +* +* p_lock +* lock guarding the subnet object. +* +* p_subnet_up_event +* Pointer to the event to set if/when the subnet comes up. +* +* state +* State of the SM. +* +* state_step_mode +* Controls the mode of progressing to next stage: +* OSM_STATE_STEP_CONTINUOUS - normal automatic progress mode +* OSM_STATE_STEP_TAKE_ONE - do one step and stop +* OSM_STATE_STEP_BREAK - stop before taking next step +* +* next_stage_signal +* Stores the signal to be provided when running the next stage. +* +* SEE ALSO +* State Manager object +*********/ + +/****s* OpenSM: State Manager/_osm_idle_item +* NAME +* _osm_idle_item +* +* DESCRIPTION +* Idle item. +* +* SYNOPSIS +*/ + +typedef osm_signal_t +(*osm_pfn_start_t)( + IN void *context1, + IN void *context2 ); + +typedef void +(*osm_pfn_done_t)( + IN void *context1, + IN void *context2 ); + +typedef struct _osm_idle_item +{ + cl_list_item_t list_item; + void* context1; + void* context2; + osm_pfn_start_t pfn_start; + osm_pfn_done_t pfn_done; +}osm_idle_item_t; + +/* +* FIELDS +* list_item +* list item. +* +* context1 +* Context pointer +* +* context2 +* Context pointer +* +* pfn_start +* Pointer to the start function. +* +* pfn_done +* Pointer to the dine function. +* SEE ALSO +* State Manager object +*********/ + +/****f* OpenSM: State Manager/osm_state_mgr_process_idle +* NAME +* osm_state_mgr_process_idle +* +* DESCRIPTION +* Formulates the osm_idle_item and inserts it into the queue and +* signals the state manager. +* +* SYNOPSIS +*/ + +ib_api_status_t +osm_state_mgr_process_idle( + IN osm_state_mgr_t* const p_mgr, + IN osm_pfn_start_t pfn_start, + IN osm_pfn_done_t pfn_done, + void* context1, + void* context2 + ); + +/* +* PARAMETERS +* p_mgr +* [in] Pointer to a State Manager object to construct. +* +* pfn_start +* [in] Pointer the start function which will be called at +* idle time. +* +* pfn_done +* [in] pointer the done function which will be called +* when outstanding smps is zero +* +* context1 +* [in] Pointer to void +* +* context2 +* [in] Pointer to void +* +* RETURN VALUE +* IB_SUCCESS or IB_ERROR +* +* NOTES +* Allows osm_state_mgr_destroy +* +* Calling osm_state_mgr_construct is a prerequisite to calling any other +* method except osm_state_mgr_init. +* +* SEE ALSO +* State Manager object, osm_state_mgr_init, +* osm_state_mgr_destroy +*********/ + +/****f* OpenSM: State Manager/osm_state_mgr_construct +* NAME +* osm_state_mgr_construct +* +* DESCRIPTION +* This function constructs a State Manager object. +* +* SYNOPSIS +*/ +void +osm_state_mgr_construct( + IN osm_state_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to a State Manager object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows osm_state_mgr_destroy +* +* Calling osm_state_mgr_construct is a prerequisite to calling any other +* method except osm_state_mgr_init. +* +* SEE ALSO +* State Manager object, osm_state_mgr_init, +* osm_state_mgr_destroy +*********/ + +/****f* OpenSM: State Manager/osm_state_mgr_destroy +* NAME +* osm_state_mgr_destroy +* +* DESCRIPTION +* The osm_state_mgr_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_state_mgr_destroy( + IN osm_state_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* State Manager object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_state_mgr_construct or osm_state_mgr_init. +* +* SEE ALSO +* State Manager object, osm_state_mgr_construct, +* osm_state_mgr_init +*********/ + +/****f* OpenSM: State Manager/osm_state_mgr_init +* NAME +* osm_state_mgr_init +* +* DESCRIPTION +* The osm_state_mgr_init function initializes a +* State Manager object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_state_mgr_init( + IN osm_state_mgr_t* const p_mgr, + IN osm_subn_t* const p_subn, + IN osm_lid_mgr_t* const p_lid_mgr, + IN osm_ucast_mgr_t* const p_ucast_mgr, + IN osm_mcast_mgr_t* const p_mcast_mgr, + IN osm_link_mgr_t* const p_link_mgr, + IN osm_drop_mgr_t* const p_drop_mgr, + IN osm_req_t* const p_req, + IN osm_stats_t* const p_stats, + IN struct _osm_sm_state_mgr* const p_sm_state_mgr, + IN const osm_sm_mad_ctrl_t* const p_mad_ctrl, + IN cl_plock_t* const p_lock, + IN cl_event_t* const p_subnet_up_event, + IN osm_log_t* const p_log ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_state_mgr_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_lid_mgr +* [in] Pointer to the LID Manager object. +* +* p_ucast_mgr +* [in] Pointer to the Unicast Manager object. +* +* p_mcast_mgr +* [in] Pointer to the Multicast Manager object. +* +* p_link_mgr +* [in] Pointer to the Link Manager object. +* +* p_drop_mgr +* [in] Pointer to the Drop Manager object. +* +* p_req +* [in] Pointer to the Request Controller object. +* +* p_stats +* [in] Pointer to the OpenSM statistics block. +* +* p_sm_state_mgr +* [in] Pointer to the SM state mgr object. +* +* p_mad_ctrl +* [in] Pointer to the SM's mad controller. +* +* p_subnet_up_event +* [in] Pointer to the event to set if/when the subnet comes up. +* +* p_log +* [in] Pointer to the log object. +* +* RETURN VALUES +* IB_SUCCESS if the State Manager object was initialized +* successfully. +* +* NOTES +* Allows calling other State Manager methods. +* +* SEE ALSO +* State Manager object, osm_state_mgr_construct, +* osm_state_mgr_destroy +*********/ + +/****f* OpenSM: State Manager/osm_sm_is_greater_than +* NAME +* osm_sm_is_greater_than +* +* DESCRIPTION +* Compares two SM's (14.4.1.2) +* +* SYNOPSIS +*/ +static inline boolean_t +osm_sm_is_greater_than ( + IN const uint8_t l_priority, + IN const ib_net64_t l_guid, + IN const uint8_t r_priority, + IN const ib_net64_t r_guid ) +{ + if( l_priority > r_priority ) + { + return( TRUE ); + } + else + { + if( l_priority == r_priority ) + { + if( cl_ntoh64(l_guid) < cl_ntoh64(r_guid) ) + { + return( TRUE ); + } + } + } + return( FALSE ); +} +/* +* 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: State Manager/osm_state_mgr_process +* NAME +* osm_state_mgr_process +* +* DESCRIPTION +* Processes and maintains the states of the SM. +* +* SYNOPSIS +*/ +void +osm_state_mgr_process( + IN osm_state_mgr_t* const p_mgr, + IN osm_signal_t signal ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_state_mgr_t object. +* +* signal +* [in] Signal to the state engine. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* State Manager +*********/ + +END_C_DECLS + +#endif /* _OSM_STATE_MGR_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_state_mgr_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_state_mgr_ctrl.h new file mode 100644 index 00000000..86043a58 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_state_mgr_ctrl.h @@ -0,0 +1,233 @@ +/* + * 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: + * Declaration of osm_state_mgr_ctrl_t. + * This object represents a controller that receives the + * State indication after a subnet sweep. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_STATE_MGR_CTRL_H_ +#define _OSM_STATE_MGR_CTRL_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/State Manager Controller +* NAME +* State Manager Controller +* +* DESCRIPTION +* The State Manager Controller object encapsulates the information +* needed to pass the dispatcher message from the dispatcher +* to the State Manager. +* +* The State Manager 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: State Manager Controller/osm_state_mgr_ctrl_t +* NAME +* osm_state_mgr_ctrl_t +* +* DESCRIPTION +* State Manager Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_state_mgr_ctrl +{ + osm_state_mgr_t *p_mgr; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_state_mgr_ctrl_t; +/* +* FIELDS +* p_mgr +* Pointer to the State Manager object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* State Manager Controller object +*********/ + +/****f* OpenSM: State Manager Controller/osm_state_mgr_ctrl_construct +* NAME +* osm_state_mgr_ctrl_construct +* +* DESCRIPTION +* This function constructs a State Manager Controller object. +* +* SYNOPSIS +*/ +void +osm_state_mgr_ctrl_construct( + IN osm_state_mgr_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a State Manager Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_state_mgr_ctrl_init, and osm_state_mgr_ctrl_destroy. +* +* Calling osm_state_mgr_ctrl_construct is a prerequisite to calling any +* other method except osm_state_mgr_ctrl_init. +* +* SEE ALSO +* State Manager Controller object, osm_state_mgr_ctrl_init, +* osm_state_mgr_ctrl_destroy +*********/ + +/****f* OpenSM: State Manager Controller/osm_state_mgr_ctrl_destroy +* NAME +* osm_state_mgr_ctrl_destroy +* +* DESCRIPTION +* The osm_state_mgr_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_state_mgr_ctrl_destroy( + IN osm_state_mgr_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* State Manager Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_state_mgr_ctrl_construct or osm_state_mgr_ctrl_init. +* +* SEE ALSO +* State Manager Controller object, osm_state_mgr_ctrl_construct, +* osm_state_mgr_ctrl_init +*********/ + +/****f* OpenSM: State Manager Controller/osm_state_mgr_ctrl_init +* NAME +* osm_state_mgr_ctrl_init +* +* DESCRIPTION +* The osm_state_mgr_ctrl_init function initializes a +* State Manager Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_state_mgr_ctrl_init( + IN osm_state_mgr_ctrl_t* const p_ctrl, + IN osm_state_mgr_t* const p_mgr, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_state_mgr_ctrl_t object to initialize. +* +* p_mgr +* [in] Pointer to an osm_state_mgr_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* IB_SUCCESS if the State Manager Controller object +* was initialized successfully. +* +* NOTES +* Allows calling other State Manager Controller methods. +* +* SEE ALSO +* State Manager Controller object, osm_state_mgr_ctrl_construct, +* osm_state_mgr_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* OSM_STATE_MGR_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_stats.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_stats.h new file mode 100644 index 00000000..07c64e1a --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_stats.h @@ -0,0 +1,125 @@ +/* + * 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: + * Declaration of osm_stats_t. + * This object represents the OpenSM statistics object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_STATS_H_ +#define _OSM_STATS_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/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 qp1_mads_outstanding; + atomic32_t qp1_mads_rcvd; + atomic32_t qp1_mads_sent; + +} 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. +* +* SEE ALSO +***************/ + +END_C_DECLS + +#endif /* _OSM_STATS_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_subnet.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_subnet.h new file mode 100644 index 00000000..49a03260 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_subnet.h @@ -0,0 +1,1161 @@ +/* + * 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: + * Declaration of osm_subn_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.12 $ + */ + +#ifndef _OSM_SUBNET_H_ +#define _OSM_SUBNET_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_SUBNET_VECTOR_MIN_SIZE 0 +#define OSM_SUBNET_VECTOR_GROW_SIZE 1 +#define OSM_SUBNET_VECTOR_CAPACITY 256 + +struct _osm_opensm_t; + +/****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 +* +*********/ + +/****f* OpenSM: Subnet/osm_pfn_ui_extension +* NAME +* osm_pfn_ui_extension +* +* DESCRIPTION +* This typedef defines the prototype for UI extension functions +* The might be registered in the subnet options to handle pre_lid_assign, +* and ui_ucast_fwd_assign. +* +* SYNOPSIS +*/ +typedef int +(*osm_pfn_ui_extension_t)( + IN void* context ); +/* +* PARAMETERS +* context +* [in] Client specific context specified in the subnet opt +* Same prefix as the UI function (suffixed by ctx) +* +* RETURN VALUE +* This function returns an int (the semantic is different between +* the different calls) +* +* SEE ALSO +* +*********/ + +/****f* OpenSM: Subnet/osm_pfn_ui_mcast_extension +* NAME +* osm_pfn_ui_mcast_extension +* +* DESCRIPTION +* This typedef defines the prototype for UI extension functions +* They might be registered in the subnet options to handle ui_mcast_fwd_assign +* +* SYNOPSIS +*/ +typedef void +(*osm_pfn_ui_mcast_extension_t)( + IN void *context, + IN ib_net16_t mlid, + IN osm_mcast_req_type_t request_type, + IN ib_net64_t port_guid ); +/* +* PARAMETERS +* context +* [in] Client specific context specified in the subnet opt +* Same prefix as the UI function (suffixed by ctx) +* +* mlid +* [in] multicast lid of the group handled. +* +* request_type +* [in] Type of MC request being handled (create/join/leave) +* +* port_guid +* [in] port gui of the port that was added/removed from the +* multicast group handled. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* +*********/ + +/****d* OpenSM: Subnet/osm_testability_modes_t +* NAME +* osm_testability_modes_t +* +* DESCRIPTION +* Enumerates the possible testability modes. +* +* SYNOPSIS +*/ +typedef enum _osm_testability_modes +{ + OSM_TEST_MODE_NONE = 0, + OSM_TEST_MODE_EXIT_BEFORE_SEND_HANDOVER, + OSM_TEST_MODE_MAX +} osm_testability_modes_t; +/***********/ + +/****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_t { + unsigned max_vls; + unsigned 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 +* +* high_limit +* The limit of High Priority component of VL Arbitration +* table (IBA 7.6.9) +* +* vlarb_high +* High priority VL Arbitration table template. +* +* vlarb_low +* Low priority VL Arbitration table template. +* +* sl2vl +* SL2VL Mapping table (IBA 7.6.6) template. +* +*********/ + +/****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 +{ + ib_net64_t guid; + ib_net64_t m_key; + ib_net64_t sm_key; + ib_net64_t subnet_prefix; + ib_net16_t m_key_lease_period; + uint32_t sweep_interval; + uint32_t max_wire_smps; + uint32_t transaction_timeout; + uint8_t sm_priority; + uint8_t lmc; + boolean_t lmc_esp0; + uint8_t max_op_vls; + uint8_t force_link_speed; + boolean_t reassign_lids; + boolean_t reassign_lfts; + boolean_t ignore_other_sm; + boolean_t single_thread; + boolean_t no_multicast_option; + 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 no_qos; + boolean_t accum_log_file; + boolean_t console; + cl_map_t port_prof_ignore_guids; + boolean_t port_profile_switch_nodes; + osm_pfn_ui_extension_t pfn_ui_pre_lid_assign; + void * ui_pre_lid_assign_ctx; + osm_pfn_ui_mcast_extension_t pfn_ui_mcast_fdb_assign; + void * ui_mcast_fdb_assign_ctx; + boolean_t sweep_on_trap; + osm_testability_modes_t testability_mode; + char * routing_engine_name; + char * lid_matrix_dump_file; + char * ucast_dump_file; + char * updn_guid_file; + char * sa_db_file; + boolean_t exit_on_fatal; + boolean_t honor_guid2lid_file; + 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; +} osm_subn_opt_t; +/* +* FIELDS +* +* guid +* The port guid that the SM is binding to. +* +* m_key +* M_Key value sent to all ports qualifing all Set(PortInfo). +* +* sm_key +* SM_Key value of the SM 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. +* +* 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. +* +* reassign_lfts +* If TRUE ignore existing LFT entries on first sweep (default). +* Otherwise only non minimal hop cases are modified. +* NOTE: A standby SM clears its first sweep flag - since the +* master SM already sweeps... +* +* ignore_other_sm_option +* This flag is TRUE if other SMs on the subnet should be ignored. +* +* no_multicast_option +* 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 SubnMgt.Set(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 SubnMgt.Set(SwitchInfo.life_state) +* +* dump_files_dir +* The directory to be used for subnet.lst osm.fdbs, osm.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. +* +* 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_guids +* A map of 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. +* +* pfn_ui_pre_lid_assign +* A UI function to be invoked prior to lid assigment. It should +* return 1 if any change was made to any lid or 0 otherwise. +* +* ui_pre_lid_assign_ctx +* A UI context (void *) to be provided to the pfn_ui_pre_lid_assign +* +* pfn_ui_mcast_fdb_assign +* A UI function to be called inside the mcast manager instead of +* the call for the build spanning tree. This will be called on +* every multicast call for create, join and leave, and is +* responsible for the mcast FDB configuration. +* +* ui_mcast_fdb_assign_ctx +* A UI context (void *) to be provided to the pfn_ui_mcast_fdb_assign +* +* sweep_on_trap +* Received traps will initiate a new sweep. +* +* testability_mode +* Object that indicates if we are running in a special testability mode. +* +* routing_engine_name +* Name of used routing engine +* (other than default Min Hop Algorithm) +* +* lid_matrix_dump_file +* Name of the lid matrix dump file from where switch +* lid matrices (min hops tables) will be loaded +* +* ucast_dump_file +* Name of the unicast routing dump file from where switch +* forwarding tables will be loaded +* +* updn_guid_file +* Pointer to name of the UPDN guid file given by User +* +* sa_db_file +* Name of the SA database file. +* +* exit_on_fatal +* If TRUE (default) - SM will exit on fatal subnet initialization issues. +* If FALSE - SM will not exit. +* Fatal initialization issues: +* a. SM recognizes 2 different nodes with the same guid, or +* 12x link with lane reversal badly configured. +* +* honor_guid2lid_file +* Always honor the guid2lid file if it exists and is valid. This +* means that the file will be honored when SM is coming out of +* STANDBY. By default this is FALSE. +* +* 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_t *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_qmap_t prtn_pkey_tbl; + cl_qmap_t mgrp_mlid_tbl; + cl_qmap_t sm_guid_tbl; + cl_list_t light_sweep_physp_list; + cl_qlist_t sa_sr_list; + cl_qlist_t sa_infr_list; + cl_ptr_vector_t node_lid_tbl; + 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; + uint16_t max_unicast_lid_ho; + uint16_t max_multicast_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_immediate_heavy_sweep; + boolean_t force_delayed_heavy_sweep; + cl_list_t new_ports_list; + boolean_t in_sweep_hop_0; + boolean_t moved_to_master_state; + boolean_t first_time_master_sweep; + boolean_t coming_out_of_standby; +} 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. +* +* mgrp_mlid_tbl +* Container of pointers to all Multicast Group objects in the subnet. +* Indexed by MLID. +* +* sm_guid_tbl +* Container of pointers to SM objects representing other SMs +* on the subnet. +* +* light_sweep_physp_list +* A list of all phys ports to scan for a change in remote +* side state in next light sweep. These ports are not down +* but for some reason the remote side did not answer. +* +* node_lid_tbl +* Container of pointers to all Node objects in the subent. +* Indexed by node LID. +* +* port_ptr_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. +* +* max_unicast_lid_ho +* The minimal max unicast lid reported by all switches +* +* max_multicast_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 : +* - During SM init set to the reassign_lfts flag value +* - Coming out of STANDBY it will be cleared (other SM worked) +* - Any change to the list of switches will set it to high +* - Set to FALSE upon end of all lft assignments. +* +* subnet_initalization_error +* Similar to the force_immediate_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_immediate_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_delayed_heavy_sweep +* In some means - similar to the force_immediate_heavy_sweep flag, only +* it'll cause a heavy sweep in the next sweep. Note that this means that +* if we are running with -s 0 (no sweeps) - then this forced heavy sweep +* will not occur. +* If we had some trouble on the subnet, that caused a strange dropping +* of ports - we will try to do another heavy sweep on our next sweep. +* +* new_ports_list +* Container of pointers to port objects that were discovered for +* the first time during a current sweep. +* +* 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. +* +* moved_to_master_state +* Used for the writing of "SUBNET UP" into /var/log/messages. +* Will be TRUE when the SM switches to Master state, and returned +* to FALSE once the sunbet is up. +* +* 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. +* +* SEE ALSO +* Subnet object +*********/ + +/****f* OpenSM: Subnet/osm_subn_construct +* NAME +* osm_subn_construct +* +* DESCRIPTION +* This function constructs a Subnet object. +* +* SYNOPSIS +*/ +void +osm_subn_construct( + IN osm_subn_t* const p_subn ); +/* +* PARAMETERS +* p_subn +* [in] Pointer to a Subnet object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_subn_init, and osm_subn_destroy. +* +* Calling osm_subn_construct is a prerequisite to calling any other +* method except osm_subn_init. +* +* SEE ALSO +* Subnet object, osm_subn_init, osm_subn_destroy +*********/ + +/****f* OpenSM: Subnet/osm_subn_destroy +* NAME +* osm_subn_destroy +* +* DESCRIPTION +* The osm_subn_destroy function destroys a subnet, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_subn_destroy( + IN osm_subn_t* const p_subn ); +/* +* PARAMETERS +* p_subn +* [in] Pointer to a Subnet object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Subnet object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_subn_construct or +* osm_subn_init. +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_init +*********/ + +/****f* OpenSM: Subnet/osm_subn_init +* NAME +* osm_subn_init +* +* DESCRIPTION +* The osm_subn_init function initializes a Subnet object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_subn_init( + IN osm_subn_t* const p_subn, + IN struct _osm_opensm_t * const p_osm, + IN const osm_subn_opt_t* const p_opt ); +/* +* PARAMETERS +* p_subn +* [in] Pointer to an osm_subn_t object to initialize. +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* RETURN VALUES +* IB_SUCCESS if the Subnet object was initialized successfully. +* +* NOTES +* Allows calling other Subnet methods. +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_destroy +*********/ + +/* + Forward references. +*/ +struct _osm_mad_addr; +struct _osm_log; +struct _osm_switch; +struct _osm_physp; +struct _osm_port; + +/****f* OpenSM: Helper/osm_get_gid_by_mad_addr +* NAME +* osm_get_gid_by_mad_addr +* +* DESCRIPTION +* Looks for the requester gid in the mad address. +* +* Note: This code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_get_gid_by_mad_addr( + IN struct _osm_log *p_log, + IN const osm_subn_t *p_subn, + IN const struct _osm_mad_addr *p_mad_addr, + OUT ib_gid_t *p_gid); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to subnet object. +* +* p_mad_addr +* [in] Pointer to mad address object. +* +* p_gid +* [out] Pointer to the GID structure to fill in. +* +* RETURN VALUES +* IB_SUCCESS if able to find the GID by address given. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/osm_get_physp_by_mad_addr +* NAME +* osm_get_physp_by_mad_addr +* +* DESCRIPTION +* Looks for the requester physical port in the mad address. +* +* Note: This code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +struct _osm_physp * +osm_get_physp_by_mad_addr( + IN struct _osm_log *p_log, + IN const osm_subn_t *p_subn, + IN struct _osm_mad_addr *p_mad_addr ); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to subnet object. +* +* p_mad_addr +* [in] Pointer to mad address object. +* +* RETURN VALUES +* Pointer to requester physical port object if found. Null otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/osm_get_port_by_mad_addr +* NAME +* osm_get_port_by_mad_addr +* +* DESCRIPTION +* Looks for the requester port in the mad address. +* +* Note: This code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +struct _osm_port * +osm_get_port_by_mad_addr( + IN struct _osm_log *p_log, + IN const osm_subn_t *p_subn, + IN struct _osm_mad_addr *p_mad_addr ); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to subnet object. +* +* p_mad_addr +* [in] Pointer to mad address object. +* +* RETURN VALUES +* Pointer to requester port object if found. Null otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Subnet/osm_get_switch_by_guid +* NAME +* osm_get_switch_by_guid +* +* DESCRIPTION +* Looks for the given switch guid in the subnet table of switches by guid. +* NOTE: this code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +struct _osm_switch * +osm_get_switch_by_guid( + IN const osm_subn_t *p_subn, + IN uint64_t guid ); +/* +* PARAMETERS +* p_subn +* [in] Pointer to an osm_subn_t object +* +* guid +* [in] The node guid in host order +* +* RETURN VALUES +* The switch structure pointer if found. NULL otherwise. +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_destroy, +* osm_switch_t +*********/ + +/****f* OpenSM: Subnet/osm_get_node_by_guid +* NAME +* osm_get_node_by_guid +* +* DESCRIPTION +* The looks for the given node giud in the subnet table of nodes by guid. +* NOTE: this code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +struct _osm_node * +osm_get_node_by_guid( + IN osm_subn_t const *p_subn, + IN uint64_t guid ); +/* +* PARAMETERS +* p_subn +* [in] Pointer to an osm_subn_t object +* +* guid +* [in] The node guid in host order +* +* RETURN VALUES +* The node structure pointer if found. NULL otherwise. +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_destroy, +* osm_node_t +*********/ + +/****f* OpenSM: Subnet/osm_get_port_by_guid +* NAME +* osm_get_port_by_guid +* +* DESCRIPTION +* The looks for the given port guid in the subnet table of ports by guid. +* NOTE: this code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +struct _osm_port * +osm_get_port_by_guid( + IN osm_subn_t const *p_subn, + IN uint64_t guid ); +/* +* PARAMETERS +* p_subn +* [in] Pointer to an osm_subn_t object +* +* guid +* [in] The port guid in host 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: Helper/osm_get_physp_by_mad_addr +* NAME +* osm_get_physp_by_mad_addr +* +* DESCRIPTION +* Looks for the requester physical port in the mad address. +* +* Note: This code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +struct _osm_physp * +osm_get_physp_by_mad_addr( + IN struct _osm_log *p_log, + IN const osm_subn_t *p_subn, + IN struct _osm_mad_addr *p_mad_addr ); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to subnet object. +* +* p_mad_addr +* [in] Pointer to mad address object. +* +* RETURN VALUES +* Pointer to requester physical port object if found. Null otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Subnet/osm_subn_set_default_opt +* NAME +* osm_subn_set_default_opt +* +* DESCRIPTION +* The osm_subn_set_default_opt function sets the default options. +* +* SYNOPSIS +*/ +void +osm_subn_set_default_opt( + IN osm_subn_opt_t* const p_opt ); +/* +* PARAMETERS +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_destroy +*********/ + +/****f* OpenSM: Subnet/osm_subn_set_default_opt +* NAME +* osm_subn_set_default_opt +* +* DESCRIPTION +* The osm_subn_set_default_opt function sets the default options. +* +* SYNOPSIS +*/ +void +osm_subn_set_default_opt( + IN osm_subn_opt_t* const p_opt ); +/* +* PARAMETERS +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_destroy +*********/ + +/****f* OpenSM: Subnet/osm_subn_parse_conf_file +* NAME +* osm_subn_parse_conf_file +* +* DESCRIPTION +* The osm_subn_parse_conf_file function parses the configuration file +* and sets the defaults accordingly. +* +* SYNOPSIS +*/ +void +osm_subn_parse_conf_file( + IN osm_subn_opt_t* const p_opt ); +/* +* PARAMETERS +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* RETURN VALUES +* None +* +* 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 +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_destroy +*********/ + +/****f* OpenSM: Subnet/osm_subn_parse_conf_file +* NAME +* osm_subn_rescan_conf_file +* +* DESCRIPTION +* The osm_subn_rescan_conf_file function parses the configuration +* file and update selected subnet options +* +* SYNOPSIS +*/ +void +osm_subn_rescan_conf_file( + IN osm_subn_opt_t* const p_opts ); +/* +* PARAMETERS +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* RETURN VALUES +* None +* +* NOTES +* This uses the same file as osm_subn_parse_conf_file() +* +*********/ + +/****f* OpenSM: Subnet/osm_subn_write_conf_file +* NAME +* osm_subn_write_conf_file +* +* DESCRIPTION +* Write the configuration file into the cache +* +* SYNOPSIS +*/ +void +osm_subn_write_conf_file( + IN osm_subn_opt_t* const p_opt ); +/* +* PARAMETERS +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* RETURN VALUES +* None +* +* 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 +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_SUBNET_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sw_info_rcv.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sw_info_rcv.h new file mode 100644 index 00000000..3695e3db --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sw_info_rcv.h @@ -0,0 +1,304 @@ +/* + * 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: + * Declaration of osm_si_rcv_t. + * This object represents the SwitchInfo Receiver object. + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_SI_RCV_H_ +#define _OSM_SI_RCV_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 Info Receiver +* NAME +* Switch Info Receiver +* +* DESCRIPTION +* The Switch Info Receiver object encapsulates the information +* needed to receive the SwitchInfo attribute from a node. +* +* The Switch Info Receiver 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: Switch Info Receiver/osm_si_rcv_t +* NAME +* osm_si_rcv_t +* +* DESCRIPTION +* Switch Info Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_si_rcv +{ + osm_subn_t *p_subn; + osm_log_t *p_log; + osm_req_t *p_req; + osm_state_mgr_t *p_state_mgr; + cl_plock_t *p_lock; + +} osm_si_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_log +* Pointer to the log object. +* +* p_req +* Pointer to the Request object. +* +* p_state_mgr +* Pointer to the State Manager object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* Switch Info Receiver object +*********/ + +/****f* OpenSM: Switch Info Receiver/osm_si_rcv_construct +* NAME +* osm_si_rcv_construct +* +* DESCRIPTION +* This function constructs a Switch Info Receiver object. +* +* SYNOPSIS +*/ +void osm_si_rcv_construct( + IN osm_si_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Switch Info Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_si_rcv_init, osm_si_rcv_destroy, +* and osm_si_rcv_is_inited. +* +* Calling osm_si_rcv_construct is a prerequisite to calling any other +* method except osm_si_rcv_init. +* +* SEE ALSO +* Switch Info Receiver object, osm_si_rcv_init, +* osm_si_rcv_destroy, osm_si_rcv_is_inited +*********/ + +/****f* OpenSM: Switch Info Receiver/osm_si_rcv_destroy +* NAME +* osm_si_rcv_destroy +* +* DESCRIPTION +* The osm_si_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_si_rcv_destroy( + IN osm_si_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Switch Info Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_si_rcv_construct or osm_si_rcv_init. +* +* SEE ALSO +* Switch Info Receiver object, osm_si_rcv_construct, +* osm_si_rcv_init +*********/ + +/****f* OpenSM: Switch Info Receiver/osm_si_rcv_init +* NAME +* osm_si_rcv_init +* +* DESCRIPTION +* The osm_si_rcv_init function initializes a +* Switch Info Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_si_rcv_init( + IN osm_si_rcv_t* const p_ctrl, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_req_t* const p_req, + IN osm_state_mgr_t* const p_state_mgr, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_si_rcv_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_state_mgr +* [in] Pointer to the State Manager object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the Switch Info Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other Switch Info Receiver methods. +* +* SEE ALSO +* Switch Info Receiver object, osm_si_rcv_construct, +* osm_si_rcv_destroy, osm_si_rcv_is_inited +*********/ + +/****f* OpenSM: Switch Info Receiver/osm_si_rcv_is_inited +* NAME +* osm_si_rcv_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_si_rcv_init. +* +* SYNOPSIS +*/ +boolean_t osm_si_rcv_is_inited( + IN const osm_si_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_si_rcv_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_si_rcv_construct or osm_si_rcv_init must be +* called before using this function. +* +* SEE ALSO +* Switch Info Receiver object, osm_si_rcv_construct, +* osm_si_rcv_init +*********/ + +/****f* OpenSM: Switch Info Receiver/osm_si_rcv_process +* NAME +* osm_si_rcv_process +* +* DESCRIPTION +* Process the SwitchInfo attribute. +* +* SYNOPSIS +*/ +void osm_si_rcv_process( + IN const osm_si_rcv_t* const p_ctrl, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_si_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's SwitchInfo attribute. +* +* RETURN VALUES +* CL_SUCCESS if the SwitchInfo processing was successful. +* +* NOTES +* This function processes a SwitchInfo attribute. +* +* SEE ALSO +* Switch Info Receiver, Switch Info Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_SI_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sw_info_rcv_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sw_info_rcv_ctrl.h new file mode 100644 index 00000000..5e745960 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sw_info_rcv_ctrl.h @@ -0,0 +1,261 @@ +/* + * 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: + * Declaration of osm_si_rcv_ctrl_t. + * This object represents a controller that receives the IBA SwitchInfo + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_SI_RCV_CTRL_H_ +#define _OSM_SI_RCV_CTRL_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/Switch Info Receive Controller +* NAME +* Switch Info Receive Controller +* +* DESCRIPTION +* The Switch Info Receive Controller object encapsulates +* the information needed to receive the SwitchInfo attribute from a node. +* +* The Switch Info Receive 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: Switch Info Receive Controller/osm_si_rcv_ctrl_t +* NAME +* osm_si_rcv_ctrl_t +* +* DESCRIPTION +* Switch Info Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_si_rcv_ctrl +{ + osm_si_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_si_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the Switch Info Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Switch Info Receive Controller object +* Switch Info Receiver object +*********/ + +/****f* OpenSM: Switch Info Receive Controller/osm_si_rcv_ctrl_construct +* NAME +* osm_si_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Switch Info Receive Controller object. +* +* SYNOPSIS +*/ +void osm_si_rcv_ctrl_construct( + IN osm_si_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Switch Info Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_si_rcv_ctrl_init, osm_si_rcv_ctrl_destroy, +* and osm_si_rcv_ctrl_is_inited. +* +* Calling osm_si_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_si_rcv_ctrl_init. +* +* SEE ALSO +* Switch Info Receive Controller object, osm_si_rcv_ctrl_init, +* osm_si_rcv_ctrl_destroy, osm_si_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Switch Info Receive Controller/osm_si_rcv_ctrl_destroy +* NAME +* osm_si_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_si_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_si_rcv_ctrl_destroy( + IN osm_si_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Switch Info Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_si_rcv_ctrl_construct or osm_si_rcv_ctrl_init. +* +* SEE ALSO +* Switch Info Receive Controller object, osm_si_rcv_ctrl_construct, +* osm_si_rcv_ctrl_init +*********/ + +/****f* OpenSM: Switch Info Receive Controller/osm_si_rcv_ctrl_init +* NAME +* osm_si_rcv_ctrl_init +* +* DESCRIPTION +* The osm_si_rcv_ctrl_init function initializes a +* Switch Info Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_si_rcv_ctrl_init( + IN osm_si_rcv_ctrl_t* const p_ctrl, + IN osm_si_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_si_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_si_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Switch Info Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Switch Info Receive Controller methods. +* +* SEE ALSO +* Switch Info Receive Controller object, osm_si_rcv_ctrl_construct, +* osm_si_rcv_ctrl_destroy, osm_si_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: Switch Info Receive Controller/osm_si_rcv_ctrl_is_inited +* NAME +* osm_si_rcv_ctrl_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_si_rcv_ctrl_init. +* +* SYNOPSIS +*/ +boolean_t osm_si_rcv_ctrl_is_inited( + IN const osm_si_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_si_rcv_ctrl_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_si_rcv_ctrl_construct or osm_si_rcv_ctrl_init must be +* called before using this function. +* +* SEE ALSO +* Switch Info Receive Controller object, osm_si_rcv_ctrl_construct, +* osm_si_rcv_ctrl_init +*********/ + +END_C_DECLS + +#endif /* _OSM_SI_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sweep_fail_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sweep_fail_ctrl.h new file mode 100644 index 00000000..3d0d35ec --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_sweep_fail_ctrl.h @@ -0,0 +1,239 @@ +/* + * 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: + * Declaration of osm_sweep_fail_ctrl_t. + * This object represents a controller that + * handles transport failures during sweeps. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_SWEEP_FAIL_CTRL_H_ +#define _OSM_SWEEP_FAIL_CTRL_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/Sweep Fail Controller +* NAME +* Sweep Fail Controller +* +* DESCRIPTION +* The Sweep Fail Controller object encapsulates +* the information needed to handle transport failures during +* sweeps. +* +* The Sweep Fail 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: Sweep Fail Controller/osm_sweep_fail_ctrl_t +* NAME +* osm_sweep_fail_ctrl_t +* +* DESCRIPTION +* Sweep Fail Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_sweep_fail_ctrl +{ + osm_log_t *p_log; + osm_state_mgr_t *p_state_mgr; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + + +} osm_sweep_fail_ctrl_t; +/* +* FIELDS +* p_log +* Pointer to the log object. +* +* p_sate_mgr +* Pointer to the state manager object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Sweep Fail Controller object +* Sweep Failr object +*********/ + +/****f* OpenSM: Sweep Fail Controller/osm_sweep_fail_ctrl_construct +* NAME +* osm_sweep_fail_ctrl_construct +* +* DESCRIPTION +* This function constructs a Sweep Fail Controller object. +* +* SYNOPSIS +*/ +void +osm_sweep_fail_ctrl_construct( + IN osm_sweep_fail_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Sweep Fail Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sweep_fail_ctrl_init, osm_sweep_fail_ctrl_destroy +* +* Calling osm_sweep_fail_ctrl_construct is a prerequisite to calling any other +* method except osm_sweep_fail_ctrl_init. +* +* SEE ALSO +* Sweep Fail Controller object, osm_sweep_fail_ctrl_init, +* osm_sweep_fail_ctrl_destroy +*********/ + +/****f* OpenSM: Sweep Fail Controller/osm_sweep_fail_ctrl_destroy +* NAME +* osm_sweep_fail_ctrl_destroy +* +* DESCRIPTION +* The osm_sweep_fail_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_sweep_fail_ctrl_destroy( + IN osm_sweep_fail_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Sweep Fail Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_sweep_fail_ctrl_construct or osm_sweep_fail_ctrl_init. +* +* SEE ALSO +* Sweep Fail Controller object, osm_sweep_fail_ctrl_construct, +* osm_sweep_fail_ctrl_init +*********/ + +/****f* OpenSM: Sweep Fail Controller/osm_sweep_fail_ctrl_init +* NAME +* osm_sweep_fail_ctrl_init +* +* DESCRIPTION +* The osm_sweep_fail_ctrl_init function initializes a +* Sweep Fail Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sweep_fail_ctrl_init( + IN osm_sweep_fail_ctrl_t* const p_ctrl, + IN osm_log_t* const p_log, + IN osm_state_mgr_t* const p_state_mgr, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sweep_fail_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_sweep_fail_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_state_mgr +* [in] Pointer to the state manager object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the Sweep Fail Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Sweep Fail Controller methods. +* +* SEE ALSO +* Sweep Fail Controller object, osm_sweep_fail_ctrl_construct, +* osm_sweep_fail_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* _OSM_SWEEP_FAIL_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_switch.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_switch.h new file mode 100644 index 00000000..2f7ca2f1 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_switch.h @@ -0,0 +1,1552 @@ +/* + * 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: + * Declaration of osm_switch_t. + * This object represents an IBA switch. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +#ifndef _OSM_SWITCH_H_ +#define _OSM_SWITCH_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/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; + osm_fwd_tbl_t fwd_tbl; + osm_lid_matrix_t lmx; + uint16_t max_lid_ho; + osm_port_profile_t *p_prof; + osm_mcast_tbl_t mcast_tbl; + uint32_t discovery_count; +} 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. +* +* fwd_tbl +* This switch's forwarding table. +* +* lmx +* LID Matrix for this switch containing the hop count +* to every LID from every port. +* +* max_lid_ho +* Max LID that is accessible from this switch. +* +* p_pro +* Pointer to array of Port Profile objects for this switch. +* +* mcast_tbl +* Multicast forwarding table for this switch. +* +* discovery_count +* The number of times this switch has been discovered +* during the current fabric sweep. This number is reset +* to zero at the start of a sweep. +* +* SEE ALSO +* Switch object +*********/ + +/****f* OpenSM: Switch/osm_switch_construct +* NAME +* osm_switch_construct +* +* DESCRIPTION +* This function constructs a Switch object. +* +* SYNOPSIS +*/ +void +osm_switch_construct( + IN osm_switch_t* const p_sw ); +/* +* PARAMETERS +* p_sw +* [in] Pointer to a Switch object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_switch_init, and osm_switch_destroy. +* +* Calling osm_switch_construct is a prerequisite to calling any other +* method except osm_switch_init. +* +* SEE ALSO +* Switch object, osm_switch_init, osm_switch_destroy +*********/ + +/****f* OpenSM: Switch/osm_switch_destroy +* NAME +* osm_switch_destroy +* +* DESCRIPTION +* The osm_switch_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_switch_destroy( + IN osm_switch_t* const p_sw ); +/* +* PARAMETERS +* p_sw +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* None. +* +* NOTES +* Performs any necessary cleanup of the specified object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_switch_construct +* or osm_switch_init. +* +* SEE ALSO +* Switch object, osm_switch_construct, osm_switch_init +*********/ + +/****f* OpenSM: Switch/osm_switch_destroy +* NAME +* osm_switch_destroy +* +* DESCRIPTION +* Destroys and deallocates the object. +* +* SYNOPSIS +*/ +void +osm_switch_delete( + IN OUT osm_switch_t** const pp_sw ); +/* +* PARAMETERS +* p_sw +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +* Switch object, osm_switch_construct, osm_switch_init +*********/ + +/****f* OpenSM: Switch/osm_switch_init +* NAME +* osm_switch_init +* +* DESCRIPTION +* The osm_switch_init function initializes a Switch object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_switch_init( + IN osm_switch_t* const p_sw, + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object to initialize. +* +* 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 +* IB_SUCCESS if the Switch object was initialized successfully. +* +* NOTES +* Allows calling other node methods. +* +* SEE ALSO +* Switch object, osm_switch_construct, osm_switch_destroy +*********/ + +/****f* OpenSM: Switch/osm_switch_new +* NAME +* osm_switch_new +* +* DESCRIPTION +* The osm_switch_init function initializes a Switch object for use. +* +* SYNOPSIS +*/ +osm_switch_t* +osm_switch_new( + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_node +* [in] Pointer to the node object of this switch +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the switch's +* SwitchInfo attribute. +* +* RETURN VALUES +* Pointer to the new initialized switch object. +* +* NOTES +* +* SEE ALSO +* Switch object, osm_switch_construct, osm_switch_destroy, +*********/ + +/****f* OpenSM: Switch/osm_switch_is_leaf_lid +* NAME +* osm_switch_is_leaf_lid +* +* DESCRIPTION +* Indicates if the specified LID is the switch's LID, or is a leaf +* of the switch. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_switch_is_leaf_lid( + IN const osm_switch_t* const p_sw, + IN const uint16_t lid_ho ) +{ + return( osm_lid_matrix_get_least_hops( &p_sw->lmx, lid_ho ) <= 1 ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* lid_ho +* [in] LID (host order) to compare. +* +* RETURN VALUES +* TRUE if the LID is the switch's LID or is a leaf of the switch, +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Switch object +*********/ + +/****f* OpenSM: Switch/osm_switch_get_hop_count +* NAME +* osm_switch_get_hop_count +* +* DESCRIPTION +* Returns the hop count at the specified LID/Port intersection. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_switch_get_hop_count( + IN const osm_switch_t* const p_sw, + IN const uint16_t lid_ho, + IN const uint8_t port_num ) +{ + return( osm_lid_matrix_get( &p_sw->lmx, 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_get_fwd_tbl_ptr +* NAME +* osm_switch_get_fwd_tbl_ptr +* +* DESCRIPTION +* Returns a pointer to the switch's forwarding table. +* +* SYNOPSIS +*/ +static inline osm_fwd_tbl_t* +osm_switch_get_fwd_tbl_ptr( + IN const osm_switch_t* const p_sw ) +{ + return( (osm_fwd_tbl_t*)&p_sw->fwd_tbl ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to a Switch object. +* +* RETURN VALUES +* Returns a pointer to the switch's forwarding table. +* +* 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 +*/ +static inline cl_status_t +osm_switch_set_hops( + IN osm_switch_t* const p_sw, + IN const uint16_t lid_ho, + IN const uint8_t port_num, + IN const uint8_t num_hops ) +{ + return( osm_lid_matrix_set( &p_sw->lmx, lid_ho, port_num, num_hops ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to a Switch object. +* +* lid_ho +* [in] LID value (host order) for which to set the count. +* +* port_num +* [in] port number for which to set the count. +* +* num_hops +* [in] value to assign to this entry. +* +* RETURN VALUES +* Returns the hop count at the specified LID/Port intersection. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_set_min_lid_size +* NAME +* osm_switch_set_min_lid_size +* +* DESCRIPTION +* Sets the size of the switch's routing table to at least accomodate the +* specified LID value (host ordered) +* +* SYNOPSIS +*/ +static inline cl_status_t +osm_switch_set_min_lid_size( + IN osm_switch_t* const p_sw, + IN const uint16_t lid_ho ) +{ + return( osm_lid_matrix_set_min_lid_size( &p_sw->lmx, lid_ho ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to a Switch object. +* +* lid_ho +* [in] LID value (host order) for which to set the count. +* +* RETURN VALUES +* Sets the size of the switch's routing table to at least accomodate the +* specified LID value (host ordered) +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_least_hops +* NAME +* osm_switch_get_least_hops +* +* DESCRIPTION +* Returns the number of hops in the short path to this lid from +* any port on the switch. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_switch_get_least_hops( + IN const osm_switch_t* const p_sw, + IN const uint16_t lid_ho ) +{ + return( osm_lid_matrix_get_least_hops( &p_sw->lmx, 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 number of hops in the short path to this lid from +* any port on the switch. +* +* NOTES +* +* SEE ALSO +* Switch object +*********/ + +/****f* OpenSM: Switch/osm_switch_get_port_by_lid +* NAME +* osm_switch_get_port_by_lid +* +* DESCRIPTION +* Returns the switch port number on which the specified LID is routed. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_switch_get_port_by_lid( + IN const osm_switch_t* const p_sw, + IN const uint16_t lid_ho ) +{ + return( osm_fwd_tbl_get( &p_sw->fwd_tbl, lid_ho ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* lid_ho +* [in] LID (host order) for which to retrieve the shortest hop count. +* +* RETURN VALUES +* Returns the switch port on which the specified LID is routed. +* +* NOTES +* +* SEE ALSO +* Switch object +*********/ + +/****f* OpenSM: Switch/osm_switch_get_physp_ptr +* NAME +* osm_switch_get_physp_ptr +* +* DESCRIPTION +* Gets the Physical Port Object at the specified port number. +* +* SYNOPSIS +*/ +osm_physp_t* +osm_switch_get_physp_ptr( + IN const osm_switch_t* const p_sw, + IN const uint32_t port_num ); +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* port_num +* [in] Port number for which to retrieve the Physical Port Object. +* +* RETURN VALUES +* Returns a pointer to the Physical Port Object object at the specified +* port number. +* A return value of zero means the port number was out of range. +* +* +* NOTES +* +* SEE ALSO +* Switch object +*********/ + +/****f* OpenSM: Switch/osm_switch_get_route_by_lid +* NAME +* osm_switch_get_route_by_lid +* +* DESCRIPTION +* Gets the physical port object that routes the specified LID. +* +* SYNOPSIS +*/ +static inline osm_physp_t* +osm_switch_get_route_by_lid( + IN const osm_switch_t* const p_sw, + IN const ib_net16_t lid ) +{ + uint8_t port_num; + + CL_ASSERT( p_sw ); + CL_ASSERT( lid ); + + port_num = osm_fwd_tbl_get( &p_sw->fwd_tbl, 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_get_si_ptr +* NAME +* osm_switch_get_si_ptr +* +* DESCRIPTION +* Returns a pointer to the SwitchInfo for this switch. +* +* SYNOPSIS +*/ +static inline ib_switch_info_t* +osm_switch_get_si_ptr( + IN const osm_switch_t* const p_sw ) +{ + return( (ib_switch_info_t*)&p_sw->switch_info ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* RETURN VALUES +* Returns a pointer to the SwitchInfo for this switch. +* +* NOTES +* +* SEE ALSO +* Switch object +*********/ + +/****f* OpenSM: Switch/osm_switch_sp0_is_lmc_capable +* NAME +* osm_switch_sp0_is_lmc_capable +* +* DESCRIPTION +* Returns whether switch port 0 (SP0) can support LMC +* +*/ +static inline unsigned +osm_switch_sp0_is_lmc_capable( + IN const osm_switch_t* const p_sw, + IN osm_subn_t *p_subn) +{ + return (p_subn->opt.lmc_esp0 && + ib_switch_info_is_enhanced_port0(&p_sw->switch_info)) ? 1 : 0; +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* p_subn +* [in] Pointer to an osm_subn_t object. +* +* RETURN VALUES +* TRUE if SP0 is enhanced and globally enabled. FALSE otherwise. +* +* NOTES +* This is workaround function, it takes into account user defined +* p_subn->opt.lmc_esp0 parameter. +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_max_block_id +* NAME +* osm_switch_get_max_block_id +* +* DESCRIPTION +* Returns the maximum block ID (host order) of this switch. +* +* SYNOPSIS +*/ +static inline uint32_t +osm_switch_get_max_block_id( + IN const osm_switch_t* const p_sw ) +{ + return( (uint32_t)(osm_fwd_tbl_get_size( &p_sw->fwd_tbl ) / + osm_fwd_tbl_get_lids_per_block( &p_sw->fwd_tbl ) ) ); +} +/* +* 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_max_block_id_in_use +* NAME +* osm_switch_get_max_block_id_in_use +* +* DESCRIPTION +* Returns the maximum block ID (host order) of this switch that +* is used for unicast routing. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_switch_get_max_block_id_in_use( + IN const osm_switch_t* const p_sw ) +{ + return( osm_fwd_tbl_get_max_block_id_in_use( &p_sw->fwd_tbl, + cl_ntoh16( p_sw->switch_info.lin_top ) ) ); +} +/* +* 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_node_ptr +* NAME +* osm_switch_get_node_ptr +* +* DESCRIPTION +* Returns a pointer to the Node object for this switch. +* +* SYNOPSIS +*/ +static inline osm_node_t* +osm_switch_get_node_ptr( + IN const osm_switch_t* const p_sw ) +{ + return( p_sw->p_node ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* RETURN VALUES +* Returns a pointer to the Node object for this switch. +* +* NOTES +* +* SEE ALSO +* Switch object +*********/ + +/****f* OpenSM: Switch/osm_switch_get_max_lid_ho +* NAME +* osm_switch_get_max_lid_ho +* +* DESCRIPTION +* Returns the maximum LID (host order) value contained +* in the switch routing tables. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_switch_get_max_lid_ho( + IN const osm_switch_t* const p_sw ) +{ + if (p_sw->max_lid_ho != 0) + return p_sw->max_lid_ho; + return( osm_lid_matrix_get_max_lid_ho( &p_sw->lmx ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to a switch object. +* +* RETURN VALUES +* Returns the maximum LID (host order) value contained +* in the switch routing tables. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_num_ports +* NAME +* osm_switch_get_num_ports +* +* DESCRIPTION +* Returns the number of ports in this switch. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_switch_get_num_ports( + IN const osm_switch_t* const p_sw ) +{ + return( osm_lid_matrix_get_num_ports( &p_sw->lmx ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* RETURN VALUES +* Returns the number of ports in this switch. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_fwd_tbl_block +* NAME +* osm_switch_get_fwd_tbl_block +* +* DESCRIPTION +* Retrieve a forwarding table block. +* +* SYNOPSIS +*/ +boolean_t +osm_switch_get_fwd_tbl_block( + IN const osm_switch_t* const p_sw, + IN const uint32_t block_id, + OUT uint8_t* const p_block ); +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* block_ID +* [in] The block_id to retrieve. +* +* p_block +* [out] Pointer to the 64 byte array to store the +* forwarding table clock specified by block_id. +* +* RETURN VALUES +* Returns true if there are more blocks necessary to +* configure all the LIDs reachable from this switch. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_supports_mcast +* NAME +* osm_switch_supports_mcast +* +* DESCRIPTION +* Indicates if a switch supports multicast. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_switch_supports_mcast( + IN const osm_switch_t* const p_sw ) +{ + return( p_sw->switch_info.mcast_cap != 0 ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* RETURN VALUES +* Returns TRUE if the switch supports multicast. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_set_switch_info +* NAME +* osm_switch_set_switch_info +* +* DESCRIPTION +* Updates the switch info attribute of this switch. +* +* SYNOPSIS +*/ +static inline void +osm_switch_set_switch_info( + IN osm_switch_t* const p_sw, + IN const ib_switch_info_t* const p_si ) +{ + CL_ASSERT( p_sw ); + CL_ASSERT( p_si ); + p_sw->switch_info = *p_si; +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to a Switch object. +* +* p_si +* [in] Pointer to the SwitchInfo attribute for this switch. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_count_path +* NAME +* osm_switch_count_path +* +* DESCRIPTION +* Counts this path in port profile. +* +* SYNOPSIS +*/ +static inline void +osm_switch_count_path( + IN osm_switch_t* const p_sw, + IN const uint8_t port + ) +{ + osm_port_prof_path_count_inc( &p_sw->p_prof[port] ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* port +* [in] Port to count path. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_set_ft_block +* NAME +* osm_switch_set_ft_block +* +* DESCRIPTION +* Copies in the specified block into the switch's Forwarding Table object. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +osm_switch_set_ft_block( + IN osm_switch_t* const p_sw, + IN const uint8_t* const p_block, + IN const uint32_t block_num ) +{ + CL_ASSERT( p_sw ); + return( osm_fwd_tbl_set_block( &p_sw->fwd_tbl, p_block, block_num ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* p_block +* [in] Pointer to the forwarding table block. +* +* block_num +* [in] Block number for this block +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_set_mft_block +* NAME +* osm_switch_set_mft_block +* +* DESCRIPTION +* Sets a block of multicast port masks into the multicast table. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +osm_switch_set_mft_block( + IN osm_switch_t* const p_sw, + IN const ib_net16_t* const p_block, + IN const uint16_t block_num, + IN const uint8_t position ) +{ + CL_ASSERT( p_sw ); + return( osm_mcast_tbl_set_block( &p_sw->mcast_tbl, p_block, + block_num, position ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* p_block +* [in] Pointer to the block of port masks to set. +* +* block_num +* [in] Block number (0-511) to set. +* +* position +* [in] Port mask position (0-15) to set. +* +* RETURN VALUE +* IB_SUCCESS on success. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_mft_block +* NAME +* osm_switch_get_mft_block +* +* DESCRIPTION +* Retrieve a block of multicast port masks from the multicast table. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_switch_get_mft_block( + IN osm_switch_t* const p_sw, + IN const uint16_t block_num, + IN const uint8_t position, + OUT ib_net16_t* const p_block ) +{ + CL_ASSERT( p_sw ); + return( osm_mcast_tbl_get_block( &p_sw->mcast_tbl, + block_num, position, p_block ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* block_num +* [in] Block number (0-511) to set. +* +* position +* [in] Port mask position (0-15) to set. +* +* p_block +* [out] Pointer to the block of port masks stored. +* +* RETURN VALUES +* Returns true if there are more blocks necessary to +* configure all the MLIDs reachable from this switch. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_mft_max_block +* NAME +* osm_switch_get_mft_max_block +* +* DESCRIPTION +* Get the max_block from the associated multicast table. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_switch_get_mft_max_block( + IN osm_switch_t* const p_sw ) +{ + CL_ASSERT( p_sw ); + return( osm_mcast_tbl_get_max_block( &p_sw->mcast_tbl ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* RETURN VALUE +*/ + +/****f* OpenSM: Switch/osm_switch_get_mft_max_block_in_use +* NAME +* osm_switch_get_mft_max_block_in_use +* +* DESCRIPTION +* Get the max_block_in_use from the associated multicast table. +* +* SYNOPSIS +*/ +static inline int16_t +osm_switch_get_mft_max_block_in_use( + IN osm_switch_t* const p_sw ) +{ + CL_ASSERT( p_sw ); + return( osm_mcast_tbl_get_max_block_in_use( &p_sw->mcast_tbl ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* RETURN VALUES +* Returns the maximum block ID in use in this switch's mcast table. +* A value of -1 indicates no blocks are in use. +* +* NOTES +* +* SEE ALSO +*/ + +/****f* OpenSM: Switch/osm_switch_get_mft_max_position +* NAME +* osm_switch_get_mft_max_position +* +* DESCRIPTION +* Get the max_position from the associated multicast table. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_switch_get_mft_max_position( + IN osm_switch_t* const p_sw ) +{ + CL_ASSERT( p_sw ); + return( osm_mcast_tbl_get_max_position( &p_sw->mcast_tbl ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* RETURN VALUE +*/ + +/****f* OpenSM: Switch/osm_switch_recommend_path +* NAME +* osm_switch_recommend_path +* +* DESCRIPTION +* Returns the recommended port on which to route this LID. +* In cases where LMC > 0, the remote side system and node +* used for the routing are tracked in the provided arrays +* (and counts) such that other lid for the same port will +* try and avoid going through the same remote system/node. +* +* SYNOPSIS +*/ +uint8_t +osm_switch_recommend_path( + IN const osm_switch_t* const p_sw, + IN const uint16_t lid_ho, + IN const boolean_t ignore_existing, + IN OUT uint64_t *remote_sys_guids, + IN OUT uint16_t *p_num_used_sys, + IN OUT uint64_t *remote_node_guids, + IN OUT uint16_t *p_num_used_nodes + ); +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* lid_ho +* [in] LID value (host order) for which to get a path advisory. +* +* 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. +* +* remote_sys_guids +* [in out] The array of remote system guids already used to +* route the other lids of the same target port (if LMC > 0). +* +* p_num_used_sys +* [in out] The number of remote systems used for routing to +* the port. +* +* remote_node_guids +* [in out] The array of remote node guids already used to route +* the other lids of the same target port (if LMC > 0). +* +* p_num_used_nodes +* [in out] The number of remote nodes used for routing to +* the port. +* +* RETURN VALUE +* Returns the recommended port on which to route this LID. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_recommend_mcast_path +* NAME +* osm_switch_recommend_mcast_path +* +* DESCRIPTION +* Returns the recommended port on which to route this LID. +* +* SYNOPSIS +*/ +uint8_t +osm_switch_recommend_mcast_path( + IN osm_switch_t* const p_sw, + IN const uint16_t lid_ho, + IN const uint16_t mlid_ho, + IN const boolean_t ignore_existing ); +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* lid_ho +* [in] LID value (host order) for of the node for with 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_fwd_tbl_size +* NAME +* osm_switch_get_fwd_tbl_size +* +* DESCRIPTION +* Returns the number of entries available in the forwarding table. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_switch_get_fwd_tbl_size( + IN const osm_switch_t* const p_sw ) +{ + return( osm_fwd_tbl_get_size( &p_sw->fwd_tbl ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch. +* +* RETURN VALUE +* Returns the number of entries available in the forwarding table. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_mcast_fwd_tbl_size +* NAME +* osm_switch_get_mcast_fwd_tbl_size +* +* DESCRIPTION +* Returns the number of entries available in the multicast forwarding table. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_switch_get_mcast_fwd_tbl_size( + IN const osm_switch_t* const p_sw ) +{ + return( cl_ntoh16( p_sw->switch_info.mcast_cap ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch. +* +* RETURN VALUE +* Returns the number of entries available in the multicast forwarding table. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_path_count_get +* NAME +* osm_switch_path_count_get +* +* DESCRIPTION +* Returns the count of the number of paths going through this port. +* +* SYNOPSIS +*/ +static inline uint32_t +osm_switch_path_count_get( + IN const osm_switch_t* const p_sw, + IN const uint8_t port_num ) +{ + return( osm_port_prof_path_count_get( &p_sw->p_prof[port_num] ) ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the Switch object. +* +* port_num +* [in] Port number for which to get path count. +* +* RETURN VALUE +* Returns the count of the number of paths going through this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_prepare_path_rebuild +* NAME +* osm_switch_prepare_path_rebuild +* +* DESCRIPTION +* Prepares a switch to rebuild pathing information. +* +* SYNOPSIS +*/ +void +osm_switch_prepare_path_rebuild( + IN osm_switch_t* const p_sw ); +/* +* PARAMETERS +* p_sw +* [in] Pointer to the Switch object. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_mcast_tbl_ptr +* NAME +* osm_switch_get_mcast_tbl_ptr +* +* DESCRIPTION +* Returns a pointer to the switch's multicast table. +* +* SYNOPSIS +*/ +static inline osm_mcast_tbl_t* +osm_switch_get_mcast_tbl_ptr( + IN const osm_switch_t* const p_sw ) +{ + return( (osm_mcast_tbl_t*)&p_sw->mcast_tbl ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch. +* +* RETURN VALUE +* Returns a pointer to the switch's multicast table. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_is_in_mcast_tree +* NAME +* osm_switch_is_in_mcast_tree +* +* DESCRIPTION +* Returns true if this switch already belongs in the tree for the specified +* multicast group. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_switch_is_in_mcast_tree( + IN const osm_switch_t* const p_sw, + IN const uint16_t mlid_ho ) +{ + const osm_mcast_tbl_t* p_tbl; + + p_tbl = &p_sw->mcast_tbl; + if( p_tbl ) + return( osm_mcast_tbl_is_any_port( &p_sw->mcast_tbl, mlid_ho ) ); + else + return( FALSE ); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch. +* +* mlid_ho +* [in] MLID (host order) of the multicast tree to check. +* +* RETURN VALUE +* Returns true if this switch already belongs in the tree for the specified +* multicast group. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Node/osm_switch_discovery_count_get +* NAME +* osm_switch_discovery_count_get +* +* DESCRIPTION +* Returns a pointer to the physical port object at the +* specified local port number. +* +* SYNOPSIS +*/ +static inline uint32_t +osm_switch_discovery_count_get( + IN const osm_switch_t* const p_switch ) +{ + return( p_switch->discovery_count ); +} +/* +* PARAMETERS +* p_switch +* [in] Pointer to an osm_switch_t object. +* +* RETURN VALUES +* Returns the discovery count for this node. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_switch_discovery_count_reset +* NAME +* osm_switch_discovery_count_reset +* +* DESCRIPTION +* Resets the discovery count for this node to zero. +* This operation should be performed at the start of a sweep. +* +* SYNOPSIS +*/ +static inline void +osm_switch_discovery_count_reset( + IN osm_switch_t* const p_switch ) +{ + p_switch->discovery_count = 0; +} +/* +* PARAMETERS +* p_switch +* [in] Pointer to an osm_switch_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_switch_discovery_count_inc +* NAME +* osm_switch_discovery_count_inc +* +* DESCRIPTION +* Increments the discovery count for this node. +* +* SYNOPSIS +*/ +static inline void +osm_switch_discovery_count_inc( + IN osm_switch_t* const p_switch ) +{ + p_switch->discovery_count++; +} +/* +* PARAMETERS +* p_switch +* [in] Pointer to an osm_switch_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +END_C_DECLS + +#endif /* _OSM_SWITCH_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_trap_rcv.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_trap_rcv.h new file mode 100644 index 00000000..5f8e7274 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_trap_rcv.h @@ -0,0 +1,326 @@ +/* + * 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: + * Declaration of osm_trap_rcv_t. + * This object represents the Trap Receiver object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#ifndef _OSM_TRAP_RCV_H_ +#define _OSM_TRAP_RCV_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/Trap Receiver +* NAME +* Trap Receiver +* +* DESCRIPTION +* The Trap Receiver object encapsulates the information +* needed to receive the Trap attribute from a node. +* +* The Trap Receiver 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: Trap Receiver/osm_trap_rcv_t +* NAME +* osm_trap_rcv_t +* +* DESCRIPTION +* Trap Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_trap_rcv +{ + osm_subn_t *p_subn; + osm_stats_t *p_stats; + osm_log_t *p_log; + osm_resp_t *p_resp; + osm_state_mgr_t *p_state_mgr; + cl_plock_t *p_lock; + cl_event_wheel_t trap_aging_tracker; +} osm_trap_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_stats +* Pointer to the OpenSM statistics block. +* +* p_log +* Pointer to the log object. +* +* p_resp +* Pointer to the generic MAD responder object. +* +* p_state_mgr +* Pointer to the State Manager object. +* +* p_lock +* Pointer to the serializing lock. +* +* trap_aging_tracker +* An event wheel tracking erceived traps and their aging. +* Basically we can start a timer every time we receive a specific +* trap and check to seee if not expired next time it is received. +* +* SEE ALSO +* Trap Receiver object +*********/ + +/****f* OpenSM: Trap Receiver/osm_trap_rcv_construct +* NAME +* osm_trap_rcv_construct +* +* DESCRIPTION +* This function constructs a Trap Receiver object. +* +* SYNOPSIS +*/ +void osm_trap_rcv_construct( + IN osm_trap_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to a Trap Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_trap_rcv_init, osm_trap_rcv_destroy +* +* Calling osm_trap_rcv_construct is a prerequisite to calling any other +* method except osm_trap_rcv_init. +* +* SEE ALSO +* Trap Receiver object, osm_trap_rcv_init, +* osm_trap_rcv_destroy +*********/ + +/****f* OpenSM: Trap Receiver/osm_trap_rcv_destroy +* NAME +* osm_trap_rcv_destroy +* +* DESCRIPTION +* The osm_trap_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_trap_rcv_destroy( + IN osm_trap_rcv_t* const p_rcv ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Trap Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_trap_rcv_construct or osm_trap_rcv_init. +* +* SEE ALSO +* Trap Receiver object, osm_trap_rcv_construct, +* osm_trap_rcv_init +*********/ + +/****f* OpenSM: Trap Receiver/osm_trap_rcv_init +* NAME +* osm_trap_rcv_init +* +* DESCRIPTION +* The osm_trap_rcv_init function initializes a +* Trap Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_trap_rcv_init( + IN osm_trap_rcv_t* const p_rcv, + IN osm_subn_t* const p_subn, + IN osm_stats_t* const p_stats, + IN osm_resp_t* const p_resp, + IN osm_log_t* const p_log, + IN osm_state_mgr_t* const p_state_mgr, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_trap_rcv_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_stats +* [in] Pointer to the OpenSM statistics block. +* +* p_resp +* [in] Pointer to the generic MAD Responder object. +* +* p_log +* [in] Pointer to the log object. +* +* p_state_mgr +* [in] Pointer to the State Manager object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the Trap Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other Trap Receiver methods. +* +* SEE ALSO +* Trap Receiver object, osm_trap_rcv_construct, +* osm_trap_rcv_destroy +*********/ + +/****f* OpenSM: Trap Receiver/osm_trap_rcv_process +* NAME +* osm_trap_rcv_process +* +* DESCRIPTION +* Process the Trap attribute. +* +* SYNOPSIS +*/ +void osm_trap_rcv_process( + IN osm_trap_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to an osm_trap_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's Trap attribute. +* +* RETURN VALUES +* IB_SUCCESS if the Trap processing was successful. +* +* NOTES +* This function processes a Trap attribute. +* +* SEE ALSO +* Trap Receiver, Trap Response Controller +*********/ + +/****f* OpenSM: Trap Receiver/osm_trap_rcv_aging_tracker_callback +* NAME +* osm_trap_rcv_aging_tracker_callback +* +* DESCRIPTION +* Callback function called by the aging tracker mechanism. +* +* SYNOPSIS +*/ +uint64_t +osm_trap_rcv_aging_tracker_callback( + IN uint64_t key, + IN uint32_t num_regs, + IN void* context ); + +/* +* PARAMETERS +* key +* [in] The key by which the event was inserted. +* +* num_regs +* [in] The number of times the same event (key) was registered. +* +* context +* [in] Pointer to the context given in the registering of the event. +* +* RETURN VALUES +* None. +* +* NOTES +* This function is called by the cl_event_wheel when the aging tracker +* event has ended. +* +* SEE ALSO +* Trap Receiver, Trap Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_TRAP_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_trap_rcv_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_trap_rcv_ctrl.h new file mode 100644 index 00000000..c46be6a3 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_trap_rcv_ctrl.h @@ -0,0 +1,232 @@ +/* + * 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: + * Declaration of osm_trap_rcv_ctrl_t. + * This object represents a controller that receives the IBA Trap + * attribute from a node. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.2 $ + */ + +#ifndef _OSM_TRAP_RCV_CTRL_H_ +#define _OSM_TRAP_RCV_CTRL_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 + +/***** OpenSM/Trap Receive Controller +* NAME +* Trap Receive Controller +* +* DESCRIPTION +* The Trap Receive Controller object encapsulates the information +* needed to receive the Trap attribute from a node. +* +* The Trap Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Yael Kalka, Mellanox +* +*********/ + +/****s* OpenSM: Trap Receive Controller/osm_trap_rcv_ctrl_t +* NAME +* osm_trap_rcv_ctrl_t +* +* DESCRIPTION +* Trap Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_trap_rcv_ctrl +{ + osm_trap_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_trap_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the Trap Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* Trap Receive Controller object +*********/ + +/****f* OpenSM: Trap Receive Controller/osm_trap_rcv_ctrl_construct +* NAME +* osm_trap_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a Trap Receive Controller object. +* +* SYNOPSIS +*/ +void +osm_trap_rcv_ctrl_construct( + IN osm_trap_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a Trap Receive Controller object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_trap_rcv_ctrl_init, osm_trap_rcv_ctrl_destroy +* +* Calling osm_trap_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_trap_rcv_ctrl_init. +* +* SEE ALSO +* Trap Receive Controller object, osm_trap_rcv_ctrl_init, +* osm_trap_rcv_ctrl_destroy +*********/ + +/****f* OpenSM: Trap Receive Controller/osm_trap_rcv_ctrl_destroy +* NAME +* osm_trap_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_trap_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_trap_rcv_ctrl_destroy( + IN osm_trap_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Trap Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_trap_rcv_ctrl_construct or osm_trap_rcv_ctrl_init. +* +* SEE ALSO +* Trap Receive Controller object, osm_trap_rcv_ctrl_construct, +* osm_trap_rcv_ctrl_init +*********/ + +/****f* OpenSM: Trap Receive Controller/osm_trap_rcv_ctrl_init +* NAME +* osm_trap_rcv_ctrl_init +* +* DESCRIPTION +* The osm_trap_rcv_ctrl_init function initializes a +* Trap Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_trap_rcv_ctrl_init( + IN osm_trap_rcv_ctrl_t* const p_ctrl, + IN osm_trap_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_trap_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_trap_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* IB_SUCCESS if the Trap Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other Trap Receive Controller methods. +* +* SEE ALSO +* Trap Receive Controller object, osm_trap_rcv_ctrl_construct, +* osm_trap_rcv_ctrl_destroy +*********/ + +END_C_DECLS + +#endif /* OSM_TRAP_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_ts_useraccess.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_ts_useraccess.h new file mode 100644 index 00000000..39df01ba --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_ts_useraccess.h @@ -0,0 +1,54 @@ +/* + * 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$ + */ + + +#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-1/ulp/opensm/user/include/opensm/osm_ucast_mgr.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_ucast_mgr.h new file mode 100644 index 00000000..25d19d55 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_ucast_mgr.h @@ -0,0 +1,328 @@ +/* + * 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: + * Declaration of osm_ucast_mgr_t. + * This object represents the Unicast Manager object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#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 + +#define OSM_UCAST_MGR_LIST_SIZE_MIN 256 + +/****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 +* +*********/ + +/****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 +{ + osm_subn_t *p_subn; + osm_req_t *p_req; + osm_log_t *p_log; + cl_plock_t *p_lock; + boolean_t any_change; + uint8_t *lft_buf; +} osm_ucast_mgr_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_req +* Pointer to the Requester object sending SMPs. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* any_change +* Initialized to FALSE at the beginning of the algorithm, +* set to TRUE by osm_ucast_mgr_set_fwd_table() if any mad +* was sent. +* +* lft_buf +* LFT buffer - used during LFT calculation/setup. +* +* SEE ALSO +* Unicast Manager object +*********/ + +/****f* OpenSM: Unicast Manager/osm_ucast_mgr_construct +* NAME +* osm_ucast_mgr_construct +* +* DESCRIPTION +* This function constructs a Unicast Manager object. +* +* SYNOPSIS +*/ +void +osm_ucast_mgr_construct( + IN osm_ucast_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to a Unicast Manager object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows osm_ucast_mgr_destroy +* +* Calling osm_ucast_mgr_construct is a prerequisite to calling any other +* method except osm_ucast_mgr_init. +* +* SEE ALSO +* Unicast Manager object, osm_ucast_mgr_init, +* osm_ucast_mgr_destroy +*********/ + +/****f* OpenSM: Unicast Manager/osm_ucast_mgr_destroy +* NAME +* osm_ucast_mgr_destroy +* +* DESCRIPTION +* The osm_ucast_mgr_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_ucast_mgr_destroy( + IN osm_ucast_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Unicast Manager object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_ucast_mgr_construct or osm_ucast_mgr_init. +* +* SEE ALSO +* Unicast Manager object, osm_ucast_mgr_construct, +* osm_ucast_mgr_init +*********/ + +/****f* OpenSM: Unicast Manager/osm_ucast_mgr_init +* NAME +* osm_ucast_mgr_init +* +* DESCRIPTION +* The osm_ucast_mgr_init function initializes a +* Unicast Manager object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_ucast_mgr_init( + IN osm_ucast_mgr_t* const p_mgr, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_ucast_mgr_t object to initialize. +* +* p_req +* [in] Pointer to the attribute Requester object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the Unicast Manager object was initialized +* successfully. +* +* NOTES +* Allows calling other Unicast Manager methods. +* +* SEE ALSO +* Unicast Manager object, osm_ucast_mgr_construct, +* osm_ucast_mgr_destroy +*********/ + +/****f* OpenSM: Unicast Manager/osm_ucast_mgr_set_fwd_table +* NAME +* osm_ucast_mgr_set_fwd_table +* +* DESCRIPTION +* Setup forwarding table for the switch (from prepared lft_buf). +* +* SYNOPSIS +*/ +void +osm_ucast_mgr_set_fwd_table( + IN osm_ucast_mgr_t* const p_mgr, + IN osm_switch_t* const p_sw ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_ucast_mgr_t object. +* +* p_mgr +* [in] Pointer to an osm_switch_t object. +* +* SEE ALSO +* Unicast Manager +*********/ + +/****f* OpenSM: Unicast Manager/osm_ucast_mgr_build_lid_matrices +* NAME +* osm_ucast_mgr_build_lid_matrices +* +* DESCRIPTION +* Build switches's lid matrices. +* +* SYNOPSIS +*/ +void +osm_ucast_mgr_build_lid_matrices( + IN osm_ucast_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_ucast_mgr_t object. +* +* NOTES +* This function processes the subnet, configuring switches' +* min hops tables (aka lid matrices). +* +* SEE ALSO +* Unicast Manager +*********/ + +/****f* OpenSM: Unicast Manager/osm_ucast_mgr_process +* NAME +* osm_ucast_mgr_process +* +* DESCRIPTION +* Process and configure the subnet's unicast forwarding tables. +* +* SYNOPSIS +*/ +osm_signal_t +osm_ucast_mgr_process( + IN osm_ucast_mgr_t* const p_mgr ); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_ucast_mgr_t object. +* +* RETURN VALUES +* Returns the appropriate signal to the caller: +* OSM_SIGNAL_DONE - operation is complete +* OSM_SIGNAL_DONE_PENDING - local operations are complete, but +* transactions are still pending on the wire. +* +* NOTES +* 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-1/ulp/opensm/user/include/opensm/osm_umadt.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_umadt.h new file mode 100644 index 00000000..80c969e0 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_umadt.h @@ -0,0 +1,143 @@ +/* + * 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: + * 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#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-1/ulp/opensm/user/include/opensm/osm_version.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_version.h new file mode 100644 index 00000000..7be8e07f --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_version.h @@ -0,0 +1,63 @@ +/* + * 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$ + */ + + +#ifndef _OSM_VERSION_H_ +#define _OSM_VERSION_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: Base/OSM_VERSION +* NAME +* OSM_VERSION +* +* DESCRIPTION +* The version string for OpenSM +* +* SYNOPSIS +*/ +#define OSM_VERSION "OpenSM Rev:openib-3.0.0" +/********/ + +END_C_DECLS + +#endif /* _OSM_VERSION_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_vl15intf.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_vl15intf.h new file mode 100644 index 00000000..f56a6ca3 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_vl15intf.h @@ -0,0 +1,417 @@ +/* + * 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: + * Declaration of osm_vl15_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#ifndef _OSM_VL15INTF_H_ +#define _OSM_VL15INTF_H_ + +#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/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_subn_t *p_subn; + cl_disp_reg_handle_t h_disp; + cl_plock_t *p_lock; + +} 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. +* +* p_subn +* Pointer to the Subnet object for this subnet. +* +* h_disp +* Handle returned from dispatcher registration. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* VL15 object +*********/ + +/****f* OpenSM: VL15/osm_vl15_construct +* NAME +* osm_vl15_construct +* +* DESCRIPTION +* This function constructs an VL15 object. +* +* SYNOPSIS +*/ +void +osm_vl15_construct( + IN osm_vl15_t* const p_vl15 ); +/* +* PARAMETERS +* p_vl15 +* [in] Pointer to a VL15 object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_vl15_init, osm_vl15_destroy, and osm_vl15_is_inited. +* +* 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, osm_vl15_is_inited +*********/ + +/****f* OpenSM: VL15/osm_vl15_destroy +* NAME +* osm_vl15_destroy +* +* DESCRIPTION +* The osm_vl15_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_vl15_destroy( + IN osm_vl15_t* const p_vl15, + IN struct _osm_mad_pool *p_pool); +/* +* PARAMETERS +* p_vl15 +* [in] Pointer to a VL15 object to destroy. +* +* p_pool +* [in] The pointer to the mad pool to return outstanding mads to +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified VL15 object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_vl15_construct or +* osm_vl15_init. +* +* SEE ALSO +* VL15 object, osm_vl15_construct, osm_vl15_init +*********/ + +/* + Initialization. + Rate specifies the minimum number of microseconds between transmissions + on VL15. +*/ +/****f* OpenSM: VL15/osm_vl15_init +* NAME +* osm_vl15_init +* +* DESCRIPTION +* The osm_vl15_init function initializes a VL15 object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_vl15_init( + IN osm_vl15_t* const p_vl15, + IN osm_vendor_t* const p_vend, + IN osm_log_t* const p_log, + IN osm_stats_t* const p_stats, + IN const int32_t max_wire_smps, + IN osm_subn_t* const p_subn, + IN cl_dispatcher_t* const p_disp, + IN cl_plock_t* const p_lock ); +/* +* 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. +* +* p_subn +* [in] Pointer to the subnet object. +* +* p_disp +* [in] Pointer to the dispatcher object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* 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, +* osm_vl15_is_inited +*********/ + +/****f* OpenSM: VL15/osm_vl15_post +* NAME +* osm_vl15_post +* +* DESCRIPTION +* Posts a MAD to the VL15 interface for transmission. +* +* SYNOPSIS +*/ +void +osm_vl15_post( + IN osm_vl15_t* const p_vl15, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_vl15 +* [in] Pointer to an osm_vl15_t object. +* +* p_madw +* [in] Pointer to a MAD wrapper structure containing the MAD. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* The osm_vl15_construct or osm_vl15_init must be called before using +* this function. +* +* SEE ALSO +* VL15 object, osm_vl15_construct, osm_vl15_init +*********/ + +/****f* OpenSM: VL15/osm_vl15_poll +* NAME +* osm_vl15_poll +* +* DESCRIPTION +* Causes the VL15 Interface to consider sending another QP0 MAD. +* +* SYNOPSIS +*/ +void +osm_vl15_poll( + IN osm_vl15_t* const p_vl ); +/* +* PARAMETERS +* p_vl15 +* [in] Pointer to an osm_vl15_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* This function signals the VL15 that it may be possible to send +* a SMP. This function checks three criteria before sending a SMP: +* 1) The VL15 worker is IDLE +* 2) There are no QP0 SMPs currently outstanding +* 3) There is something on the VL15 FIFO to send +* +* SEE ALSO +* VL15 object, osm_vl15_construct, osm_vl15_init +*********/ + +/****f* OpenSM: VL15/osm_vl15_shutdown +* NAME +* osm_vl15_shutdown +* +* DESCRIPTION +* Cleanup all outstanding MADs on both fifo's. +* This is required to return all outstanding MAD resources. +* +* SYNOPSIS +*/ +void +osm_vl15_shutdown( + IN osm_vl15_t* const p_vl, + IN osm_mad_pool_t* const p_mad_pool); +/* +* PARAMETERS +* p_vl15 +* [in] Pointer to an osm_vl15_t object. +* +* p_mad_pool +* [in] The MAD pool owning the mads. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* VL15 object, osm_vl15_construct, osm_vl15_init +*********/ + +END_C_DECLS + +#endif /* _OSM_VL15INTF_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_vl_arb_rcv.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_vl_arb_rcv.h new file mode 100644 index 00000000..9b57aeef --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_vl_arb_rcv.h @@ -0,0 +1,265 @@ +/* + * 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: + * Declaration of osm_vla_rcv_t. + * This object represents the VL Arbitration Receiver object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#ifndef _OSM_VLA_RCV_H_ +#define _OSM_VLA_RCV_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/VL Arbitration Receiver +* NAME +* VL Arbitration Receiver +* +* DESCRIPTION +* The VL Arbitration Receiver object encapsulates the information +* needed to set or get the vl arbitration attribute from a port. +* +* The VL Arbitration Receiver object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ + +/****s* OpenSM: VL Arbitration Receiver/osm_vla_rcv_t +* NAME +* osm_vla_rcv_t +* +* DESCRIPTION +* VL Arbitration Receiver structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_vla_rcv +{ + osm_subn_t *p_subn; + osm_req_t *p_req; + osm_log_t *p_log; + cl_plock_t *p_lock; + +} osm_vla_rcv_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_req +* Pointer to the generic attribute request object. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* VL Arbitration Receiver object +*********/ + +/****f* OpenSM: VL Arbitration Receiver/osm_vla_rcv_construct +* NAME +* osm_vla_rcv_construct +* +* DESCRIPTION +* This function constructs a VL Arbitration Receiver object. +* +* SYNOPSIS +*/ +void osm_vla_rcv_construct( + IN osm_vla_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a VL Arbitration Receiver object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_vla_rcv_destroy +* +* Calling osm_vla_rcv_construct is a prerequisite to calling any other +* method except osm_vla_rcv_init. +* +* SEE ALSO +* VL Arbitration Receiver object, osm_vla_rcv_init, +* osm_vla_rcv_destroy +*********/ + +/****f* OpenSM: VL Arbitration Receiver/osm_vla_rcv_destroy +* NAME +* osm_vla_rcv_destroy +* +* DESCRIPTION +* The osm_vla_rcv_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_vla_rcv_destroy( + IN osm_vla_rcv_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* VL Arbitration Receiver object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_vla_rcv_construct or osm_vla_rcv_init. +* +* SEE ALSO +* VL Arbitration Receiver object, osm_vla_rcv_construct, +* osm_vla_rcv_init +*********/ + +/****f* OpenSM: VL Arbitration Receiver/osm_vla_rcv_init +* NAME +* osm_vla_rcv_init +* +* DESCRIPTION +* The osm_vla_rcv_init function initializes a +* VL Arbitration Receiver object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_vla_rcv_init( + IN osm_vla_rcv_t* const p_ctrl, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_vla_rcv_t object to initialize. +* +* p_req +* [in] Pointer to an osm_req_t object. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the VL Arbitration Receiver object was initialized +* successfully. +* +* NOTES +* Allows calling other VL Arbitration Receiver methods. +* +* SEE ALSO +* VL Arbitration Receiver object, osm_vla_rcv_construct, +* osm_vla_rcv_destroy +*********/ + +/****f* OpenSM: VL Arbitration Receiver/osm_vla_rcv_process +* NAME +* osm_vla_rcv_process +* +* DESCRIPTION +* Process the vl arbitration attribute. +* +* SYNOPSIS +*/ +void osm_vla_rcv_process( + IN const osm_vla_rcv_t* const p_ctrl, + IN osm_madw_t* const p_madw ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_vla_rcv_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the MAD +* that contains the node's SLtoVL attribute. +* +* RETURN VALUES +* CL_SUCCESS if the SLtoVL processing was successful. +* +* NOTES +* This function processes a SLtoVL attribute. +* +* SEE ALSO +* VL Arbitration Receiver, VL Arbitration Response Controller +*********/ + +END_C_DECLS + +#endif /* _OSM_VLA_RCV_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_vl_arb_rcv_ctrl.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_vl_arb_rcv_ctrl.h new file mode 100644 index 00000000..bca54d61 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/osm_vl_arb_rcv_ctrl.h @@ -0,0 +1,261 @@ +/* + * 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: + * Declaration of osm_vla_rcv_ctrl_t. + * This object represents a controller that set or get resp the + * IBA VL Arbitration Table attribute from a port. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#ifndef _OSM_VLA_RCV_CTRL_H_ +#define _OSM_VLA_RCV_CTRL_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/VL Arbitration Table Receive Controller +* NAME +* VL Arbitration Receive Controller +* +* DESCRIPTION +* The VL Arbitration Receive Controller object encapsulates +* the information needed to get or set VL Arbitration of a port. +* +* The VL Arbitration Receive Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ + +/****s* OpenSM: VL Arbitration Receive Controller/osm_vla_rcv_ctrl_t +* NAME +* osm_vla_rcv_ctrl_t +* +* DESCRIPTION +* VL Arbitration Receive Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _osm_vla_rcv_ctrl +{ + osm_vla_rcv_t *p_rcv; + osm_log_t *p_log; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + +} osm_vla_rcv_ctrl_t; +/* +* FIELDS +* p_rcv +* Pointer to the VL Arbitration Receiver object. +* +* p_log +* Pointer to the log object. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* SEE ALSO +* VL Arbitration Receive Controller object +* VL Arbitration Receiver object +*********/ + +/****f* OpenSM: VL Arbitration Receive Controller/osm_vla_rcv_ctrl_construct +* NAME +* osm_vla_rcv_ctrl_construct +* +* DESCRIPTION +* This function constructs a VL Arbitration Receive Controller object. +* +* SYNOPSIS +*/ +void osm_vla_rcv_ctrl_construct( + IN osm_vla_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a VL Arbitration Receive Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_vla_rcv_ctrl_init, osm_vla_rcv_ctrl_destroy, +* and osm_vla_rcv_ctrl_is_inited. +* +* Calling osm_vla_rcv_ctrl_construct is a prerequisite to calling any other +* method except osm_vla_rcv_ctrl_init. +* +* SEE ALSO +* VL Arbitration Receive Controller object, osm_vla_rcv_ctrl_init, +* osm_vla_rcv_ctrl_destroy, osm_vla_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: VL Arbitration Receive Controller/osm_vla_rcv_ctrl_destroy +* NAME +* osm_vla_rcv_ctrl_destroy +* +* DESCRIPTION +* The osm_vla_rcv_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_vla_rcv_ctrl_destroy( + IN osm_vla_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* VL Arbitration Receive Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_vla_rcv_ctrl_construct or osm_vla_rcv_ctrl_init. +* +* SEE ALSO +* VL Arbitration Receive Controller object, osm_vla_rcv_ctrl_construct, +* osm_vla_rcv_ctrl_init +*********/ + +/****f* OpenSM: VL Arbitration Receive Controller/osm_vla_rcv_ctrl_init +* NAME +* osm_vla_rcv_ctrl_init +* +* DESCRIPTION +* The osm_vla_rcv_ctrl_init function initializes a +* VL Arbitration Receive Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_vla_rcv_ctrl_init( + IN osm_vla_rcv_ctrl_t* const p_ctrl, + IN osm_vla_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_vla_rcv_ctrl_t object to initialize. +* +* p_rcv +* [in] Pointer to an osm_vla_rcv_t object. +* +* p_log +* [in] Pointer to the log object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* CL_SUCCESS if the VL Arbitration Receive Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other VL Arbitration Receive Controller methods. +* +* SEE ALSO +* VL Arbitration Receive Controller object, osm_vla_rcv_ctrl_construct, +* osm_vla_rcv_ctrl_destroy, osm_vla_rcv_ctrl_is_inited +*********/ + +/****f* OpenSM: VL Arbitration Receive Controller/osm_vla_rcv_ctrl_is_inited +* NAME +* osm_vla_rcv_ctrl_is_inited +* +* DESCRIPTION +* Indicates if the object has been initialized with osm_vla_rcv_ctrl_init. +* +* SYNOPSIS +*/ +boolean_t osm_vla_rcv_ctrl_is_inited( + IN const osm_vla_rcv_ctrl_t* const p_ctrl ); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_vla_rcv_ctrl_t object. +* +* RETURN VALUES +* TRUE if the object was initialized successfully, +* FALSE otherwise. +* +* NOTES +* The osm_vla_rcv_ctrl_construct or osm_vla_rcv_ctrl_init must be +* called before using this function. +* +* SEE ALSO +* VL Arbitration Receive Controller object, osm_vla_rcv_ctrl_construct, +* osm_vla_rcv_ctrl_init +*********/ + +END_C_DECLS + +#endif /* _OSM_VLA_RCV_CTRL_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/opensm/st.h b/branches/WOF2-1/ulp/opensm/user/include/opensm/st.h new file mode 100644 index 00000000..ee0ba918 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/opensm/st.h @@ -0,0 +1,107 @@ +/* + * 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$ + */ + + +/* @(#) st.h 5.1 89/12/14 */ + +#ifndef ST_INCLUDED +#define ST_INCLUDED + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +#if (__WORDSIZE == 64) || defined (_WIN64) +#define st_ptr_t unsigned long long +#else +#define st_ptr_t unsigned long +#endif + +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-1/ulp/opensm/user/include/unistd.h b/branches/WOF2-1/ulp/opensm/user/include/unistd.h new file mode 100644 index 00000000..08fb5372 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/unistd.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2002-2006 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. + * + * $Id: osm_base.h 1689 2006-09-12 20:55:47Z eitan $ + */ + + + +/* + * Abstract: + * Work around for cmpatibility mode with Linux. + * + */ diff --git a/branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor.h b/branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor.h new file mode 100644 index 00000000..fedbe081 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor.h @@ -0,0 +1,78 @@ +/* + * 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: + * Include file used by OpenSM to pull in the correct vendor file. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +/* + this is the generic include file which includes + the proper vendor specific file +*/ +#include + +#if defined( OSM_VENDOR_INTF_TEST ) +#include +#elif defined( OSM_VENDOR_INTF_UMADT ) +#include +#elif defined( OSM_VENDOR_INTF_MTL ) +/* HACK - I do not know how to prevent complib from loading kernel H files */ +#undef __init +#include +#elif defined( OSM_VENDOR_INTF_TS ) +#undef __init +#include +#elif defined( OSM_VENDOR_INTF_ANAFA ) +#undef __init +#include +#elif defined( OSM_VENDOR_INTF_SIM ) +#undef __init +#include +#elif defined( OSM_VENDOR_INTF_OPENIB ) +#include +#elif defined( OSM_VENDOR_INTF_AL ) +#include +#elif +#error No MAD Interface selected! +#error Choose an interface in osm_vendor_select.h +#endif + + diff --git a/branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_al.h b/branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_al.h new file mode 100644 index 00000000..98cc8af6 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_al.h @@ -0,0 +1,372 @@ +/* + * 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$ + */ + + + +/* + * 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + + + + +#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-1/ulp/opensm/user/include/vendor/osm_vendor_api.h b/branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_api.h new file mode 100644 index 00000000..e4c61284 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_api.h @@ -0,0 +1,519 @@ +/* + * 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: + * Specification of the OpenSM transport API. This API is OpenSM's view + * of the Infiniband transport. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_VENDOR_API_H_ +#define _OSM_VENDOR_API_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +/****s* OpenSM Vendor API/osm_vend_mad_recv_callback_t +* NAME +* osm_vend_mad_recv_callback_t +* +* DESCRIPTION +* Function prototype for the vendor MAD receive callback. +* The vendor layer calls this function for MAD receives. +* +* SYNOPSIS +*/ +typedef void (*osm_vend_mad_recv_callback_t)( + IN osm_madw_t *p_madw, + IN void* bind_context, + IN osm_madw_t *p_req_madw ); +/* +* PARAMETERS +* p_madw +* [in] The received MAD wrapper. +* +* bind_context +* [in] User context supplied during the bind call. +* +* p_req_madw +* [in] Pointer to the request mad wrapper that generated this response. +* If the inbound MAD is not a response, this field is NULL. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* OpenSM Vendor API/osm_vend_mad_send_err_callback_t +* NAME +* osm_vend_mad_send_err_callback_t +* +* DESCRIPTION +* Function prototype for the vendor send failure callback. +* The vendor layer calls this function when MADs expecting +* a response are completed in error, most likely due to a +* timeout. +* +* SYNOPSIS +*/ +typedef void (*osm_vend_mad_send_err_callback_t)( + IN void* bind_context, + IN osm_madw_t *p_madw ); +/* +* PARAMETERS +* bind_context +* [in] User context supplied during the bind call. +* +* p_madw +* [in] Pointer to the request mad that failed. +* +* RETURN VALUES +* None. +* +* NOTES +* The vendor layer does not call this function (or any other) +* for MADs that were not expecting a response. +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_new +* NAME +* osm_vendor_new +* +* DESCRIPTION +* Allocates and initializes a new osm_vendor_t object. +* OpenSM calls this function before any other in the vendor API. +* This object is passed as a parameter to all other vendor functions. +* +* SYNOPSIS +*/ +osm_vendor_t* +osm_vendor_new( + IN osm_log_t* const p_log, + IN const uint32_t timeout ); +/* +* PARAMETERS +* p_log +* [in] Pointer to the log object to use. +* +* timeout +* [in] transaction timeout +* +* RETURN VALUES +* Returns a pointer to the vendor object. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* OpenSM Vendor API/osm_vendor_delete +* NAME +* osm_vendor_delete +* +* DESCRIPTION +* Dealocate the vendor object. +* +* SYNOPSIS +*/ +void +osm_vendor_delete( + IN osm_vendor_t** const pp_vend ); +/* +* PARAMETERS +* pp_vend +* [in/out] pointer to pointer to vendor objcet to be deleted +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_get_ports +* NAME +* osm_vendor_get_ports +* +* DESCRIPTION +* Returns an array of available port attribute structures. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_vendor_get_all_port_attr( + IN osm_vendor_t* const p_vend, + IN ib_port_attr_t* const p_attr_array, + IN uint32_t* const p_num_ports ); +/* +* PARAMETERS +* p_vend +* [in] Pointer to the vendor object to initialize. +* +* p_attr_array +* [in/out] Pointer to pre-allocated array of port attributes. +* If it is NULL - then the command only updates the p_num_ports, +* and return IB_INSUFFICIENT_MEMORY. +* +* p_num_ports +* [in/out] Pointer to a variable to hold the total number of ports +* available on the local machine.. +* +* RETURN VALUES +* IB_SUCCESS on success. +* IB_INSUFFICIENT_MEMORY if the attribute array was not large enough. +* The number of attributes needed is returned in num_guids. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_init +* NAME +* osm_vendor_init +* +* DESCRIPTION +* The osm_vendor_init function initializes the vendor transport layer. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_vendor_init( + IN osm_vendor_t* const p_vend, + IN osm_log_t * const p_log, + IN const uint32_t timeout ); +/* +* PARAMETERS +* p_vend +* [in] Pointer to the vendor object to initialize. +* +* p_log +* [in] Pointer to OpenSM's log object. Vendor code may +* use the log object to send messages to OpenSM's log. +* +* timeout +* [in] Transaction timeout value in milliseconds. +* A value of 0 disables timeouts. +* +* RETURN VALUE +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_bind +* NAME +* osm_vendor_bind +* +* DESCRIPTION +* The osm_vendor_bind function registers with the vendor transport layer +* per Mad Class per PortGuid for mad transport capability. +* +* SYNOPSIS +*/ +osm_bind_handle_t +osm_vendor_bind( + IN osm_vendor_t* const p_vend, + IN osm_bind_info_t* const p_bind_info, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_vend_mad_recv_callback_t mad_recv_callback, + IN osm_vend_mad_send_err_callback_t send_err_callback, + IN void* context ); +/* +* PARAMETERS +* p_vend +* [in] pointer to the vendor object +* +* p_osm_bind_info +* [in] pointer to a struct defining the type of bind to perform. +* +* p_mad_pool +* [in] pointer to a mad wrappers pool to be used for allocating +* mad wrappers on send and receive. +* +* mad_recv_callback +* [in] the callback function to be invoked on mad receive. +* +* send_err_callback +* [in] the callback function to be invoked on mad transaction errors. +* +* context +* [in] the context to be provided to the callbacks as bind_ctx. +* +* RETURN VALUE +* On success, a valid bind handle. +* OSM_BIND_INVALID_HANDLE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_unbind +* NAME +* osm_vendor_unbind +* +* DESCRIPTION +* Unbind the given bind handle (obtained by osm_vendor_bind). +* +* SYNOPSIS +*/ +void +osm_vendor_unbind( + IN osm_bind_handle_t h_bind ); +/* +* PARAMETERS +* h_bind +* [in] the bind handle to release. +* +* RETURN VALUE +* NONE. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_get +* NAME +* osm_vendor_get +* +* DESCRIPTION +* Obtain a mad wrapper holding actual mad buffer to be sent via +* the transport. +* +* SYNOPSIS +*/ +ib_mad_t* +osm_vendor_get( + IN osm_bind_handle_t h_bind, + IN const uint32_t mad_size, + IN osm_vend_wrap_t* const p_vend_wrap ); +/* +* PARAMETERS +* h_bind +* [in] the bind handle obtained by calling osm_vendor_bind +* +* mad_size +* [in] the actual mad size required +* +* p_vend_wrap +* [out] the returned mad vendor wrapper +* +* RETURN VALUE +* IB_SUCCESS on succesful completion. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_send +* NAME +* osm_vendor_send +* +* DESCRIPTION +* +* SYNOPSIS +*/ +ib_api_status_t +osm_vendor_send( + IN osm_bind_handle_t h_bind, + IN osm_madw_t* const p_madw, + IN boolean_t const resp_expected); +/* +* PARAMETERS +* h_bind +* [in] the bind handle obtained by calling osm_vendor_bind +* +* p_madw +* [in] pointer to the Mad Wrapper structure for the MAD to be sent. +* +* resp_expected +* [in] boolean value declaring the mad as a request (expecting a response). +* +* RETURN VALUE +* IB_SUCCESS on succesful completion. +* +* NOTES +* 1. Only mads that expect a response are tracked for transaction competion. +* 2. A mad that does not expect a response is being put back immediatly after +* being sent. +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_put +* NAME +* osm_vendor_put +* +* DESCRIPTION +* Return a mad vandor 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-1/ulp/opensm/user/include/vendor/osm_vendor_sa_api.h b/branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_sa_api.h new file mode 100644 index 00000000..734d83fb --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_sa_api.h @@ -0,0 +1,879 @@ +/* + * 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: + * Specification of the OpenSM SA Client API. This API uses the basic osm + * vendor API to provide SA Client interface. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_VENDOR_SA_API_H_ +#define _OSM_VENDOR_SA_API_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +/****d* OpenSM Vendor SA Client/osmv_flags_t +* NAME +* osmv_flags_t +* +* DESCRIPTION +* Access layer flags used to direct the operation of various calls. +* +* SYNOPSIS +*/ +typedef uint32_t osmv_flags_t; +#define OSM_SA_FLAGS_SYNC 0x00000001 +/* +* VALUES +* OSM_SA_FLAGS_SYNC +* Indicates that the given operation should be performed synchronously. +* The call will block until it completes. Callbacks will still be +* invoked. +* +* SEE ALSO +* osmv_query_sa +*****/ + +/****d* OpenSM Vendor SA Client/osmv_query_type_t +* NAME +* osmv_query_type_t +* +* DESCRIPTION +* Abstracted queries supported by the access layer. +* +* SYNOPSIS +*/ +typedef enum _osmv_query_type +{ + OSMV_QUERY_USER_DEFINED, + + OSMV_QUERY_ALL_SVC_RECS, + OSMV_QUERY_SVC_REC_BY_NAME, + OSMV_QUERY_SVC_REC_BY_ID, + + OSMV_QUERY_CLASS_PORT_INFO, + + OSMV_QUERY_NODE_REC_BY_NODE_GUID, + OSMV_QUERY_PORT_REC_BY_LID, + OSMV_QUERY_PORT_REC_BY_LID_AND_NUM, + + OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK, + OSMV_QUERY_SLVL_BY_LID_AND_PORTS, + + OSMV_QUERY_PATH_REC_BY_PORT_GUIDS, + OSMV_QUERY_PATH_REC_BY_GIDS, + OSMV_QUERY_PATH_REC_BY_LIDS, + + OSMV_QUERY_UD_MULTICAST_SET, + OSMV_QUERY_UD_MULTICAST_DELETE, + + OSMV_QUERY_MULTIPATH_REC, + +} osmv_query_type_t; +/* +* VALUES +* OSMV_QUERY_USER_DEFINED +* Query the SA based on user-defined input. Queries of this type +* should reference an osmv_user_query_t structure as input to the +* query. +* +* OSMV_QUERY_SVC_REC_BY_NAME +* Query for service records based on the service name. Queries of +* this type should reference an ib_svc_name_t structure as input +* to the query. +* +* OSMV_QUERY_SVC_REC_BY_ID +* Query for service records based on the service ID. Queries of +* this type should reference an ib_net64_t value that indicates +* the ID of the service being requested. +* +* OSMV_QUERY_NODE_REC_BY_NODE_GUID +* Query for node information based on the node's GUID. Queries of +* this type should reference an ib_net64_t value that indicates +* the GUID of the node being requested. +* +* OSMV_QUERY_PORT_REC_BY_LID +* Query for port information based on the port's base LID. Queries +* of this type should reference an ib_net16_t value that indicates +* the base LID of the port being requested. +* +* OSMV_QUERY_PORT_REC_BY_LID_AND_NUM +* Query for port information based on the port's LID and port num. +* Queries of this type should reference an osmv_user_query_t +* structure as input to the query. The port num and lid should +* be provided by it. +* +* OSMV_QUERY_PATH_REC_BY_PORT_GUIDS +* Query for path records between the specified pair of port GUIDs. +* Queries of this type should reference an osmv_guid_pair_t +* structure that indicates the GUIDs of the path being requested. +* +* OSMV_QUERY_PATH_REC_BY_GIDS +* Query for path records between the specified pair of port GIDs. +* Queries of this type should reference an osmv_gid_pair_t +* structure that indicates the GIDs of the path being requested. +* +* OSMV_QUERY_PATH_REC_BY_LIDS +* Query for path records between the specified pair of port LIDs. +* Queries of this type should reference an osmv_lid_pair_t +* structure that indicates the LIDs of the path being requested. +* +* NOTES +* This enum is used to define abstracted queries provided by the access +* layer. Users may issue queries not listed here by sending MADs directly +* to subnet administration or a class manager. These queries are +* intended to represent those most often used by clients. +* +* SEE ALSO +* osmv_query, osmv_query_req_t, osmv_user_query_t, osmv_gid_pair_t, +* osmv_lid_pair_t osmv_guid_pair_t +*****/ + +/****s* OpenSM Vendor SA Client/osmv_user_query_t +* NAME +* osmv_user_query_t +* +* DESCRIPTION +* User-defined query information. +* +* SYNOPSIS +*/ +typedef struct _osmv_user_query +{ + uint8_t method; + ib_net16_t attr_id; + ib_net16_t attr_offset; + ib_net32_t attr_mod; + ib_net64_t comp_mask; + void *p_attr; +} osmv_user_query_t; +/* +* FIELDS +* +* method +* Method to be used +* +* attr_id +* Attribute identifier of query data. +* +* attr_offset +* Size of the query attribute, in 8-byte words. Users can set +* this value by passing in the sizeof( attribute ) into the +* ib_get_attr_offset() routine. +* +* attr_mod +* Attribute modifier for query request. +* +* comp_mask +* Indicates the attribute components that are specified for the +* query. +* +* p_attr +* References the attribute structure used as input into the query. +* This field is ignored if comp_mask is set to 0. +* +* NOTES +* This structure is used to describe a user-defined query. The attribute +* ID, attribute offset, component mask, and attribute structure must match +* those defined by the IBA specification. Users should refer to chapter +* 15 of the IBA specification for additional details. +* +* SEE ALSO +* osmv_query_type_t, ib_get_attr_offset, ib_get_attr_size, osmv_query_sa +*****/ + +/****s* OpenSM Vendor SA Client/osmv_gid_pair_t +* NAME +* osmv_gid_pair_t +* +* DESCRIPTION +* Source and destination GIDs. +* +* SYNOPSIS +*/ +typedef struct _osmv_gid_pair +{ + ib_gid_t src_gid; + ib_gid_t dest_gid; +} osmv_gid_pair_t; +/* +* FIELDS +* src_gid +* Source GID of a path. +* +* dest_gid +* Destination GID of a path. +* +* NOTES +* This structure is used to describe the endpoints of a path. +* +* SEE ALSO +* ib_gid_t +*****/ + +/****s* OpenSM Vendor SA Client/osmv_lid_pair_t +* NAME +* osmv_lid_pair_t +* +* DESCRIPTION +* Source and destination LIDs. +* +* SYNOPSIS +*/ +typedef struct _osmv_lid_pair +{ + ib_net16_t src_lid; + ib_net16_t dest_lid; +} osmv_lid_pair_t; +/* +* FIELDS +* src_lid +* Source LID of a path. +* +* dest_lid +* Destination LID of a path. +* +* NOTES +* This structure is used to describe the endpoints of a path. +*****/ + +/****s* OpenSM Vendor SA Client/osmv_guid_pair_t +* NAME +* osmv_guid_pair_t +* +* DESCRIPTION +* Source and destination GUIDs. These may be port or channel adapter +* GUIDs, depending on the context in which this structure is used. +* +* SYNOPSIS +*/ +typedef struct _osmv_guid_pair +{ + ib_net64_t src_guid; + ib_net64_t dest_guid; +} osmv_guid_pair_t; +/* +* FIELDS +* src_guid +* Source GUID of a path. +* +* dest_guid +* Destination GUID of a path. +* +* NOTES +* This structure is used to describe the endpoints of a path. The given +* GUID pair may belong to either ports or channel adapters. +* +* SEE ALSO +* ib_guid_t +*****/ + +/****s* OpenSM Vendor SA Client/osmv_multipath_req_t +* NAME +* osmv_multipath_req_t +* +* DESCRIPTION +* Fields from which to generate a MultiPathRecord request. +* +* SYNOPSIS +*/ +typedef struct _osmv_multipath_req_t +{ + ib_net64_t comp_mask; + uint16_t pkey; + boolean_t reversible; + uint8_t num_path; + uint8_t sl; + uint8_t independence; + uint8_t sgid_count; + uint8_t dgid_count; + ib_gid_t gids[IB_MULTIPATH_MAX_GIDS]; +} osmv_multipath_req_t; +/* +* FIELDS +* +* NOTES +* This structure is used to describe a multipath request. +* +* SEE ALSO +*****/ + +/****s* OpenSM Vendor SA Client/osmv_query_res_t +* NAME +* osmv_query_res_t +* +* DESCRIPTION +* Contains the results of a subnet administration query. +* +* SYNOPSIS +*/ +typedef struct _osmv_query_res +{ + const void *query_context; + ib_api_status_t status; + osmv_query_type_t query_type; + uint32_t result_cnt; + osm_madw_t *p_result_madw; +} osmv_query_res_t; +/* +* FIELDS +* query_context +* User-defined context information associated with the query +* through the osm_vendor_query_sa call. +* +* status +* Indicates the success of the query operation. +* +* query_type +* Indicates the type of query for which the results are being +* returned. This matches the query_type specified through the +* osm_vendor_query_sa call. +* +* result_cnt +* The number of result structures that were returned by the query. +* +* p_result_madw +* For queries returning IB_SUCCESS or IB_REMOTE_ERROR, this +* references the MAD wrapper returned by subnet administration +* containing the list of results or the returned error code. +* +* NOTES +* A query result structure is returned to a client through their +* osmv_pfn_query_cb_t routine to notify them of the results of a subnet +* administration query. If the query was successful or received an error +* from subnet administration, p_result_madw will reference a MAD wrapper +* containing the results. The MAD referenced by p_result_madw is owned by +* the user and remains available even after their callback returns. Users +* must call osm_mad_pool_put() to return the MAD wrapper back to the +* mad pool when they are done accessing the results. +* +* To retrieve individual result structures from the p_result_madw, users +* may call osmv_get_query_result(). +* +* SEE ALSO +* osmv_query_sa, osmv_pfn_query_cb_t, ib_api_status_t, +* osmv_query_status_t, osmv_query_type_t, +* osmv_get_query_result +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_result +* NAME +* osmv_get_query_result +* +* DESCRIPTION +* Retrieves a result structure from a MADW returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline void* +osmv_get_query_result( + IN osm_madw_t *p_result_madw, + IN uint32_t result_index ) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT( p_result_madw ); + p_sa_mad = (ib_sa_mad_t*)osm_madw_get_mad_ptr( p_result_madw ); + CL_ASSERT( p_sa_mad ); + CL_ASSERT( ib_get_attr_size( p_sa_mad->attr_offset ) * (result_index + 1) + + IB_SA_MAD_HDR_SIZE <= p_result_madw->mad_size ); + + return( p_sa_mad->data + + (ib_get_attr_size( p_sa_mad->attr_offset ) * result_index) ); +} +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a result structure from a +* call to osmv_query_sa(). The type of result structure must be known to +* the user either through the user's context or the query_type returned as +* part of the osmv_query_res_t structure. +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_path_rec +* NAME +* osmv_get_query_path_rec +* +* DESCRIPTION +* Retrieves a path record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_path_rec_t* +osmv_get_query_path_rec( + IN osm_madw_t *p_result_madw, + IN uint32_t result_index ) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT( p_result_madw ); + p_sa_mad = (ib_sa_mad_t*)osm_madw_get_mad_ptr( p_result_madw ); + CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD ); + + return( (ib_path_rec_t*)osmv_get_query_result( p_result_madw, result_index ) ); +} +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a path record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_path_rec_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_portinfo_rec +* NAME +* osmv_get_query_portinfo_rec +* +* DESCRIPTION +* Retrieves a port info record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_portinfo_record_t* +osmv_get_query_portinfo_rec( + IN osm_madw_t *p_result_madw, + IN uint32_t result_index ) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT( p_result_madw ); + p_sa_mad = (ib_sa_mad_t*)osm_madw_get_mad_ptr( p_result_madw ); + CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_PORTINFO_RECORD ); + + return( (ib_portinfo_record_t*)osmv_get_query_result( p_result_madw, + result_index ) ); +} +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a port info record result +* from a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_portinfo_record_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_node_rec +* NAME +* osmv_get_query_node_rec +* +* DESCRIPTION +* Retrieves a node record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_node_record_t* +osmv_get_query_node_rec( + IN osm_madw_t *p_result_madw, + IN uint32_t result_index ) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT( p_result_madw ); + p_sa_mad = (ib_sa_mad_t*)osm_madw_get_mad_ptr( p_result_madw ); + CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_NODE_RECORD ); + + return( (ib_node_record_t*)osmv_get_query_result( p_result_madw, + result_index ) ); +} +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a node record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_node_record_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_svc_rec +* NAME +* osmv_get_query_svc_rec +* +* DESCRIPTION +* Retrieves a service record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_service_record_t* +osmv_get_query_svc_rec( + IN osm_madw_t *p_result_madw, + IN uint32_t result_index ) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT( p_result_madw ); + p_sa_mad = (ib_sa_mad_t*)osm_madw_get_mad_ptr( p_result_madw ); + CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_SERVICE_RECORD ); + + return( (ib_service_record_t*)osmv_get_query_result( p_result_madw, + result_index ) ); +} +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a service record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_service_record_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_mc_rec +* NAME +* osmv_get_query_mc_rec +* +* DESCRIPTION +* Retrieves a multicast record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_member_rec_t* +osmv_get_query_mc_rec( + IN osm_madw_t *p_result_madw, + IN uint32_t result_index ) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT( p_result_madw ); + p_sa_mad = (ib_sa_mad_t*)osm_madw_get_mad_ptr( p_result_madw ); + CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_MCMEMBER_RECORD ); + + return( (ib_member_rec_t*)osmv_get_query_result( p_result_madw, + result_index ) ); +} +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a service record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_member_rec_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_inform_info_rec +* NAME +* osmv_get_query_inform_info_rec +* +* DESCRIPTION +* Retrieves an InformInfo record result from a MAD returned by +* a call to osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_inform_info_record_t* +osmv_get_query_inform_info_rec( + IN osm_madw_t *p_result_madw, + IN uint32_t result_index ) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT( p_result_madw ); + p_sa_mad = (ib_sa_mad_t*)osm_madw_get_mad_ptr( p_result_madw ); + CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_INFORM_INFO_RECORD ); + + return( (ib_inform_info_record_t*)osmv_get_query_result( p_result_madw, + result_index ) ); +} +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a service record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_inform_info_record_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_pfn_query_cb_t +* NAME +* osmv_pfn_query_cb_t +* +* DESCRIPTION +* User-defined callback invoked on completion of subnet administration +* query. +* +* SYNOPSIS +*/ +typedef void +(*osmv_pfn_query_cb_t)( + IN osmv_query_res_t *p_query_res ); +/* +* PARAMETERS +* p_query_res +* [in] This is a reference to a structure containing the result of +* the query. +* +* NOTES +* This routine is invoked to notify a client of the result of a subnet +* administration query. The p_query_rec parameter references the result +* of the query and, in the case of a successful query, any information +* returned by subnet administration. +* +* In the kernel, this callback is usually invoked using a tasklet, +* dependent on the implementation of the underlying verbs provider driver. +* +* SEE ALSO +* osmv_query_res_t +*****/ + +/****s* OpenSM Vendor SA Client/osmv_query_req_t +* NAME +* osmv_query_req_t +* +* DESCRIPTION +* Information used to request an access layer provided query of subnet +* administration. +* +* SYNOPSIS +*/ +typedef struct _osmv_query_req +{ + osmv_query_type_t query_type; + const void *p_query_input; + ib_net64_t sm_key; + + uint32_t timeout_ms; + uint32_t retry_cnt; + osmv_flags_t flags; + + const void *query_context; + osmv_pfn_query_cb_t pfn_query_cb; +} osmv_query_req_t; +/* +* FIELDS +* query_type +* Indicates the type of query that the access layer should +* perform. +* +* p_query_input +* A pointer to the input for the query. The data referenced by +* this structure is dependent on the type of query being requested +* and is determined by the specified query_type. +* +* sm_key +* The M_Key to be provided with the SA MAD for authentication. +* Normally 0 is used. +* +* timeout_ms +* Specifies the number of milliseconds to wait for a response for +* this query until retrying or timing out the request. +* +* retry_cnt +* Specifies the number of times that the query will be retried +* before failing the request. +* +* flags +* Used to describe the mode of operation. Set to IB_FLAGS_SYNC to +* process the called routine synchronously. +* +* query_context +* User-defined context information associated with this query. +* The context data is returned to the user as a part of their +* query callback. +* +* pfn_query_cb +* A user-defined callback that is invoked upon completion of the +* query. +* +* NOTES +* This structure is used when requesting an osm vendor provided query +* of subnet administration. Clients specify the type of query through +* the query_type field. Based on the type of query, the p_query_input +* field is set to reference the appropriate data structure. +* +* The information referenced by the p_query_input field is one of the +* following: +* +* -- a NULL terminated service name +* -- a service id +* -- a single GUID +* -- a pair of GUIDs specified through an osmv_guid_pair_t structure +* -- a pair of GIDs specified through an osmv_gid_pair_t structure +* +* SEE ALSO +* osmv_query_type_t, osmv_pfn_query_cb_t, osmv_guid_pair_t, +* osmv_gid_pair_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_bind_sa +* NAME +* osmv_bind_sa +* +* DESCRIPTION +* Bind to the SA service and return a handle to be used for later +* queries. +* +* +* SYNOPSIS +*/ +osm_bind_handle_t +osmv_bind_sa( + IN osm_vendor_t * const p_vend, + IN osm_mad_pool_t * const p_mad_pool, + IN ib_net64_t port_guid + ); +/* +* PARAMETERS +* p_vend +* [in] an osm_vendor object to work with +* +* p_mad_pool +* [in] mad pool to obtain madw from +* +* port_guid +* [in] the port guid to attach to. +* +* RETURN VALUE +* Bind handle to be used for later SA queries or OSM_BIND_INVALID_HANDLE +* +* NOTES +* +* SEE ALSO +* osmv_query_sa +*********/ + +/****f* OpenSM Vendor SA Client/osmv_query_sa +* NAME +* osmv_query_sa +* +* DESCRIPTION +* Query the SA given an SA query request (similar to IBAL ib_query). +* +* SYNOPSIS +*/ +ib_api_status_t +osmv_query_sa( + IN osm_bind_handle_t h_bind, + IN const osmv_query_req_t * const p_query_req + ); +/* +* PARAMETERS +* h_bind +* [in] bind handle for this port. Should be previously +* obtained by calling osmv_bind_sa +* +* p_query_req +* [in] an SA query request structure. +* +* RETURN VALUE +* IB_SUCCESS if completed successfuly (or in ASYNC mode +* if the request was sent). +* +* NOTES +* +* SEE ALSO +* osmv_bind_sa +*********/ + +END_C_DECLS + +#endif /* _OSM_VENDOR_SA_API_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_select.h b/branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_select.h new file mode 100644 index 00000000..b766b67b --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/vendor/osm_vendor_select.h @@ -0,0 +1,76 @@ +/* + * 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: + * Include file that defines which vendor files to compile. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +#ifndef _OSM_VENDOR_SELECT_H_ +#define _OSM_VENDOR_SELECT_H_ + +///////////////////////////////////////////////////// +// +// MAD INTERFACE SELECTION +// +///////////////////////////////////////////////////// + +/* + TEST and UMADT must be specified in the 'make' command line, + with VENDOR=test or VENDOR=umadt. +*/ +#ifndef OSM_VENDOR_INTF_OPENIB +#ifndef OSM_VENDOR_INTF_TEST +#ifndef OSM_VENDOR_INTF_UMADT +#ifndef OSM_VENDOR_INTF_MTL +#ifndef OSM_VENDOR_INTF_TS +#ifndef OSM_VENDOR_INTF_SIM +#ifndef OSM_VENDOR_INTF_AL +#define OSM_VENDOR_INTF_AL +#endif /* AL */ +#endif /* TS */ +#endif /* SIM */ +#endif /* MTL */ +#endif /* UMADT */ +#endif /* TEST */ +#endif /* OPENIB */ + +#endif /* _OSM_VENDOR_SELECT_H_ */ + diff --git a/branches/WOF2-1/ulp/opensm/user/include/vendor/winosm_common.h b/branches/WOF2-1/ulp/opensm/user/include/vendor/winosm_common.h new file mode 100644 index 00000000..cb2a2864 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/include/vendor/winosm_common.h @@ -0,0 +1,251 @@ +#ifndef _OSM_COMMON_H_ +#define _OSM_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include + +#pragma warning(disable : 4996) +#pragma warning(disable : 4100) + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + + + +#ifndef _GETOPT_H_ + +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 + +/* Global variables for getopt_long */ +char *optarg; + +struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}; +#endif + + +/************************************************************************/ +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); +/**************************************************************************/ +static __inline +void FileTimeToTimeval(LPFILETIME pft, struct timeval * ptv) +{ /* Note that LONGLONG is a 64-bit value */ +LONGLONG ll; + +if(!pft || !ptv) +goto Exit; + +ll = ((LONGLONG) pft->dwHighDateTime << 32); +ll += (LONGLONG) pft->dwLowDateTime; +#ifdef __GNUC__ +ll -= 116444736000000000ll; +#else +ll -= 116444736000000000; +#endif + +ptv->tv_sec = (long) (ll / 10000000); +ptv->tv_usec = (long) (ll - ((LONGLONG)(ptv->tv_sec) * 10000000)) / 10; + +Exit:; +}/* FileTimeToTimeval */ + +/********************************************************************************/ +static __inline +int gettimeofday(struct timeval *ptv, struct timezone *tzp) +{ +static int QueryCounter = 2; +FILETIME CurrentTime; +/* TODO : We need to add it , since in DDK - compiler does not like vars that are not in use */ +UNREFERENCED_PARAMETER(tzp); +if(!ptv) +goto Exit; + +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; +/* HANDLE hThread = GetCurrentThread(); +int ThreadPrio = GetThreadPriority(hThread); + +SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); */ +GetSystemTimeAsFileTime(&CurrentTime); +QueryPerformanceCounter(&Counter); +/* SetThreadPriority(hThread, ThreadPrio); */ + +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 the highest bits to prevent overflows */ +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 the highest bits to prevent overflows */ +Counter.QuadPart *= 10000000; /* Because we need time stamp in units of 100 ns */ +Counter.QuadPart /= Frequency.QuadPart; /* counter of 0.1 microseconds */ + +if(LastCounter.QuadPart > Counter.QuadPart) +{ /* Counter value wrapped */ +#ifdef __GNUC__ +Offset.QuadPart += (0x7f00000000ll * 10000000ll) / Frequency.QuadPart; +#else +Offset.QuadPart += (0x7f00000000 * 10000000) / Frequency.QuadPart; +#endif +} +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; +} + +/* Now let's use the adjusted performance counter time for the time stamp */ +CurrentTime.dwLowDateTime = Counter.LowPart; +CurrentTime.dwHighDateTime = Counter.HighPart; +} +else +{ +GetSystemTimeAsFileTime(&CurrentTime); +} + +FileTimeToTimeval(&CurrentTime,ptv); + +Exit:; +return(0); +}/* int gettimeofday(struct timeval *ptv, void *tzp) */ +/*****************************************************************************/ + + +#ifndef getpid +#define getpid() GetCurrentProcessId() +#endif + +#define sleep(sec) SleepEx((sec)*1000,TRUE) +#define usleep(usec) SleepEx(usec/1000,TRUE) +//#define MT_ALIGN8 __declspec(align(8)) +/* Verify the correct ETIMEDOUT value is defined in all compiled files */ +#ifndef ETIMEDOUT +#define ETIMEDOUT (10060) +#endif + +#ifndef strtoull +#define strtoull _strtoui64 +#endif + +#define OSM_MAX_LOG_NAME_SIZE 2048 +#define unlink(str) _unlink(str) +#define strnicmp _strnicmp + +/* The following defines replace syslog.h */ +#define openlog(a,b,c) + +#define closelog() + +static __inline void +syslog(int priority, ...) {} + +#define LOG_INFO 0 +#define LOG_WARNING 1 +#define LOG_ERR 2 +/*****************************************/ + +/****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 +* This function returns string containing the default cache path for osm use. +* +* NOTES +*/ + +/* Implementation of strtok_r for windows: since strtok in windows is safe, + just ignore the last variable, and call strtok. */ +static inline +char *strtok_r(char *s1, const char *s2, char **lasts) +{ + return strtok(s1, s2); +} +#endif /* _OSM_COMMON_H_ */ diff --git a/branches/WOF2-1/ulp/opensm/user/libopensm/Makefile b/branches/WOF2-1/ulp/opensm/user/libopensm/Makefile new file mode 100755 index 00000000..58189757 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/libopensm/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-1/ulp/opensm/user/libopensm/SOURCES b/branches/WOF2-1/ulp/opensm/user/libopensm/SOURCES new file mode 100644 index 00000000..ed287d52 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/libopensm/SOURCES @@ -0,0 +1,62 @@ +!if $(FREEBUILD) +TARGETNAME=opensm_ibal +!else +TARGETNAME=opensm_ibald +!endif +TARGETTYPE=LIBRARY + +!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 + +USE_NTDLL=1 +OVR_DIR=..\addon + + +SOURCES=\ + osm_log.c \ + osm_mad_pool.c \ + osm_helper.c + +OSM_HOME=.. + +TARGETLIBS=\ +!if $(FREEBUILD) + $(LIBPATH)\*\ibal.lib \ + $(LIBPATH)\*\complib.lib \ + $(TARGETPATH)\*\osmv_ibal.lib + +!else + $(LIBPATH)\*\ibald.lib \ + $(LIBPATH)\*\complibd.lib \ + $(TARGETPATH)\*\osmv_ibald.lib +!endif + +#DO NOT TOUCH the order of search path , until ib_types.h merging process will be done +INCLUDES= \ + $(OSM_HOME)\include; \ + $(OSM_HOME); \ + $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; + +# Could be any special flag needed for this project +USER_C_FLAGS=$(USER_C_FLAGS) /MD +#Add preproccessor definitions +C_DEFINES=$(C_DEFINES) -DWIN32 -D__WIN__ -D__i386__ -Dinline=__inline -DMT_LITTLE_ENDIAN -DOSM_VENDOR_INTF_AL +C_DEFINES=$(C_DEFINES) -I.. -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 +#MSC_OPTIMIZATION= /O0 diff --git a/branches/WOF2-1/ulp/opensm/user/libopensm/osm_helper.c b/branches/WOF2-1/ulp/opensm/user/libopensm/osm_helper.c new file mode 100644 index 00000000..d16b8fda --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/libopensm/osm_helper.c @@ -0,0 +1,2534 @@ +/* + * 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: + * Implementation of opensm helper functions. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.19 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#define LINE_LENGTH 256 + +/* we use two tables - one for queries and one for responses */ +const char* const __ib_sa_method_str[] = +{ + "RESERVED", /* 0 */ + "SubnAdmGet", /* 1 */ + "SubnAdmSet", /* 2 */ + "RESERVED", /* 3 */ + "RESERVED", /* 4 */ + "RESERVED", /* 5 */ + "SubnAdmReport", /* 6 */ + "RESERVED", /* 7 */ + "RESERVED", /* 8 */ + "RESERVED", /* 9 */ + "RESERVED", /* A */ + "RESERVED", /* B */ + "RESERVED", /* C */ + "RESERVED", /* D */ + "RESERVED", /* E */ + "RESERVED", /* F */ + "RESERVED", /* 10 */ + "RESERVED", /* 11 */ + "SubnAdmGetTable", /* 12 */ + "SubnAdmGetTraceTable", /* 13 */ + "SubnAdmGetMulti", /* 14 */ + "SubnAdmDelete", /* 15 */ + "UNKNOWN" /* 16 */ +}; + +const char* const __ib_sa_resp_method_str[] = +{ + "RESERVED", /* 80 */ + "SubnAdmGetResp", /* 81 */ + "RESERVED (SetResp?)", /* 82 */ + "RESERVED", /* 83 */ + "RESERVED", /* 84 */ + "RESERVED", /* 85 */ + "SubnAdmReportResp", /* 86 */ + "RESERVED", /* 87 */ + "RESERVED", /* 88 */ + "RESERVED", /* 89 */ + "RESERVED", /* 8A */ + "RESERVED", /* 8B */ + "RESERVED", /* 8C */ + "RESERVED", /* 8D */ + "RESERVED", /* 8E */ + "RESERVED", /* 8F */ + "RESERVED", /* 90 */ + "RESERVED", /* 91 */ + "SubnAdmGetTableResp", /* 92 */ + "RESERVED", /* 93 */ + "SubnAdmGetMultiResp", /* 94 */ + "SubnAdmDeleteResp", /* 95 */ + "UNKNOWN" +}; + +#define OSM_SA_METHOD_STR_UNKNOWN_VAL 0x16 + +const char* const __ib_sm_method_str[] = +{ + "RESERVED0", /* 0 */ + "SubnGet", /* 1 */ + "SubnSet", /* 2 */ + "RESERVED3", /* 3 */ + "RESERVED4", /* 4 */ + "SubnTrap", /* 5 */ + "RESERVED6", /* 6 */ + "SubnTrapRepress", /* 7 */ + "RESERVED8", /* 8 */ + "RESERVED9", /* 9 */ + "RESERVEDA", /* A */ + "RESERVEDB", /* B */ + "RESERVEDC", /* C */ + "RESERVEDD", /* D */ + "RESERVEDE", /* E */ + "RESERVEDF", /* F */ + "RESERVED10", /* 10 */ + "SubnGetResp", /* 11 */ + "RESERVED12", /* 12 */ + "RESERVED13", /* 13 */ + "RESERVED14", /* 14 */ + "RESERVED15", /* 15 */ + "RESERVED16", /* 16 */ + "RESERVED17", /* 17 */ + "RESERVED18", /* 18 */ + "RESERVED19", /* 19 */ + "RESERVED1A", /* 1A */ + "RESERVED1B", /* 1B */ + "RESERVED1C", /* 1C */ + "RESERVED1D", /* 1D */ + "RESERVED1E", /* 1E */ + "RESERVED1F", /* 1F */ + "UNKNOWN" /* 20 */ +}; + +#define OSM_SM_METHOD_STR_UNKNOWN_VAL 0x21 + +const char* const __ib_sm_attr_str[] = +{ + "RESERVED", /* 0 */ + "ClassPortInfo", /* 1 */ + "Notice", /* 2 */ + "InformInfo", /* 3 */ + "RESERVED", /* 4 */ + "RESERVED", /* 5 */ + "RESERVED", /* 6 */ + "RESERVED", /* 7 */ + "RESERVED", /* 8 */ + "RESERVED", /* 9 */ + "RESERVED", /* A */ + "RESERVED", /* B */ + "RESERVED", /* C */ + "RESERVED", /* D */ + "RESERVED", /* E */ + "RESERVED", /* F */ + "NodeDescription", /* 10 */ + "NodeInfo", /* 11 */ + "SwitchInfo", /* 12 */ + "UNKNOWN", /* 13 */ + "GUIDInfo", /* 14 */ + "PortInfo", /* 15 */ + "P_KeyTable", /* 16 */ + "SLtoVLMappingTable", /* 17 */ + "VLArbitrationTable", /* 18 */ + "LinearForwardingTable", /* 19 */ + "RandomForwardingTable", /* 1A */ + "MulticastForwardingTable", /* 1B */ + "UNKNOWN", /* 1C */ + "UNKNOWN", /* 1D */ + "UNKNOWN", /* 1E */ + "UNKNOWN", /* 1F */ + "SMInfo", /* 20 */ + "UNKNOWN" /* 21 - always highest value */ +}; + +#define OSM_SM_ATTR_STR_UNKNOWN_VAL 0x21 + +const char* const __ib_sa_attr_str[] = +{ + "RESERVED", /* 0 */ + "ClassPortInfo", /* 1 */ + "Notice", /* 2 */ + "InformInfo", /* 3 */ + "RESERVED", /* 4 */ + "RESERVED", /* 5 */ + "RESERVED", /* 6 */ + "RESERVED", /* 7 */ + "RESERVED", /* 8 */ + "RESERVED", /* 9 */ + "RESERVED", /* A */ + "RESERVED", /* B */ + "RESERVED", /* C */ + "RESERVED", /* D */ + "RESERVED", /* E */ + "RESERVED", /* F */ + "RESERVED", /* 10 */ + "NodeRecord", /* 11 */ + "PortInfoRecord", /* 12 */ + "SLtoVLMappingTableRecord", /* 13 */ + "SwitchInfoRecord", /* 14 */ + "LinearForwardingTableRecord", /* 15 */ + "RandomForwardingTableRecord", /* 16 */ + "MulticastForwardingTableRecord", /* 17 */ + "SMInfoRecord", /* 18 */ + "RESERVED", /* 19 */ + "RandomForwardingTable", /* 1A */ + "MulticastForwardingTable", /* 1B */ + "UNKNOWN", /* 1C */ + "UNKNOWN", /* 1D */ + "UNKNOWN", /* 1E */ + "UNKNOWN", /* 1F */ + "LinkRecord", /* 20 */ + "UNKNOWN", /* 21 */ + "UNKNOWN", /* 22 */ + "UNKNOWN", /* 23 */ + "UNKNOWN", /* 24 */ + "UNKNOWN", /* 25 */ + "UNKNOWN", /* 26 */ + "UNKNOWN", /* 27 */ + "UNKNOWN", /* 28 */ + "UNKNOWN", /* 29 */ + "UNKNOWN", /* 2A */ + "UNKNOWN", /* 2B */ + "UNKNOWN", /* 2C */ + "UNKNOWN", /* 2D */ + "UNKNOWN", /* 2E */ + "UNKNOWN", /* 2F */ + "GuidInfoRecord", /* 30 */ + "ServiceRecord", /* 31 */ + "UNKNOWN", /* 32 */ + "P_KeyTableRecord", /* 33 */ + "UNKNOWN", /* 34 */ + "PathRecord", /* 35 */ + "VLArbitrationTableRecord", /* 36 */ + "UNKNOWN", /* 37 */ + "MCMemberRecord", /* 38 */ + "TraceRecord", /* 39 */ + "MultiPathRecord", /* 3A */ + "ServiceAssociationRecord", /* 3B */ + "UNKNOWN", /* 3C */ + "UNKNOWN", /* 3D */ + "UNKNOWN", /* 3E */ + "UNKNOWN", /* 3F */ + "UNKNOWN", /* 40 */ + "UNKNOWN", /* 41 */ + "UNKNOWN", /* 42 */ + "UNKNOWN", /* 43 */ + "UNKNOWN", /* 44 */ + "UNKNOWN", /* 45 */ + "UNKNOWN", /* 46 */ + "UNKNOWN", /* 47 */ + "UNKNOWN", /* 48 */ + "UNKNOWN", /* 49 */ + "UNKNOWN", /* 4A */ + "UNKNOWN", /* 4B */ + "UNKNOWN", /* 4C */ + "UNKNOWN", /* 4D */ + "UNKNOWN", /* 4E */ + "UNKNOWN", /* 4F */ + "UNKNOWN", /* 50 */ + "UNKNOWN", /* 51 */ + "UNKNOWN", /* 52 */ + "UNKNOWN", /* 53 */ + "UNKNOWN", /* 54 */ + "UNKNOWN", /* 55 */ + "UNKNOWN", /* 56 */ + "UNKNOWN", /* 57 */ + "UNKNOWN", /* 58 */ + "UNKNOWN", /* 59 */ + "UNKNOWN", /* 5A */ + "UNKNOWN", /* 5B */ + "UNKNOWN", /* 5C */ + "UNKNOWN", /* 5D */ + "UNKNOWN", /* 5E */ + "UNKNOWN", /* 5F */ + "UNKNOWN", /* 60 */ + "UNKNOWN", /* 61 */ + "UNKNOWN", /* 62 */ + "UNKNOWN", /* 63 */ + "UNKNOWN", /* 64 */ + "UNKNOWN", /* 65 */ + "UNKNOWN", /* 66 */ + "UNKNOWN", /* 67 */ + "UNKNOWN", /* 68 */ + "UNKNOWN", /* 69 */ + "UNKNOWN", /* 6A */ + "UNKNOWN", /* 6B */ + "UNKNOWN", /* 6C */ + "UNKNOWN", /* 6D */ + "UNKNOWN", /* 6E */ + "UNKNOWN", /* 6F */ + "UNKNOWN", /* 70 */ + "UNKNOWN", /* 71 */ + "UNKNOWN", /* 72 */ + "UNKNOWN", /* 73 */ + "UNKNOWN", /* 74 */ + "UNKNOWN", /* 75 */ + "UNKNOWN", /* 76 */ + "UNKNOWN", /* 77 */ + "UNKNOWN", /* 78 */ + "UNKNOWN", /* 79 */ + "UNKNOWN", /* 7A */ + "UNKNOWN", /* 7B */ + "UNKNOWN", /* 7C */ + "UNKNOWN", /* 7D */ + "UNKNOWN", /* 7E */ + "UNKNOWN", /* 7F */ + "UNKNOWN", /* 80 */ + "UNKNOWN", /* 81 */ + "UNKNOWN", /* 82 */ + "UNKNOWN", /* 83 */ + "UNKNOWN", /* 84 */ + "UNKNOWN", /* 85 */ + "UNKNOWN", /* 86 */ + "UNKNOWN", /* 87 */ + "UNKNOWN", /* 88 */ + "UNKNOWN", /* 89 */ + "UNKNOWN", /* 8A */ + "UNKNOWN", /* 8B */ + "UNKNOWN", /* 8C */ + "UNKNOWN", /* 8D */ + "UNKNOWN", /* 8E */ + "UNKNOWN", /* 8F */ + "UNKNOWN", /* 90 */ + "UNKNOWN", /* 91 */ + "UNKNOWN", /* 92 */ + "UNKNOWN", /* 93 */ + "UNKNOWN", /* 94 */ + "UNKNOWN", /* 95 */ + "UNKNOWN", /* 96 */ + "UNKNOWN", /* 97 */ + "UNKNOWN", /* 98 */ + "UNKNOWN", /* 99 */ + "UNKNOWN", /* 9A */ + "UNKNOWN", /* 9B */ + "UNKNOWN", /* 9C */ + "UNKNOWN", /* 9D */ + "UNKNOWN", /* 9E */ + "UNKNOWN", /* 9F */ + "UNKNOWN", /* A0 */ + "UNKNOWN", /* A1 */ + "UNKNOWN", /* A2 */ + "UNKNOWN", /* A3 */ + "UNKNOWN", /* A4 */ + "UNKNOWN", /* A5 */ + "UNKNOWN", /* A6 */ + "UNKNOWN", /* A7 */ + "UNKNOWN", /* A8 */ + "UNKNOWN", /* A9 */ + "UNKNOWN", /* AA */ + "UNKNOWN", /* AB */ + "UNKNOWN", /* AC */ + "UNKNOWN", /* AD */ + "UNKNOWN", /* AE */ + "UNKNOWN", /* AF */ + "UNKNOWN", /* B0 */ + "UNKNOWN", /* B1 */ + "UNKNOWN", /* B2 */ + "UNKNOWN", /* B3 */ + "UNKNOWN", /* B4 */ + "UNKNOWN", /* B5 */ + "UNKNOWN", /* B6 */ + "UNKNOWN", /* B7 */ + "UNKNOWN", /* B8 */ + "UNKNOWN", /* B9 */ + "UNKNOWN", /* BA */ + "UNKNOWN", /* BB */ + "UNKNOWN", /* BC */ + "UNKNOWN", /* BD */ + "UNKNOWN", /* BE */ + "UNKNOWN", /* BF */ + "UNKNOWN", /* C0 */ + "UNKNOWN", /* C1 */ + "UNKNOWN", /* C2 */ + "UNKNOWN", /* C3 */ + "UNKNOWN", /* C4 */ + "UNKNOWN", /* C5 */ + "UNKNOWN", /* C6 */ + "UNKNOWN", /* C7 */ + "UNKNOWN", /* C8 */ + "UNKNOWN", /* C9 */ + "UNKNOWN", /* CA */ + "UNKNOWN", /* CB */ + "UNKNOWN", /* CC */ + "UNKNOWN", /* CD */ + "UNKNOWN", /* CE */ + "UNKNOWN", /* CF */ + "UNKNOWN", /* D0 */ + "UNKNOWN", /* D1 */ + "UNKNOWN", /* D2 */ + "UNKNOWN", /* D3 */ + "UNKNOWN", /* D4 */ + "UNKNOWN", /* D5 */ + "UNKNOWN", /* D6 */ + "UNKNOWN", /* D7 */ + "UNKNOWN", /* D8 */ + "UNKNOWN", /* D9 */ + "UNKNOWN", /* DA */ + "UNKNOWN", /* DB */ + "UNKNOWN", /* DC */ + "UNKNOWN", /* DD */ + "UNKNOWN", /* DE */ + "UNKNOWN", /* DF */ + "UNKNOWN", /* E0 */ + "UNKNOWN", /* E1 */ + "UNKNOWN", /* E2 */ + "UNKNOWN", /* E3 */ + "UNKNOWN", /* E4 */ + "UNKNOWN", /* E5 */ + "UNKNOWN", /* E6 */ + "UNKNOWN", /* E7 */ + "UNKNOWN", /* E8 */ + "UNKNOWN", /* E9 */ + "UNKNOWN", /* EA */ + "UNKNOWN", /* EB */ + "UNKNOWN", /* EC */ + "UNKNOWN", /* ED */ + "UNKNOWN", /* EE */ + "UNKNOWN", /* EF */ + "UNKNOWN", /* F0 */ + "UNKNOWN", /* F1 */ + "UNKNOWN", /* F2 */ + "InformInfoRecord", /* F3 */ + "UNKNOWN" /* F4 - always highest value */ +}; + +#define OSM_SA_ATTR_STR_UNKNOWN_VAL 0xF4 + + +/********************************************************************** + **********************************************************************/ +const char* +ib_get_sa_method_str( + IN uint8_t method ) +{ + if (method & 0x80) + { + method = method & 0x7f; + if( method >= OSM_SA_METHOD_STR_UNKNOWN_VAL ) + method = OSM_SA_METHOD_STR_UNKNOWN_VAL; + /* it is a response - use the response table */ + return( __ib_sa_resp_method_str[method] ); + } + else + { + if( method >= OSM_SA_METHOD_STR_UNKNOWN_VAL ) + method = OSM_SA_METHOD_STR_UNKNOWN_VAL; + return( __ib_sa_method_str[method] ); + } +} + +/********************************************************************** + **********************************************************************/ +const char* +ib_get_sm_method_str( + IN uint8_t method ) +{ + if (method & 0x80) method = (method & 0x0F) | 0x10; + if( method >= OSM_SM_METHOD_STR_UNKNOWN_VAL ) + method = OSM_SM_METHOD_STR_UNKNOWN_VAL; + return( __ib_sm_method_str[method] ); +} + +/********************************************************************** + **********************************************************************/ +const char* +ib_get_sm_attr_str( + IN ib_net16_t attr ) +{ + uint16_t host_attr; + host_attr = cl_ntoh16( attr ); + + if( host_attr >= OSM_SM_ATTR_STR_UNKNOWN_VAL ) + host_attr = OSM_SM_ATTR_STR_UNKNOWN_VAL; + + return( __ib_sm_attr_str[host_attr] ); +} + +/********************************************************************** + **********************************************************************/ +const char* +ib_get_sa_attr_str( + IN ib_net16_t attr ) +{ + uint16_t host_attr; + host_attr = cl_ntoh16( attr ); + + if( host_attr >= OSM_SA_ATTR_STR_UNKNOWN_VAL ) + host_attr = OSM_SA_ATTR_STR_UNKNOWN_VAL; + + return( __ib_sa_attr_str[host_attr] ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_dbg_do_line( + IN char** pp_local, + IN const uint32_t buf_size, + IN const char* const p_prefix_str, + IN const char* const p_new_str, + IN uint32_t* const p_total_len ) +{ + char line[LINE_LENGTH]; + uint32_t len; + + sprintf( line, "%s%s", p_prefix_str, p_new_str ); + len = (uint32_t) strlen( line ); + *p_total_len += len; + if( *p_total_len + sizeof('\0') > buf_size ) + return( IB_INSUFFICIENT_MEMORY ); + + strcpy( *pp_local, line ); + *pp_local += len; + return( IB_SUCCESS ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_dbg_get_capabilities_str( + IN char* p_buf, + IN const uint32_t buf_size, + IN const char* const p_prefix_str, + IN const ib_port_info_t* const p_pi ) +{ + uint32_t total_len = 0; + char *p_local = p_buf; + + strcpy( p_local, "Capability Mask:\n" ); + p_local += strlen( p_local ); + + if( p_pi->capability_mask & IB_PORT_CAP_RESV0 ) + { + if( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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( osm_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_RESV26 ) + { + if( osm_dbg_do_line( &p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV26\n", &total_len ) != IB_SUCCESS ) + return; + } + if( p_pi->capability_mask & IB_PORT_CAP_RESV27 ) + { + if( osm_dbg_do_line( &p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV27\n", &total_len ) != IB_SUCCESS ) + return; + } + if( p_pi->capability_mask & IB_PORT_CAP_RESV28) + { + if( osm_dbg_do_line( &p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV28\n", &total_len ) != IB_SUCCESS ) + return; + } + if( p_pi->capability_mask & IB_PORT_CAP_RESV29 ) + { + if( osm_dbg_do_line( &p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV29\n", &total_len ) != IB_SUCCESS ) + return; + } + if( p_pi->capability_mask & IB_PORT_CAP_RESV30 ) + { + if( osm_dbg_do_line( &p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV30\n", &total_len ) != IB_SUCCESS ) + return; + } + if( p_pi->capability_mask & IB_PORT_CAP_RESV31 ) + { + if( osm_dbg_do_line( &p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV31\n", &total_len ) != IB_SUCCESS ) + return; + } + + return; +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_port_info( + IN osm_log_t* const p_log, + IN const ib_net64_t node_guid, + IN const ib_net64_t port_guid, + IN const uint8_t port_num, + IN const ib_port_info_t* const p_pi, + IN const osm_log_level_t log_level ) +{ + char buf[BUF_SIZE]; + + if( osm_log_is_active( p_log, log_level ) ) + { + osm_log( p_log, log_level, + "PortInfo dump:\n" + "\t\t\t\tport number.............0x%X\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................0x%X\n" + "\t\t\t\tmaster_sm_base_lid......0x%X\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..........0x%X\n" + "\t\t\t\tlink_width_enabled......0x%X\n" + "\t\t\t\tlink_width_supported....0x%X\n" + "\t\t\t\tlink_width_active.......0x%X\n" + "\t\t\t\tlink_speed_supported....0x%X\n" + "\t\t\t\tport_state..............%s\n" + "\t\t\t\tstate_info2.............0x%X\n" + "\t\t\t\tm_key_protect_bits......0x%X\n" + "\t\t\t\tlmc.....................0x%X\n" + "\t\t\t\tlink_speed..............0x%X\n" + "\t\t\t\tmtu_smsl................0x%X\n" + "\t\t\t\tvl_cap_init_type........0x%X\n" + "\t\t\t\tvl_high_limit...........0x%X\n" + "\t\t\t\tvl_arb_high_cap.........0x%X\n" + "\t\t\t\tvl_arb_low_cap..........0x%X\n" + "\t\t\t\tinit_rep_mtu_cap........0x%X\n" + "\t\t\t\tvl_stall_life...........0x%X\n" + "\t\t\t\tvl_enforce..............0x%X\n" + "\t\t\t\tm_key_violations........0x%X\n" + "\t\t\t\tp_key_violations........0x%X\n" + "\t\t\t\tq_key_violations........0x%X\n" + "\t\t\t\tguid_cap................0x%X\n" + "\t\t\t\tclient_reregister.......0x%X\n" + "\t\t\t\tsubnet_timeout..........0x%X\n" + "\t\t\t\tresp_time_value.........0x%X\n" + "\t\t\t\terror_threshold.........0x%X\n" + "", + port_num, + cl_ntoh64( node_guid ), + cl_ntoh64( port_guid ), + cl_ntoh64( p_pi->m_key ), + cl_ntoh64( p_pi->subnet_prefix ), + cl_ntoh16( p_pi->base_lid ), + cl_ntoh16( p_pi->master_sm_base_lid ), + cl_ntoh32( p_pi->capability_mask ), + cl_ntoh16( p_pi->diag_code ), + cl_ntoh16( p_pi->m_key_lease_period ), + p_pi->local_port_num, + p_pi->link_width_enabled, + p_pi->link_width_supported, + p_pi->link_width_active, + ib_port_info_get_link_speed_sup( p_pi ), + ib_get_port_state_str( ib_port_info_get_port_state( p_pi ) ), + p_pi->state_info2, + ib_port_info_get_mpb( p_pi ), + ib_port_info_get_lmc( p_pi ), + p_pi->link_speed, + p_pi->mtu_smsl, + p_pi->vl_cap, + p_pi->vl_high_limit, + p_pi->vl_arb_high_cap, + p_pi->vl_arb_low_cap, + p_pi->mtu_cap, + p_pi->vl_stall_life, + p_pi->vl_enforce, + cl_ntoh16( p_pi->m_key_violations ), + cl_ntoh16( p_pi->p_key_violations ), + cl_ntoh16( p_pi->q_key_violations ), + p_pi->guid_cap, + ib_port_info_get_client_rereg( p_pi ), + ib_port_info_get_timeout( p_pi ), + p_pi->resp_time_value, + p_pi->error_threshold + ); + + /* show the capabilities mask */ + osm_dbg_get_capabilities_str( buf, BUF_SIZE, "\t\t\t\t", p_pi ); + + osm_log( p_log, log_level, "%s", buf ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_portinfo_record( + IN osm_log_t* const p_log, + IN const ib_portinfo_record_t* const p_pir, + IN const osm_log_level_t log_level ) +{ + char buf[BUF_SIZE]; + const ib_port_info_t * const p_pi = &p_pir->port_info; + + if( osm_log_is_active( p_log, log_level ) ) + { + osm_log( p_log, log_level, + "PortInfo Record dump:\n" + "\t\t\t\tRID\n" + "\t\t\t\tEndPortLid..............0x%X\n" + "\t\t\t\tPortNum.................0x%X\n" + "\t\t\t\tReserved................0x%X\n" + "\t\t\t\tPortInfo dump:\n" + "\t\t\t\tm_key...................0x%016" PRIx64 "\n" + "\t\t\t\tsubnet_prefix...........0x%016" PRIx64 "\n" + "\t\t\t\tbase_lid................0x%X\n" + "\t\t\t\tmaster_sm_base_lid......0x%X\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..........0x%X\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 */ + osm_dbg_get_capabilities_str( buf, BUF_SIZE, "\t\t\t\t", p_pi ); + + osm_log( p_log, log_level, "%s", buf ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_guidinfo_record( + IN osm_log_t* const p_log, + IN const ib_guidinfo_record_t* const p_gir, + IN const osm_log_level_t log_level ) +{ + const ib_guid_info_t * const p_gi = &p_gir->guid_info; + + if( osm_log_is_active( p_log, log_level ) ) + { + osm_log( p_log, log_level, + "GUIDInfo Record dump:\n" + "\t\t\t\tRID\n" + "\t\t\t\tLid.....................0x%X\n" + "\t\t\t\tBlockNum................0x%X\n" + "\t\t\t\tReserved................0x%X\n" + "\t\t\t\tGUIDInfo dump:\n" + "\t\t\t\tReserved................0x%X\n" + "\t\t\t\tGUID 0..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 1..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 2..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 3..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 4..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 5..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 6..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 7..................0x%016" PRIx64 "\n", + cl_ntoh16(p_gir->lid), + p_gir->block_num, + p_gir->resv, + cl_ntoh32(p_gir->reserved), + cl_ntoh64(p_gi->guid[0]), + cl_ntoh64(p_gi->guid[1]), + cl_ntoh64(p_gi->guid[2]), + cl_ntoh64(p_gi->guid[3]), + cl_ntoh64(p_gi->guid[4]), + cl_ntoh64(p_gi->guid[5]), + cl_ntoh64(p_gi->guid[6]), + cl_ntoh64(p_gi->guid[7]) + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_node_info( + IN osm_log_t* const p_log, + IN const ib_node_info_t* const p_ni, + IN const osm_log_level_t log_level ) +{ + if( osm_log_is_active( p_log, log_level ) ) + { + osm_log( p_log, log_level, + "NodeInfo dump:\n" + "\t\t\t\tbase_version............0x%X\n" + "\t\t\t\tclass_version...........0x%X\n" + "\t\t\t\tnode_type...............%s\n" + "\t\t\t\tnum_ports...............0x%X\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................0x%X\n" + "\t\t\t\tvendor_id...............0x%X\n" + "", + p_ni->base_version, + p_ni->class_version, + ib_get_node_type_str( p_ni->node_type ), + p_ni->num_ports, + cl_ntoh64( p_ni->sys_guid ), + cl_ntoh64( p_ni->node_guid ), + cl_ntoh64( p_ni->port_guid ), + cl_ntoh16( p_ni->partition_cap ), + cl_ntoh16( p_ni->device_id ), + cl_ntoh32( p_ni->revision ), + ib_node_info_get_local_port_num( p_ni ), + cl_ntoh32( ib_node_info_get_vendor_id( p_ni ) ) + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_node_record( + IN osm_log_t* const p_log, + IN const ib_node_record_t* const p_nr, + IN const osm_log_level_t log_level ) +{ + const ib_node_info_t * const p_ni = &p_nr->node_info; + + if( osm_log_is_active( p_log, log_level ) ) + { + char desc[sizeof(p_nr->node_desc.description) + 1]; + + 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.....................0x%X\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...............0x%X\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................0x%X\n" + "\t\t\t\tvendor_id...............0x%X\n" + "\t\t\t\tNodeDescription\n" + "\t\t\t\t%s\n" + "", + cl_ntoh16(p_nr->lid), + cl_ntoh16(p_nr->resv), + p_ni->base_version, + p_ni->class_version, + ib_get_node_type_str( p_ni->node_type ), + p_ni->num_ports, + cl_ntoh64( p_ni->sys_guid ), + cl_ntoh64( p_ni->node_guid ), + cl_ntoh64( p_ni->port_guid ), + cl_ntoh16( p_ni->partition_cap ), + cl_ntoh16( p_ni->device_id ), + cl_ntoh32( p_ni->revision ), + ib_node_info_get_local_port_num( p_ni ), + cl_ntoh32( ib_node_info_get_vendor_id( p_ni )), + desc + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_path_record( + IN osm_log_t* const p_log, + IN const ib_path_rec_t* const p_pr, + IN const osm_log_level_t log_level ) +{ + if( osm_log_is_active( p_log, log_level ) ) + { + osm_log( p_log, log_level, + "PathRecord dump:\n" + "\t\t\t\tservice_id..............0x%016" PRIx64 "\n" + "\t\t\t\tdgid....................0x%016" PRIx64 " : " + "0x%016" PRIx64 "\n" + "\t\t\t\tsgid....................0x%016" PRIx64 " : " + "0x%016" PRIx64 "\n" + "\t\t\t\tdlid....................0x%X\n" + "\t\t\t\tslid....................0x%X\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\tsl......................0x%X\n" + "\t\t\t\tmtu.....................0x%X\n" + "\t\t\t\trate....................0x%X\n" + "\t\t\t\tpkt_life................0x%X\n" + "\t\t\t\tpreference..............0x%X\n" + "\t\t\t\tresv2...................0x%X\n" + "\t\t\t\tresv3...................0x%X\n" + "", + *(uint64_t*)p_pr->service_id, + cl_ntoh64( p_pr->dgid.unicast.prefix ), + cl_ntoh64( p_pr->dgid.unicast.interface_id ), + cl_ntoh64( p_pr->sgid.unicast.prefix ), + cl_ntoh64( p_pr->sgid.unicast.interface_id ), + cl_ntoh16( p_pr->dlid ), + cl_ntoh16( p_pr->slid ), + cl_ntoh32( p_pr->hop_flow_raw ), + p_pr->tclass, + p_pr->num_path, + cl_ntoh16( p_pr->pkey ), + cl_ntoh16( p_pr->qos_class_sl ), + p_pr->mtu, + p_pr->rate, + p_pr->pkt_life, + p_pr->preference, + *(uint32_t*)&p_pr->resv2, + *((uint16_t*)&p_pr->resv2 + 2) + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_multipath_record( + IN osm_log_t* const p_log, + IN const ib_multipath_rec_t* const p_mpr, + IN const osm_log_level_t log_level ) +{ + int i; + char buf_line[1024]; + ib_gid_t const *p_gid; + + if( osm_log_is_active( p_log, log_level ) ) + { + memset(buf_line, 0, sizeof(buf_line)); + p_gid = p_mpr->gids; + if ( p_mpr->sgid_count ) + { + for (i = 0; i < p_mpr->sgid_count; i++) + { + sprintf( buf_line, "%s\t\t\t\tsgid%02d.................." + "0x%016" PRIx64 " : 0x%016" PRIx64 "\n", + buf_line, i + 1, cl_ntoh64( p_gid->unicast.prefix ), + cl_ntoh64( p_gid->unicast.interface_id ) ); + p_gid++; + } + } + if ( p_mpr->dgid_count ) + { + for (i = 0; i < p_mpr->dgid_count; i++) + { + sprintf( buf_line, "%s\t\t\t\tdgid%02d.................." + "0x%016" PRIx64 " : 0x%016" PRIx64 "\n", + buf_line, i + 1, cl_ntoh64( p_gid->unicast.prefix ), + cl_ntoh64( p_gid->unicast.interface_id ) ); + p_gid++; + } + } + osm_log( p_log, log_level, + "MultiPath Record dump:\n" + "\t\t\t\thop_flow_raw............0x%X\n" + "\t\t\t\ttclass..................0x%X\n" + "\t\t\t\tnum_path_revers.........0x%X\n" + "\t\t\t\tpkey....................0x%X\n" + "\t\t\t\tresv0...................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\tresv1...................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" + "%s\n" + "", + cl_ntoh32( p_mpr->hop_flow_raw ), + p_mpr->tclass, + p_mpr->num_path, + cl_ntoh16( p_mpr->pkey ), + p_mpr->resv0, + cl_ntoh16( p_mpr->sl ), + p_mpr->mtu, + p_mpr->rate, + p_mpr->pkt_life, + p_mpr->resv1, + p_mpr->independence, + p_mpr->sgid_count, + p_mpr->dgid_count, + buf_line + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_mc_record( + IN osm_log_t* const p_log, + IN const ib_member_rec_t* const p_mcmr, + IN const osm_log_level_t log_level ) +{ + + if( osm_log_is_active( p_log, log_level ) ) + { + osm_log( p_log, log_level, + "MCMember Record dump:\n" + "\t\t\t\tMGID....................0x%016" PRIx64 " : " + "0x%016" PRIx64 "\n" + "\t\t\t\tPortGid.................0x%016" PRIx64 " : " + "0x%016" PRIx64 "\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" + "", + cl_ntoh64( p_mcmr->mgid.unicast.prefix ), + cl_ntoh64( p_mcmr->mgid.unicast.interface_id ), + cl_ntoh64( p_mcmr->port_gid.unicast.prefix ), + cl_ntoh64( p_mcmr->port_gid.unicast.interface_id ), + cl_ntoh32( p_mcmr->qkey ), + cl_ntoh16( p_mcmr->mlid ), + p_mcmr->mtu, + p_mcmr->tclass, + cl_ntoh16( p_mcmr->pkey ), + p_mcmr->rate, + p_mcmr->pkt_life, + cl_ntoh32( p_mcmr->sl_flow_hop ), + p_mcmr->scope_state, + p_mcmr->proxy_join + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_service_record( + IN osm_log_t* const p_log, + IN const ib_service_record_t* const p_sr, + IN const osm_log_level_t log_level ) +{ + char buf_service_key[35]; + char buf_service_name[65]; + + if( osm_log_is_active( p_log, log_level ) ) + { + 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..............0x%016" PRIx64 " : " + "0x%016" PRIx64 "\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 ), + 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 ), + buf_service_key, + buf_service_name, + p_sr->service_data8[0], p_sr->service_data8[1], + p_sr->service_data8[2], p_sr->service_data8[3], + p_sr->service_data8[4], p_sr->service_data8[5], + p_sr->service_data8[6], p_sr->service_data8[7], + p_sr->service_data8[8], p_sr->service_data8[9], + p_sr->service_data8[10], p_sr->service_data8[11], + p_sr->service_data8[12], p_sr->service_data8[13], + p_sr->service_data8[14], p_sr->service_data8[15], + cl_ntoh16(p_sr->service_data16[0]), + cl_ntoh16(p_sr->service_data16[1]), + cl_ntoh16(p_sr->service_data16[2]), + cl_ntoh16(p_sr->service_data16[3]), + cl_ntoh16(p_sr->service_data16[4]), + cl_ntoh16(p_sr->service_data16[5]), + cl_ntoh16(p_sr->service_data16[6]), + cl_ntoh16(p_sr->service_data16[7]), + cl_ntoh32(p_sr->service_data32[0]), + cl_ntoh32(p_sr->service_data32[1]), + cl_ntoh32(p_sr->service_data32[2]), + cl_ntoh32(p_sr->service_data32[3]), + cl_ntoh64(p_sr->service_data64[0]), + cl_ntoh64(p_sr->service_data64[1]) + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_inform_info( + IN osm_log_t* const p_log, + IN const ib_inform_info_t* const p_ii, + IN const osm_log_level_t log_level ) +{ + uint32_t qpn; + uint8_t resp_time_val; + + if( osm_log_is_active( p_log, log_level ) ) + { + + ib_inform_info_get_qpn_resp_time(p_ii->g_or_v.generic.qpn_resp_time_val, + &qpn, &resp_time_val); + + if (p_ii->is_generic) + { + osm_log( p_log, log_level, + "InformInfo dump:\n" + "\t\t\t\tgid.....................0x%016" PRIx64 " : 0x%016" PRIx64 "\n" + "\t\t\t\tlid_range_begin.........0x%X\n" + "\t\t\t\tlid_range_end...........0x%X\n" + "\t\t\t\tis_generic..............0x%X\n" + "\t\t\t\tsubscribe...............0x%X\n" + "\t\t\t\ttrap_type...............0x%X\n" + "\t\t\t\ttrap_num................%u\n" + "\t\t\t\tqpn.....................0x%06X\n" + "\t\t\t\tresp_time_val...........0x%X\n" + "\t\t\t\tnode_type...............0x%06X\n" + "", + cl_ntoh64( p_ii->gid.unicast.prefix ), + cl_ntoh64( p_ii->gid.unicast.interface_id ), + cl_ntoh16( p_ii->lid_range_begin ), + cl_ntoh16( p_ii->lid_range_end ), + p_ii->is_generic, + p_ii->subscribe, + cl_ntoh16( p_ii->trap_type ), + cl_ntoh16( p_ii->g_or_v.generic.trap_num ), + cl_ntoh32(qpn), + resp_time_val, + cl_ntoh32(ib_inform_info_get_node_type( p_ii )) + ); + } + else + { + osm_log( p_log, log_level, + "InformInfo dump:\n" + "\t\t\t\tgid.....................0x%016" PRIx64 " : 0x%016" PRIx64 "\n" + "\t\t\t\tlid_range_begin.........0x%X\n" + "\t\t\t\tlid_range_end...........0x%X\n" + "\t\t\t\tis_generic..............0x%X\n" + "\t\t\t\tsubscribe...............0x%X\n" + "\t\t\t\ttrap_type...............0x%X\n" + "\t\t\t\tdev_id..................0x%X\n" + "\t\t\t\tqpn.....................0x%06X\n" + "\t\t\t\tresp_time_val...........0x%X\n" + "\t\t\t\tvendor_id...............0x%06X\n" + "", + cl_ntoh64( p_ii->gid.unicast.prefix ), + cl_ntoh64( p_ii->gid.unicast.interface_id ), + cl_ntoh16( p_ii->lid_range_begin ), + cl_ntoh16( p_ii->lid_range_end ), + p_ii->is_generic, + p_ii->subscribe, + cl_ntoh16( p_ii->trap_type ), + cl_ntoh16( p_ii->g_or_v.vend.dev_id ), + cl_ntoh32(qpn), + resp_time_val, + cl_ntoh32(ib_inform_info_get_node_type( p_ii )) + ); + } + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_inform_info_record( + IN osm_log_t* const p_log, + IN const ib_inform_info_record_t* const p_iir, + IN const osm_log_level_t log_level ) +{ + 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( osm_log_is_active( p_log, log_level ) ) + { + + 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...........0x%016" PRIx64 " : " + "0x%016" PRIx64 "\n" + "\t\t\t\tSubscriberEnum..........0x%X\n" + "\t\t\t\tInformInfo dump:\n" + "\t\t\t\tgid.....................0x%016" PRIx64 " : 0x%016" PRIx64 "\n" + "\t\t\t\tlid_range_begin.........0x%X\n" + "\t\t\t\tlid_range_end...........0x%X\n" + "\t\t\t\tis_generic..............0x%X\n" + "\t\t\t\tsubscribe...............0x%X\n" + "\t\t\t\ttrap_type...............0x%X\n" + "\t\t\t\ttrap_num................%u\n" + "\t\t\t\tqpn.....................0x%06X\n" + "\t\t\t\tresp_time_val...........0x%X\n" + "\t\t\t\tnode_type...............0x%06X\n" + "", + cl_ntoh64( p_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(qpn), + resp_time_val, + cl_ntoh32(ib_inform_info_get_node_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...........0x%016" PRIx64 " : " + "0x%016" PRIx64 "\n" + "\t\t\t\tSubscriberEnum..........0x%X\n" + "\t\t\t\tInformInfo dump:\n" + "\t\t\t\tgid.....................0x%016" PRIx64 " : 0x%016" PRIx64 "\n" + "\t\t\t\tlid_range_begin.........0x%X\n" + "\t\t\t\tlid_range_end...........0x%X\n" + "\t\t\t\tis_generic..............0x%X\n" + "\t\t\t\tsubscribe...............0x%X\n" + "\t\t\t\ttrap_type...............0x%X\n" + "\t\t\t\tdev_id..................0x%X\n" + "\t\t\t\tqpn.....................0x%06X\n" + "\t\t\t\tresp_time_val...........0x%X\n" + "\t\t\t\tvendor_id...............0x%06X\n" + "", + cl_ntoh64( p_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.vend.dev_id ), + cl_ntoh32(qpn), + resp_time_val, + cl_ntoh32(ib_inform_info_get_node_type( &p_iir->inform_info )) + ); + } + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_link_record( + IN osm_log_t* const p_log, + IN const ib_link_record_t* const p_lr, + IN const osm_log_level_t log_level ) +{ + if( osm_log_is_active( p_log, log_level ) ) + { + osm_log( p_log, log_level, + "Link Record dump:\n" + "\t\t\t\tfrom_lid................0x%X\n" + "\t\t\t\tfrom_port_num...........0x%X\n" + "\t\t\t\tto_port_num.............0x%X\n" + "\t\t\t\tto_lid..................0x%X\n" + "", + cl_ntoh16( p_lr->from_lid ), + p_lr->from_port_num, + p_lr->to_port_num, + cl_ntoh16( p_lr->to_lid ) + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_switch_info( + IN osm_log_t* const p_log, + IN const ib_switch_info_t* const p_si, + IN const osm_log_level_t log_level ) +{ + if( osm_log_is_active( p_log, log_level ) ) + { + osm_log( p_log, OSM_LOG_VERBOSE, + "SwitchInfo dump:\n" + "\t\t\t\tlin_cap.................0x%X\n" + "\t\t\t\trand_cap................0x%X\n" + "\t\t\t\tmcast_cap...............0x%X\n" + "\t\t\t\tlin_top.................0x%X\n" + "\t\t\t\tdef_port................0x%X\n" + "\t\t\t\tdef_mcast_pri_port......0x%X\n" + "\t\t\t\tdef_mcast_not_port......0x%X\n" + "\t\t\t\tlife_state..............0x%X\n" + "\t\t\t\tlids_per_port...........0x%X\n" + "\t\t\t\tpartition_enf_cap.......0x%X\n" + "\t\t\t\tflags...................0x%X\n" + "", + cl_ntoh16( p_si->lin_cap ), + cl_ntoh16( p_si->rand_cap ), + cl_ntoh16( p_si->mcast_cap ), + cl_ntoh16( p_si->lin_top ), + p_si->def_port, + p_si->def_mcast_pri_port, + p_si->def_mcast_not_port, + p_si->life_state, + cl_ntoh16( p_si->lids_per_port ), + cl_ntoh16( p_si->enforce_cap ), + p_si->flags + ); + } +} + + +/********************************************************************** + **********************************************************************/ +void +osm_dump_switch_info_record( + IN osm_log_t* const p_log, + IN const ib_switch_info_record_t* const p_sir, + IN const osm_log_level_t log_level ) +{ + if( osm_log_is_active( p_log, log_level ) ) + { + osm_log( p_log, log_level, + "SwitchInfo Record dump:\n" + "\t\t\t\tRID\n" + "\t\t\t\tlid.....................0x%X\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................0x%X\n" + "\t\t\t\tdef_mcast_pri_port......0x%X\n" + "\t\t\t\tdef_mcast_not_port......0x%X\n" + "\t\t\t\tlife_state..............0x%X\n" + "\t\t\t\tlids_per_port...........0x%X\n" + "\t\t\t\tpartition_enf_cap.......0x%X\n" + "\t\t\t\tflags...................0x%X\n" + "", + cl_ntoh16( p_sir->lid ), + cl_ntoh16( p_sir->switch_info.lin_cap ), + cl_ntoh16( p_sir->switch_info.rand_cap ), + cl_ntoh16( p_sir->switch_info.mcast_cap ), + cl_ntoh16( p_sir->switch_info.lin_top ), + p_sir->switch_info.def_port, + p_sir->switch_info.def_mcast_pri_port, + p_sir->switch_info.def_mcast_not_port, + p_sir->switch_info.life_state, + cl_ntoh16( p_sir->switch_info.lids_per_port ), + cl_ntoh16( p_sir->switch_info.enforce_cap ), + p_sir->switch_info.flags + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_pkey_block( + IN osm_log_t* const p_log, + IN uint64_t port_guid, + IN uint16_t block_num, + IN uint8_t port_num, + IN const ib_pkey_table_t* const p_pkey_tbl, + IN const osm_log_level_t log_level ) +{ + int i; + char buf_line[1024]; + + if( osm_log_is_active( p_log, log_level ) ) + { + buf_line[0] = '\0'; + for (i = 0; i < 32; i++) + sprintf( buf_line,"%s 0x%04x |", + buf_line, 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............0x%X\n\tP_Key Table: %s\n", + cl_ntoh64( port_guid ), + block_num, + port_num, + buf_line + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_slvl_map_table( + IN osm_log_t* const p_log, + IN uint64_t port_guid, + IN uint8_t in_port_num, + IN uint8_t out_port_num, + IN const ib_slvl_table_t* const p_slvl_tbl, + IN const osm_log_level_t log_level ) +{ + uint8_t i; + char buf_line1[1024]; + char buf_line2[1024]; + + if( osm_log_is_active( p_log, log_level ) ) + { + buf_line1[0] = '\0'; + buf_line2[0] = '\0'; + for (i = 0; i < 16; i++) + sprintf( buf_line1,"%s %-2u |", buf_line1, i); + for (i = 0; i < 16; i++) + sprintf( buf_line2,"%s0x%01X |", + buf_line2, 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..........0x%X\n" + "\t\t\tout_port_num.........0x%X\n\tSL: | %s\n\tVL: | %s\n", + cl_ntoh64( port_guid ), + in_port_num, + out_port_num, + buf_line1, buf_line2 + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_vl_arb_table( + IN osm_log_t* const p_log, + IN uint64_t port_guid, + IN uint8_t block_num, + IN uint8_t port_num, + IN const ib_vl_arb_table_t* const p_vla_tbl, + IN const osm_log_level_t log_level ) +{ + int i; + char buf_line1[1024]; + char buf_line2[1024]; + + if( osm_log_is_active( p_log, log_level ) ) + { + buf_line1[0] = '\0'; + buf_line2[0] = '\0'; + for (i = 0; i < 32; i++) + sprintf( buf_line1,"%s 0x%01X |", + buf_line1, p_vla_tbl->vl_entry[i].vl); + for (i = 0; i < 32; i++) + sprintf( buf_line2,"%s 0x%01X |", + buf_line2, 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............0x%X\n\tVL : | %s\n\tWEIGHT:| %s\n", + cl_ntoh64( port_guid ), + block_num, + port_num, + buf_line1, buf_line2 + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_sm_info( + IN osm_log_t* const p_log, + IN const ib_sm_info_t* const p_smi, + IN const osm_log_level_t log_level ) +{ + if( osm_log_is_active( p_log, log_level ) ) + { + osm_log( p_log, OSM_LOG_DEBUG, + "SMInfo dump:\n" + "\t\t\t\tguid....................0x%016" PRIx64 "\n" + "\t\t\t\tsm_key..................0x%016" PRIx64 "\n" + "\t\t\t\tact_count...............%u\n" + "\t\t\t\tpriority................%u\n" + "\t\t\t\tsm_state................%u\n" + "", + cl_ntoh64( p_smi->guid ), + cl_ntoh64( p_smi->sm_key ), + cl_ntoh32( p_smi->act_count ), + ib_sminfo_get_priority( p_smi ), + ib_sminfo_get_state( p_smi ) + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_sm_info_record( + IN osm_log_t* const p_log, + IN const ib_sminfo_record_t* const p_smir, + IN const osm_log_level_t log_level ) +{ + if( osm_log_is_active( p_log, log_level ) ) + { + osm_log( p_log, OSM_LOG_DEBUG, + "SMInfo Record dump:\n" + "\t\t\t\tRID\n" + "\t\t\t\tLid.....................0x%X\n" + "\t\t\t\tReserved................0x%X\n" + "\t\t\t\tSMInfo dump:\n" + "\t\t\t\tguid....................0x%016" PRIx64 "\n" + "\t\t\t\tsm_key..................0x%016" PRIx64 "\n" + "\t\t\t\tact_count...............%u\n" + "\t\t\t\tpriority................%u\n" + "\t\t\t\tsm_state................%u\n" + "", + cl_ntoh16( p_smir->lid ), + cl_ntoh16( p_smir->resv0 ), + cl_ntoh64( p_smir->sm_info.guid ), + cl_ntoh64( p_smir->sm_info.sm_key ), + cl_ntoh32( p_smir->sm_info.act_count ), + ib_sminfo_get_priority( &p_smir->sm_info ), + ib_sminfo_get_state( &p_smir->sm_info ) + ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_notice( + IN osm_log_t* const p_log, + IN const ib_mad_notice_attr_t *p_ntci, + IN const osm_log_level_t log_level ) +{ + char buff[1024]; + buff[0] = '\0'; + + if( osm_log_is_active( p_log, log_level ) ) + { + if (ib_notice_is_generic(p_ntci)) + { + /* immediate data based on the trap */ + switch (cl_ntoh16(p_ntci->g_or_v.generic.trap_num)) { + case 64: + case 65: + case 66: + case 67: + sprintf(buff, + "\t\t\t\tsrc_gid..................0x%016" PRIx64 + ":0x%016" PRIx64 "\n", + cl_ntoh64(p_ntci->data_details.ntc_64_67.gid.unicast.prefix), + cl_ntoh64(p_ntci->data_details.ntc_64_67.gid.unicast.interface_id)); + break; + case 128: + sprintf(buff, + "\t\t\t\tsw_lid...................0x%04X\n", + cl_ntoh16(p_ntci->data_details.ntc_128.sw_lid)); + break; + case 129: + case 130: + case 131: + sprintf(buff, + "\t\t\t\tlid......................0x%04X\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......................0x%04x\n" + "\t\t\t\tnew_cap_mask.............0x%08x\n", + cl_ntoh16(p_ntci->data_details.ntc_144.lid), + cl_ntoh32(p_ntci->data_details.ntc_144.new_cap_mask)); + break; + case 145: + sprintf(buff, + "\t\t\t\tlid......................0x%04X\n" + "\t\t\t\tnew_sys_guid.............0x%016" PRIx64 "\n", + cl_ntoh16(p_ntci->data_details.ntc_145.lid), + cl_ntoh64(p_ntci->data_details.ntc_145.new_sys_guid)); + break; + } + + osm_log( p_log, log_level, + "Generic Notice dump:\n" + "\t\t\t\ttype.....................0x%02X\n" + "\t\t\t\tprod_type................%u\n" + "\t\t\t\ttrap_num.................%u\n%s" + "", + ib_notice_get_type(p_ntci), + cl_ntoh32(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.....................0x%04x\n" + "\t\t\t\tvendor...................%u\n" + "\t\t\t\tdevice_id................%u\n" + "", + cl_ntoh16(ib_notice_get_type(p_ntci)), + cl_ntoh32(ib_notice_get_vend_id(p_ntci)), + cl_ntoh16(p_ntci->g_or_v.vend.dev_id) + ); + } + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_dr_smp( + IN osm_log_t* const p_log, + IN const ib_smp_t* const p_smp, + IN const osm_log_level_t log_level ) +{ + uint32_t i; + char buf[BUF_SIZE]; + char line[BUF_SIZE]; + + if( osm_log_is_active( p_log, log_level ) ) + { + sprintf( buf, + "SMP dump:\n" + "\t\t\t\tbase_ver................0x%X\n" + "\t\t\t\tmgmt_class..............0x%X\n" + "\t\t\t\tclass_ver...............0x%X\n" + "\t\t\t\tmethod..................0x%X (%s)\n", + p_smp->base_ver, + p_smp->mgmt_class, + p_smp->class_ver, + p_smp->method, ib_get_sm_method_str(p_smp->method)); + + if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR) + { + sprintf( line, + "\t\t\t\tD bit...................0x%X\n" + "\t\t\t\tstatus..................0x%X\n", + ib_smp_is_d(p_smp), + ib_smp_get_status(p_smp)); + } + else + { + sprintf( line, + "\t\t\t\tstatus..................0x%X\n", + cl_ntoh16(p_smp->status)); + } + strcat( buf, line ); + + sprintf( line, + "\t\t\t\thop_ptr.................0x%X\n" + "\t\t\t\thop_count...............0x%X\n" + "\t\t\t\ttrans_id................0x%" PRIx64 "\n" + "\t\t\t\tattr_id.................0x%X (%s)\n" + "\t\t\t\tresv....................0x%X\n" + "\t\t\t\tattr_mod................0x%X\n" + "\t\t\t\tm_key...................0x%016" PRIx64 "\n", + p_smp->hop_ptr, + p_smp->hop_count, + cl_ntoh64(p_smp->trans_id), + cl_ntoh16(p_smp->attr_id), + ib_get_sm_attr_str( p_smp->attr_id ), + cl_ntoh16(p_smp->resv), + cl_ntoh32(p_smp->attr_mod), + cl_ntoh64(p_smp->m_key) + ); + strcat( buf, line ); + + if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR) + { + sprintf( line, + "\t\t\t\tdr_slid.................0x%X\n" + "\t\t\t\tdr_dlid.................0x%X\n", + cl_ntoh16(p_smp->dr_slid), + cl_ntoh16(p_smp->dr_dlid) + ); + strcat( buf, line ); + + strcat( buf, "\n\t\t\t\tInitial path: " ); + + for( i = 0; i <= p_smp->hop_count; i++ ) + { + sprintf( line, "[%X]", p_smp->initial_path[i] ); + strcat( buf, line ); + } + + strcat( buf, "\n\t\t\t\tReturn path: " ); + + for( i = 0; i <= p_smp->hop_count; i++ ) + { + sprintf( line, "[%X]", p_smp->return_path[i] ); + strcat( buf, line ); + } + + strcat( buf, "\n\t\t\t\tReserved: " ); + + for( i = 0; i < 7; i++ ) + { + sprintf( line, "[%0X]", p_smp->resv1[i] ); + strcat( buf, line ); + } + + strcat( buf, "\n" ); + + for( i = 0; i < 64; i += 16 ) + { + sprintf( line, "\n\t\t\t\t%02X %02X %02X %02X " + "%02X %02X %02X %02X" + " %02X %02X %02X %02X %02X %02X %02X %02X\n", + p_smp->data[i], + p_smp->data[i+1], + p_smp->data[i+2], + p_smp->data[i+3], + p_smp->data[i+4], + p_smp->data[i+5], + p_smp->data[i+6], + p_smp->data[i+7], + p_smp->data[i+8], + p_smp->data[i+9], + p_smp->data[i+10], + p_smp->data[i+11], + p_smp->data[i+12], + p_smp->data[i+13], + p_smp->data[i+14], + p_smp->data[i+15] ); + + strcat( buf, line ); + } + } + else + { + /* not a Direct Route so provide source and destination lids */ + strcat(buf, "\t\t\t\tMAD IS LID ROUTED\n"); + } + + osm_log( p_log, log_level, + "%s\n", buf ); + + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_sa_mad( + IN osm_log_t* const p_log, + IN const ib_sa_mad_t* const p_mad, + IN const osm_log_level_t log_level ) +{ + 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; + } + + if( osm_log_is_active( p_log, log_level ) ) + { + sprintf( buf, + "SA MAD dump:\n" + "\t\t\t\tbase_ver................0x%X\n" + "\t\t\t\tmgmt_class..............0x%X\n" + "\t\t\t\tclass_ver...............0x%X\n" + "\t\t\t\tmethod..................0x%X (%s)\n" + "\t\t\t\tstatus..................0x%X\n" + "\t\t\t\tresv....................0x%X\n" + "\t\t\t\ttrans_id................0x%" PRIx64 "\n" + "\t\t\t\tattr_id.................0x%X (%s)\n" + "\t\t\t\tresv1...................0x%X\n" + "\t\t\t\tattr_mod................0x%X\n" + "\t\t\t\trmpp_version............0x%X\n" + "\t\t\t\trmpp_type...............0x%X\n" + "\t\t\t\trmpp_flags..............0x%X\n" + "\t\t\t\trmpp_status.............0x%X\n" + "\t\t\t\tseg_num.................0x%X\n" + "\t\t\t\tpayload_len/new_win.....0x%X\n" + "\t\t\t\tsm_key..................0x%016" PRIx64 "\n" + "\t\t\t\tattr_offset.............0x%X\n" + "\t\t\t\tresv2...................0x%X\n" + "\t\t\t\tcomp_mask...............0x%016" PRIx64 "\n", + p_mad->base_ver, + p_mad->mgmt_class, + p_mad->class_ver, + p_mad->method, ib_get_sa_method_str(p_mad->method), + cl_ntoh16(p_mad->status), + cl_ntoh16(p_mad->resv), + cl_ntoh64(p_mad->trans_id), + cl_ntoh16(p_mad->attr_id), + ib_get_sa_attr_str( p_mad->attr_id ), + cl_ntoh16(p_mad->resv1), + cl_ntoh32(p_mad->attr_mod), + p_mad->rmpp_version, + p_mad->rmpp_type, + p_mad->rmpp_flags, + p_mad->rmpp_status, + cl_ntoh32(p_mad->seg_num), + cl_ntoh32(p_mad->paylen_newwin), + cl_ntoh64(p_mad->sm_key), + cl_ntoh16(p_mad->attr_offset), + cl_ntoh16(p_mad->resv3), + cl_ntoh64(p_mad->comp_mask) + ); + + strcat( buf, "\n" ); + + osm_log( p_log, log_level, + "%s\n", buf ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_dr_path( + IN osm_log_t* const p_log, + IN const osm_dr_path_t* const p_path, + IN const osm_log_level_t log_level) +{ + uint32_t i; + char buf[BUF_SIZE]; + char line[BUF_SIZE]; + + if( osm_log_is_active( p_log, log_level) ) + { + sprintf( buf, "Directed Path Dump of %u hop path:" + "\n\t\t\t\tPath = ", p_path->hop_count ); + + for( i = 0; i <= p_path->hop_count; i++ ) + { + sprintf( line, "[%X]", p_path->path[i] ); + strcat( buf, line ); + } + osm_log( p_log, log_level, + "%s\n", buf ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_smp_dr_path( + IN osm_log_t* const p_log, + IN const ib_smp_t* const p_smp, + IN const osm_log_level_t log_level + ) +{ + uint32_t i; + char buf[BUF_SIZE]; + char line[BUF_SIZE]; + + if( osm_log_is_active( p_log, log_level) ) + { + sprintf( buf, "Received SMP on a %u hop path:" + "\n\t\t\t\tInitial path = ", p_smp->hop_count ); + + for( i = 0; i <= p_smp->hop_count; i++ ) + { + sprintf( line, "[%X]", p_smp->initial_path[i] ); + strcat( buf, line ); + } + + strcat( buf, "\n\t\t\t\tReturn path = " ); + + for( i = 0; i <= p_smp->hop_count; i++ ) + { + sprintf( line, "[%X]", p_smp->return_path[i] ); + strcat( buf, line ); + } + + osm_log( p_log, log_level, + "%s\n", buf ); + } +} + +const char* const __osm_sm_state_str[] = +{ + "OSM_SM_STATE_NO_STATE", /* 0 */ + "OSM_SM_STATE_INIT", /* 1 */ + "OSM_SM_STATE_IDLE", /* 2 */ + "OSM_SM_STATE_SWEEP_LIGHT", /* 3 */ + "OSM_SM_STATE_SWEEP_LIGHT_WAIT", /* 4 */ + "OSM_SM_STATE_SWEEP_HEAVY_SELF", /* 5 */ + "OSM_SM_STATE_SWEEP_HEAVY_SUBNET", /* 6 */ + "OSM_SM_STATE_SET_SM_UCAST_LID", /* 7 */ + "OSM_SM_STATE_SET_SM_UCAST_LID_WAIT", /* 8 */ + "OSM_SM_STATE_SET_SM_UCAST_LID_DONE", /* 9 */ + "OSM_SM_STATE_SET_SUBNET_UCAST_LIDS", /* 10 */ + "OSM_SM_STATE_SET_SUBNET_UCAST_LIDS_WAIT", /* 11 */ + "OSM_SM_STATE_SET_SUBNET_UCAST_LIDS_DONE", /* 12 */ + "OSM_SM_STATE_SET_UCAST_TABLES", /* 13 */ + "OSM_SM_STATE_SET_UCAST_TABLES_WAIT", /* 14 */ + "OSM_SM_STATE_SET_UCAST_TABLES_DONE", /* 15 */ + "OSM_SM_STATE_SET_MCAST_TABLES", /* 16 */ + "OSM_SM_STATE_SET_MCAST_TABLES_WAIT", /* 17 */ + "OSM_SM_STATE_SET_MCAST_TABLES_DONE", /* 18 */ + "OSM_SM_STATE_SET_LINK_PORTS", /* 19 */ + "OSM_SM_STATE_SET_LINK_PORTS_WAIT", /* 20 */ + "OSM_SM_STATE_SET_LINK_PORTS_DONE", /* 21 */ + "OSM_SM_STATE_SET_ARMED", /* 22 */ + "OSM_SM_STATE_SET_ARMED_WAIT", /* 23 */ + "OSM_SM_STATE_SET_ARMED_DONE", /* 24 */ + "OSM_SM_STATE_SET_ACTIVE", /* 25 */ + "OSM_SM_STATE_SET_ACTIVE_WAIT", /* 26 */ + "OSM_SM_STATE_LOST_NEGOTIATION", /* 27 */ + "OSM_SM_STATE_STANDBY", /* 28 */ + "OSM_SM_STATE_SUBNET_UP", /* 29 */ + "OSM_SM_STATE_PROCESS_REQUEST", /* 30 */ + "OSM_SM_STATE_PROCESS_REQUEST_WAIT", /* 31 */ + "OSM_SM_STATE_PROCESS_REQUEST_DONE", /* 32 */ + "OSM_SM_STATE_MASTER_OR_HIGHER_SM_DETECTED",/* 33 */ + "OSM_SM_STATE_SET_PKEY", /* 34 */ + "OSM_SM_STATE_SET_PKEY_WAIT", /* 35 */ + "OSM_SM_STATE_SET_PKEY_DONE", /* 36 */ + "UNKNOWN STATE!!" /* 37 */ +}; + +const char* const __osm_sm_signal_str[] = +{ + "OSM_SIGNAL_NONE", /* 0 */ + "OSM_SIGNAL_SWEEP", /* 1 */ + "OSM_SIGNAL_CHANGE_DETECTED", /* 2 */ + "OSM_SIGNAL_NO_PENDING_TRANSACTIONS", /* 3 */ + "OSM_SIGNAL_DONE", /* 4 */ + "OSM_SIGNAL_DONE_PENDING", /* 5 */ + "OSM_SIGNAL_LOST_SM_NEGOTIATION", /* 6 */ + "OSM_SIGNAL_LIGHT_SWEEP_FAIL", /* 7 */ + "OSM_SIGNAL_IDLE_TIME_PROCESS", /* 8 */ + "OSM_SIGNAL_IDLE_TIME_PROCESS_REQUEST", /* 9 */ + "OSM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED", /* 10 */ + "OSM_SIGNAL_EXIT_STBY", /* 11 */ + "UNKNOWN SIGNAL!!" /* 12 */ +}; + +/********************************************************************** + **********************************************************************/ +const char* +osm_get_sm_state_str( + IN osm_sm_state_t state ) +{ + if( state > OSM_SM_STATE_MAX ) + state = OSM_SM_STATE_MAX; + return( __osm_sm_state_str[state] ); +} + +/********************************************************************** + **********************************************************************/ +const char* +osm_get_sm_signal_str( + IN osm_signal_t signal ) +{ + if( signal > OSM_SIGNAL_MAX ) + signal = OSM_SIGNAL_MAX; + return( __osm_sm_signal_str[signal] ); +} + +/********************************************************************** + **********************************************************************/ + +static const char* const __osm_disp_msg_str[] = +{ + "OSM_MSG_REQ", + "OSM_MSG_MAD_NODE_INFO", + "OSM_MSG_MAD_PORT_INFO,", + "OSM_MSG_MAD_SWITCH_INFO", + "OSM_MSG_MAD_NODE_DESC", + "OSM_MSG_NO_SMPS_OUTSTANDING", + "OSM_MSG_MAD_NODE_RECORD", + "OSM_MSG_MAD_PORTINFO_RECORD", + "OSM_MSG_MAD_SERVICE_RECORD", + "OSM_MSG_MAD_PATH_RECORD", + "OSM_MSG_MAD_MCMEMBER_RECORD", + "OSM_MSG_MAD_LINK_RECORD", + "OSM_MSG_MAD_SMINFO_RECORD", + "OSM_MSG_MAD_CLASS_PORT_INFO", + "OSM_MSG_MAD_INFORM_INFO", + "OSM_MSG_MAD_LFT_RECORD", + "OSM_MSG_MAD_LFT", + "OSM_MSG_MAD_SM_INFO", + "OSM_MSG_MAD_NOTICE", + "OSM_MSG_LIGHT_SWEEP_FAIL", + "OSM_MSG_MAD_MFT", + "OSM_MSG_MAD_PKEY_TBL_RECORD", + "OSM_MSG_MAD_VL_ARB_RECORD", + "OSM_MSG_MAD_SLVL_TBL_RECORD", + "OSM_MSG_MAD_PKEY", + "OSM_MSG_MAD_VL_ARB", + "OSM_MSG_MAD_SLVL", + "OSM_MSG_MAD_GUIDINFO_RECORD", + "OSM_MSG_MAD_INFORM_INFO_RECORD", +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + "OSM_MSG_MAD_MULTIPATH_RECORD", +#endif + "UNKNOWN!!" +}; + +/********************************************************************** + **********************************************************************/ +const char* +osm_get_disp_msg_str( + IN cl_disp_msgid_t msg ) +{ + if( msg > OSM_MSG_MAX ) + msg = OSM_MSG_MAX; + return( __osm_disp_msg_str[msg] ); +} + +static const char* const __osm_port_state_str_fixed_width[] = +{ + "NOC", + "DWN", + "INI", + "ARM", + "ACT", + "???" +}; + +/********************************************************************** + **********************************************************************/ +const char* +osm_get_port_state_str_fixed_width( + IN uint8_t port_state ) +{ + if( port_state > IB_LINK_ACTIVE ) + port_state = IB_LINK_ACTIVE + 1; + return( __osm_port_state_str_fixed_width[port_state] ); +} + +static const char* const __osm_node_type_str_fixed_width[] = +{ + "??", + "CA", + "SW", + "RT", +}; + +/********************************************************************** + **********************************************************************/ +const char* +osm_get_node_type_str_fixed_width( + IN uint32_t node_type ) +{ + if( node_type >= IB_NOTICE_NODE_TYPE_ROUTER ) + node_type = 0; + return( __osm_node_type_str_fixed_width[node_type] ); +} + +/********************************************************************** + **********************************************************************/ +const char* +osm_get_manufacturer_str( + IN uint64_t const guid_ho ) +{ + 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* 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: + return( hp_str ); + case OSM_VENDOR_ID_RIOWORKS: + return( rioworks_str ); + default: + return( unknown_str ); + } +} + +static const char* const __osm_mtu_str_fixed_width[] = +{ + "??? ", + "256 ", + "512 ", + "1024", + "2048", + "4096" +}; + +/********************************************************************** + **********************************************************************/ +const char* +osm_get_mtu_str( + IN uint8_t const mtu ) +{ + if( mtu > IB_MTU_LEN_4096 ) + return( __osm_mtu_str_fixed_width[0] ); + else + return( __osm_mtu_str_fixed_width[mtu] ); +} + +static const char* const __osm_lwa_str_fixed_width[] = +{ + "???", + "1x ", + "4x ", + "???", + "???", + "???", + "???", + "???", + "12x" +}; + +/********************************************************************** + **********************************************************************/ +const char* +osm_get_lwa_str( + IN uint8_t const lwa ) +{ + if( lwa > 8 ) + return( __osm_lwa_str_fixed_width[0] ); + else + return( __osm_lwa_str_fixed_width[lwa] ); +} + +/********************************************************************** + **********************************************************************/ +static const char* const __osm_lsa_str_fixed_width[] = +{ + "???", + "2.5", + "5 ", + "???", + "10 " +}; + +const char* +osm_get_lsa_str( + IN uint8_t const lsa ) +{ + if( lsa > 4 ) + return( __osm_lsa_str_fixed_width[0] ); + else + return( __osm_lsa_str_fixed_width[lsa] ); +} + +/********************************************************************** + **********************************************************************/ + +const char* const __osm_sm_mgr_signal_str[] = +{ + "OSM_SM_SIGNAL_INIT", /* 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_MASTER_OR_HIGHER_SM_DETECTED_DONE", /* 11 */ + "OSM_SM_SIGNAL_WAIT_FOR_HANDOVER", /* 12 */ + "UNKNOWN STATE!!" /* 13 */ + +}; + +/********************************************************************** + **********************************************************************/ +const char* +osm_get_sm_mgr_signal_str( + IN osm_sm_signal_t signal ) +{ + if( signal > OSM_SM_SIGNAL_MAX ) + signal = OSM_SM_SIGNAL_MAX; + return( __osm_sm_mgr_signal_str[signal] ); +} + +const char* const __osm_sm_mgr_state_str[] = +{ + "IB_SMINFO_STATE_NOTACTIVE", /* 0 */ + "IB_SMINFO_STATE_DISCOVERING", /* 1 */ + "IB_SMINFO_STATE_STANDBY", /* 2 */ + "IB_SMINFO_STATE_MASTER", /* 3 */ + "IB_SMINFO_STATE_INIT", /* 4 */ + "UNKNOWN STATE!!" /* 5 */ + +}; + +const char* +osm_get_sm_mgr_state_str( + IN uint16_t state ) +{ + if( state > IB_SMINFO_STATE_INIT ) + state = IB_SMINFO_STATE_INIT + 1; + return( __osm_sm_mgr_state_str[state] ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/libopensm/osm_log.c b/branches/WOF2-1/ulp/opensm/user/libopensm/osm_log.c new file mode 100644 index 00000000..e7bc851f --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/libopensm/osm_log.c @@ -0,0 +1,327 @@ +/* + * 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: + * Implementaion of osm_log_t. + * This object represents the log file. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.8 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int log_exit_count = 0; + +#ifndef WIN32 +#include +#include +#include + +static char *month_str[] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" +}; +#else +void +OsmReportState( + IN const char *p_str); +#endif /* ndef WIN32 */ + +#ifndef WIN32 + +static void truncate_log_file(osm_log_t* const p_log) +{ + int fd = fileno(p_log->out_port); + if (ftruncate(fd, 0) < 0) + fprintf(stderr, "truncate_log_file: cannot truncate: %s\n", + strerror(errno)); + if (lseek(fd, 0, SEEK_SET) < 0) + fprintf(stderr, "truncate_log_file: cannot rewind: %s\n", + strerror(errno)); + p_log->count = 0; +} + +#else /* Windows */ + +static void truncate_log_file(osm_log_t* const p_log) +{ + fprintf(stderr, "truncate_log_file: cannot truncate on windows system (yet)\n"); +} +#endif /* ndef WIN32 */ + +int osm_log_printf(osm_log_t *p_log, osm_log_level_t level, + const char *fmt, ...) +{ + va_list args; + int ret; + + if (!(p_log->level&level)) + return 0; + + va_start(args, fmt); + ret = vfprintf(stdout, fmt, args); + va_end(args); + + if (p_log->flush || level&OSM_LOG_ERROR) + fflush( stdout ); + + return ret; +} + +void +osm_log( + IN osm_log_t* const p_log, + IN const osm_log_level_t verbosity, + IN const char *p_str, ... ) +{ + char buffer[LOG_ENTRY_SIZE_MAX]; + va_list args; + int ret; + +#ifdef WIN32 + SYSTEMTIME st; + uint32_t pid = GetCurrentThreadId(); +#else + pid_t pid = 0; + time_t tim; + struct tm result; + uint64_t time_usecs; + uint32_t usecs; + + time_usecs = cl_get_time_stamp(); + tim = time_usecs/1000000; + usecs = time_usecs % 1000000; + localtime_r(&tim, &result); +#endif /* WIN32 */ + + /* If this is a call to syslog - always print it */ + if ( verbosity & (OSM_LOG_SYS | p_log->level) ) + { + va_start( args, p_str ); + vsprintf( buffer, p_str, args ); + va_end(args); + + /* this is a call to the syslog */ + if (verbosity & OSM_LOG_SYS) + { + cl_log_event("OpenSM", LOG_INFO, buffer , NULL, 0); + + /* SYSLOG should go to stdout too */ + if (p_log->out_port != stdout) + { + printf("%s\n", buffer); + fflush( stdout ); + } +#ifdef WIN32 + OsmReportState(buffer); +#endif /* WIN32 */ + } + + /* regular log to default out_port */ + cl_spinlock_acquire( &p_log->lock ); + + if (p_log->max_size && p_log->count > p_log->max_size) + { + /* truncate here */ + fprintf(stderr, "osm_log: log file exceeds the limit %lu. Truncating.\n", + p_log->max_size); + truncate_log_file(p_log); + } + +#ifdef WIN32 + GetLocalTime(&st); + _retry: + ret = fprintf( p_log->out_port, "[%02d:%02d:%02d:%03d][%04X] -> %s", + st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, + pid, buffer ); +#else + pid = pthread_self(); + _retry: + ret = fprintf( p_log->out_port, "%s %02d %02d:%02d:%02d %06d [%04X] -> %s", + (result.tm_mon < 12 ? month_str[result.tm_mon] : "???"), + result.tm_mday, result.tm_hour, + result.tm_min, result.tm_sec, + usecs, pid, buffer ); +#endif + + /* flush log */ + if (ret > 0 && (p_log->flush || (verbosity & OSM_LOG_ERROR)) && + fflush( p_log->out_port ) < 0) + ret = -1; + + if (ret >= 0) + { + log_exit_count = 0; + p_log->count += ret; + } + else if (log_exit_count < 3) + { + log_exit_count++; + if (errno == ENOSPC && p_log->max_size) { + fprintf(stderr, "osm_log: write failed: %s. Truncating log file.\n", + strerror(errno)); + truncate_log_file(p_log); + goto _retry; + } + fprintf(stderr, "osm_log: write failed: %s\n", strerror(errno)); + } + + cl_spinlock_release( &p_log->lock ); + } +} + +void +osm_log_raw( + IN osm_log_t* const p_log, + IN const osm_log_level_t verbosity, + IN const char *p_buf ) +{ + if( p_log->level & verbosity ) + { + cl_spinlock_acquire( &p_log->lock ); + printf( "%s", p_buf ); + cl_spinlock_release( &p_log->lock ); + + /* + Flush log on errors too. + */ + if( p_log->flush || (verbosity & OSM_LOG_ERROR) ) + fflush( stdout ); + } +} + +boolean_t +osm_is_debug(void) +{ +#if defined( _DEBUG_ ) + return TRUE; +#else + return FALSE; +#endif /* defined( _DEBUG_ ) */ +} + +ib_api_status_t +osm_log_init_v2( + IN osm_log_t* const p_log, + IN const boolean_t flush, + IN const uint8_t log_flags, + IN const char *log_file, + IN const unsigned long max_size, + IN const boolean_t accum_log_file ) +{ + struct stat st; + + p_log->level = log_flags; + p_log->flush = flush; + p_log->count = 0; + p_log->max_size = 0; + + 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 (accum_log_file) + p_log->out_port = fopen(log_file, "a+"); + else + p_log->out_port = fopen(log_file, "w+"); + + if (!p_log->out_port) + { + if (accum_log_file) + printf("Cannot open %s for appending. Permission denied\n", log_file); + else + printf("Cannot open %s for writing. Permission denied\n", log_file); + + return(IB_UNKNOWN_ERROR); + } + + if (fstat(fileno(p_log->out_port), &st) == 0) + p_log->count = st.st_size; + + p_log->max_size = max_size; + } + + openlog("OpenSM", LOG_CONS | LOG_PID, LOG_USER); + + if (cl_spinlock_init( &p_log->lock ) == CL_SUCCESS) + return IB_SUCCESS; + else + return IB_ERROR; +} + +ib_api_status_t +osm_log_init( + IN osm_log_t* const p_log, + IN const boolean_t flush, + IN const uint8_t log_flags, + IN const char *log_file, + IN const boolean_t accum_log_file ) +{ + return osm_log_init_v2( p_log, flush, log_flags, log_file, 0, accum_log_file ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/libopensm/osm_mad_pool.c b/branches/WOF2-1/ulp/opensm/user/libopensm/osm_mad_pool.c new file mode 100644 index 00000000..03ccd341 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/libopensm/osm_mad_pool.c @@ -0,0 +1,302 @@ +/* + * 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: + * 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#define OSM_MAD_POOL_MIN_SIZE 256 +#define OSM_MAD_POOL_GROW_SIZE 256 + + +/********************************************************************** + **********************************************************************/ +cl_status_t +__osm_mad_pool_ctor( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ) +{ + osm_madw_t *p_madw = p_object; + + UNUSED_PARAM( context ); + osm_madw_construct( p_madw ); + /* CHECK THIS. DOCS DON'T DESCRIBE THIS OUT PARAM. */ + *pp_pool_item = &p_madw->pool_item; + return( CL_SUCCESS ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mad_pool_construct( + IN osm_mad_pool_t* const p_pool ) +{ + CL_ASSERT( p_pool ); + + memset( p_pool, 0, sizeof(*p_pool) ); + cl_qlock_pool_construct( &p_pool->madw_pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mad_pool_destroy( + IN osm_mad_pool_t* const p_pool ) +{ + CL_ASSERT( p_pool ); + + /* HACK: we still rarely see some mads leaking - so ignore this */ + /* cl_qlock_pool_destroy( &p_pool->madw_pool ); */ +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mad_pool_init( + IN osm_mad_pool_t* const p_pool, + IN osm_log_t* const p_log ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_mad_pool_init ); + + p_pool->p_log = p_log; + + status = cl_qlock_pool_init( + &p_pool->madw_pool, + OSM_MAD_POOL_MIN_SIZE, + 0, + OSM_MAD_POOL_GROW_SIZE, + sizeof( osm_madw_t ), + __osm_mad_pool_ctor, + NULL, + p_pool ); + if( status != IB_SUCCESS ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_mad_pool_init: ERR 0702: " + "Grow pool initialization failed (%s)\n", + ib_get_err_str(status) ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +osm_madw_t* +osm_mad_pool_get( + IN osm_mad_pool_t* const p_pool, + IN osm_bind_handle_t h_bind, + IN const uint32_t total_size, + IN const osm_mad_addr_t* const p_mad_addr ) +{ + osm_madw_t *p_madw; + ib_mad_t *p_mad; + + OSM_LOG_ENTER( p_pool->p_log, osm_mad_pool_get ); + + CL_ASSERT( h_bind != OSM_BIND_INVALID_HANDLE ); + CL_ASSERT( total_size ); + + /* + First, acquire a mad wrapper from the mad wrapper pool. + */ + p_madw = (osm_madw_t*)cl_qlock_pool_get( &p_pool->madw_pool ); + if( p_madw == NULL ) + { + osm_log( p_pool->p_log, OSM_LOG_ERROR, + "osm_mad_pool_get: ERR 0703: " + "Unable to acquire MAD wrapper object\n" ); + 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 ) + { + osm_log( p_pool->p_log, OSM_LOG_ERROR, + "osm_mad_pool_get: ERR 0704: " + "Unable to acquire wire MAD\n" ); + + /* Don't leak wrappers! */ + cl_qlock_pool_put( &p_pool->madw_pool, (cl_pool_item_t*)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 ); + + osm_log( p_pool->p_log, OSM_LOG_DEBUG, + "osm_mad_pool_get: Acquired p_madw = %p, p_mad = %p, " + "size = %u\n", p_madw, p_madw->p_mad, total_size ); + + Exit: + OSM_LOG_EXIT( p_pool->p_log ); + return( p_madw ); +} + +/********************************************************************** + **********************************************************************/ +osm_madw_t* +osm_mad_pool_get_wrapper( + IN osm_mad_pool_t* const p_pool, + IN osm_bind_handle_t h_bind, + IN const uint32_t total_size, + IN const ib_mad_t* const p_mad, + IN const osm_mad_addr_t* const p_mad_addr ) +{ + osm_madw_t *p_madw; + + OSM_LOG_ENTER( p_pool->p_log, osm_mad_pool_get_wrapper ); + + 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 = (osm_madw_t*)cl_qlock_pool_get( &p_pool->madw_pool ); + if( p_madw == NULL ) + { + osm_log( p_pool->p_log, OSM_LOG_ERROR, + "osm_mad_pool_get_wrapper: ERR 0705: " + "Unable to acquire MAD wrapper object\n" ); + 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 ); + + osm_log( p_pool->p_log, OSM_LOG_DEBUG, + "osm_mad_pool_get_wrapper: Acquired p_madw = %p, p_mad = %p " + "size = %u\n", p_madw, p_madw->p_mad, total_size ); + + Exit: + OSM_LOG_EXIT( p_pool->p_log ); + return( p_madw ); +} + +/********************************************************************** + **********************************************************************/ +osm_madw_t* +osm_mad_pool_get_wrapper_raw( + IN osm_mad_pool_t* const p_pool ) +{ + osm_madw_t *p_madw; + + OSM_LOG_ENTER( p_pool->p_log, osm_mad_pool_get_wrapper_raw ); + + p_madw = (osm_madw_t*)cl_qlock_pool_get( &p_pool->madw_pool ); + + osm_log( p_pool->p_log, OSM_LOG_DEBUG, + "osm_mad_pool_get_wrapper_raw: " + "Getting p_madw = %p\n", p_madw ); + + osm_madw_init( p_madw, 0, 0, 0 ); + osm_madw_set_mad( p_madw, 0 ); + cl_atomic_inc( &p_pool->mads_out ); + + OSM_LOG_EXIT( p_pool->p_log ); + return( p_madw ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mad_pool_put( + IN osm_mad_pool_t* const p_pool, + IN osm_madw_t* const p_madw ) +{ + OSM_LOG_ENTER( p_pool->p_log, osm_mad_pool_put ); + + CL_ASSERT( p_madw ); + + osm_log( p_pool->p_log, OSM_LOG_DEBUG, + "osm_mad_pool_put: Releasing p_madw = %p, p_mad = %p\n", + p_madw, p_madw->p_mad ); + + /* + 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 + */ + cl_qlock_pool_put( &p_pool->madw_pool, (cl_pool_item_t*)p_madw ); + cl_atomic_dec( &p_pool->mads_out ); + + OSM_LOG_EXIT( p_pool->p_log ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/libvendor/Makefile b/branches/WOF2-1/ulp/opensm/user/libvendor/Makefile new file mode 100644 index 00000000..58189757 --- /dev/null +++ b/branches/WOF2-1/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 $(NTMAKEENV)\makefile.def diff --git a/branches/WOF2-1/ulp/opensm/user/libvendor/SOURCES b/branches/WOF2-1/ulp/opensm/user/libvendor/SOURCES new file mode 100644 index 00000000..66a35156 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/libvendor/SOURCES @@ -0,0 +1,60 @@ +!if $(FREEBUILD) +TARGETNAME=osmv_ibal +!else +TARGETNAME=osmv_ibald +!endif +TARGETTYPE=LIBRARY + +!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 + +USE_NTDLL=1 +USE_NATIVE_EH=1 +OVR_DIR=..\addon + + +SOURCES=\ + osm_vendor_al.c \ + osm_vendor_mlx_sa.c \ + winosm_common.c + +OSM_HOME=.. + +TARGETLIBS=\ +!if $(FREEBUILD) + $(LIBPATH)\*\ibal.lib \ + $(LIBPATH)\*\complib.lib +!else + $(LIBPATH)\*\ibald.lib \ + $(LIBPATH)\*\complibd.lib +!endif + +#DO NOT TOUCH the order of search path , until ib_types.h merging process will be done +INCLUDES= \ + $(OSM_HOME)\include; \ + $(OSM_HOME); \ + $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; + +# Could be any special flag needed for this project +USER_C_FLAGS=$(USER_C_FLAGS) +#Add preproccessor definitions +C_DEFINES=$(C_DEFINES) -DWIN32 -D__WIN__ -D__i386__ -Dinline=__inline -DMT_LITTLE_ENDIAN -DOSM_VENDOR_INTF_AL +C_DEFINES=$(C_DEFINES) -I.. -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 +#MSC_OPTIMIZATION= /O0 diff --git a/branches/WOF2-1/ulp/opensm/user/libvendor/osm_vendor_al.c b/branches/WOF2-1/ulp/opensm/user/libvendor/osm_vendor_al.c new file mode 100644 index 00000000..3cf3c080 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/libvendor/osm_vendor_al.c @@ -0,0 +1,1533 @@ +/* + * 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. + * 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: + * Linux User Mode + * + * $Revision: 1.8 $ + */ + +/* + Next available error code: 0x300 +*/ +#ifdef __WIN__ +/* Suppress all warning regarding casting void* to specific pointer object */ +#pragma warning(disable : 4305) +#endif + +#include + +#ifdef OSM_VENDOR_INTF_AL + +#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_al_ca_err_callback ); + + 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_al_ca_destroy_callback ); + + 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_al_err_callback ); + + 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, __osm_al_send_callback ); + 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 remove 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, + "__osm_al_send_callback: " + "Destroying av handle %p.\n", 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, + "__osm_al_send_callback: ERR 3333 " + " Mad Completed with WQE Error : %s.\n",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, + "__osm_al_send_callback: " + "The Mad is a response , thus handeled in __osm_al_send_callback\n"); + p_new_madw = p_vw->p_resp_madw; + p_bind->rcv_callback( p_new_madw, p_bind->client_context, + p_madw ); + + } + } + else + { + osm_log( p_vend->p_log, OSM_LOG_DEBUG, + "__osm_al_send_callback: " + "Returning MAD to pool, TID = 0x%" PRIx64 ".\n", + cl_ntoh64( p_mad->trans_id ) ); + osm_mad_pool_put( p_bind->p_osm_pool, p_madw ); + if ( status_elem != IB_SUCCESS ) + osm_log( p_vend->p_log, OSM_LOG_ERROR, + "__osm_al_send_callback: ERR 3b0b " + "request mad had failed.\n"); + goto Exit; + } + + + + + + Exit: + 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 expeceted) + ================|==============================================|======================================= + 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, __osm_al_rcv_callback ); + UNUSED_PARAM(h_mad_svc); + CL_ASSERT( p_elem->context1 == NULL ); + CL_ASSERT( p_elem->context2 == NULL ); + /* + osm_log( p_vend->p_log, OSM_LOG_VERBOSE, + "__osm_al_rcv_callback: " + "Handling Transaction : 0x%" PRIx64 " .\n", + cl_ntoh64(p_elem->p_mad_buf->trans_id)); + */ + p_new_mad = ib_get_mad_buf( p_elem ); + osm_log( p_vend->p_log, OSM_LOG_DEBUG, + "__osm_al_rcv_callback: " + "Acquired implicitly MAD %p.\n", 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 = p_elem->pkey_index; + mad_addr.addr_type.gsi.service_level = p_elem->remote_sl; + mad_addr.addr_type.gsi.global_route = FALSE; + } + + /* + If this MAD is a response to a previous request, + then grab our pre-allocated MAD wrapper. + Otherwise, allocate a new MAD wrapper. + 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, + "__osm_al_rcv_callback: " + "The Mad is a response , thus handeled in __osm_al_send_callback\n"); + 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); + goto Exit; + } + else + { + osm_log( p_vend->p_log, OSM_LOG_DEBUG, + "__osm_al_rcv_callback: " + "The Mad is a request , thus handeled in __osm_al_rcv_callback\n"); + 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) ); + } + + + Exit: + 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, osm_vendor_init ); + + p_vend->p_log = p_log; + + /* + Open our instance of AL. + */ + status = ib_open_al( &p_vend->h_al ); + if( status != IB_SUCCESS ) + { + osm_log( p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_init: ERR 3B03: " + "Error opening AL (%s).\n", + ib_get_err_str( status ) ); + + goto Exit; + } + + p_vend->timeout = timeout; + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +osm_vendor_t* +osm_vendor_new( + IN osm_log_t* const p_log, + IN const uint32_t timeout ) +{ + ib_api_status_t status; + osm_vendor_t *p_vend; + + OSM_LOG_ENTER( p_log, osm_vendor_new ); + + 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, __osm_ca_info_init ); + + 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 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 ) ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_vend->p_log ); + return( status ); +} + + +/********************************************************************** + **********************************************************************/ +void +osm_ca_info_destroy( + IN osm_vendor_t* const p_vend, + IN osm_ca_info_t* const p_ca_info ) +{ + OSM_LOG_ENTER( p_vend->p_log, osm_ca_info_destroy ); + + 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, osm_ca_info_new ); + + 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; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_vend->p_log ); + return( p_ca_info ); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_vendor_get_ca_guids( + IN osm_vendor_t* const p_vend, + IN ib_net64_t** const p_guids, + IN size_t* const p_num_guids ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_vend->p_log, __osm_vendor_get_ca_guids ); + + 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, osm_vendor_get_all_port_attr ); + + 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, osm_vendor_get_ca_guid ); + + 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, osm_vendor_get_port_num ); + + 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, __osm_vendor_open_ca ); + + 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, osm_vendor_bind ); + + 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; + mad_svc.method_array[IB_MAD_METHOD_GET] = TRUE; + mad_svc.method_array[IB_MAD_METHOD_SET] = TRUE; + mad_svc.method_array[IB_MAD_METHOD_DELETE] = TRUE; + mad_svc.method_array[IB_MAD_METHOD_TRAP] = TRUE; + mad_svc.method_array[IB_MAD_METHOD_GETTABLE] = TRUE; + + + status = ib_reg_mad_svc( + p_bind->h_qp, + &mad_svc, + &p_bind->h_svc ); + + if( status != IB_SUCCESS ) + { + 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_vendor_unbind ); + + 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, osm_vendor_get ); + + 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, osm_vendor_put ); + + CL_ASSERT( p_vw ); + CL_ASSERT( p_vw->p_elem ); + CL_ASSERT( p_vw->h_bind == h_bind ); + + if( osm_log_get_level( p_vend->p_log ) >= OSM_LOG_DEBUG ) + { + + osm_log( p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_put: " + "Retiring MAD %p.\n", ib_get_mad_buf( p_vw->p_elem ) ); + // "Retiring MAD %p.\n", p_mad); + } + + 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, osm_vendor_send ); + + 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, + "__osm_al_send: " + "Destroying av handle %p.\n", 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 ); + /* 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; + } + + 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_vendor_local_lid_change ); + + 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, osm_vendor_set_sm ); + + 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 ); +} + +#endif /* OSM_VENDOR_INTF_AL */ diff --git a/branches/WOF2-1/ulp/opensm/user/libvendor/osm_vendor_mlx_sa.c b/branches/WOF2-1/ulp/opensm/user/libvendor/osm_vendor_mlx_sa.c new file mode 100644 index 00000000..ed123c67 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/libvendor/osm_vendor_mlx_sa.c @@ -0,0 +1,879 @@ +/* + * 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$ + */ + + + + +#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; + 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, __osmv_sa_mad_rcv_cb ); + + 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 */ + query_res.result_cnt = + (uintn_t) + ( ( p_madw->mad_size - IB_SA_MAD_HDR_SIZE ) / + ib_get_attr_size( p_sa_mad->attr_offset ) ); + osm_log( p_bind->p_log, OSM_LOG_DEBUG, + "__osmv_sa_mad_rcv_cb: Count = %u = %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, __osmv_sa_mad_err_cb ); + + /* 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, __osmv_get_lid_and_sm_lid_by_port_guid ); + + /* 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_nump_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, osmv_bind_sa ); + + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_bind_sa: " + "Binding to port 0x%" PRIx64 ".\n", + cl_ntoh64( port_guid ) ); + + bind_info.port_guid = port_guid; + bind_info.mad_class = IB_MCLASS_SUBN_ADM; + bind_info.class_version = 2; + bind_info.is_responder = TRUE; + bind_info.is_trap_processor = FALSE; + bind_info.is_report_processor = TRUE; + bind_info.send_q_size = 256; + bind_info.recv_q_size = 256; + + /* allocate the new sa bind info */ + p_sa_bind_info = + (osmv_sa_bind_info_t *)malloc(sizeof(osmv_sa_bind_info_t)); + if (! p_sa_bind_info) + { + osm_log( p_log, OSM_LOG_ERROR, + "osmv_bind_sa: ERR 0505: " + "Fail to allocate new bidn structure\n" ); + p_sa_bind_info = OSM_BIND_INVALID_HANDLE; + goto Exit; + } + + /* store some important context */ + p_sa_bind_info->p_log = p_log; + p_sa_bind_info->port_guid = port_guid; + p_sa_bind_info->p_mad_pool = p_mad_pool; + p_sa_bind_info->p_vendor = p_vend; + p_sa_bind_info->last_lids_update_sec = 0; + + /* Bind to the lower level */ + p_sa_bind_info->h_bind = + osm_vendor_bind( p_vend, + &bind_info, + p_mad_pool, + __osmv_sa_mad_rcv_cb, + __osmv_sa_mad_err_cb, + p_sa_bind_info); /* context provided to CBs */ + + if (p_sa_bind_info->h_bind == OSM_BIND_INVALID_HANDLE) + { + free(p_sa_bind_info); + p_sa_bind_info = OSM_BIND_INVALID_HANDLE; + osm_log( p_log, OSM_LOG_ERROR, + "osmv_bind_sa: ERR 0506: " + "Fail to bind to vendor SMI.\n" ); + goto Exit; + } + + /* obtain the sm_lid from the vendor */ + status = + __osmv_get_lid_and_sm_lid_by_port_guid( + p_vend, port_guid, + &p_sa_bind_info->last_lids_update_sec, + &p_sa_bind_info->lid, + &p_sa_bind_info->sm_lid); + if (status != IB_SUCCESS) + { + free(p_sa_bind_info); + p_sa_bind_info = OSM_BIND_INVALID_HANDLE; + osm_log( p_log, OSM_LOG_ERROR, + "osmv_bind_sa: ERR 0507: " + "Fail to obtain the sm lid.\n" ); + goto Exit; + } + + /* initialize the sync_event */ + cl_event_construct( &p_sa_bind_info->sync_event ); + cl_status = cl_event_init( &p_sa_bind_info->sync_event, TRUE ); + if( cl_status != CL_SUCCESS ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osmv_bind_sa: ERR 0508: " + "cl_init_event failed: %s\n", + ib_get_err_str(cl_status) + ); + free(p_sa_bind_info); + p_sa_bind_info = OSM_BIND_INVALID_HANDLE; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return ( p_sa_bind_info ); +} + +/***************************************************************************** + *****************************************************************************/ + +/****t* OSM Vendor SA Client/osmv_sa_mad_data + * NAME + * osmv_sa_mad_data + * + * DESCRIPTION + * Extra fields required to perform a mad query + * This struct is passed to the actual send method + * + * SYNOPSIS + */ +typedef struct _osmv_sa_mad_data +{ + /* MAD data. */ + uint8_t method; + ib_net16_t attr_id; + ib_net16_t attr_offset; + ib_net32_t attr_mod; + ib_net64_t comp_mask; + void *p_attr; +} osmv_sa_mad_data_t; +/* + * method + * The method of the mad to be sent + * + * attr_id + * Attribute ID + * + * attr_offset + * Offset as defined by RMPP + * + * attr_mod + * Attribute modifier + * + * comp_mask + * The component mask of the query + * + * p_attr + * A pointer to the record of the attribute to be sent. + * + *****/ + +/***************************************************************************** + *****************************************************************************/ +/* Send a MAD out on the GSI interface */ +ib_api_status_t +__osmv_send_sa_req( + IN osmv_sa_bind_info_t* p_bind, + IN const osmv_sa_mad_data_t * const p_sa_mad_data, + IN const osmv_query_req_t * const p_query_req ) +{ + ib_api_status_t status; + ib_mad_t *p_mad_hdr; + ib_sa_mad_t *p_sa_mad; + osm_madw_t *p_madw; + osm_log_t *p_log = p_bind->p_log; + static atomic32_t trans_id; + boolean_t sync; + osmv_query_req_t *p_query_req_copy; + + OSM_LOG_ENTER( p_log, __osmv_send_sa_req ); + + /* + 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 = IB_DEFAULT_PKEY; + p_madw->resp_expected = TRUE; + p_madw->fail_msg = CL_DISP_MSGID_NONE; + + /* + Provide MAD context such that the call back will know what to do. + We have to keep the entire request structure so we know the CB. + Since we can not rely on the client to keep it arroud until + the response - we duplicate it and will later dispose it (in CB). + To store on the MADW we cast it into what opensm has: + p_madw->context.arb_context.context1 + */ + p_query_req_copy = malloc(sizeof(*p_query_req_copy)); + *p_query_req_copy = *p_query_req; + p_madw->context.arb_context.context1 = p_query_req_copy; + + /* we can support async as well as sync calls */ + sync = ((p_query_req->flags & OSM_SA_FLAGS_SYNC) == OSM_SA_FLAGS_SYNC); + + /* send the mad asynchronously */ + status = osm_vendor_send( + osm_madw_get_bind_handle( p_madw ), + p_madw, + p_madw->resp_expected ); + + /* if synchronous - wait on the event */ + if (sync) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__osmv_send_sa_req: " + "Waiting for async event.\n" ); + cl_event_wait_on( &p_bind->sync_event, EVENT_NO_TIMEOUT, FALSE ); + cl_event_reset(&p_bind->sync_event); + status = p_madw->status; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return status; +} + +/***************************************************************************** + *****************************************************************************/ +/* + * Query the SA based on the user's request. + */ +ib_api_status_t +osmv_query_sa( + IN osm_bind_handle_t h_bind, + IN const osmv_query_req_t * const p_query_req + ) +{ + osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *)h_bind; + osmv_sa_mad_data_t sa_mad_data; + osmv_user_query_t *p_user_query; + ib_service_record_t svc_rec; + ib_node_record_t node_rec; + ib_portinfo_record_t port_info; + ib_path_rec_t path_rec; + ib_class_port_info_t class_port_info; + osm_log_t *p_log = p_bind->p_log; + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osmv_query_sa ); + + /* Set the request information. */ + sa_mad_data.method = IB_MAD_METHOD_GETTABLE; + sa_mad_data.attr_mod = 0; + + /* Set the MAD attributes and component mask correctly. */ + switch ( p_query_req->query_type ) + { + + case OSMV_QUERY_USER_DEFINED: + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "USER_DEFINED\n" ); + p_user_query = ( osmv_user_query_t * ) p_query_req->p_query_input; + if (p_user_query->method) sa_mad_data.method = p_user_query->method; + sa_mad_data.attr_offset = p_user_query->attr_offset; + sa_mad_data.attr_id = p_user_query->attr_id; + sa_mad_data.attr_mod = p_user_query->attr_mod; + sa_mad_data.comp_mask = p_user_query->comp_mask; + sa_mad_data.p_attr = p_user_query->p_attr; +#if (0) +#ifdef OSM_VENDOR_INTF_AL + /* HACK for OFED OSM: convert lid order from network to + host for IB_MAD_ATTR_PORTINFO_RECORD */ + if ( (sa_mad_data.attr_id == IB_MAD_ATTR_PORTINFO_RECORD) && + (sa_mad_data.comp_mask & IB_PIR_COMPMASK_LID)) + { + ib_portinfo_record_t * p_pir = (ib_portinfo_record_t *)sa_mad_data.p_attr; + p_pir->lid = cl_ntoh16(p_pir->lid); + } +#endif +#endif + break; + + case OSMV_QUERY_ALL_SVC_RECS: + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "SVC_REC_BY_NAME\n" ); + sa_mad_data.method = IB_MAD_METHOD_GETTABLE; + sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_service_record_t ) ); + sa_mad_data.comp_mask = 0; + sa_mad_data.p_attr = &svc_rec; + break; + + case OSMV_QUERY_SVC_REC_BY_NAME: + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "SVC_REC_BY_NAME\n" ); + sa_mad_data.method = IB_MAD_METHOD_GET; + sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_mad_data.comp_mask = IB_SR_COMPMASK_SNAME; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_service_record_t ) ); + sa_mad_data.p_attr = &svc_rec; + memcpy( svc_rec.service_name, p_query_req->p_query_input, + sizeof( ib_svc_name_t ) ); + break; + + case OSMV_QUERY_SVC_REC_BY_ID: + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "SVC_REC_BY_ID\n" ); + sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_mad_data.comp_mask = IB_SR_COMPMASK_SID; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_service_record_t ) ); + sa_mad_data.p_attr = &svc_rec; + svc_rec.service_id = *( ib_net64_t * ) ( p_query_req->p_query_input ); + break; + + case OSMV_QUERY_CLASS_PORT_INFO: + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s","CLASS_PORT_INFO\n" ); + sa_mad_data.method = IB_MAD_METHOD_GET; + sa_mad_data.attr_id = IB_MAD_ATTR_CLASS_PORT_INFO; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_class_port_info_t ) ); + sa_mad_data.comp_mask = 0; + sa_mad_data.p_attr = &class_port_info; + + break; + + case OSMV_QUERY_NODE_REC_BY_NODE_GUID: + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s","NODE_REC_BY_NODE_GUID\n" ); + sa_mad_data.method = IB_MAD_METHOD_GETTABLE; + sa_mad_data.attr_id = IB_MAD_ATTR_NODE_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_node_record_t ) ); + sa_mad_data.comp_mask = IB_NR_COMPMASK_NODEGUID; + sa_mad_data.p_attr = &node_rec; + node_rec.node_info.node_guid = + *( ib_net64_t * ) ( p_query_req->p_query_input ); + + break; + + case OSMV_QUERY_PORT_REC_BY_LID: + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s","PORT_REC_BY_LID\n" ); + sa_mad_data.attr_id = IB_MAD_ATTR_PORTINFO_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_portinfo_record_t ) ); + sa_mad_data.comp_mask = IB_PIR_COMPMASK_LID; + sa_mad_data.p_attr = &port_info; + port_info.lid = *( ib_net16_t * ) ( p_query_req->p_query_input ); + break; + + case OSMV_QUERY_PORT_REC_BY_LID_AND_NUM: + sa_mad_data.method = IB_MAD_METHOD_GET; + p_user_query = ( osmv_user_query_t * ) p_query_req->p_query_input; + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s","PORT_REC_BY_LID_AND_NUM\n" ); + sa_mad_data.attr_id = IB_MAD_ATTR_PORTINFO_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_portinfo_record_t ) ); + sa_mad_data.comp_mask = IB_PIR_COMPMASK_LID | IB_PIR_COMPMASK_PORTNUM; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK: + sa_mad_data.method = IB_MAD_METHOD_GET; + p_user_query = ( osmv_user_query_t * ) p_query_req->p_query_input; + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s","OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK\n" ); + sa_mad_data.attr_id = IB_MAD_ATTR_VLARB_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_vl_arb_table_record_t ) ); + sa_mad_data.comp_mask = IB_VLA_COMPMASK_LID | IB_VLA_COMPMASK_OUT_PORT | IB_VLA_COMPMASK_BLOCK; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_SLVL_BY_LID_AND_PORTS: + sa_mad_data.method = IB_MAD_METHOD_GET; + p_user_query = ( osmv_user_query_t * ) p_query_req->p_query_input; + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s","OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK\n" ); + sa_mad_data.attr_id = IB_MAD_ATTR_SLVL_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_slvl_table_record_t ) ); + sa_mad_data.comp_mask = IB_SLVL_COMPMASK_LID | IB_SLVL_COMPMASK_OUT_PORT | IB_SLVL_COMPMASK_IN_PORT; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_PATH_REC_BY_PORT_GUIDS: + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s","PATH_REC_BY_PORT_GUIDS\n" ); + memset(&path_rec, 0, sizeof(ib_path_rec_t )); + sa_mad_data.attr_id = IB_MAD_ATTR_PATH_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_path_rec_t ) ); + sa_mad_data.comp_mask = ( IB_PR_COMPMASK_DGID | IB_PR_COMPMASK_SGID ); + sa_mad_data.p_attr = &path_rec; + ib_gid_set_default( &path_rec.dgid, + ( ( osmv_guid_pair_t * ) ( p_query_req-> + p_query_input ) )-> + dest_guid ); + ib_gid_set_default( &path_rec.sgid, + ( ( osmv_guid_pair_t * ) ( p_query_req-> + p_query_input ) )-> + src_guid ); + break; + + case OSMV_QUERY_PATH_REC_BY_GIDS: + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s","PATH_REC_BY_GIDS\n" ); + memset(&path_rec, 0, sizeof(ib_path_rec_t )); + sa_mad_data.attr_id = IB_MAD_ATTR_PATH_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_path_rec_t ) ); + sa_mad_data.comp_mask = ( IB_PR_COMPMASK_DGID | IB_PR_COMPMASK_SGID ); + sa_mad_data.p_attr = &path_rec; + memcpy( &path_rec.dgid, + &( ( osmv_gid_pair_t * ) ( p_query_req->p_query_input ) )-> + dest_gid, sizeof( ib_gid_t ) ); + memcpy( &path_rec.sgid, + &( ( osmv_gid_pair_t * ) ( p_query_req->p_query_input ) )-> + src_gid, sizeof( ib_gid_t ) ); + break; + + case OSMV_QUERY_PATH_REC_BY_LIDS: + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s","PATH_REC_BY_LIDS\n" ); + memset(&path_rec, 0, sizeof(ib_path_rec_t )); + sa_mad_data.method = IB_MAD_METHOD_GET; + sa_mad_data.attr_id = IB_MAD_ATTR_PATH_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_path_rec_t ) ); + sa_mad_data.comp_mask = ( IB_PR_COMPMASK_DLID | IB_PR_COMPMASK_SLID ); + sa_mad_data.p_attr = &path_rec; + path_rec.dlid = + ( ( osmv_lid_pair_t * ) ( p_query_req->p_query_input ) )->dest_lid; + path_rec.slid = + ( ( osmv_lid_pair_t * ) ( p_query_req->p_query_input ) )->src_lid; + break; + + case OSMV_QUERY_UD_MULTICAST_SET: + sa_mad_data.method = IB_MAD_METHOD_SET; + p_user_query = ( osmv_user_query_t * ) p_query_req->p_query_input; + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s","OSMV_QUERY_UD_MULTICAST_SET\n" ); + sa_mad_data.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_member_rec_t ) ); + sa_mad_data.comp_mask = p_user_query->comp_mask; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_UD_MULTICAST_DELETE: + sa_mad_data.method = IB_MAD_METHOD_DELETE; + p_user_query = ( osmv_user_query_t * ) p_query_req->p_query_input; + osm_log( p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s","OSMV_QUERY_UD_MULTICAST_DELETE\n" ); + sa_mad_data.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset( sizeof( ib_member_rec_t ) ); + sa_mad_data.comp_mask = p_user_query->comp_mask; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + default: + osm_log( p_log, OSM_LOG_ERROR, + "osmv_query_sa DBG:001 %s","UNKNOWN\n" ); + CL_ASSERT( 0 ); + return IB_ERROR; + } + + status = __osmv_send_sa_req( h_bind, &sa_mad_data, p_query_req ); + + OSM_LOG_EXIT( p_log ); + return status; +} + + +/***************************************************************************** + *****************************************************************************/ + + + diff --git a/branches/WOF2-1/ulp/opensm/user/libvendor/winosm_common.c b/branches/WOF2-1/ulp/opensm/user/libvendor/winosm_common.c new file mode 100644 index 00000000..361d2c00 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/libvendor/winosm_common.c @@ -0,0 +1,249 @@ +#include +#include +#include +#include + +int optind=1; +int opterr=1; +int optopt='?'; +int iArg=1; + +char* +GetOsmTempPath(void) +{ + char* temp_path; + int length; + temp_path = (char*)cl_malloc(OSM_MAX_LOG_NAME_SIZE); + 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 = (char*)cl_malloc(OSM_MAX_LOG_NAME_SIZE); + 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; +} + +/****************************************************************************/ +int getopt_long_only(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-1/ulp/opensm/user/opensm/Makefile b/branches/WOF2-1/ulp/opensm/user/opensm/Makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/opensm/user/opensm/SOURCES b/branches/WOF2-1/ulp/opensm/user/opensm/SOURCES new file mode 100644 index 00000000..dd38a9b0 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/SOURCES @@ -0,0 +1,62 @@ +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=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) +!endif + +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 +SOURCES=\ + osm.mc \ + opensm.rc \ + osm_files.c\ + osm_drop_mgr.c\ + osm_prtn_config.c\ + osm_sa_mcmember_record.c\ + osm_sa_path_record.c\ + +OSM_HOME=.. + +TARGETLIBS=\ +!if $(FREEBUILD) + $(LIBPATH)\*\ibal.lib \ + $(LIBPATH)\*\complib.lib \ + $(TARGETPATH)\*\osmv_ibal.lib \ + $(TARGETPATH)\*\opensm_ibal.lib + +!else + $(LIBPATH)\*\ibald.lib \ + $(LIBPATH)\*\complibd.lib \ + $(TARGETPATH)\*\osmv_ibald.lib \ + $(TARGETPATH)\*\opensm_ibald.lib +!endif + +#DO NOT TOUCH the order of search path , until ib_types.h merging process will be done +INCLUDES= \ + $(OSM_HOME)\include; \ + $(OSM_HOME); \ + $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; + +# Could be any special flag needed for this project +USER_C_FLAGS=$(USER_C_FLAGS) /MD +#Add preproccessor definitions +C_DEFINES=$(C_DEFINES) -DWIN32 -D__WIN__ -D__i386__ -Dinline=__inline -DMT_LITTLE_ENDIAN -DOSM_VENDOR_INTF_AL +C_DEFINES=$(C_DEFINES) -I.. -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 +#MSC_OPTIMIZATION= /O0 diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/cl_dispatcher.c b/branches/WOF2-1/ulp/opensm/user/opensm/cl_dispatcher.c new file mode 100644 index 00000000..dd2f78f6 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/cl_dispatcher.c @@ -0,0 +1,405 @@ +/* + * 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: + * Implementation of Dispatcher abstraction. + * + * Environment: + * All + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#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_thread_pool_construct( &p_disp->worker_threads ); + 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-1/ulp/opensm/user/opensm/cl_event_wheel.c b/branches/WOF2-1/ulp/opensm/user/opensm/cl_event_wheel.c new file mode 100644 index 00000000..a4ec7aa5 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/cl_event_wheel.c @@ -0,0 +1,663 @@ +/* + * 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$ + */ + + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +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; +} + +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; + + OSM_LOG_ENTER( p_event_wheel->p_log, __cl_event_wheel_callback); + + /* might be during closing ... */ + if (p_event_wheel->closing) + { + goto JustExit; + } + + 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); + osm_log (p_event_wheel->p_log, OSM_LOG_DEBUG, + "__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) + { + osm_log (p_event_wheel->p_log, OSM_LOG_ERROR, + "__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); + } + JustExit: + OSM_LOG_EXIT( p_event_wheel->p_log ); +} + +/* + * 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, + IN osm_log_t *p_log) +{ + cl_status_t cl_status = CL_SUCCESS; + + OSM_LOG_ENTER( p_log, cl_event_wheel_init ); + + /* initialize */ + p_event_wheel->p_log = p_log; + 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) + { + osm_log (p_event_wheel->p_log, OSM_LOG_ERROR, + "cl_event_wheel_init : ERR 6101: " + "Failed to initialize cl_spinlock\n" ); + goto Exit; + } + 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 */ + + if (cl_status != CL_SUCCESS) + { + osm_log (p_event_wheel->p_log, OSM_LOG_ERROR, + "cl_event_wheel_init : ERR 6102: " + "Failed to initialize cl_timer\n" ); + goto Exit; + } + Exit: + OSM_LOG_EXIT( p_event_wheel->p_log ); + return(cl_status); +} + +cl_status_t +cl_event_wheel_init_ex( + IN cl_event_wheel_t* const p_event_wheel, + IN osm_log_t *p_log, + IN cl_spinlock_t *p_external_lock) +{ + cl_status_t cl_status; + + cl_status = cl_event_wheel_init(p_event_wheel, p_log); + 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; + + OSM_LOG_ENTER( p_event_wheel->p_log, cl_event_wheel_dump ); + + p_list_item = cl_qlist_head(&p_event_wheel->events_wheel); + osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG, + "cl_event_wheel_dump: " + "event_wheel ptr:%p\n", + p_event_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); + osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG, + "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 ); + } + OSM_LOG_EXIT( p_event_wheel->p_log ); +} + +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; + + OSM_LOG_ENTER( p_event_wheel->p_log, cl_event_wheel_destroy ); + + /* 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); + + osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG, + "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) ); + + OSM_LOG_EXIT( p_event_wheel->p_log ); +} + +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; + + OSM_LOG_ENTER( p_event_wheel->p_log, cl_event_wheel_reg ); + + /* 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 )) + { + osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG, + "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++; + + osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG, + "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 */ + osm_log (p_event_wheel->p_log, OSM_LOG_INFO, + "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) + { + osm_log (p_event_wheel->p_log, OSM_LOG_ERROR, + "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 ); + OSM_LOG_EXIT( p_event_wheel->p_log ); + + 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; + + OSM_LOG_ENTER( p_event_wheel->p_log, cl_event_wheel_unreg ); + + osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG, + "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) ); + + osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG, + "cl_event_wheel_unreg: " + "Removed key:0x%"PRIx64"\n", key ); + + /* free the item */ + free(p_event); + } + else + { + osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG, + "cl_event_wheel_unreg: " + "Did not find key:0x%"PRIx64"\n", key ); + } + + CL_SPINLOCK_RELEASE( &p_event_wheel->lock ); + OSM_LOG_EXIT( p_event_wheel->p_log ); + +} + +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; + + OSM_LOG_ENTER( p_event_wheel->p_log, cl_event_wheel_num_regs ); + + /* try to find the key in the map */ + osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG, + "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 ); + OSM_LOG_EXIT( p_event_wheel->p_log ); + 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" Conetxt:%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" Conetxt:%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" Conetxt:%s\n", key, (char *)context); +} + +int +main () +{ + osm_log_t log; + cl_event_wheel_t event_wheel; + /* uint64_t key; */ + + /* construct */ + osm_log_construct( &log ); + cl_event_wheel_construct( &event_wheel ); + + /* init */ + osm_log_init_v2( &log, TRUE, 0xff, NULL, 0, FALSE); + cl_event_wheel_init( &event_wheel, &log ); + + /* 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 Registred: %u\n", cl_event_wheel_num_regs(&event_wheel, 1)); + printf("Event 2 Registred: %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-1/ulp/opensm/user/opensm/main.c b/branches/WOF2-1/ulp/opensm/user/opensm/main.c new file mode 100644 index 00000000..77552a63 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/main.c @@ -0,0 +1,1158 @@ +/* + * 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 the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF 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 opensm. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.23 $ + */ +#pragma warning(disable : 4996) + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include "stdio.h" +#include +#include +#include +#include +#include +#include +#include + +/******************************************************************** + 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 opensm object. + One opensm object is required per subnet. + Future versions could support multiple subnets by + instantiating more than one opensm object. +*/ +osm_opensm_t osm; +volatile unsigned int osm_exit_flag = 0; +HANDLE osm_exit_event = NULL; + +#define GUID_ARRAY_SIZE 64 +#define INVALID_GUID (0xFFFFFFFFFFFFFFFFULL) + +typedef struct _osm_main_args_t +{ + int argc; + char** argv; + boolean_t is_service; +} osm_main_args_t; + +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; + +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") ) + { + InterlockedCompareExchange((LONG *)&g_service_state , SERVICE_STATE_STARTED_OK, SERVICE_STATE_STARTING); + return; + } + + if ( !strcmp(p_str, "Found remote SM with non-matching sm_key. Exiting\n") || + !strcmp(p_str, "Errors on subnet. Duplicate GUID found ""by link from a port to itself. ""See osm log for more details\n") || + !strcmp(p_str, "Errors on subnet. SM found duplicated guids or 12x ""link with lane reversal badly configured. ""See osm log for more details\n") || + !strcmp(p_str, "Fatal: Error restoring Guid-to-Lid persistent database\n") ) + + { + InterlockedCompareExchange((LONG *)&g_service_state , SERVICE_STATE_START_FAILED, SERVICE_STATE_STARTING); + return; + } + + if( !strcmp(p_str, "OpenSM Rev:openib-1.2.0\n") || + !strcmp(p_str, "OpenSM Rev:openib-2.0.3\n") || + !strcmp(p_str, "OpenSM Rev:openib-3.0.0\n") || + !strcmp(p_str, "Entering MASTER state\n") || + !strcmp(p_str, "Exiting SM\n") ) + { + // This are messages that it is safe to ignore + return; + } + CL_ASSERT(FALSE); + +} + +/********************************************************************** + **********************************************************************/ +void show_usage(void); + +void +show_usage(void) +{ + printf( "\n------- OpenSM - Usage and options ----------------------\n" ); + printf( "Usage: opensm [options]\n"); + printf( "Options:\n" ); + printf( "-c\n" + "--cache-options\n" + " Cache the given command line options into the file\n" + " /var/cache/osm/opensm.opts for use next invocation\n" + " The cache directory can be changed by the environment\n" + " variable OSM_CACHE_DIR\n\n"); + printf( "-g[=]\n" + "--guid[=]\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( "-l \n" + "--lmc \n" + " This option specifies the subnet's LMC value.\n" + " The number of LIDs assigned to each port is 2^LMC.\n" + " The LMC value must be in the range 0-7.\n" + " LMC values > 0 allow multiple paths between ports.\n" + " LMC values > 0 should only be used if the subnet\n" + " topology actually provides multiple paths between\n" + " ports, i.e. multiple interconnects between switches.\n" + " Without -l, OpenSM defaults to LMC = 0, which allows\n" + " one path between any two ports.\n\n" ); + printf( "-p \n" + "--priority \n" + " This option specifies the SM's PRIORITY.\n" + " This will effect the handover cases, where master\n" + " is chosen by priority and GUID.\n\n" ); + printf( "-smkey \n" + " This option specifies the SM's SM_Key (64 bits).\n" + " This will effect SM authentication.\n\n" ); + printf( "-r\n" + "--reassign_lids\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( "-R\n" + "--routing_engine \n" + " This option chooses routing engine instead of Min Hop\n" + " algorithm (default). Supported engines: updn, file\n\n"); + printf( "-U\n" + "--ucast_file \n" + " This option specifies name of the unicast dump file\n" + " from where switch forwarding tables will be loaded.\n\n"); + printf ("-a\n" + "--add_guid_file \n" + " Set the root nodes for the Up/Down routing algorithm\n" + " to the guids provided in the given file (one to a line)\n" + "\n"); + printf( "-o\n" + "--once\n" + " This option causes OpenSM to configure the subnet\n" + " once, then exit. Ports remain in the ACTIVE state.\n\n" ); + printf( "-s \n" + "--sweep \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( "-t \n" + "--timeout \n" + " This option specifies the time in milliseconds\n" + " used for transaction timeouts.\n" + " Specifying -t 0 disables timeouts.\n" + " Without -t, OpenSM defaults to a timeout value of\n" + " 200 milliseconds.\n\n" ); + printf( "-maxsmps \n" + " 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( "-i \n" + "-ignore-guids \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( "-x\n" + "--honor_guid2lid\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( "-f\n" + "--log_file\n" + " This option defines the log to be the given file.\n" + " By default, the log goes to %temp%/log/osm.log.\n" + " For the log to go to standard output use -f stdout.\n\n"); + printf( "-e\n" + "--erase_log_file\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( "-P\n" + "--Pconfig\n" + " This option defines the optional partition configuration file.\n" + " The default name is '%s'.\n\n", OSM_DEFAULT_PARTITION_CONFIG_FILE); + printf( "-Q\n" + "--no_qos\n" + " This option disables QoS setup.\n\n"); + printf( "-N\n" + "--no_part_enforce\n" + " This option disables partition enforcement on switch external ports.\n\n"); + printf( "-y\n" + "--stay_on_fatal\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( "-v\n" + "--verbose\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\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 \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( "-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 - 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( "-h\n" + "--help\n" + " Display this usage info then exit.\n\n" ); + printf( "-?\n" + " Display this usage info then exit.\n\n" ); + fflush( stdout ); + osm_exit_flag = TRUE; +} + +/********************************************************************** + **********************************************************************/ +void show_menu(void); + +void +show_menu(void) +{ + printf("\n------- Interactive Menu -------\n"); + printf("X - Exit.\n\n"); +} + +/********************************************************************** + **********************************************************************/ +ib_net64_t +get_port_guid( + IN osm_opensm_t *p_osm, uint64_t port_guid, + IN boolean_t is_service) +{ + uint32_t i; + uint32_t choice = 0; + char junk[128]; + boolean_t done_flag = FALSE; + ib_api_status_t status; + uint32_t num_ports = GUID_ARRAY_SIZE; + ib_port_attr_t attr_array[GUID_ARRAY_SIZE]; + + /* + 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 defined ( OSM_VENDOR_INTF_OPENIB ) + /* If port_guid is 0, and this is gen2 - use the default port whose info is in attr_array[0] */ + if ( port_guid == 0 ) + { + printf("Using default GUID 0x%" PRIx64 "\n", cl_hton64(attr_array[0].port_guid)); + return( attr_array[0].port_guid ); + } +#endif /* OSM_VENDOR_INTF_OPENIB */ + + /* If port_guid is 0, and we are in windows - find the first port with link_state != DOWN and + use it as default port. */ + if ( port_guid == 0 ) + { + for ( i = 0; i < num_ports; i++ ) + { + if (attr_array[i].link_state > IB_LINK_DOWN) + { + /* Use this port */ + printf("Using default guid 0x%" PRIx64 "\n", cl_hton64(attr_array[i].port_guid)); + return( attr_array[i].port_guid ); + } + } + /* If we are running as a service, and all ports are doen we return the + first port (we can't open a window, as a service)*/ + if (is_service) { + return( attr_array[0].port_guid ); + } + } + + /* More than one possible port - list all ports and let the user to choose. */ + while( done_flag == FALSE ) + { + printf( "\nChoose a local port number with which to bind:\n\n" ); + /* If this is gen2 code - then port 0 has details of the default port used. + no need to print it. + If this is not gen2 code - need to print details of all ports. */ +#if defined ( OSM_VENDOR_INTF_OPENIB ) + for( i = 1; i < num_ports; i++ ) + { + printf("\t%u: GUID = 0x%8" PRIx64 ", lid = 0x%04X, state = %s\n", + i, cl_ntoh64( attr_array[i].port_guid ), + attr_array[i].lid, + ib_get_port_state_str( attr_array[i].link_state ) ); + } + printf( "\nEnter choice (1-%u): ", i-1 ); +# else + for( i = 0; i < num_ports; i++ ) + { + /* + Print the index + 1 since by convention, port numbers + start with 1 on host channel adapters. + */ + + printf("\t%u: GUID = 0x%8" PRIx64 ", lid = 0x%04X, state = %s\n", + i+1, cl_ntoh64( attr_array[i].port_guid ), + attr_array[i].lid, + ib_get_port_state_str( attr_array[i].link_state ) ); + } + printf( "\nEnter choice (1-%u): ", i ); +#endif /* OSM_VENDOR_INTF_OPENIB */ + + fflush( stdout ); + if (scanf( "%u", &choice )) + { + /* If gen2 code - choice can be between 1 to num_ports-1 + if not gen2 code - choice can be between 1 to num_ports */ +#if defined ( OSM_VENDOR_INTF_OPENIB ) + if( choice >= num_ports ) +# else + if( choice > num_ports || choice < 1 ) +#endif /* OSM_VENDOR_INTF_OPENIB */ + { + printf("\nError: Lame choice!\n"); + fflush( stdin ); + } + else + { + done_flag = TRUE; + } + } + else + { + /* get rid of the junk in the selection line */ + scanf( "%s", junk ); + printf("\nError: Lame choice!\n"); + fflush( stdin ); + } + } +#if defined ( OSM_VENDOR_INTF_OPENIB ) + printf("Choice guid=0x%8" PRIx64 "\n", cl_ntoh64( attr_array[choice].port_guid )); + return( attr_array[choice].port_guid ); +# else + return( attr_array[choice - 1].port_guid ); +#endif /* OSM_VENDOR_INTF_OPENIB */ +} + +/********************************************************************** + **********************************************************************/ +#define OSM_MAX_IGNORE_GUID_LINES_LEN 128 +int +parse_ignore_guids_file(IN char *guids_file_name, + IN osm_opensm_t *p_osm) +{ + FILE *fh; + char line[OSM_MAX_IGNORE_GUID_LINES_LEN]; + char *p_c, *p_ec; + uint32_t line_num = 0; + uint64_t port_guid; + ib_api_status_t status = IB_SUCCESS; + unsigned int port_num; + + OSM_LOG_ENTER( &p_osm->log, parse_ignore_guids_file ); + + fh = fopen( guids_file_name, "r" ); + if( fh == NULL ) + { + osm_log( &p_osm->log, OSM_LOG_ERROR, + "parse_ignore_guids_file: ERR 0601: " + "Unable to open ignore guids file (%s)\n" ); + status = IB_ERROR; + goto Exit; + } + + /* + * Parse the file and add to the ignore guids map. + */ + while( fgets( line, OSM_MAX_IGNORE_GUID_LINES_LEN, fh ) != NULL ) + { + line_num++; + p_c = line; + while ( (*p_c == ' ') && (*p_c != '\0')) p_c++ ; + port_guid = cl_hton64( strtoull( p_c, &p_ec, 16 ) ); + if (p_ec == p_c) + { + osm_log( &p_osm->log, OSM_LOG_ERROR, + "parse_ignore_guids_file: ERR 0602: " + "Error in line (%u): %s\n" , + line_num, line + ); + status = IB_ERROR; + goto Exit; + } + + while ( (*p_ec == ' ') && (*p_ec != '\0')) p_ec++ ; + if (! sscanf(p_ec, "%d", &port_num)) + { + osm_log( &p_osm->log, OSM_LOG_ERROR, + "parse_ignore_guids_file: ERR 0603: " + "Error in line (%u): %s\n" , + line_num, p_ec + ); + status = IB_ERROR; + goto Exit; + } + /* Make sure the port_num isn't greater than 256 */ + if (port_num > 256) + { + osm_log( &p_osm->log, OSM_LOG_ERROR, + "parse_ignore_guids_file: ERR 0604: " + "Error in line (%u): %s. " + "port number is greater than 256 (%d) \n", + line_num, p_ec, port_num + ); + status = IB_ERROR; + goto Exit; + } + /* ok insert it */ + osm_port_prof_set_ignored_port(&p_osm->subn, port_guid, (uint8_t)port_num); + osm_log( &p_osm->log, OSM_LOG_DEBUG, + "parse_ignore_guids_file: " + "Inserted Port: 0x%" PRIx64 " into ignored guids list\n" , + port_guid + ); + + } + + fclose( fh ); + + Exit: + OSM_LOG_EXIT( &p_osm->log ); + return ( status ); + +} + +/********************************************************************** + **********************************************************************/ +int +opensm_main( + void *osm_main_args) +{ + int argc = ((osm_main_args_t*)osm_main_args)->argc; + char** argv = ((osm_main_args_t*)osm_main_args)->argv; + osm_subn_opt_t opt; + ib_net64_t sm_key = 0; + ib_api_status_t status; + uint32_t log_flags = OSM_LOG_DEFAULT_LEVEL; + int long temp; + uint32_t dbg_lvl; + boolean_t run_once_flag = FALSE; + boolean_t mem_track = FALSE; + uint32_t next_option; + uint32_t exitTimeout; + boolean_t cache_options = FALSE; + char *ignore_guids_file_name = NULL; + uint32_t val; + const char * const short_option = "i:f:ed:g:l:L:s:t:a:R:U:P:NQvVhorcyx"; + + + /* + 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[] = + { + { "service", 0, NULL, 'Z'}, + { "debug", 1, NULL, 'd'}, + { "guid", 1, NULL, 'g'}, + { "ignore_guids", 1, NULL, 'i'}, + { "lmc", 1, NULL, 'l'}, + { "sweep", 1, NULL, 's'}, + { "timeout", 1, NULL, 't'}, + { "verbose", 0, NULL, 'v'}, + { "D", 1, NULL, 'D'}, + { "log_file", 1, NULL, 'f'}, + { "log_limit", 1, NULL, 'L'}, + { "erase_log_file",0, NULL, 'e'}, + { "Pconfig", 1, NULL, 'P'}, + { "no_part_enforce",0,NULL, 'N'}, + { "no_qos", 0, NULL, 'Q'}, + { "maxsmps", 1, NULL, 'n'}, + { "console", 0, 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_file" ,1, NULL, 'U'}, + { "add_guid_file", 1, NULL, 'a'}, + { "cache-options", 0, NULL, 'c'}, + { "stay_on_fatal", 0, NULL, 'y'}, + { "honor_guid2lid", 0, NULL, 'x'}, + { NULL, 0, NULL, 0 } /* Required at the end of the array */ + }; + printf("-------------------------------------------------\n"); + printf("%s\n", OSM_VERSION); + + osm_subn_set_default_opt(&opt); + osm_subn_parse_conf_file(&opt); + + printf("Command Line Arguments:\n"); + do + { + next_option = getopt_long_only(argc, argv, short_option, + long_option, NULL); + switch(next_option) + { + case 'Z': + /* + service option - nothing to do + */ + 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. + */ + ignore_guids_file_name = optarg; + printf(" Ignore Guids File = %s\n", ignore_guids_file_name); + break; + + case 'g': + /* + Specifies port guid with which to bind. + */ + opt.guid = cl_hton64( strtoull( optarg, NULL, 16 )); + if (! opt.guid) + { + /* If guid is 0 - need to display the guid list */ + opt.guid = INVALID_GUID; + } + else + printf(" Guid <0x%"PRIx64">\n", cl_hton64( opt.guid )); + break; + + case 's': + val = strtol(optarg, NULL, 0); + /* Check that the number is not too large */ + if ( ((uint32_t)(val * 1000000)) / 1000000 != val ) + fprintf(stderr, "ERROR: sweep interval given is too large. Ignoring it.\n"); + else + { + opt.sweep_interval = val; + printf(" sweep interval = %d\n", opt.sweep_interval); + } + break; + + case 't': + opt.transaction_timeout = strtol(optarg, NULL, 0); + printf(" Transaction timeout = %d\n", opt.transaction_timeout); + break; + + case 'n': + opt.max_wire_smps = strtol(optarg, NULL, 0); + if( opt.max_wire_smps <= 0 ) + opt.max_wire_smps = 0x7FFFFFFF; + printf(" Max wire smp's = %d\n", opt.max_wire_smps); + break; + + case 'q': + /* + * OpenSM interactive console + */ + opt.console = TRUE; + printf(" Enabling OpenSM interactive console\n"); + break; + + 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 >= 10) + { + /* Please look at osm_subnet.h for list of testability modes. */ + opt.testability_mode = dbg_lvl - 9; + } + 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."); + return( -1 ); + } + opt.lmc = (uint8_t)temp; + printf(" LMC = %d\n", temp); + break; + + case 'D': + log_flags = strtol(optarg, NULL, 0); + printf(" verbose option -D = 0x%x\n", log_flags); + break; + + case 'f': + if (!strcmp(optarg, "stdout")) + /* output should be to standard output */ + opt.log_file = NULL; + else + opt.log_file = optarg; + break; + + case 'L': + opt.log_max_size = strtoul(optarg, NULL, 0) * (1024*1024); + printf(" Log file max size is %lu bytes\n", opt.log_max_size); + break; + + case 'e': + opt.accum_log_file = FALSE; + printf(" Creating new log file\n"); + break; + + case 'P': + opt.partition_config_file = optarg; + break; + + case 'N': + opt.no_partition_enforcement = TRUE; + break; + + case 'Q': + opt.no_qos = TRUE; + break; + + case 'y': + opt.exit_on_fatal = FALSE; + printf(" Staying on fatal initialization errors\n"); + break; + + case 'v': + log_flags = (log_flags <<1 )|1; + printf(" Verbose option -v (log flags = 0x%X)\n", log_flags ); + break; + + case 'V': + log_flags = 0xFFFFFFFF; + opt.force_log_flush = TRUE; + printf(" Big V selected\n"); + break; + + case 'p': + temp = strtol(optarg, NULL, 0); + if (0 > temp || 15 < temp) { + fprintf(stderr, "ERROR: priority must be between 0 and 15\n"); + return (-1); + } + opt.sm_priority = (uint8_t)temp; + printf(" Priority = %d\n", temp); + break; + + case 'k': + sm_key = cl_hton64( strtoull( optarg, NULL, 16 )); + printf(" SM Key <0x%"PRIx64">\n", cl_hton64( sm_key )); + opt.sm_key = sm_key; + break; + + case 'R': + opt.routing_engine_name = optarg; + printf(" Activate \'%s\' routing engine\n", optarg); + break; + + case 'U': + opt.ucast_dump_file = optarg; + printf(" Ucast dump file is \'%s\'\n", optarg); + break; + + case 'a': + /* + Specifies port guids file + */ + opt.updn_guid_file = optarg; + printf (" UPDN Guid File: %s\n", opt.updn_guid_file ); + break; + + case 'c': + cache_options = TRUE; + printf (" Caching command line options\n"); + break; + + case 'x': + opt.honor_guid2lid_file = TRUE; + printf (" Honor guid2lid file, if possible\n"); + break; + + case 'h': + case '?': + case ':': + show_usage(); + return 0; + break; + + case -1: + break; /* done with option */ + default: /* something wrong */ + abort(); + } + } + while(next_option != -1); + + if (opt.log_file != NULL ) + printf(" Log File: %s\n", opt.log_file ); + /* Done with options description */ + printf("-------------------------------------------------\n"); + + opt.log_flags = (uint8_t)log_flags; + + status = osm_opensm_init( &osm, &opt ); + if( status != IB_SUCCESS ) + { + char buffer[LOG_ENTRY_SIZE_MAX]; + 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); + sprintf(buffer, "Error from osm_opensm_init: %s. See opensm log file for more details", err_str); + /* We will just exit, and not go to Exit, since we don't + want the destroy to be called. */ + cl_log_event("OpenSM", LOG_ERR, buffer , NULL, 0); + g_service_state = SERVICE_STATE_START_FAILED; + 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, ((osm_main_args_t*)osm_main_args)->is_service ); + + if ( opt.guid == 0 ) + { + printf( "Error: Could not get port guid \n" ); + status = IB_ERROR; + goto Exit; + } + + if ( cache_options == TRUE ) + osm_subn_write_conf_file( &opt ); + + status = osm_opensm_bind( &osm, opt.guid ); + if( status != IB_SUCCESS ) + { + printf( "\nError from osm_opensm_bind (0x%X)\n", status ); + goto Exit; + } + + /* + * Define some port guids to ignore during path equalization + */ + if (ignore_guids_file_name != NULL) + { + status = parse_ignore_guids_file(ignore_guids_file_name, &osm); + if( status != IB_SUCCESS ) + { + printf( "\nError from parse_ignore_guids_file (0x%X)\n", status ); + goto Exit; + } + } + + osm_opensm_sweep( &osm ); + + status = osm_opensm_wait_for_subnet_up( + &osm, EVENT_NO_TIMEOUT, TRUE ); + + if( status != CL_SUCCESS ) + { + printf( "\nError from osm_opensm_wait_for_subnet_up (0x%X)\n", status ); + goto Exit; + } + + if( run_once_flag == FALSE ) + { + /* + Sit here forever + In the future, some sort of console interactivity could + be implemented in this loop. + */ + WaitForSingleObject(osm_exit_event, INFINITE); + osm_exit_flag = TRUE; + } + + /* wait for all transactions to end */ + CL_ASSERT( ((opt.polling_retry_number + 1) * opt.transaction_timeout / 1000.0) < 0x100000000ULL ); + exitTimeout = + (uint32_t) ((opt.polling_retry_number + 1) * opt.transaction_timeout / 1000.0); + + if (exitTimeout < 3) exitTimeout = 3; + + /* + printf( "\n------- OpenSM Exiting (in %u seconds) -------\n", + exitTimeout); + sleep(exitTimeout); + */ + + if (osm.mad_pool.mads_out) + fprintf(stdout, + "There are still %u MADs out. Forcing the exit of the OpenSM application...\n", + osm.mad_pool.mads_out); + + Exit: + g_service_state = SERVICE_STATE_START_FAILED; + osm_opensm_destroy( &osm ); + + exit( 0 ); +} + +SERVICE_STATUS OsmServiceStatus; +SERVICE_STATUS_HANDLE OsmServiceStatusHandle; + +VOID SvcDebugOut(LPSTR String, DWORD Status); +VOID WINAPI OsmServiceCtrlHandler (DWORD opcode); +__stdcall OsmServiceStart (DWORD argc, LPTSTR *argv); + +DWORD OsmServiceInitialization (DWORD argc, LPTSTR *argv, + DWORD *specificError); + +int __cdecl +main ( + int argc, + char* argv[] ) +{ + int i; + boolean_t run_as_service = FALSE; + osm_main_args.argc = argc; + osm_main_args.argv = argv; + /* If there are arguments that the executable is ran with, then this is + not running as service - just run the opensm_main. */ + for (i = 0 ; i< argc ; i++) + if (!strcmp(argv[i], "--service")) + { + run_as_service = TRUE; + osm_main_args.is_service = TRUE; + break; + } + osm_exit_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if(osm_exit_event == NULL) + { + printf( "\nCreateEvent failed gle=%d\n", GetLastError()); + return( 1 ); + } + + if (!run_as_service) + { + /* Running as executable */ + osm_main_args.is_service = FALSE; + return opensm_main(&osm_main_args); + } + else + { + /* Running as service */ + SERVICE_TABLE_ENTRY DispatchTable[] = + { + { "OsmService", OsmServiceStart }, + { NULL, NULL } + }; + // Give older versions of opensm a chance to stop + Sleep(3000); + + if (!StartServiceCtrlDispatcher( DispatchTable)) + { + SvcDebugOut(" [OSM_SERVICE] StartServiceCtrlDispatcher (%d)\n", + GetLastError()); + } + } +} + +VOID SvcDebugOut(LPSTR String, DWORD Status) +{ + CHAR Buffer[1024]; + if (strlen(String) < 1000) + { + sprintf(Buffer, String, Status); + OutputDebugStringA(Buffer); + } +} + +VOID WINAPI OsmServiceCtrlHandler (DWORD Opcode) +{ + DWORD status; + + switch(Opcode) + { + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + // 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] SetServiceStatus error %ld\n", + status); + } + + SvcDebugOut(" [OSM_SERVICE] Leaving OsmService \n",0); + return; + + case SERVICE_CONTROL_INTERROGATE: + // Fall through to send current status. + 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\n", + status); + } + return; +} + +__stdcall 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_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN; + OsmServiceStatus.dwWin32ExitCode = 0; + OsmServiceStatus.dwServiceSpecificExitCode = 0; + OsmServiceStatus.dwCheckPoint = 0; + OsmServiceStatus.dwWaitHint = 2000; + + OsmServiceStatusHandle = RegisterServiceCtrlHandler( + "OsmService", + OsmServiceCtrlHandler); + + if (OsmServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) + { + SvcDebugOut(" [OSM_SERVICE] RegisterServiceCtrlHandler failed %d\n", GetLastError()); + 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\n",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); + 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); + } + + // This is where the service does its work. + SvcDebugOut(" [OSM_SERVICE] Returning the Main Thread \n",0); + + return 1; +} + +// Stub initialization function. +DWORD OsmServiceInitialization(DWORD argc, LPTSTR *argv, + DWORD *specificError) +{ + if (CreateThread(NULL, 0, opensm_main, &osm_main_args, 0, NULL) == NULL) + { + SvcDebugOut(" [OSM_SERVICE] failed to create thread (%d)\n", + GetLastError()); + return(1); + } + return(0); +} diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/opensm.opts b/branches/WOF2-1/ulp/opensm/user/opensm/opensm.opts new file mode 100644 index 00000000..122e151e --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/opensm.opts @@ -0,0 +1,139 @@ +# +# DEVICE ATTRIBUTES OPTIONS +# +# The port GUID on which the OpenSM is running. +#guid + +# M_Key value sent to all ports qualifing all Set(PortInfo). +#m_key 0x0000000000000000 + +# The lease period used for the M_Key on this subnet in [msec] +#m_key_lease_period 0 + +# SM_Key value of the SM to qualify rcv SA queries as 'trusted' +#sm_key 0x0100000000000000 + +# Subnet prefix used on this subnet +#subnet_prefix 0xfe80000000000000 + +# The LMC value used on this subnet +#lmc 0 + +# The code of maximal time a packet can live in a switch +# The actual time is 4.096usec * 2^ +# The value 0x14 disables this mechanism +#packet_life_time 0x12 + +# The code of maximal time a packet can wait at the head of +# transmission queue. +# The actual time is 4.096usec * 2^ +# The value 0x14 disables this mechanism +#head_of_queue_lifetime 0x12 + +# The maximal time a packet can wait at the head of queue on +# switch port connected to a HCA +#leaf_head_of_queue_lifetime 0x0c + +# Limit the maximal operational VLs +#max_op_vls 5 + +# The subnet_timeout code that will be set for all the ports +# The actual timeout is 4.096usec * 2^ +#subnet_timeout 18 + +# Threshold of local phy errors for sending Trap 129 +#local_phy_errors_threshold 0x08 + +# Threshold of credits over-run errors for sending Trap 129 +#overrun_errors_threshold 0x08 + +# +# SWEEP OPTIONS +# +# The number of seconds between subnet sweeps (0 disables it) +#sweep_interval 10 + +# If TRUE cause all lids to be re-assigned +#reassign_lids FALSE + +# If TRUE ignore existing LFT entries on first sweep (default). +# Otherwise only non minimal hop cases are modified. +# NOTE: A standby SM clears its first sweep flag - since the +# master SM already sweeps... +#reassign_lfts TRUE + +# If true forces every sweep to be a heavy sweep +#force_heavy_sweep FALSE + +# If true every trap will cause a heavy sweep. +# NOTE: successive same traps (>10) are supressed +#sweep_on_trap TRUE + +# +# ROUTING OPTIONS +# +# If true do not count switches as link subscriptions +#port_profile_switch_nodes FALSE + +# Activate the Up/Down routing algorithm +#updn_activate FALSE + +# +# HANDOVER - MULTIPLE SM's OPTIONS +# +# SM priority used for deciding who is the master +#sm_priority 1 + +# If TRUE other SM's on the subnet should be ignored +#ignore_other_sm FALSE + +# Timeout in [sec] between two polls of active master SM +#sminfo_polling_timeout 10000 + +# Number of failing polls of remote SM that declares it dead +#polling_retry_number 4 + +# +# TIMING AND THREADING OPTIONS +# +# Number of MADs sent in parallel +#max_wire_smps 4 + +# The time taken to a transaction to finish in [msec] +#transaction_timeout 200 + +# Maximal time in [msec] a message can stay in the incoming message queue. +# If there is more then one message in the queue and the last message +# stayed in the queue more then this value any SA request will be +# immediately returned with a BUSY status. +#max_msg_fifo_timeout 10000 + +# Use a single thread for handling SA queries +#single_thread FALSE + +# +# DEBUG FEATURES +# +# The log flags used +#log_flags 0x03 + +# Force flush of the log file after each log message +#force_log_flush TRUE + +# Log file to be used +#log_file + +#accum_log_file TRUE + +# The directory to hold the file OpenSM dumps +#dump_files_dir + +# If TRUE if OpenSM should disable multicast support +#no_multicast_option FALSE + +# No multicast routing is performed if TRUE +#disable_multicast FALSE + +# If TRUE opensm will exit on fatal initialization issues +#exit_on_fatal TRUE + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/opensm.rc b/branches/WOF2-1/ulp/opensm/user/opensm/opensm.rc new file mode 100644 index 00000000..525ef064 --- /dev/null +++ b/branches/WOF2-1/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 "Debug OpenSM Subnet Manager Application" +#define VER_INTERNALNAME_STR "opensm.exe" +#define VER_ORIGINALFILENAME_STR "opensm.exe" +#else +#define VER_FILEDESCRIPTION_STR "OpenSM Subnet Manager Application" +#define VER_INTERNALNAME_STR "opensm.exe" +#define VER_ORIGINALFILENAME_STR "opensm.exe" +#endif +#include diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm.mc b/branches/WOF2-1/ulp/opensm/user/opensm/osm.mc new file mode 100644 index 00000000..3030f718 --- /dev/null +++ b/branches/WOF2-1/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-1/ulp/opensm/user/opensm/osm_console.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_console.c new file mode 100644 index 00000000..9eadd40d --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_console.c @@ -0,0 +1,226 @@ +/* + * 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$ + */ + + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE /* for getline */ +#include +#include +#include +#include + +#define OSM_COMMAND_LINE_LEN 120 +#define OSM_COMMAND_PROMPT "$ " + +struct command { + char *name; + void (*help_function)(void); + void (*parse_function)(char **p_last, osm_opensm_t *p_osm); +}; + +static const struct command console_cmds[]; + +static inline char *next_token(char **p_last) +{ + return strtok_r(NULL, " \t\n", p_last); +} + +static void help_command() +{ + int i; + + printf("Supported commands and syntax:\n"); + printf("help []\n"); + /* skip help command */ + for (i = 1; console_cmds[i].name; i++) + console_cmds[i].help_function(); +} + +static void help_loglevel() +{ + printf("loglevel []\n"); +} + +static void help_priority() +{ + printf("priority []\n"); +} + +/* more help routines go here */ + +static void help_parse(char **p_last, osm_opensm_t *p_osm) +{ + char *p_cmd; + int i, found = 0; + + p_cmd = next_token(p_last); + if (!p_cmd) + help_command(); + else { + for (i = 1; console_cmds[i].name; i++) { + if (!strcmp(p_cmd, console_cmds[i].name)) { + found = 1; + console_cmds[i].help_function(); + break; + } + } + if (!found) { + printf("Command %s not found\n\n", p_cmd); + help_command(); + } + } +} + +static void loglevel_parse(char **p_last, osm_opensm_t *p_osm) +{ + char *p_cmd; + int level; + + p_cmd = next_token(p_last); + if (!p_cmd) + printf("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)) { + printf("Setting log level to 0x%x\n", level); + osm_log_set_level(&p_osm->log, level); + } else + printf("Invalid log level 0x%x\n", level); + } +} + +static void priority_parse(char **p_last, osm_opensm_t *p_osm) +{ + char *p_cmd; + int priority; + + p_cmd = next_token(p_last); + if (!p_cmd) + printf("Current sm-priority is %d\n", p_osm->subn.opt.sm_priority); + else { + priority = strtol(p_cmd, NULL, 0); + if (0 > priority || 15 < priority) + printf("Invalid sm-priority %d; must be between 0 and 15\n", priority); + else { + printf("Setting sm-priority to %d\n", priority); + p_osm->subn.opt.sm_priority = (uint8_t)priority; + /* Does the SM state machine need a kick now ? */ + } + } +} + +/* more parse routines go here */ + +static const struct command console_cmds[] = +{ + { "help", &help_command, &help_parse}, + { "loglevel", &help_loglevel, &loglevel_parse}, + { "priority", &help_priority, &priority_parse}, + { 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; + + /* find first token which is the command */ + p_cmd = strtok_r(line, " \t\n", &p_last); + if (p_cmd) { + for (i = 0; console_cmds[i].name; i++) { + if (!strcmp(p_cmd, console_cmds[i].name)) { + found = 1; + console_cmds[i].parse_function(&p_last, p_osm); + break; + } + } + if (!found) { + printf("Command %s not found\n\n", p_cmd); + help_command(); + } + } else { + printf("Error parsing command line: %s\n", line); + return; + } +} + +void osm_console_prompt(void) +{ + printf("%s", OSM_COMMAND_PROMPT); + fflush(stdout); +} + +void osm_console(osm_opensm_t *p_osm) +{ + struct pollfd pollfd; + char *p_line; + size_t len; + ssize_t n; + + pollfd.fd = 0; + pollfd.events = POLLIN; + pollfd.revents = 0; + + if (poll(&pollfd, 1, 10000) <= 0) + return; + + if (pollfd.revents|POLLIN) { + p_line = NULL; + /* Get input line */ + n = getline(&p_line, &len, stdin); + if (n > 0) { + /* Parse and act on input */ + parse_cmd_line(p_line, p_osm); + free(p_line); + } else { + printf("Input error\n"); + fflush(stdin); + } + osm_console_prompt(); + } +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_db_files.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_db_files.c new file mode 100644 index 00000000..43a90d10 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_db_files.c @@ -0,0 +1,796 @@ +/* + * 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: + * Implemntation of the osm_db interface using simple text files + * + * $Revision: 1.4 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +/****d* Database/OSM_DB_MAX_LINE_LEN + * NAME + * OSM_DB_MAX_LINE_LEN + * + * DESCRIPTION + * The Maximal line length allowed for the file + * + * SYNOPSIS + */ +#define OSM_DB_MAX_LINE_LEN 1024 +/**********/ + +/****d* Database/OSM_DB_MAX_GUID_LEN + * NAME + * OSM_DB_MAX_GUID_LEN + * + * DESCRIPTION + * The Maximal word length allowed for the file (guid or lid) + * + * SYNOPSIS + */ +#define OSM_DB_MAX_GUID_LEN 32 +/**********/ + +/****s* OpenSM: Database/osm_db_domain_imp + * NAME + * osm_db_domain_imp + * + * DESCRIPTION + * An implementation for domain of the database based on text files and + * hash tables. + * + * SYNOPSIS + */ +typedef struct _osm_db_domain_imp { + char *file_name; + st_table *p_hash; + cl_spinlock_t lock; +} osm_db_domain_imp_t; +/* + * FIELDS + * + * SEE ALSO + * osm_db_domain_t + *********/ + +/****s* OpenSM: Database/osm_db_imp_t + * NAME + * osm_db_imp_t + * + * DESCRIPTION + * An implementation for file based database + * + * SYNOPSIS + */ +typedef struct _osm_db_imp { + char *db_dir_name; +} osm_db_imp_t; +/* + * FIELDS + * + * db_dir_name + * The directory holding the database + * + * SEE ALSO + * osm_db_t + *********/ + +/*************************************************************************** + ***************************************************************************/ +void +osm_db_construct( + IN osm_db_t* const p_db ) +{ + memset(p_db, 0, sizeof(osm_db_t)); + cl_list_construct( &p_db->domains ); +} + +/*************************************************************************** + ***************************************************************************/ +void +osm_db_domain_destroy( + IN osm_db_domain_t* const p_db_domain) +{ + osm_db_domain_imp_t *p_domain_imp; + p_domain_imp = (osm_db_domain_imp_t *)p_db_domain->p_domain_imp; + + osm_db_clear( p_db_domain ); + + cl_spinlock_destroy( &p_domain_imp->lock ); + + st_free_table( p_domain_imp->p_hash ); + free( p_domain_imp->file_name ); + free( p_domain_imp ); +} + +/*************************************************************************** + ***************************************************************************/ +void +osm_db_destroy( + IN osm_db_t* const p_db ) +{ + osm_db_domain_t *p_domain; + + while ((p_domain = cl_list_remove_head( &p_db->domains )) != NULL ) + { + osm_db_domain_destroy( p_domain ); + free( p_domain ); + } + cl_list_destroy( &p_db->domains ); + free( p_db->p_db_imp ); +} + +/*************************************************************************** + ***************************************************************************/ +int +osm_db_init( + IN osm_db_t* const p_db, + IN osm_log_t *p_log ) +{ + osm_db_imp_t *p_db_imp; + struct stat dstat; + + OSM_LOG_ENTER( p_log, osm_db_init ); + + p_db_imp = (osm_db_imp_t *)malloc(sizeof(osm_db_imp_t)); + CL_ASSERT( p_db_imp != NULL); + + p_db_imp->db_dir_name = getenv("OSM_CACHE_DIR"); + if (!p_db_imp->db_dir_name || !(*p_db_imp->db_dir_name)) + p_db_imp->db_dir_name = OSM_DEFAULT_CACHE_DIR; + + /* Create the directory if it doesn't exist */ + /* There is a difference in creating directory between windows and linux */ +#ifdef __WIN__ + /* Check if the directory exists. If not - create it. */ + CreateDirectory(p_db_imp->db_dir_name, NULL); +#else /* __WIN__ */ + /* make sure the directory exists */ + if (lstat(p_db_imp->db_dir_name, &dstat)) + { + if (mkdir(p_db_imp->db_dir_name, 0755)) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_db_init: ERR 6101: " + " Failed to create the db directory:%s\n", + p_db_imp->db_dir_name); + OSM_LOG_EXIT( p_log ); + return 1; + } + } +#endif + + p_db->p_log = p_log; + p_db->p_db_imp = (void*)p_db_imp; + + cl_list_init( &p_db->domains, 5 ); + + OSM_LOG_EXIT( p_log ); + + return 0; +} + +/*************************************************************************** + ***************************************************************************/ +osm_db_domain_t* +osm_db_domain_init( + IN osm_db_t* const p_db, + IN char *domain_name) +{ + osm_db_domain_t *p_domain; + osm_db_domain_imp_t *p_domain_imp; + int dir_name_len; + osm_log_t *p_log = p_db->p_log; + FILE *p_file; + + OSM_LOG_ENTER( p_log, osm_db_domain_init ); + + /* allocate a new domain object */ + p_domain = (osm_db_domain_t *)malloc(sizeof(osm_db_domain_t)); + CL_ASSERT( p_domain != NULL ); + + p_domain_imp = + (osm_db_domain_imp_t *)malloc(sizeof(osm_db_domain_imp_t)); + CL_ASSERT( p_domain_imp != NULL ); + + dir_name_len = strlen(((osm_db_imp_t*)p_db->p_db_imp)->db_dir_name); + + /* set the domain file name */ + p_domain_imp->file_name = + (char *)malloc(sizeof(char)*(dir_name_len) + strlen(domain_name) + 2); + CL_ASSERT(p_domain_imp->file_name != NULL); + strcpy(p_domain_imp->file_name,((osm_db_imp_t*)p_db->p_db_imp)->db_dir_name); + strcat(p_domain_imp->file_name,domain_name); + + /* make sure the file exists - or exit if not writable */ + p_file = fopen(p_domain_imp->file_name, "a+"); + if (! p_file) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_db_domain_init: 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; + unsigned int line_num; + + OSM_LOG_ENTER( p_log, osm_db_restore ); + + /* 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, + "osm_db_restore: 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, + "osm_db_restore: 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, + "osm_db_restore: ERR 610A: " + " Illegal key from line:%u : %s (file:%s)\n", + line_num, sLine, p_domain_imp->file_name); + status = 1; + goto EndParsing; + } + + p_key = (char *)malloc(sizeof(char)*(strlen(p_first_word) + 1)); + strcpy(p_key, p_first_word); + + p_rest_of_line = strtok_r(NULL, "\n", &p_last); + if (p_rest_of_line != NULL) + { + p_accum_val = + (char*)malloc(sizeof(char)*(strlen(p_rest_of_line) + 1)); + strcpy(p_accum_val, p_rest_of_line); + } + else + { + p_accum_val = (char*)malloc(2); + strcpy(p_accum_val, "\0"); + } + } + else if (sLine[0] != '\n') + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_db_restore: 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, + (st_data_t*)&p_prev_val)) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_db_restore: 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; + } + + /* store our key and value */ + st_insert(p_domain_imp->p_hash, + (st_data_t)p_key, (st_data_t)p_accum_val); + osm_log( p_log, OSM_LOG_DEBUG, + "osm_db_restore: " + "Got key:%s value:%s\n", p_key, p_accum_val); + } + else + { + /* accumulate into the value */ + p_prev_val = p_accum_val; + p_accum_val = + (char *)malloc(strlen(p_prev_val) + strlen(sLine) + 1); + strcpy(p_accum_val, p_prev_val); + free(p_prev_val); + strcat(p_accum_val, sLine); + } + } /* in key */ + } /* while lines or last line */ + + EndParsing: + fclose(p_file); + + Exit: + cl_spinlock_release( &p_domain_imp->lock ); + OSM_LOG_EXIT( p_log ); + return status; +} + +/*************************************************************************** + ***************************************************************************/ +int +__osm_dump_tbl_entry(st_data_t key, st_data_t val, st_data_t arg) +{ + FILE *p_file = (FILE*)arg; + char *p_key = (char*)key; + char *p_val = (char *)val; + + fprintf(p_file, "%s %s\n\n", p_key, p_val); + return ST_CONTINUE; +} + +int +osm_db_store( + IN osm_db_domain_t *p_domain) +{ + osm_log_t *p_log = p_domain->p_db->p_log; + osm_db_domain_imp_t *p_domain_imp; + FILE *p_file; + int status = 0; + char *p_tmp_file_name; + + OSM_LOG_ENTER( p_log, osm_db_store ); + + p_domain_imp = (osm_db_domain_imp_t *)p_domain->p_domain_imp; + p_tmp_file_name = + (char *)malloc(sizeof(char)*(strlen(p_domain_imp->file_name)+8)); + strcpy(p_tmp_file_name, p_domain_imp->file_name); + strcat(p_tmp_file_name,".tmp"); + + cl_spinlock_acquire( &p_domain_imp->lock ); + + /* open up the output file */ + p_file = fopen(p_tmp_file_name, "w"); + if (! p_file) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_db_store: ERR 6107: " + " Failed to open the db file:%s for writing\n", + p_domain_imp->file_name); + status = 1; + goto Exit; + } + + st_foreach(p_domain_imp->p_hash, __osm_dump_tbl_entry, (st_data_t)p_file); + fclose(p_file); + + /* move the domain file */ + status = remove(p_domain_imp->file_name); + if (status) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_db_store: 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, + "osm_db_store: 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 */ +int +__osm_clear_tbl_entry(st_data_t key, st_data_t val, st_data_t arg) +{ + free((char*)key); + free((char*)val); + return ST_DELETE; +} + +int +osm_db_clear( + IN osm_db_domain_t *p_domain) +{ + osm_db_domain_imp_t *p_domain_imp = + (osm_db_domain_imp_t *)p_domain->p_domain_imp; + + cl_spinlock_acquire( &p_domain_imp->lock ); + st_foreach(p_domain_imp->p_hash, __osm_clear_tbl_entry, (st_data_t)NULL); + cl_spinlock_release( &p_domain_imp->lock ); + + return 0; +} + +/*************************************************************************** + ***************************************************************************/ +int +__osm_get_key_of_tbl_entry(st_data_t key, st_data_t val, st_data_t arg) +{ + cl_list_t *p_list = (cl_list_t *)arg; + cl_list_insert_tail(p_list, (void*)key); + return ST_CONTINUE; +} + +int +osm_db_keys( + IN osm_db_domain_t *p_domain, + OUT cl_list_t* p_key_list) +{ + osm_db_domain_imp_t *p_domain_imp = + (osm_db_domain_imp_t *)p_domain->p_domain_imp; + + cl_spinlock_acquire( &p_domain_imp->lock ); + + st_foreach(p_domain_imp->p_hash, + __osm_get_key_of_tbl_entry, (st_data_t)p_key_list); + + cl_spinlock_release( &p_domain_imp->lock ); + + return 0; +} + +/*************************************************************************** + ***************************************************************************/ +char * +osm_db_lookup( + IN osm_db_domain_t *p_domain, + IN char *const p_key) +{ + osm_db_domain_imp_t *p_domain_imp = + (osm_db_domain_imp_t *)p_domain->p_domain_imp; + char *p_val = NULL; + + cl_spinlock_acquire( &p_domain_imp->lock ); + + if (!st_lookup(p_domain_imp->p_hash, (st_data_t)p_key, (st_data_t*)&p_val)) + p_val = NULL; + + cl_spinlock_release( &p_domain_imp->lock ); + + return p_val; +} + +/*************************************************************************** + ***************************************************************************/ +int +osm_db_update( + IN osm_db_domain_t *p_domain, + IN char *const p_key, + IN char *const p_val) +{ + osm_log_t *p_log = p_domain->p_db->p_log; + osm_db_domain_imp_t *p_domain_imp = + (osm_db_domain_imp_t *)p_domain->p_domain_imp; + char *p_prev_val = NULL; + char *p_new_key; + char *p_new_val; + + cl_spinlock_acquire( &p_domain_imp->lock ); + + if (st_lookup(p_domain_imp->p_hash, + (st_data_t)p_key, (st_data_t*)&p_prev_val)) + { + osm_log( p_log, OSM_LOG_DEBUG, + "osm_db_update: " + " Key:%s previously exists in:%s with value:%s\n", + p_key, + p_domain_imp->file_name, + p_prev_val); + p_new_key = p_key; + } + else + { + /* need to allocate the key */ + p_new_key = malloc(sizeof(char)*(strlen(p_key) + 1)); + strcpy(p_new_key, p_key); + } + + /* need to arange a new copy of the value */ + p_new_val = malloc(sizeof(char)*(strlen(p_val) + 1)); + strcpy(p_new_val, p_val); + + st_insert(p_domain_imp->p_hash, (st_data_t)p_new_key, (st_data_t)p_new_val); + + if (p_prev_val) + free(p_prev_val); + + cl_spinlock_release( &p_domain_imp->lock ); + + return 0; +} + +/*************************************************************************** + ***************************************************************************/ +int +osm_db_delete( + IN osm_db_domain_t *p_domain, + IN char *const p_key) +{ + osm_log_t *p_log = p_domain->p_db->p_log; + osm_db_domain_imp_t *p_domain_imp = + (osm_db_domain_imp_t *)p_domain->p_domain_imp; + char *p_prev_val = NULL; + int res; + + OSM_LOG_ENTER( p_log, osm_db_delete ); + + cl_spinlock_acquire( &p_domain_imp->lock ); + if (st_delete(p_domain_imp->p_hash, + (st_data_t*)&p_key, (st_data_t*)&p_prev_val)) + { + if (st_lookup(p_domain_imp->p_hash, + (st_data_t)p_key, (st_data_t*)&p_prev_val)) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_db_delete: " + " 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, + "osm_db_update: " + " 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-1/ulp/opensm/user/opensm/osm_db_pack.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_db_pack.c new file mode 100644 index 00000000..14b923e8 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_db_pack.c @@ -0,0 +1,172 @@ +/* + * 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$ + */ + + + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +static inline void +__osm_pack_guid(uint64_t guid, char *p_guid_str) +{ + sprintf(p_guid_str, "0x%016" PRIx64, guid); +} + +static inline uint64_t +__osm_unpack_guid(char *p_guid_str) +{ +#if __WORDSIZE == 64 + return (strtoul(p_guid_str, NULL, 0)); +#else + return (strtoull(p_guid_str, NULL, 0)); +#endif +} + +static inline void +__osm_pack_lids(uint16_t min_lid, uint16_t max_lid, char *p_lid_str) +{ + sprintf(p_lid_str, "0x%04x 0x%04x", min_lid, max_lid); +} + +static inline int +__osm_unpack_lids( + IN char *p_lid_str, + OUT uint16_t *p_min_lid, + OUT uint16_t *p_max_lid ) +{ + unsigned long tmp; + char *p_next; + char *p_num; + char lids_str[24]; + + strncpy(lids_str, p_lid_str, 23); + lids_str[23] = '\0'; + p_num = strtok_r(lids_str, " \t", &p_next); + if (! p_num) return 1; + tmp = strtoul(p_num, NULL, 0); + CL_ASSERT( tmp < 0x10000 ); + *p_min_lid = (uint16_t)tmp; + + p_num = strtok_r(NULL, " \t", &p_next); + if (! p_num) return 1; + tmp = strtoul(p_num, NULL, 0); + CL_ASSERT( tmp < 0x10000 ); + *p_max_lid = (uint16_t)tmp; + + return 0; +} + +int +osm_db_guid2lid_guids( + IN osm_db_domain_t* const p_g2l, + OUT cl_qlist_t* p_guid_list ) +{ + char *p_key; + cl_list_t keys; + osm_db_guid_elem_t *p_guid_elem; + + cl_list_construct( &keys ); + cl_list_init( &keys , 10); + + if (osm_db_keys(p_g2l, &keys)) + return 1; + + while ( (p_key = cl_list_remove_head( &keys )) != NULL ) + { + p_guid_elem = (osm_db_guid_elem_t*)malloc(sizeof(osm_db_guid_elem_t)); + CL_ASSERT( p_guid_elem != NULL ); + + p_guid_elem->guid = __osm_unpack_guid(p_key); + cl_qlist_insert_head(p_guid_list, &p_guid_elem->item); + } + + cl_list_destroy( &keys ); + return 0; +} + +int +osm_db_guid2lid_get( + IN osm_db_domain_t* const p_g2l, + IN uint64_t guid, + OUT uint16_t *p_min_lid, + OUT uint16_t *p_max_lid) +{ + char guid_str[20]; + char *p_lid_str; + uint16_t min_lid, max_lid; + + __osm_pack_guid(guid, guid_str); + p_lid_str = osm_db_lookup(p_g2l, guid_str); + if (! p_lid_str) + return 1; + if (__osm_unpack_lids(p_lid_str, &min_lid, &max_lid)) + return 1; + + if (p_min_lid) *p_min_lid = min_lid; + if (p_max_lid) *p_max_lid = max_lid; + + return 0; +} + +int +osm_db_guid2lid_set( + IN osm_db_domain_t* const p_g2l, + IN uint64_t guid, + IN uint16_t min_lid, + IN uint16_t max_lid) +{ + char guid_str[20]; + char lid_str[16]; + + __osm_pack_guid(guid, guid_str); + __osm_pack_lids(min_lid, max_lid, lid_str); + + return( osm_db_update( p_g2l, guid_str, lid_str) ); +} + +int +osm_db_guid2lid_delete( + IN osm_db_domain_t* const p_g2l, + IN uint64_t guid ) +{ + char guid_str[20]; + __osm_pack_guid(guid, guid_str); + return( osm_db_delete( p_g2l, guid_str) ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_drop_mgr.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_drop_mgr.c new file mode 100644 index 00000000..eb8bbd4b --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_drop_mgr.c @@ -0,0 +1,721 @@ +/* + * 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: + * Implementation of osm_drop_mgr_t. + * This object represents the Drop Manager object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#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_drop_mgr_construct( + IN osm_drop_mgr_t* const p_mgr ) +{ + CL_ASSERT( p_mgr ); + memset( p_mgr, 0, sizeof(*p_mgr) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_drop_mgr_destroy( + IN osm_drop_mgr_t* const p_mgr ) +{ + CL_ASSERT( p_mgr ); + + OSM_LOG_ENTER( p_mgr->p_log, osm_drop_mgr_destroy ); + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_drop_mgr_init( + IN osm_drop_mgr_t* const p_mgr, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_req_t* const p_req, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_drop_mgr_init ); + + osm_drop_mgr_construct( p_mgr ); + + p_mgr->p_log = p_log; + p_mgr->p_subn = p_subn; + p_mgr->p_lock = p_lock; + p_mgr->p_req = p_req; + + OSM_LOG_EXIT( p_mgr->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_drop_mgr_remove_router( + IN const osm_drop_mgr_t* const p_mgr, + IN const ib_net64_t portguid ) +{ + osm_router_t *p_rtr; + cl_qmap_t* p_rtr_guid_tbl; + + p_rtr_guid_tbl = &p_mgr->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( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_drop_mgr_remove_router: " + "Cleaned router for port guid 0x%016" PRIx64 "\n", + cl_ntoh64( portguid ) ); + osm_router_delete( &p_rtr ); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_drop_mgr_remove_port( + IN const osm_drop_mgr_t* const p_mgr, + IN osm_port_t* p_port ) +{ + ib_net64_t port_guid; + osm_port_t *p_port_check; + cl_list_t* p_new_ports_list; + cl_list_iterator_t cl_list_item; + cl_qmap_t* p_port_guid_tbl; + cl_qmap_t* p_sm_guid_tbl; + osm_mcm_info_t* p_mcm; + osm_mgrp_t* p_mgrp; + cl_ptr_vector_t* p_port_lid_tbl; + uint16_t min_lid_ho; + uint16_t max_lid_ho; + uint16_t lid_ho; + uint32_t port_num; + uint32_t remote_port_num; + uint32_t num_physp; + osm_node_t *p_node; + osm_node_t *p_remote_node; + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + 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( p_mgr->p_log, __osm_drop_mgr_remove_port ); + + port_guid = osm_port_get_guid( p_port ); + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_drop_mgr_remove_port: " + "Unreachable port 0x%016" PRIx64 "\n", + cl_ntoh64( port_guid ) ); + + /* + Remove this port from the new_ports_list, if it exists there. + Remove this port from the guid and LID tables. + Remove also from the sm guid table - if the object + exists there. + */ + p_new_ports_list = &p_mgr->p_subn->new_ports_list; + cl_list_item = cl_list_head(p_new_ports_list); + while( cl_list_item != cl_list_end(p_new_ports_list) ) + { + if ( (osm_port_t*)(cl_list_obj(cl_list_item)) == p_port ) + { + /* Found the port in the new_ports_list. Remove it from there. */ + cl_list_remove_item(p_new_ports_list, cl_list_item); + break; + } + cl_list_item = cl_list_next(cl_list_item); + } + + p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl; + p_port_check = (osm_port_t*)cl_qmap_remove( p_port_guid_tbl, port_guid ); + if( p_port_check != p_port ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_drop_mgr_remove_port: ERR 0101: " + "Port 0x%016" PRIx64 " not in guid table\n", + cl_ntoh64( port_guid ) ); + goto Exit; + } + + p_sm_guid_tbl = &p_mgr->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( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_drop_mgr_remove_port: " + "Cleaned SM for port guid\n" ); + + free(p_sm); + } + + __osm_drop_mgr_remove_router( p_mgr, port_guid ); + + osm_port_get_lid_range_ho( p_port, &min_lid_ho, &max_lid_ho ); + + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_drop_mgr_remove_port: " + "Clearing abandoned LID range [0x%X,0x%X]\n", + min_lid_ho, max_lid_ho ); + + p_port_lid_tbl = &p_mgr->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 ); + + /* + For each Physical Port associated with this port: + Unlink the remote Physical Port, if any + Re-initialize each Physical Port. + */ + + num_physp = osm_port_get_num_physp( p_port ); + for( port_num = 0; port_num < num_physp; port_num++ ) + { + p_physp = osm_port_get_phys_ptr( p_port, (uint8_t)port_num ); + + if( p_physp ) + { + p_remote_physp = osm_physp_get_remote( p_physp ); + if( p_remote_physp && osm_physp_is_valid( p_remote_physp ) ) + { + osm_port_t* p_remote_port; + + p_node = osm_physp_get_node_ptr( p_physp ); + p_remote_node = osm_physp_get_node_ptr( p_remote_physp ); + remote_port_num = osm_physp_get_port_num( p_remote_physp ); + p_remote_port = (osm_port_t*)cl_qmap_get( p_port_guid_tbl, p_remote_physp->port_guid ); + + if ( p_remote_port != (osm_port_t*)cl_qmap_end( p_port_guid_tbl ) ) + { + /* 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 (osm_port_discovery_count_get( p_remote_port ) && + osm_physp_get_port_state( p_remote_physp ) == IB_LINK_ACTIVE ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_drop_mgr_remove_port: " + "Forcing delayed heavy sweep. Remote " + "port 0x%016" PRIx64 " port num: 0x%X " + "was recognized in ACTIVE state\n", + cl_ntoh64( p_remote_physp->port_guid ), + remote_port_num ); + p_mgr->p_subn->force_delayed_heavy_sweep = TRUE; + } + } + + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_drop_mgr_remove_port: " + "Unlinking local node 0x%016" PRIx64 ", port 0x%X" + "\n\t\t\t\tand remote node 0x%016" PRIx64 + ", port 0x%X\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 ); + + osm_node_unlink( p_node, (uint8_t)port_num, + p_remote_node, (uint8_t)remote_port_num ); + + /* 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 ( osm_node_get_type( p_remote_node ) != IB_NODE_TYPE_SWITCH ) + { + if ( p_remote_port != (osm_port_t*)cl_qmap_end( p_port_guid_tbl ) ) + { + osm_port_discovery_count_reset( p_remote_port ); + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_drop_mgr_remove_port: " + "Resetting discovery count of node: " + "0x%016" PRIx64 " port num:0x%X\n", + cl_ntoh64( osm_node_get_node_guid( p_remote_node ) ), + remote_port_num ); + } + } + } + + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_drop_mgr_remove_port: " + "Clearing physical port number 0x%X\n", + port_num ); + + osm_physp_destroy( p_physp ); + } + } + + p_mcm = (osm_mcm_info_t*)cl_qlist_remove_head( &p_port->mcm_list ); + while( p_mcm != (osm_mcm_info_t *)cl_qlist_end( &p_port->mcm_list ) ) + { + p_mgrp = (osm_mgrp_t *)cl_qmap_get( &p_mgr->p_subn->mgrp_mlid_tbl, + p_mcm->mlid ); + if(p_mgrp != (osm_mgrp_t *)cl_qmap_end( &p_mgr->p_subn->mgrp_mlid_tbl ) ) + { + osm_mgrp_remove_port(p_mgr->p_subn, p_mgr->p_log, p_mgrp, p_port->guid ); + osm_mcm_info_delete( (osm_mcm_info_t*)p_mcm ); + } + p_mcm = (osm_mcm_info_t*)cl_qlist_remove_head( &p_port->mcm_list ); + } + + /* initialize the p_node - may need to get node_desc later */ + p_node = p_port->p_node; + + osm_port_delete( &p_port ); + + /* issue a notice - trap 65 */ + + /* details of the notice */ + notice.generic_type = 0x83; /* is generic subn mgt type */ + ib_notice_set_prod_type_ho(¬ice, 4); /* A class manager generator */ + /* endport ceases to be reachable */ + notice.g_or_v.generic.trap_num = CL_HTON16(65); + /* The sm_base_lid is saved in network order already. */ + notice.issuer_lid = p_mgr->p_subn->sm_base_lid; + /* following C14-72.1.2 and table 119 p725 */ + /* we need to provide the GID */ + port_gid.unicast.prefix = p_mgr->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 = p_mgr->p_subn->opt.subnet_prefix; + notice.issuer_gid.unicast.interface_id = p_mgr->p_subn->sm_port_guid; + + status = osm_report_notice(p_mgr->p_log, p_mgr->p_subn, ¬ice); + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_drop_mgr_remove_port: ERR 0103: " + "Error sending trap reports (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + + if (osm_log_is_active( p_mgr->p_log, OSM_LOG_INFO )) + { + char desc[IB_NODE_DESCRIPTION_SIZE + 1]; + + if (p_node) + { + memcpy(desc, p_node->node_desc.description, IB_NODE_DESCRIPTION_SIZE); + desc[IB_NODE_DESCRIPTION_SIZE] = '\0'; + } + osm_log( p_mgr->p_log, OSM_LOG_INFO, + "__osm_drop_mgr_remove_port: " + "Removed port with GUID:0x%016" PRIx64 + " LID range [0x%X,0x%X] of node:%s\n", + cl_ntoh64( port_gid.unicast.interface_id ), + min_lid_ho, max_lid_ho, p_node ? desc : "UNKNOWN" ); + } + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_drop_mgr_remove_switch( + IN const osm_drop_mgr_t* const p_mgr, + 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( p_mgr->p_log, __osm_drop_mgr_remove_switch ); + + node_guid = osm_node_get_node_guid( p_node ); + p_sw_guid_tbl = &p_mgr->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( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_drop_mgr_remove_switch: 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( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +__osm_drop_mgr_process_node( + IN const osm_drop_mgr_t* const p_mgr, + IN osm_node_t* p_node ) +{ + osm_physp_t *p_physp; + osm_port_t *p_port; + osm_node_t *p_node_check; + cl_qmap_t *p_node_guid_tbl; + uint32_t port_num; + uint32_t max_ports; + ib_net64_t port_guid; + cl_qmap_t* p_port_guid_tbl; + boolean_t return_val = FALSE; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_drop_mgr_process_node ); + + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_drop_mgr_process_node: " + "Unreachable node 0x%016" PRIx64 "\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) ) ); + + /* + Delete all the logical and physical port objects + associated with this node. + */ + p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl; + + 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( osm_physp_is_valid( p_physp ) ) + { + port_guid = osm_physp_get_port_guid( p_physp ); + + p_port = (osm_port_t*)cl_qmap_get( p_port_guid_tbl, port_guid ); + + if( p_port != (osm_port_t*)cl_qmap_end( p_port_guid_tbl ) ) + __osm_drop_mgr_remove_port( p_mgr, p_port ); + } + } + + return_val = TRUE; + + if (p_node->sw) + __osm_drop_mgr_remove_switch( p_mgr, p_node ); + + p_node_guid_tbl = &p_mgr->p_subn->node_guid_tbl; + p_node_check = (osm_node_t*)cl_qmap_remove( p_node_guid_tbl, + osm_node_get_node_guid( p_node ) ); + if( p_node_check != p_node ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_drop_mgr_process_node: 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( p_mgr->p_log ); + return( return_val ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_drop_mgr_check_node( + IN const osm_drop_mgr_t* const p_mgr, + IN osm_node_t* p_node ) +{ + ib_net64_t node_guid; + osm_physp_t *p_physp; + osm_port_t *p_port; + cl_qmap_t* p_port_guid_tbl; + ib_net64_t port_guid; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_drop_mgr_check_node ); + + node_guid = osm_node_get_node_guid( p_node ); + + if ( osm_node_get_type( p_node ) != IB_NODE_TYPE_SWITCH ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_drop_mgr_check_node: 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( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_drop_mgr_check_node: " + "Node 0x%016" PRIx64 " no switch in table\n", + cl_ntoh64( node_guid ) ); + + __osm_drop_mgr_process_node( p_mgr, p_node ); + goto Exit; + } + + /* Make sure we have a port object for port zero */ + p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl; + p_physp = osm_node_get_physp_ptr( p_node, 0 ); + if ( !osm_physp_is_valid( p_physp ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_drop_mgr_check_node: " + "Node 0x%016" PRIx64 " no valid physical port 0\n", + cl_ntoh64( node_guid ) ); + + __osm_drop_mgr_process_node( p_mgr, p_node ); + goto Exit; + } + + port_guid = osm_physp_get_port_guid( p_physp ); + + p_port = (osm_port_t*)cl_qmap_get( + p_port_guid_tbl, port_guid ); + + if( p_port == (osm_port_t*)cl_qmap_end( p_port_guid_tbl ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_drop_mgr_check_node: " + "Node 0x%016" PRIx64 " has no port object\n", + cl_ntoh64( node_guid ) ); + + __osm_drop_mgr_process_node( p_mgr, p_node ); + goto Exit; + } + + if ( osm_port_discovery_count_get( p_port ) == 0 ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_drop_mgr_check_node: " + "Node 0x%016" PRIx64 " port has discovery count zero\n", + cl_ntoh64( node_guid ) ); + + __osm_drop_mgr_process_node( p_mgr, p_node ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); + return; +} + +/********************************************************************** + **********************************************************************/ +void +osm_drop_mgr_process( + IN const osm_drop_mgr_t* const p_mgr ) +{ + cl_qmap_t *p_node_guid_tbl; + cl_qmap_t *p_port_guid_tbl; + cl_list_t *p_lsweep_ports; + osm_port_t *p_port; + osm_port_t *p_next_port; + osm_node_t *p_node; + osm_node_t *p_next_node; + ib_net64_t port_guid; + ib_net64_t node_guid; + uint8_t port_num; + osm_physp_t *p_physp; + + CL_ASSERT( p_mgr ); + + OSM_LOG_ENTER( p_mgr->p_log, osm_drop_mgr_process ); + + p_node_guid_tbl = &p_mgr->p_subn->node_guid_tbl; + p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl; + p_lsweep_ports = &p_mgr->p_subn->light_sweep_physp_list; + + CL_PLOCK_EXCL_ACQUIRE( p_mgr->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 ) ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + node_guid = osm_node_get_node_guid( p_node ); + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_drop_mgr_process: " + "Checking node 0x%016" PRIx64 "\n", + cl_ntoh64( node_guid ) ); + } + + /* + 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( osm_node_discovery_count_get( p_node ) == 0 ) + __osm_drop_mgr_process_node( p_mgr, 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 ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + node_guid = osm_node_get_node_guid( p_node ); + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_drop_mgr_process: " + "Checking full discovery of node 0x%016" PRIx64 "\n", + cl_ntoh64( node_guid ) ); + } + + if ( osm_node_get_type( p_node ) != IB_NODE_TYPE_SWITCH ) + continue; + + /* We are handling a switch node */ + __osm_drop_mgr_check_node( p_mgr, 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 ) ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + port_guid = osm_port_get_guid( p_port ); + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_drop_mgr_process: " + "Checking port 0x%016" PRIx64 "\n", + cl_ntoh64( port_guid ) ); + } + + /* + If the port is unreachable, remove it from the guid table. + */ + if( osm_port_discovery_count_get( p_port ) == 0 ) + __osm_drop_mgr_remove_port( p_mgr, p_port ); + } + + /* + scan through all the ports left - if the port is not DOWN and + it does not have a valid remote port - we need to track it for + next light sweep scan... + */ + cl_list_remove_all( p_lsweep_ports ); + 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 ); + + 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 (osm_physp_is_valid(p_physp) && + (osm_physp_get_port_state(p_physp) != IB_LINK_DOWN) && + ! osm_physp_get_remote(p_physp)) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_drop_mgr_process: ERR 0108: " + "Unknown remote side for node 0x%016" PRIx64 + " port %u. Adding to light sweep sampling list\n", + cl_ntoh64( osm_node_get_node_guid( p_node )), + port_num); + + osm_dump_dr_path(p_mgr->p_log, + osm_physp_get_dr_path_ptr( p_physp ), + OSM_LOG_ERROR); + + cl_list_insert_head( p_lsweep_ports, p_physp ); + } + } + } + + CL_PLOCK_RELEASE( p_mgr->p_lock ); + OSM_LOG_EXIT( p_mgr->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_files.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_files.c new file mode 100644 index 00000000..c7f6fbf7 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_files.c @@ -0,0 +1,99 @@ +#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 +#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-1/ulp/opensm/user/opensm/osm_fwd_tbl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_fwd_tbl.c new file mode 100644 index 00000000..1365f385 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_fwd_tbl.c @@ -0,0 +1,115 @@ +/* + * 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: + * Implementation of osm_fwd_tbl_t. + * This object represents a unicast forwarding table. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_fwd_tbl_init( + IN osm_fwd_tbl_t* const p_tbl, + IN const ib_switch_info_t* const p_si ) +{ + uint16_t tbl_cap; + ib_api_status_t status = IB_SUCCESS; + + /* + Determine the type and size of the forwarding table + used by this switch, then initialize accordingly. + The current implementation only supports switches + with linear forwarding tables. + */ + tbl_cap = cl_ntoh16( p_si->lin_cap ); + + if( tbl_cap == 0 ) + { + /* + This switch does not support linear forwarding + tables. Error out for now. + */ + status = IB_UNSUPPORTED; + goto Exit; + } + + p_tbl->p_rnd_tbl = NULL; + + p_tbl->p_lin_tbl = osm_lin_tbl_new( tbl_cap ); + + if( p_tbl->p_lin_tbl == NULL ) + { + status = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + + Exit: + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_fwd_tbl_destroy( + IN osm_fwd_tbl_t* const p_tbl ) +{ + if( p_tbl->p_lin_tbl ) + { + CL_ASSERT( p_tbl->p_rnd_tbl == NULL ); + osm_lin_tbl_delete( &p_tbl->p_lin_tbl ); + } + else + { + osm_rand_tbl_delete( &p_tbl->p_rnd_tbl ); + } +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_inform.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_inform.c new file mode 100644 index 00000000..2bd875c1 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_inform.c @@ -0,0 +1,763 @@ +/* + * 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: + * Implementation of inform record functions. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.18 $ + */ + +#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_construct( + IN osm_infr_t* const p_infr ) +{ + memset( p_infr, 0, sizeof(osm_infr_t) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_infr_destroy( + IN osm_infr_t* const p_infr ) +{ + free( p_infr ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_infr_init( + IN osm_infr_t* const p_infr, + IN const osm_infr_t *p_infr_rec ) +{ + CL_ASSERT( p_infr ); + + /* what else do we need in the inform_record ??? */ + + /* copy the contents of the provided informinfo */ + memcpy( p_infr, p_infr_rec, sizeof(osm_infr_t) ); +} + +/********************************************************************** + **********************************************************************/ +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 ) + { + osm_infr_init( p_infr, p_infr_rec ); + } + + return( p_infr ); +} + +/********************************************************************** + **********************************************************************/ +void +__dump_all_informs( + IN osm_subn_t const *p_subn, + IN osm_log_t *p_log) +{ + cl_list_item_t* p_list_item; + + OSM_LOG_ENTER( p_log, __dump_all_informs ); + + if( !osm_log_is_active( p_log, OSM_LOG_DEBUG ) ) + goto Exit; + + 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 ); + } + + Exit: + OSM_LOG_EXIT( p_log ); +} + +/********************************************************************** + * Match an infr by the InformInfo and Address vector + **********************************************************************/ +static cl_status_t +__match_inf_rec( + IN const cl_list_item_t* const p_list_item, + IN void* context ) +{ + osm_infr_t* p_infr_rec = (osm_infr_t *)context; + osm_infr_t* p_infr = (osm_infr_t*)p_list_item; + osm_log_t *p_log = p_infr_rec->p_infr_rcv->p_log; + cl_status_t status = CL_NOT_FOUND; + ib_gid_t all_zero_gid; + + OSM_LOG_ENTER( p_log, __match_inf_rec); + + if ( memcmp( &p_infr->report_addr, + &p_infr_rec->report_addr, + sizeof(p_infr_rec->report_addr)) ) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__match_inf_rec: " + "Differ by Address\n" ); + goto Exit; + } + + memset( &all_zero_gid, 0, sizeof(ib_gid_t) ); + + /* if inform_info.gid is not zero, ignore lid range */ + if ( !memcmp( &p_infr_rec->inform_record.inform_info.gid, + &all_zero_gid, + sizeof(p_infr_rec->inform_record.inform_info.gid)) ) + { + if ( memcmp( &p_infr->inform_record.inform_info.gid, + &p_infr_rec->inform_record.inform_info.gid, + sizeof(p_infr->inform_record.inform_info.gid)) ) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__match_inf_rec: " + "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, + "__match_inf_rec: " + "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, + "__match_inf_rec: " + "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, + "__match_inf_rec: " + "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, + "__match_inf_rec: " + "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, + "__match_inf_rec: " + "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, + "__match_inf_rec: " + "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, + "__match_inf_rec: " + "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, + "__match_inf_rec: " + "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, + "__match_inf_rec: " + "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, + "__match_inf_rec: " + "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, + "__match_inf_rec: " + "Differ by InformInfo.Vendor.VendorIdLSB\n" ); + else + status = CL_SUCCESS; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return status; +} + +/********************************************************************** + **********************************************************************/ +osm_infr_t* +osm_infr_get_by_rec( + IN osm_subn_t const *p_subn, + IN osm_log_t *p_log, + IN osm_infr_t* const p_infr_rec ) +{ + cl_list_item_t* p_list_item; + + OSM_LOG_ENTER( p_log, osm_infr_get_by_rec ); + + __dump_all_informs( p_subn, p_log ); + + osm_log( p_log, OSM_LOG_DEBUG, + "osm_infr_get_by_rec: " + "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, + "osm_infr_get_by_rec: " + "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_infr_insert_to_db ); + + osm_log( p_log, OSM_LOG_DEBUG, + "osm_infr_insert_to_db: " + "Inserting new InformInfo Record into Database\n" ); + osm_log( p_log, OSM_LOG_DEBUG, + "osm_infr_insert_to_db: " + "Dump before insertion (size %d)\n", + cl_qlist_count(&p_subn->sa_infr_list) ); + __dump_all_informs( p_subn, p_log ); + +#if 0 + osm_dump_inform_info( p_log, + &(p_infr->inform_record.inform_info), OSM_LOG_DEBUG ); +#endif + + cl_qlist_insert_head( &p_subn->sa_infr_list, + &p_infr->list_item ); + + osm_log( p_log, OSM_LOG_DEBUG, + "osm_infr_insert_to_db: " + "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) +{ + OSM_LOG_ENTER( p_log, osm_infr_remove_from_db ); + + osm_log( p_log, OSM_LOG_DEBUG, + "osm_infr_remove_from_db: " + "Removing InformInfo Subscribing GID:0x%016" PRIx64 " : 0x%016" PRIx64 + " Enum:0x%X from Database\n", + cl_ntoh64(p_infr->inform_record.subscriber_gid.unicast.prefix), + cl_ntoh64(p_infr->inform_record.subscriber_gid.unicast.interface_id), + p_infr->inform_record.subscriber_enum + ); + + osm_dump_inform_info( p_log, &(p_infr->inform_record.inform_info), OSM_LOG_DEBUG ); + + cl_qlist_remove_item( &p_subn->sa_infr_list, + &p_infr->list_item ); + + osm_infr_destroy( p_infr ); + + OSM_LOG_EXIT( p_log ); +} + +/********************************************************************** + * Send a report: + * Given a target address to send to and the notice. + * We need to send SubnAdmReport + **********************************************************************/ +static ib_api_status_t +__osm_send_report( + IN osm_infr_t* p_infr_rec, /* the informinfo */ + IN ib_mad_notice_attr_t* p_ntc /* notice to send */ + ) +{ + osm_madw_t* p_report_madw; + ib_mad_notice_attr_t* p_report_ntc; + ib_mad_t* p_mad; + ib_sa_mad_t* p_sa_mad; + static atomic32_t trap_fwd_trans_id = 0x02DAB000; + ib_api_status_t status; + osm_log_t * p_log = p_infr_rec->p_infr_rcv->p_log; + + OSM_LOG_ENTER( p_log, __osm_send_report ); + + /* 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, + "__osm_send_report: " + "Forwarding Notice Event from LID:0x%X" + " to InformInfo LID: 0x%X 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->p_infr_rcv->p_mad_pool, + p_infr_rec->h_bind, + MAD_BLOCK_SIZE, + &(p_infr_rec->report_addr) ); + + p_report_madw->resp_expected = TRUE; + + if( !p_report_madw ) + { + osm_log( p_log, OSM_LOG_ERROR, + "__osm_send_report: ERR 0203: " + "osm_mad_pool_get failed\n" ); + status = IB_ERROR; + goto Exit; + } + + /* advance trap trans id (cant simply ++ on some systems inside ntoh) */ + p_mad = osm_madw_get_mad_ptr( p_report_madw ); + ib_mad_init_new( p_mad, + IB_MCLASS_SUBN_ADM, + 2, + IB_MAD_METHOD_REPORT, + cl_hton64( (uint64_t)cl_atomic_inc( &trap_fwd_trans_id ) ), + IB_MAD_ATTR_NOTICE, + 0 ); + + p_sa_mad = osm_madw_get_sa_mad_ptr( p_report_madw ); + + p_report_ntc = (ib_mad_notice_attr_t*)&(p_sa_mad->data); + + /* copy the notice */ + *p_report_ntc = *p_ntc; + + /* The TRUE is for: response is expected */ + status = osm_vendor_send( p_report_madw->h_bind, p_report_madw, TRUE ); + if ( status != IB_SUCCESS ) + { + osm_log( p_log, OSM_LOG_ERROR, + "__osm_send_report: ERR 0204: " + "osm_vendor_send status = %s\n", + ib_get_err_str(status) ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return(status); +} + +/********************************************************************** + * This routine compares a given Notice and a ListItem of InformInfo type. + * PREREQUISITE: + * The Notice.GID should be pre-filled with the trap generator GID + **********************************************************************/ +static void +__match_notice_to_inf_rec( + IN cl_list_item_t* const p_list_item, + IN void* context ) +{ + osm_infr_match_ctxt_t* p_infr_match = (osm_infr_match_ctxt_t *)context; + ib_mad_notice_attr_t* p_ntc = p_infr_match->p_ntc; + cl_list_t* p_infr_to_remove_list = p_infr_match->p_remove_infr_list; + osm_infr_t* p_infr_rec = (osm_infr_t*)p_list_item; + ib_inform_info_t *p_ii = &(p_infr_rec->inform_record.inform_info); + cl_status_t status = CL_NOT_FOUND; + osm_log_t *p_log = p_infr_rec->p_infr_rcv->p_log; + osm_subn_t *p_subn = p_infr_rec->p_infr_rcv->p_subn; + ib_gid_t source_gid; + osm_port_t* p_src_port; + osm_port_t* p_dest_port; + + OSM_LOG_ENTER( p_log, __match_notice_to_inf_rec ); + + /* 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, + "__match_notice_to_inf_rec: " + "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, + "__match_notice_to_inf_rec: " + "Mismatch by LID Range. Needed: 0x%X <= 0x%X <= 0x%X\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, + "__match_notice_to_inf_rec: " + "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, + "__match_notice_to_inf_rec: " + "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, + "__match_notice_to_inf_rec: " + "Mismatch by Trap Num\n" ); + goto Exit; + } + + /* ProducerType ProducerType match or 0xFFFFFF */ + if ( (cl_ntoh32(ib_inform_info_get_node_type(p_ii)) != 0xFFFFFF) && + (ib_inform_info_get_node_type(p_ii) != ib_notice_get_prod_type(p_ntc)) ) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__match_notice_to_inf_rec: " + "Mismatch by Node Type: II=0x%06X Trap=0x%06X\n", + cl_ntoh32(ib_inform_info_get_node_type(p_ii)), + cl_ntoh32(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, + "__match_notice_to_inf_rec: " + "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, + "__match_notice_to_inf_rec: " + "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_port_t*)cl_qmap_get( &p_subn->port_guid_tbl, + source_gid.unicast.interface_id ); + + if( p_src_port == (osm_port_t*)cl_qmap_end( &(p_subn->port_guid_tbl)) ) + { + osm_log( p_log, OSM_LOG_INFO, + "__match_notice_to_inf_rec: " + "Cannot find source port with GUID:0x%016" PRIx64 "\n", + cl_ntoh64(source_gid.unicast.interface_id) ); + goto Exit; + } + + p_dest_port = + cl_ptr_vector_get( &p_subn->port_lid_tbl, + cl_ntoh16(p_infr_rec->report_addr.dest_lid) ); + if( !p_dest_port ) + { + osm_log( p_log, OSM_LOG_INFO, + "__match_notice_to_inf_rec: " + "Cannot find destination port with LID:0x%04x\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, + "__match_notice_to_inf_rec: " + "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, + "__match_notice_to_inf_rec: " + "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_notice_to_inf_rec: " + "MATCH! Sending Report...\n" ); + __osm_send_report( p_infr_rec, p_ntc ); + status = CL_SUCCESS; + + Exit: + OSM_LOG_EXIT( p_log ); +} + +/********************************************************************** + * Once a Trap was received by osm_trap_rcv, or a Trap sourced by + * the SM was sent (Traps 64-67), this routine is called with a copy of + * the notice data. + * Given a notice attribute - compare and see if it matches the InformInfo + * element and if it does - call the Report(Notice) for the + * target QP registered by the address stored in the InformInfo element + **********************************************************************/ +ib_api_status_t +osm_report_notice( + IN osm_log_t* const p_log, + IN osm_subn_t* p_subn, + IN ib_mad_notice_attr_t *p_ntc ) +{ + 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, osm_report_notice ); + + /* + * 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, + "osm_report_notice: " + "Ignoring Notice Reports since Inform List is not initialized yet!\n" ); + return IB_ERROR; + } + + /* an official Event information log */ + if ( ib_notice_is_generic(p_ntc) ) + { + osm_log( p_log, OSM_LOG_INFO, + "osm_report_notice: " + "Reporting Generic Notice type:%u num:%u" + " from LID:0x%04X GID:0x%016" PRIx64 + ",0x%016" PRIx64 "\n", + ib_notice_get_type(p_ntc), + cl_ntoh16(p_ntc->g_or_v.generic.trap_num), + cl_ntoh16(p_ntc->issuer_lid), + cl_ntoh64(p_ntc->issuer_gid.unicast.prefix), + cl_ntoh64(p_ntc->issuer_gid.unicast.interface_id) + ); + } + else + { + osm_log( p_log, OSM_LOG_INFO, + "osm_report_notice: " + "Reporting Vendor Notice type:%u vend:%u dev:%u" + " from LID:0x%04X GID:0x%016" PRIx64 + ",0x%016" PRIx64 "\n", + ib_notice_get_type(p_ntc), + cl_ntoh32(ib_notice_get_vend_id(p_ntc)), + cl_ntoh16(p_ntc->g_or_v.vend.dev_id), + cl_ntoh16(p_ntc->issuer_lid), + cl_ntoh64(p_ntc->issuer_gid.unicast.prefix), + cl_ntoh64(p_ntc->issuer_gid.unicast.interface_id) + ); + } + + /* Create a list that will hold all the infr records that should + be removed due to violation. o13-17.1.2 */ + cl_list_construct( &infr_to_remove_list ); + cl_list_init( &infr_to_remove_list, 5 ); + context.p_remove_infr_list = &infr_to_remove_list; + context.p_ntc = p_ntc; + + /* go over all inform info available at the subnet */ + /* try match to the given notice and send if match */ + cl_qlist_apply_func(&(p_subn->sa_infr_list), + __match_notice_to_inf_rec, + &context ); + + /* If we inserted items into the infr_to_remove_list - we need to + remove them */ + p_infr_rec = (osm_infr_t*)cl_list_remove_head(&infr_to_remove_list); + while ( p_infr_rec != NULL ) + { + p_next_infr_rec = (osm_infr_t*)cl_list_remove_head(&infr_to_remove_list); + osm_infr_remove_from_db ( p_subn, p_log, p_infr_rec ); + p_infr_rec = p_next_infr_rec; + } + cl_list_destroy(&infr_to_remove_list); + + OSM_LOG_EXIT( p_log ); + + return(IB_SUCCESS); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_lid_mgr.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_lid_mgr.c new file mode 100644 index 00000000..565fa2c4 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_lid_mgr.c @@ -0,0 +1,1494 @@ +/* + * 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: + * Implementation of osm_lid_mgr_t. + * This file implements the LID Manager object which is responsible for + * assigning LIDs to all ports on the subnet. + * + * DATA STRUCTURES: + * p_subn->port_lid_tbl : a vector pointing from lid to its port. + * osm db guid2lid domain : a hash from guid to lid (min lid). + * p_subn->port_guid_tbl : a map from guid to discovered port obj. + * + * ALGORITHM: + * + * 0. we define a function to obtain the correct port lid: + * __osm_lid_mgr_get_port_lid( p_mgr, port, &min_lid ): + * 0.1 if the port info lid matches the guid2lid return 0 + * 0.2 if the port info has a lid and that range is empty in + * port_lid_tbl, return 0 and update the port_lid_tbl and + * guid2lid + * 0.3 else find an empty space in port_lid_tbl, update the + * port_lid_tbl and guid2lid, return 1 to flag a change required. + * + * 1. During initialization: + * 1.1 initialize the guid2lid database domain. + * 1.2 if reassign_lid is not set: + * 1.2.1 read the persistent data for the domain. + * 1.2.2 validate no duplicate use of lids and lids are 2^(lmc-1) + * + * 2. During SM port lid assignment: + * 2.1 if reassign_lids is set, make it 2^lmc + * 2.2 cleanup all port_lid_tbl and re-fill it according to guid2lid + * 2.3 call __osm_lid_mgr_get_port_lid the SM port + * 2.4 set the port info + * + * 3. During all other ports lid assignment: + * 3.1 go through all ports in the subnet + * 3.1.1 call __osm_lid_mgr_get_port_min_lid + * 3.1.2 if a change required send the port info + * 3.2 if any change send the signal PENDING... + * + * 4. Store the guid2lid + * + * Environment: + * Linux User Mode + * + * $Revision: 1.15 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + lid range item of qlist + **********************************************************************/ +typedef struct _osm_lid_mgr_range { + cl_list_item_t item; + uint16_t min_lid; + uint16_t max_lid; +} osm_lid_mgr_range_t; + +/********************************************************************** + **********************************************************************/ +void +osm_lid_mgr_construct( + IN osm_lid_mgr_t* const p_mgr ) +{ + memset( p_mgr, 0, sizeof(*p_mgr) ); + cl_ptr_vector_construct( &p_mgr->used_lids ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_lid_mgr_destroy( + IN osm_lid_mgr_t* const p_mgr ) +{ + cl_list_item_t *p_item; + + OSM_LOG_ENTER( p_mgr->p_log, osm_lid_mgr_destroy ); + + cl_ptr_vector_destroy( &p_mgr->used_lids ); + p_item = cl_qlist_remove_head( &p_mgr->free_ranges ); + while ( p_item != cl_qlist_end( &p_mgr->free_ranges ) ) + { + free((osm_lid_mgr_range_t *)p_item); + p_item = cl_qlist_remove_head( &p_mgr->free_ranges ); + } + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** +Validate the guid to lid data by making sure that under the current +LMC we did not get duplicates. If we do flag them as errors and remove +the entry. +**********************************************************************/ +static void +__osm_lid_mgr_validate_db( + IN osm_lid_mgr_t* p_mgr) +{ + cl_qlist_t guids; + osm_db_guid_elem_t *p_item; + uint16_t lid; + uint16_t min_lid; + uint16_t max_lid; + uint16_t lmc_mask; + boolean_t lids_ok; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_lid_mgr_validate_db ); + + if (p_mgr->p_subn->opt.lmc) + lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1); + else + lmc_mask = 0xffff; + + cl_qlist_init( &guids ); + + if (osm_db_guid2lid_guids( p_mgr->p_g2l, &guids )) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_lid_mgr_validate_db: ERR 0310: " + "could not get guid list\n"); + goto Exit; + } + + p_item = (osm_db_guid_elem_t*)cl_qlist_remove_head(&guids); + while ((cl_list_item_t*)p_item != cl_qlist_end(&guids)) + { + if (osm_db_guid2lid_get( p_mgr->p_g2l, p_item->guid, &min_lid, &max_lid )) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_lid_mgr_validate_db: 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_unicast_lid_ho)) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_lid_mgr_validate_db: ERR 0312: " + "Illegal LID range [0x%x:0x%x] 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, + "__osm_lid_mgr_validate_db: ERR 0313: " + "LID range [0x%x:0x%x] for guid:0x%016" PRIx64 + " is not aligned according to mask:0x%04x\n", + min_lid, max_lid, p_item->guid, lmc_mask + ); + lids_ok = FALSE; + } + else + { + /* check if the lids were not previously assigned */ + for (lid = min_lid; lid <= max_lid; lid++) + { + if (( cl_ptr_vector_get_size( &p_mgr->used_lids ) > lid ) && + ( cl_ptr_vector_get( &p_mgr->used_lids, lid ) ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_lid_mgr_validate_db: ERR 0314: " + "0x%04x for guid:0x%016" PRIx64 + " was previously used\n", + lid, p_item->guid + ); + lids_ok = FALSE; + } + } + } + + if (!lids_ok) + { + if (osm_db_guid2lid_delete( p_mgr->p_g2l, p_item->guid )) + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_lid_mgr_validate_db: ERR 0315: " + "failed to delete entry for guid:0x%016" PRIx64 + "\n", + p_item->guid + ); + } + else + { + /* mark it was visited */ + for (lid = min_lid; lid <= max_lid; lid++) + cl_ptr_vector_set( &p_mgr->used_lids, lid, (void *)1); + } + } /* got a lid */ + p_item = (osm_db_guid_elem_t*)cl_qlist_remove_head(&guids); + } /* all guids */ + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_lid_mgr_init( + IN osm_lid_mgr_t* const p_mgr, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_db_t* const p_db, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_lid_mgr_init ); + + CL_ASSERT( p_req ); + CL_ASSERT( p_subn ); + CL_ASSERT( p_lock ); + CL_ASSERT( p_db ); + + osm_lid_mgr_construct( p_mgr ); + + p_mgr->p_log = p_log; + p_mgr->p_subn = p_subn; + p_mgr->p_db = p_db; + p_mgr->p_lock = p_lock; + p_mgr->p_req = p_req; + + /* 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, + "osm_lid_mgr_init: ERR 0316: " + "Error initializing Guid-to-Lid persistent database\n"); + status = IB_ERROR; + goto Exit; + } + + cl_ptr_vector_init( &p_mgr->used_lids, 100, 40 ); + cl_qlist_init( &p_mgr->free_ranges ); + + /* we use the stored guid to lid table if not forced to reassign */ + if (!p_mgr->p_subn->opt.reassign_lids) + { + if (osm_db_restore(p_mgr->p_g2l)) + { +#ifndef __WIN__ + /* + * When Windows is BSODing, it might corrupt files that were + * previously opened for writing, even if the files are closed. + * This is because of Windows write caching option. + * As a result, we might see corrupted guid2lid file. + */ + if (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, + "osm_lid_mgr_init: ERR 0317: " + "Error restoring Guid-to-Lid persistent database\n"); + } + } + + /* we need to make sure we did not get duplicates with + current lmc */ + __osm_lid_mgr_validate_db(p_mgr); + } + +Exit: + OSM_LOG_EXIT( p_mgr->p_log ); + return( status ); +} + +static uint16_t +__osm_trim_lid( + IN uint16_t lid ) +{ + if ((lid > IB_LID_UCAST_END_HO) || + (lid < IB_LID_UCAST_START_HO)) + return 0; + return lid; +} + +/********************************************************************** + initialize the manager for a new sweep: + scans the known persistent assignment and port_lid_tbl + re-calculate all empty ranges. + cleanup invalid port_lid_tbl entries +**********************************************************************/ +static int +__osm_lid_mgr_init_sweep( + IN osm_lid_mgr_t* const p_mgr ) +{ + cl_ptr_vector_t *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl; + cl_ptr_vector_t *p_persistent_vec = &p_mgr->used_lids; + uint16_t max_defined_lid; + uint16_t max_persistent_lid; + uint16_t max_discovered_lid; + uint16_t lid; + uint16_t disc_min_lid; + uint16_t disc_max_lid; + uint16_t db_min_lid; + uint16_t db_max_lid; + int status = 0; + cl_list_item_t *p_item; + boolean_t is_free; + osm_lid_mgr_range_t *p_range = NULL; + osm_port_t *p_port; + cl_qmap_t *p_port_guid_tbl; + uint8_t lmc_num_lids = (uint8_t)(1 << p_mgr->p_subn->opt.lmc); + uint16_t lmc_mask; + uint16_t req_lid, num_lids; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_lid_mgr_init_sweep ); + + if (p_mgr->p_subn->opt.lmc) + lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1); + else + lmc_mask = 0xffff; + + /* if we came out of standby we need to discard any previous guid2lid + info we might have. + Do this only if the honor_guid2lid_file option is FALSE. If not, then + need to honor this file. */ + if ( p_mgr->p_subn->coming_out_of_standby == TRUE ) + { + if ( p_mgr->p_subn->opt.honor_guid2lid_file == FALSE ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_init_sweep: " + "Ignore guid2lid file when coming out of standby\n"); + osm_db_clear( p_mgr->p_g2l ); + for (lid = 0; lid < cl_ptr_vector_get_size(&p_mgr->used_lids); lid++) + cl_ptr_vector_set(p_persistent_vec, lid, NULL); + } + else + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_init_sweep: " + "Honor current guid2lid file when coming out of standby\n"); + osm_db_clear( p_mgr->p_g2l ); + if (osm_db_restore(p_mgr->p_g2l)) + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_lid_mgr_init_sweep: ERR 0306: " + "Error restoring Guid-to-Lid persistent database. Ignoring it\n"); + } + } + + /* we need to cleanup the empty ranges list */ + p_item = cl_qlist_remove_head( &p_mgr->free_ranges ); + while ( p_item != cl_qlist_end( &p_mgr->free_ranges ) ) + { + free( (osm_lid_mgr_range_t *)p_item ); + p_item = cl_qlist_remove_head( &p_mgr->free_ranges ); + } + + /* first clean up the port_by_lid_tbl */ + for (lid = 0; lid < cl_ptr_vector_get_size(p_discovered_vec); lid++) + cl_ptr_vector_set(p_discovered_vec, lid, NULL); + + /* we if are in the first sweep and in reassign lids mode + we should ignore all the available info and simply define one + huge empty range */ + if ((p_mgr->p_subn->first_time_master_sweep == TRUE) && + (p_mgr->p_subn->opt.reassign_lids == TRUE )) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_init_sweep: " + "Skipping all lids as we are reassigning them\n"); + p_range = + (osm_lid_mgr_range_t *)malloc(sizeof(osm_lid_mgr_range_t)); + p_range->min_lid = 1; + goto AfterScanningLids; + } + + /* go over all discovered ports and mark their entries */ + p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl; + + for( p_port = (osm_port_t*)cl_qmap_head( p_port_guid_tbl ); + p_port != (osm_port_t*)cl_qmap_end( p_port_guid_tbl ); + p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item ) ) + { + osm_port_get_lid_range_ho(p_port, &disc_min_lid, &disc_max_lid); + disc_min_lid = __osm_trim_lid(disc_min_lid); + disc_max_lid = __osm_trim_lid(disc_max_lid); + for (lid = disc_min_lid; lid <= disc_max_lid; lid++) + cl_ptr_vector_set(p_discovered_vec, lid, p_port ); + /* make sure the guid2lid entry is valid. If not, clean it. */ + if (!osm_db_guid2lid_get( p_mgr->p_g2l, + cl_ntoh64(osm_port_get_guid(p_port)), + &db_min_lid, &db_max_lid)) + { + if ( !p_port->p_node->sw || + osm_switch_sp0_is_lmc_capable(p_port->p_node->sw, p_mgr->p_subn)) + num_lids = lmc_num_lids; + else + num_lids = 1; + + if ((num_lids != 1) && + (((db_min_lid & lmc_mask) != db_min_lid) || + (db_max_lid - db_min_lid + 1 < num_lids)) ) + { + /* Not aligned, or not wide enough, then remove the entry */ + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_init_sweep: " + "Cleaning persistent entry for guid:0x%016" PRIx64 + " illegal range:[0x%x:0x%x]\n", + cl_ntoh64(osm_port_get_guid(p_port)), db_min_lid, + db_max_lid ); + osm_db_guid2lid_delete( p_mgr->p_g2l, + cl_ntoh64(osm_port_get_guid(p_port))); + for ( lid = db_min_lid ; lid <= db_max_lid ; lid++ ) + cl_ptr_vector_set(p_persistent_vec, lid, NULL); + } + } + } + + /* + Our task is to find free lid ranges. + A lid can be used if + 1. a persistent assignment exists + 2. the lid is used by a discovered port that does not have a persistent + assignment. + + scan through all lid values of both the persistent table and + discovered table. + If the lid has an assigned port in the discovered table: + * make sure the lid matches the persistent table, or + * there is no other persistent assignment for that lid. + * else cleanup the port_by_lid_tbl, mark this as empty range. + Else if the lid does not have an entry in the persistent table + mark it as free. + */ + + /* find the range of lids to scan */ + max_discovered_lid = (uint16_t)cl_ptr_vector_get_size(p_discovered_vec); + max_persistent_lid = (uint16_t)cl_ptr_vector_get_size(p_persistent_vec); + + /* but the vectors have one extra entry for lid=0 */ + if (max_discovered_lid) max_discovered_lid--; + if (max_persistent_lid) max_persistent_lid--; + + if (max_persistent_lid > max_discovered_lid) + max_defined_lid = max_persistent_lid; + else + max_defined_lid = max_discovered_lid; + + for (lid = 1; lid <= max_defined_lid ; lid++) + { + is_free = TRUE; + /* first check to see if the lid is used by a persistent assignment */ + if ((lid <= max_persistent_lid) && cl_ptr_vector_get(p_persistent_vec, lid)) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_init_sweep: " + "0x%04x is not free as its mapped by the persistent db\n", + lid); + is_free = FALSE; + } + else + { + /* check this is a discovered port */ + if (lid <= max_discovered_lid && (p_port = (osm_port_t *)cl_ptr_vector_get(p_discovered_vec, lid))) + { + /* we have a port. Now lets see if we can preserve its lid range. */ + /* For that, we need to make sure: + 1. The port has a (legal) persistency entry. Then the local lid + is free (we will use the persistency value). + 2. Can the port keep its local assignment? + a. Make sure the lid a aligned. + b. Make sure all needed lids (for the lmc) are free according + to persistency table. + */ + /* qualify the guid of the port is not persistently mapped to + another range */ + if (!osm_db_guid2lid_get( p_mgr->p_g2l, + cl_ntoh64(osm_port_get_guid(p_port)), + &db_min_lid, &db_max_lid)) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_init_sweep: " + "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, + "__osm_lid_mgr_init_sweep: " + "0x%04x is free as it was discovered " + "but not aligned\n", + lid ); + } + else + { + /* check that all needed lids are not persistently mapped */ + is_free = FALSE; + for ( req_lid = disc_min_lid + 1 ; req_lid <= disc_max_lid ; req_lid++ ) + { + if ((req_lid <= max_persistent_lid) && cl_ptr_vector_get(p_persistent_vec, req_lid)) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_init_sweep: " + "0x%04x is free as it was discovered " + "but mapped\n", + lid ); + is_free = TRUE; + break; + } + } + + if (is_free == FALSE) + { + /* This port will use its local lid, and consume the entire required lid range. + Thus we can skip that range. */ + /* If the disc_max_lid is greater then lid, we can skip right to it, + since we've done all neccessary checks on the lids in between. */ + if (disc_max_lid > lid) + lid = disc_max_lid; + } + } + } + } + } + + if (is_free) + { + if (p_range) + { + p_range->max_lid = lid; + } + else + { + p_range = + (osm_lid_mgr_range_t *)malloc(sizeof(osm_lid_mgr_range_t)); + p_range->min_lid = lid; + p_range->max_lid = lid; + } + } + else + { + /* this lid is used so we need to finalize the previous free range */ + if (p_range) + { + cl_qlist_insert_tail( &p_mgr->free_ranges, &p_range->item ); + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_init_sweep: " + "new free lid range [0x%x:0x%x]\n", + p_range->min_lid, p_range->max_lid); + p_range = NULL; + } + } + } + + AfterScanningLids: + /* after scanning all known lids we need to extend the last range + to the max allowed lid */ + if (!p_range) + { + p_range = + (osm_lid_mgr_range_t *)malloc(sizeof(osm_lid_mgr_range_t)); + /* + The p_range can be NULL in one of 2 cases: + 1. If max_defined_lid == 0. In this case, we want the entire range. + 2. If all lids discovered in the loop where mapped. In this case, + no free range exists and we want to define it after the last + mapped lid. + */ + p_range->min_lid = lid; + } + p_range->max_lid = p_mgr->p_subn->max_unicast_lid_ho - 1; + cl_qlist_insert_tail( &p_mgr->free_ranges, &p_range->item ); + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_init_sweep: " + "final free lid range [0x%x:0x%x]\n", + p_range->min_lid, p_range->max_lid ); + + OSM_LOG_EXIT( p_mgr->p_log ); + return status; +} + +/********************************************************************** + check if the given range of lids is free +**********************************************************************/ +static boolean_t +__osm_lid_mgr_is_range_not_persistent( + IN osm_lid_mgr_t* const p_mgr, + IN const uint16_t lid, + IN const uint16_t num_lids ) +{ + uint16_t i; + cl_status_t status; + osm_port_t *p_port; + const uint8_t start_lid = (uint8_t)(1 << p_mgr->p_subn->opt.lmc); + const cl_ptr_vector_t* const p_tbl = &p_mgr->used_lids; + + if( lid < start_lid ) + return( FALSE ); + + for( i = lid; i < lid + num_lids; i++ ) + { + status = cl_ptr_vector_at( p_tbl, i, (void*)&p_port ); + if( status == CL_SUCCESS ) + { + if(p_port != NULL) + return( FALSE ); + } + else + { + /* + We are out of range in the array. + Consider all further entries "free". + */ + return( TRUE ); + } + } + + return( TRUE ); +} + +/********************************************************************** +find a free lid range +**********************************************************************/ +static void +__osm_lid_mgr_find_free_lid_range( + IN osm_lid_mgr_t* const p_mgr, + IN const uint8_t num_lids, + OUT uint16_t* const p_min_lid, + OUT uint16_t* const p_max_lid ) +{ + uint16_t lid; + cl_list_item_t *p_item; + cl_list_item_t *p_next_item; + osm_lid_mgr_range_t *p_range = NULL; + uint8_t lmc_num_lids; + uint16_t lmc_mask; + + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_find_free_lid_range: " + "LMC = %u, number LIDs = %u\n", + p_mgr->p_subn->opt.lmc, num_lids ); + + lmc_num_lids = (1 << p_mgr->p_subn->opt.lmc ); + if (p_mgr->p_subn->opt.lmc) + lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1); + else + lmc_mask = 0xffff; + + /* + Search the list of free lid ranges for a range which is big enough + */ + p_item = cl_qlist_head( &p_mgr->free_ranges ); + while( p_item != cl_qlist_end( &p_mgr->free_ranges ) ) + { + p_next_item = cl_qlist_next( p_item ); + p_range = (osm_lid_mgr_range_t *)p_item; + + lid = p_range->min_lid; + + /* if we require more then one lid we must align to LMC */ + if (num_lids > 1) + { + if ((lid & lmc_mask) != lid) + lid = (lid + lmc_num_lids) & lmc_mask; + } + + /* but we can be out of the range */ + if (lid + num_lids - 1 <= p_range->max_lid) + { + /* ok let us use that range */ + if (lid + num_lids - 1 == p_range->max_lid) + { + /* we consumed the entire range */ + cl_qlist_remove_item( &p_mgr->free_ranges, p_item ); + } + else + { + /* only update the available range */ + p_range->min_lid = lid + num_lids; + } + + *p_min_lid = lid; + *p_max_lid = (uint16_t)(lid + num_lids - 1); + return; + } + p_item = p_next_item; + } + + /* + Couldn't find a free range of lids. + */ + *p_min_lid = *p_max_lid = 0; + /* if we run out of lids, give an error and abort! */ + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_lid_mgr_find_free_lid_range: ERR 0307: " + "OPENSM RAN OUT OF LIDS!!!\n" ); + CL_ASSERT( 0 ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_lid_mgr_cleanup_discovered_port_lid_range( + IN osm_lid_mgr_t* p_mgr, + IN osm_port_t *p_port ) +{ + cl_ptr_vector_t *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl; + uint16_t lid, min_lid, max_lid; + uint16_t max_tbl_lid = (uint16_t)(cl_ptr_vector_get_size( p_discovered_vec )); + + osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid); + min_lid = __osm_trim_lid(min_lid); + max_lid = __osm_trim_lid(max_lid); + for (lid = min_lid; lid <= max_lid; lid++) + { + if ((lid < max_tbl_lid ) && + (p_port == (osm_port_t*)cl_ptr_vector_get(p_discovered_vec, lid))) + cl_ptr_vector_set(p_discovered_vec, lid, NULL ); + } +} + +/********************************************************************** + 0.1 if the port info lid matches the guid2lid return 0 + 0.2 if the port info has a lid and that range is empty in + port_lid_tbl, return 0 and update the port_lid_tbl and + guid2lid + 0.3 else find an empty space in port_lid_tbl, update the + port_lid_tbl and guid2lid, return 1 to flag a change required. +**********************************************************************/ +static int +__osm_lid_mgr_get_port_lid( + IN osm_lid_mgr_t* const p_mgr, + IN osm_port_t * const p_port, + OUT uint16_t* const p_min_lid, + OUT uint16_t* const p_max_lid) +{ + uint16_t lid, min_lid, max_lid; + uint64_t guid; + uint8_t num_lids = (1 << p_mgr->p_subn->opt.lmc); + int lid_changed = 0; + uint16_t lmc_mask; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_lid_mgr_get_port_lid ); + + if (p_mgr->p_subn->opt.lmc) + lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1); + else + lmc_mask = 0xffff; + + /* get the lid from the guid2lid */ + guid = cl_ntoh64( osm_port_get_guid( p_port ) ); + + /* if the port is a base switch port 0 then we only need one lid */ + if( p_port->p_node->sw && + !osm_switch_sp0_is_lmc_capable(p_port->p_node->sw, p_mgr->p_subn)) + num_lids = 1; + + /* if the port matches the guid2lid */ + if (!osm_db_guid2lid_get( p_mgr->p_g2l, guid, &min_lid, &max_lid)) + { + *p_min_lid = min_lid; + *p_max_lid = min_lid + num_lids - 1; + if (min_lid == cl_ntoh16(osm_port_get_base_lid(p_port))) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_get_port_lid: " + "0x%016" PRIx64" matches its known lid:0x%04x\n", + guid, min_lid ); + goto Exit; + } + else + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_get_port_lid: " + "0x%016" PRIx64 + " with lid:0x%04x does not match its known lid:0x%04x\n", + guid, cl_ntoh16(osm_port_get_base_lid(p_port)), min_lid); + __osm_lid_mgr_cleanup_discovered_port_lid_range( p_mgr, p_port ); + /* we still need to send the setting to the target port */ + lid_changed = 1; + goto Exit; + } + } + else + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_get_port_lid: " + "0x%016" PRIx64" has no persistent lid assigned\n", + guid ); + } + + /* if the port info carries a lid it must be lmc aligned and not mapped + by the pesistent storage */ + min_lid = cl_ntoh16(osm_port_get_base_lid(p_port)); + + /* we want to ignore the discovered lid if we are also on first sweep of + reassign lids flow */ + if (min_lid && + ! ((p_mgr->p_subn->first_time_master_sweep == TRUE) && + (p_mgr->p_subn->opt.reassign_lids == TRUE ))) + { + /* make sure lid is valid */ + if ((num_lids == 1) || ((min_lid & lmc_mask) == min_lid)) + { + /* is it free */ + if (__osm_lid_mgr_is_range_not_persistent(p_mgr, min_lid, num_lids)) + { + *p_min_lid = min_lid; + *p_max_lid = min_lid + num_lids - 1; + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_get_port_lid: " + "0x%016" PRIx64" lid range:[0x%x-0x%x] is free\n", + guid, *p_min_lid, *p_max_lid ); + goto NewLidSet; + } + else + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_get_port_lid: " + "0x%016" PRIx64 + " existing lid range:[0x%x:0x%x] is not free\n", + guid, min_lid, min_lid + num_lids - 1 ); + } + } + else + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_get_port_lid: " + "0x%016" PRIx64 + " existing lid range:[0x%x:0x%x] is not lmc aligned\n", + guid, min_lid, min_lid + num_lids - 1 ); + } + } + + /* first cleanup the existing discovered lid range */ + __osm_lid_mgr_cleanup_discovered_port_lid_range( p_mgr, p_port ); + + /* find an empty space */ + __osm_lid_mgr_find_free_lid_range(p_mgr, num_lids, p_min_lid, p_max_lid); + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_get_port_lid: " + "0x%016" PRIx64" assigned a new lid range:[0x%x-0x%x]\n", + guid, *p_min_lid, *p_max_lid ); + lid_changed = 1; + + NewLidSet: + /* update the guid2lid db and used_lids */ + osm_db_guid2lid_set(p_mgr->p_g2l, guid, *p_min_lid, *p_max_lid); + for (lid = *p_min_lid; lid <= *p_max_lid; lid++) + cl_ptr_vector_set(&p_mgr->used_lids, lid, (void*)1); + + Exit: + /* make sure the assigned lids are marked in port_lid_tbl */ + for (lid = *p_min_lid; lid <= *p_max_lid; lid++) + cl_ptr_vector_set(&p_mgr->p_subn->port_lid_tbl, lid, p_port); + + OSM_LOG_EXIT( p_mgr->p_log ); + return lid_changed; +} + +/********************************************************************** + Set to INIT the remote port of the given physical port + **********************************************************************/ +static void +__osm_lid_mgr_set_remote_pi_state_to_init( + IN osm_lid_mgr_t * const p_mgr, + IN osm_physp_t* const p_physp) +{ + ib_port_info_t *p_pi; + osm_physp_t *p_rem_physp = osm_physp_get_remote(p_physp); + + if ( p_rem_physp == NULL ) + return; + + if (osm_physp_is_valid( p_rem_physp )) + { + p_pi = osm_physp_get_port_info_ptr( p_rem_physp ); + /* but in some rare cases the remote side might be irresponsive */ + if (p_pi) + ib_port_info_set_port_state( p_pi, IB_LINK_INIT ); + } +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +__osm_lid_mgr_set_physp_pi( + IN osm_lid_mgr_t * const p_mgr, + IN osm_port_t* const p_port, + IN osm_physp_t* const p_physp, + IN ib_net16_t const lid ) +{ + uint8_t payload[IB_SMP_DATA_SIZE]; + ib_port_info_t* p_pi = (ib_port_info_t*)payload; + const ib_port_info_t* p_old_pi; + osm_madw_context_t context; + osm_node_t* p_node; + ib_api_status_t status; + uint8_t mtu; + uint8_t op_vls; + uint8_t port_num; + boolean_t send_set = FALSE; + boolean_t new_port = FALSE; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_lid_mgr_set_physp_pi ); + + /* + Don't bother doing anything if this Physical Port is not valid. + This allows simplified code in the caller. + */ + if( p_physp == NULL ) + goto Exit; + + if( !osm_physp_is_valid( 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). + */ + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_set_physp_pi: " + "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 = osm_physp_get_port_info_ptr( p_physp ); + + /* + First, copy existing parameters from the PortInfo attribute we + already have for this node. + + Second, update with default values that we know must be set for + every Physical Port and the LID and set the neighbor MTU field + appropriately. + + Third, send the SMP to this physical port. + */ + + memset( payload, 0, IB_SMP_DATA_SIZE ); + + /* Correction by FUJITSU */ + if( port_num != 0 ) + { + memcpy( payload, p_old_pi, sizeof(ib_port_info_t) ); + } + + /* + Correction following a bug injected by the previous + FUJITSU line: + + 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 + */ + /* these values can be set only for hca ports, so if we are + on a switch node, set these values to zero */ + if ( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH ) + p_pi->state_info2 = 0x0; + else + { + p_pi->state_info2 = 0x02; + /* Check to see if the value we are setting is different than + the value in the port_info. If it is, turn on send_set flag */ + 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; + } + + ib_port_info_set_port_state( p_pi, IB_LINK_NO_CHANGE ); + + p_pi->m_key = p_mgr->p_subn->opt.m_key; + /* Check to see if the value we are setting is different than + the value in the port_info. If it is, turn on send_set flag */ + 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; + /* Check to see if the value we are setting is different than + the value in the port_info. If it is, turn on send_set flag */ + if (memcmp( &p_pi->subnet_prefix, &p_old_pi->subnet_prefix, + sizeof(p_pi->subnet_prefix) )) + send_set = TRUE; + + p_pi->base_lid = lid; + /* Check to see if the value we are setting is different than + the value in the port_info. If it is, turn on send_set flag */ + 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; + /* Check to see if the value we are setting is different than + the value in the port_info. If it is, turn on send_set flag */ + 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; + /* Check to see if the value we are setting is different than + the value in the port_info. If it is, turn on send_set flag */ + 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 HCA ports + */ + ib_port_info_set_timeout( p_pi, p_mgr->p_subn->opt.subnet_timeout ); + /* Check to see if the value we are setting is different than + the value in the port_info. If it is, turn on send_set flag */ + if (ib_port_info_get_timeout( p_pi ) != ib_port_info_get_timeout( p_old_pi )) + send_set = TRUE; + + if( port_num != 0 ) + { + /* + HCA's 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; + /* Check to see if the value we are setting is different than + the value in the port_info. If it is, turn on send_set flag */ + if (memcmp( &p_pi->link_width_enabled, &p_old_pi->link_width_enabled, + sizeof(p_pi->link_width_enabled) )) + send_set = TRUE; + + if ( p_mgr->p_subn->opt.force_link_speed ) + ib_port_info_set_link_speed_enabled( p_pi, IB_LINK_SPEED_ACTIVE_2_5 ); + else if (ib_port_info_get_link_speed_enabled( p_old_pi ) != ib_port_info_get_link_speed_sup( p_pi )) + ib_port_info_set_link_speed_enabled( p_pi, IB_PORT_LINK_SPEED_ENABLED_MASK ); + else + ib_port_info_set_link_speed_enabled( p_pi, ib_port_info_get_link_speed_enabled( p_old_pi )); + if (memcmp( &p_pi->link_speed, &p_old_pi->link_speed, + sizeof(p_pi->link_speed) )) + send_set = TRUE; + + /* M_KeyProtectBits are always zero */ + p_pi->mkey_lmc = p_mgr->p_subn->opt.lmc; + /* Check to see if the value we are setting is different than + the value in the port_info. If it is, turn on send_set flag */ + 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))) + { + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_set_physp_pi: " + "Sending Link Down due to op_vls or mtu change. MTU:%u,%u VL_CAP:%u,%u\n", + 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 the remote + port is also going through "down" state into "init"... + */ + __osm_lid_mgr_set_remote_pi_state_to_init(p_mgr, p_physp); + + ib_port_info_set_port_state( p_pi, IB_LINK_DOWN ); + if ( ib_port_info_get_port_state(p_pi) != + ib_port_info_get_port_state(p_old_pi) ) + send_set = TRUE; + } + } + else + { + /* + For Port 0, NeighborMTU is relevant only for Enh. SP0. + In this case, we'll set the MTU according to the mtu_cap + */ + ib_port_info_set_neighbor_mtu( p_pi, ib_port_info_get_mtu_cap( p_old_pi ) ); + if ( ib_port_info_get_neighbor_mtu(p_pi) != + ib_port_info_get_neighbor_mtu(p_old_pi) ) + send_set = TRUE; + + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_set_physp_pi: " + "Updating neighbor_mtu on switch port 0 to:%u\n", + 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; + /* Check to see if the value we are setting is different than + the value in the port_info. If it is, turn on send_set flag */ + 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.update_master_sm_base_lid = FALSE; + context.pi_context.ignore_errors = FALSE; + 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 it is in + the p_subn->new_ports_list list. + */ + if ( cl_is_object_in_list(&p_mgr->p_subn->new_ports_list, p_port) ) + { + /* p_port is in new_ports_list, mark new_port as TRUE */ + new_port = TRUE; + } + + if ( ( p_mgr->p_subn->first_time_master_sweep == TRUE || + new_port == TRUE ) && + !p_mgr->p_subn->opt.no_clients_rereg && + ( (p_old_pi->capability_mask & IB_PORT_CAP_HAS_CLIENT_REREG) != 0 ) ) + ib_port_info_set_client_rereg( p_pi, 1 ); + 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. + 3. got_set_resp on the physical port is FALSE. This means we haven't seen + this port before and we need to send Set of PortInfo to it. + */ + if (send_set || p_mgr->p_subn->first_time_master_sweep == TRUE || + p_physp->got_set_resp == FALSE) + { + + p_mgr->send_set_reqs = TRUE; + status = osm_req_set( p_mgr->p_req, + osm_physp_get_dr_path_ptr( p_physp ), + payload, + sizeof(payload), + IB_MAD_ATTR_PORT_INFO, + cl_hton32(osm_physp_get_port_num( p_physp )), + CL_DISP_MSGID_NONE, + &context ); + } + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); + return (send_set || p_mgr->p_subn->first_time_master_sweep == TRUE || + p_physp->got_set_resp == FALSE); +} + +/********************************************************************** + Processes our own node + Lock must already be held. +**********************************************************************/ +static boolean_t +__osm_lid_mgr_process_our_sm_node( + IN osm_lid_mgr_t* const p_mgr ) +{ + osm_port_t *p_port; + uint16_t min_lid_ho; + uint16_t max_lid_ho; + osm_physp_t *p_physp; + boolean_t res = TRUE; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_lid_mgr_process_our_sm_node ); + + /* + Acquire our own port object. + */ + p_port = (osm_port_t*)cl_qmap_get( &p_mgr->p_subn->port_guid_tbl, + p_mgr->p_subn->sm_port_guid ); + + if( p_port == (osm_port_t*)cl_qmap_end( &p_mgr->p_subn->port_guid_tbl ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_lid_mgr_process_our_sm_node: ERR 0308: " + "Can't acquire SM's port object, GUID 0x%016" PRIx64 "\n", + cl_ntoh64( p_mgr->p_subn->sm_port_guid ) ); + res = FALSE; + goto Exit; + } + + /* + Determine the LID this SM will use for its own port. + Be careful. With an LMC > 0, the bottom of the LID range becomes + unusable, since port hardware will mask off least significant bits, + leaving a LID of 0 (invalid). Therefore, make sure that we always + configure the SM with a LID that has non-zero bits, even after + LMC masking by hardware. + */ + __osm_lid_mgr_get_port_lid(p_mgr, p_port, &min_lid_ho, &max_lid_ho); + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_lid_mgr_process_our_sm_node: " + "Current base LID is 0x%X\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 ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_lid_mgr_process_our_sm_node: " + "Assigning SM's port 0x%016" PRIx64 + "\n\t\t\t\tto LID range [0x%X,0x%X]\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. + */ + p_physp = osm_port_get_default_phys_ptr( p_port ); + + __osm_lid_mgr_set_physp_pi( p_mgr, p_port, p_physp, cl_hton16( min_lid_ho ) ); + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); + return res; +} + +/********************************************************************** + **********************************************************************/ +osm_signal_t +osm_lid_mgr_process_sm( + IN osm_lid_mgr_t* const p_mgr ) +{ + osm_signal_t signal = OSM_SIGNAL_DONE_PENDING; + + OSM_LOG_ENTER( p_mgr->p_log, osm_lid_mgr_process_sm ); + + CL_ASSERT( p_mgr->p_subn->sm_port_guid ); + + CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock ); + + /* initialize the port_lid_tbl and empty ranges list following the + persistent db */ + __osm_lid_mgr_init_sweep( p_mgr ); + + if (p_mgr->p_subn->opt.pfn_ui_pre_lid_assign) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "osm_lid_mgr_process_sm: " + "Invoking UI function pfn_ui_pre_lid_assign\n" ); + p_mgr->p_subn->opt.pfn_ui_pre_lid_assign( + p_mgr->p_subn->opt.ui_pre_lid_assign_ctx ); + } + + /* Set the send_set_reqs of the p_mgr to FALSE, and + we'll see if any set requests were sent. If not - + can signal OSM_SIGNAL_DONE */ + p_mgr->send_set_reqs = FALSE; + if ( __osm_lid_mgr_process_our_sm_node( p_mgr ) == FALSE ) + /* The initialization failed */ + signal = OSM_SIGNAL_DONE; + + if ( p_mgr->send_set_reqs == FALSE ) + signal = OSM_SIGNAL_DONE; + + CL_PLOCK_RELEASE( p_mgr->p_lock ); + + OSM_LOG_EXIT( p_mgr->p_log ); + return( signal ); +} + +/********************************************************************** + 1 go through all ports in the subnet. + 1.1 call __osm_lid_mgr_get_port_min_lid + 1.2 if a change is required send the port info + 2 if any change send the signal PENDING... +**********************************************************************/ +osm_signal_t +osm_lid_mgr_process_subnet( + IN osm_lid_mgr_t* const p_mgr ) +{ + osm_signal_t signal; + cl_qmap_t *p_port_guid_tbl; + osm_port_t *p_port; + ib_net64_t port_guid; + uint16_t min_lid_ho, max_lid_ho; + osm_physp_t *p_physp; + int lid_changed; + + CL_ASSERT( p_mgr ); + + OSM_LOG_ENTER( p_mgr->p_log, osm_lid_mgr_process_subnet ); + + CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock ); + + CL_ASSERT( p_mgr->p_subn->sm_port_guid ); + + /* Set the send_set_reqs of the p_mgr to FALSE, and + we'll see if any set requests were sent. If not - + can signal OSM_SIGNAL_DONE */ + p_mgr->send_set_reqs = FALSE; + + p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl; + + for( p_port = (osm_port_t*)cl_qmap_head( p_port_guid_tbl ); + p_port != (osm_port_t*)cl_qmap_end( p_port_guid_tbl ); + p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item ) ) + { + port_guid = osm_port_get_guid( p_port ); + + /* + Our own port is a special case in that we want to + assign a LID to ourselves first, since we have to + advertise that LID value to the other ports. + + For that reason, our node is treated separately and + we will not add it to any of these lists. + */ + if( port_guid == p_mgr->p_subn->sm_port_guid ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_lid_mgr_process_subnet: " + "Skipping our own port 0x%016" PRIx64 "\n", + cl_ntoh64( port_guid ) ); + } + else + { + /* + get the port lid range - we need to send it on first active sweep or + if there was a change (the result of the __osm_lid_mgr_get_port_lid) + */ + lid_changed = + __osm_lid_mgr_get_port_lid(p_mgr, p_port, &min_lid_ho, &max_lid_ho); + + /* we can call the function to update the port info as it known to + look for any field change and will only send an updated if required */ + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "osm_lid_mgr_process_subnet: " + "Assigned port 0x%016" PRIx64 + ", LID [0x%X,0x%X]\n", cl_ntoh64( port_guid ), + min_lid_ho, max_lid_ho ); + + p_physp = osm_port_get_default_phys_ptr( p_port ); + /* the proc returns the fact it sent a set port info */ + if (__osm_lid_mgr_set_physp_pi( p_mgr, p_port, p_physp, cl_hton16( min_lid_ho ))) + p_mgr->send_set_reqs = TRUE; + } + } /* all ports */ + + /* store the guid to lid table in persistent db */ + osm_db_store( p_mgr->p_g2l ); + + if ( p_mgr->send_set_reqs == FALSE ) + signal = OSM_SIGNAL_DONE; + else + signal = OSM_SIGNAL_DONE_PENDING; + + CL_PLOCK_RELEASE( p_mgr->p_lock ); + + OSM_LOG_EXIT( p_mgr->p_log ); + return( signal ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_lin_fwd_rcv.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_lin_fwd_rcv.c new file mode 100644 index 00000000..70e9673d --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_lin_fwd_rcv.c @@ -0,0 +1,160 @@ +/* + * 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: + * Implementation of osm_lft_rcv_t. + * This object represents the NodeDescription Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_lft_rcv_construct( + IN osm_lft_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_lft_rcv_destroy( + IN osm_lft_rcv_t* const p_rcv ) +{ + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_lft_rcv_destroy ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_lft_rcv_init( + IN osm_lft_rcv_t* const p_rcv, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_lft_rcv_init ); + + osm_lft_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_lft_rcv_process( + IN const osm_lft_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ) +{ + 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( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_lft_rcv_process ); + + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_block = (uint8_t*)ib_smp_get_payload_ptr( p_smp ); + block_num = cl_ntoh32( p_smp->attr_mod ); + + /* + Acquire the switch object for this switch. + */ + p_lft_context = osm_madw_get_lft_context_ptr( p_madw ); + node_guid = p_lft_context->node_guid; + + CL_PLOCK_EXCL_ACQUIRE( p_rcv->p_lock ); + p_sw = osm_get_switch_by_guid( p_rcv->p_subn, node_guid ); + + if( !p_sw ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_lft_rcv_process: ERR 0401: " + "LFT received for nonexistent node " + "0x%" PRIx64 "\n", cl_ntoh64( node_guid ) ); + } + else + { + status = osm_switch_set_ft_block( p_sw, p_block, block_num ); + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_lft_rcv_process: ERR 0402: " + "Setting forwarding table block failed (%s)" + "\n\t\t\t\tSwitch 0x%" PRIx64 "\n", + ib_get_err_str( status ), + cl_ntoh64( node_guid ) ); + } + } + + CL_PLOCK_RELEASE( p_rcv->p_lock ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_lin_fwd_rcv_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_lin_fwd_rcv_ctrl.c new file mode 100644 index 00000000..b3071b60 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_lin_fwd_rcv_ctrl.c @@ -0,0 +1,125 @@ +/* + * 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: + * Implementation of osm_lft_rcv_ctrl_t. + * This object represents the LFT Receive controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_lft_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_lft_rcv_process( ((osm_lft_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_lft_rcv_ctrl_construct( + IN osm_lft_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_lft_rcv_ctrl_destroy( + IN osm_lft_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_lft_rcv_ctrl_init( + IN osm_lft_rcv_ctrl_t* const p_ctrl, + IN osm_lft_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_lft_rcv_ctrl_init ); + + osm_lft_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_LFT, + __osm_lft_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_lft_rcv_ctrl_init: ERR 1601: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_lin_fwd_tbl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_lin_fwd_tbl.c new file mode 100644 index 00000000..9a8d8034 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_lin_fwd_tbl.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF 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_lin_fwd_tbl_t. + * This object represents an linear forwarding table. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + + +inline size_t +__osm_lin_tbl_compute_obj_size( + IN const uint32_t num_ports ) +{ + return( sizeof(osm_lin_fwd_tbl_t) + (num_ports - 1) ); +} + +/********************************************************************** + **********************************************************************/ +osm_lin_fwd_tbl_t* +osm_lin_tbl_new( + IN uint16_t const size ) +{ + osm_lin_fwd_tbl_t* p_tbl; + + /* + The capacity reported by the switch includes LID 0, + so add 1 to the end of the range here for this assert. + */ + CL_ASSERT( size <= IB_LID_UCAST_END_HO + 1 ); + p_tbl = (osm_lin_fwd_tbl_t*)malloc( + __osm_lin_tbl_compute_obj_size( size ) ); + + /* + Initialize the table to OSM_NO_PATH, which means "invalid port" + */ + memset( p_tbl, OSM_NO_PATH, __osm_lin_tbl_compute_obj_size( size ) ); + if( p_tbl != NULL ) + { + p_tbl->size = (uint16_t)size; + } + return( p_tbl ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_lin_tbl_delete( + IN osm_lin_fwd_tbl_t** const pp_tbl ) +{ + free( *pp_tbl ); + *pp_tbl = NULL; +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_link_mgr.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_link_mgr.c new file mode 100644 index 00000000..4eddf18c --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_link_mgr.c @@ -0,0 +1,514 @@ +/* + * 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: + * Implementation of osm_link_mgr_t. + * This file implements the Link Manager object. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.15 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/********************************************************************** + **********************************************************************/ +void +osm_link_mgr_construct( + IN osm_link_mgr_t* const p_mgr ) +{ + memset( p_mgr, 0, sizeof(*p_mgr) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_link_mgr_destroy( + IN osm_link_mgr_t* const p_mgr ) +{ + OSM_LOG_ENTER( p_mgr->p_log, osm_link_mgr_destroy ); + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_link_mgr_init( + IN osm_link_mgr_t* const p_mgr, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_link_mgr_init ); + + CL_ASSERT( p_req ); + CL_ASSERT( p_subn ); + CL_ASSERT( p_lock ); + + osm_link_mgr_construct( p_mgr ); + + p_mgr->p_log = p_log; + p_mgr->p_subn = p_subn; + p_mgr->p_lock = p_lock; + p_mgr->p_req = p_req; + + OSM_LOG_EXIT( p_mgr->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_link_mgr_set_physp_pi( + IN osm_link_mgr_t* const p_mgr, + IN osm_physp_t* const p_physp, + IN uint8_t const port_state ) +{ + uint8_t payload[IB_SMP_DATA_SIZE]; + ib_port_info_t* const p_pi = (ib_port_info_t*)payload; + const ib_port_info_t* p_old_pi; + osm_madw_context_t context; + osm_node_t* p_node; + ib_api_status_t status; + uint8_t port_num; + uint8_t mtu; + uint8_t op_vls; + boolean_t esp0 = FALSE; + boolean_t send_set = FALSE; + osm_physp_t *p_remote_physp; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_link_mgr_set_physp_pi ); + + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + + p_node = osm_physp_get_node_ptr( p_physp ); + + port_num = osm_physp_get_port_num( p_physp ); + + if( port_num == 0 ) + { + ib_switch_info_t* p_sw_info; + + /* + HCA's don't have a port 0, and for switch port 0, + we need to check if this is enhanced port 0 or base port 0. + For base port 0 the following parameters are not valid. (p824, table 145) + */ + if (!p_node->sw) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_link_mgr_set_physp_pi: ERR 4201: " + "Cannot find switch by guid: 0x%" PRIx64 "\n", + cl_ntoh64( p_node->node_info.node_guid ) ); + goto Exit; + } + + p_sw_info = osm_switch_get_si_ptr(p_node->sw); + if (ib_switch_info_is_enhanced_port0( p_sw_info ) == FALSE) + { + /* This means the switch doesn't support enhanced port zero. + Can skip it. */ + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_link_mgr_set_physp_pi: " + "Skipping port 0, GUID 0x%016" PRIx64 "\n", + cl_ntoh64( osm_physp_get_port_guid( p_physp ) ) ); + } + goto Exit; + } + esp0 = TRUE; + } + + /* + PAST THIS POINT WE ARE HANDLING EITHER A NON PORT 0 OR ENHANCED PORT 0 + */ + + p_old_pi = osm_physp_get_port_info_ptr( p_physp ); + + memset( payload, 0, IB_SMP_DATA_SIZE ); + + /* Correction by FUJITSU */ + memcpy( payload, p_old_pi, sizeof(ib_port_info_t) ); + + /* + Correction following a bug injected by the previous + FUJITSU line: + + 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 - 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; + + /* 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 or Enh. SP0 */ + if( osm_node_get_type( p_node ) != IB_NODE_TYPE_SWITCH || + port_num == 0 ) + { + 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 = 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 = 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; + + if (esp0 == FALSE) + p_pi->mkey_lmc = p_mgr->p_subn->opt.lmc; + else + { + if (p_mgr->p_subn->opt.lmc_esp0) + p_pi->mkey_lmc = p_mgr->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, 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; + } + + /* + Several timeout mechanisms: + */ + p_remote_physp = osm_physp_get_remote( p_physp ); + if (port_num != 0 && p_remote_physp && + osm_physp_is_valid(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, p_mgr->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, p_mgr->p_subn->opt.leaf_head_of_queue_lifetime); + ib_port_info_set_vl_stall_count( + p_pi, p_mgr->p_subn->opt.leaf_vl_stall_count); + } + else + { + ib_port_info_set_hoq_lifetime( + p_pi, p_mgr->p_subn->opt.head_of_queue_lifetime); + ib_port_info_set_vl_stall_count( + p_pi, p_mgr->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, + 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; + + /* + 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 ( p_mgr->p_subn->opt.force_link_speed ) + ib_port_info_set_link_speed_enabled( p_pi, IB_LINK_SPEED_ACTIVE_2_5 ); + else if (ib_port_info_get_link_speed_enabled( p_old_pi ) != ib_port_info_get_link_speed_sup( p_pi )) + ib_port_info_set_link_speed_enabled( p_pi, IB_PORT_LINK_SPEED_ENABLED_MASK ); + else + ib_port_info_set_link_speed_enabled( p_pi, ib_port_info_get_link_speed_enabled( p_old_pi )); + 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( 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; + + /* also the context can flag the need to check for errors. */ + context.pi_context.ignore_errors = FALSE; + } + else + { + /* + Since the only change we try to do is to modify the port + state we can ignore the errors that might be caused by a + race in setting the state and the actual state the port is + in. + */ + context.pi_context.ignore_errors = FALSE; + } + + ib_port_info_set_port_state( p_pi, port_state ); + if (port_state != IB_LINK_NO_CHANGE && + ib_port_info_get_port_state(p_pi) != + 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.update_master_sm_base_lid = FALSE; + 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 an hca port or a switch port zero and got_set_resp is FALSE + (in this case we sent a PortInfoSet in the osm_lid_mgr, but for some + reason we didn't get a response) - try and re-send. + 3. This is a switch port and: + a. first_time_master_sweep flag on the subnet is TRUE. This means the + SM just became master, and it then needs to send at PortInfoSet to + every port (and this is the first time we can send a PortInfoSet to + switch external ports). + b. got_set_resp on the physical port is FALSE. This means we haven't + seen this port before - need to send PortInfoSet to it. + */ + if (send_set || + (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH && p_physp->got_set_resp == FALSE) || + (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH && port_num == 0 && + p_physp->got_set_resp == FALSE) || + (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH && port_num != 0 && + (p_mgr->p_subn->first_time_master_sweep == TRUE || p_physp->got_set_resp == FALSE))) + { + p_mgr->send_set_reqs = TRUE; + status = osm_req_set( p_mgr->p_req, + osm_physp_get_dr_path_ptr( p_physp ), + payload, + sizeof(payload), + IB_MAD_ATTR_PORT_INFO, + cl_hton32(port_num), + CL_DISP_MSGID_NONE, + &context ); + } + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static osm_signal_t +__osm_link_mgr_process_port( + IN osm_link_mgr_t* const p_mgr, + IN osm_port_t* const p_port, + IN const uint8_t link_state ) +{ + uint32_t i; + uint32_t num_physp; + osm_physp_t *p_physp; + uint8_t current_state; + osm_signal_t signal = OSM_SIGNAL_DONE; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_link_mgr_process_port ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_link_mgr_process_port: " + "Port 0x%" PRIx64 " going to %s\n", + cl_ntoh64( osm_port_get_guid( p_port ) ), + 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_port_get_num_physp( p_port ); + 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_port_get_phys_ptr( p_port, (uint8_t)i ); + if( p_physp && osm_physp_is_valid( p_physp ) ) + { + 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) || + (current_state < link_state) ) + { + p_mgr->send_set_reqs = FALSE; + __osm_link_mgr_set_physp_pi( + p_mgr, + p_physp, + link_state ); + + if ( p_mgr->send_set_reqs == TRUE ) + signal = OSM_SIGNAL_DONE_PENDING; + } + else + { + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_link_mgr_process_port: " + "Physical port 0x%X already %s. Skipping\n", + osm_physp_get_port_num( p_physp ), + ib_get_port_state_str( current_state ) ); + } + } + } + } + + OSM_LOG_EXIT( p_mgr->p_log ); + return( signal ); +} + +/********************************************************************** + **********************************************************************/ +osm_signal_t +osm_link_mgr_process( + IN osm_link_mgr_t* const p_mgr, + IN const uint8_t link_state ) +{ + cl_qmap_t *p_port_guid_tbl; + osm_port_t *p_port; + osm_signal_t signal = OSM_SIGNAL_DONE; + + OSM_LOG_ENTER( p_mgr->p_log, osm_link_mgr_process ); + + p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl; + + CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock ); + + 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 ) ) + { + if( __osm_link_mgr_process_port( p_mgr, p_port, link_state ) == + OSM_SIGNAL_DONE_PENDING ) + signal = OSM_SIGNAL_DONE_PENDING; + } + + CL_PLOCK_RELEASE( p_mgr->p_lock ); + + OSM_LOG_EXIT( p_mgr->p_log ); + return( signal ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_matrix.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_matrix.c new file mode 100644 index 00000000..8fb8e128 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_matrix.c @@ -0,0 +1,156 @@ +/* + * 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: + * Implementation of osm_lid_matrix_t. + * This file implements the LID Matrix object. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_lid_matrix_destroy( + IN osm_lid_matrix_t* const p_lmx ) +{ + cl_vector_destroy( &p_lmx->lid_vec ); +} + +/********************************************************************** + Initializer function called by cl_vector +**********************************************************************/ +cl_status_t +__osm_lid_matrix_vec_init( + IN void* const p_elem, + IN void* context ) +{ + osm_lid_matrix_t* const p_lmx = (osm_lid_matrix_t*)context; + + memset( p_elem, OSM_NO_PATH, p_lmx->num_ports + 1); + return( CL_SUCCESS ); +} + +/********************************************************************** + Initializer function called by cl_vector +**********************************************************************/ +void +__osm_lid_matrix_vec_clear( + IN const size_t index, + IN void* const p_elem, + IN void* context ) +{ + osm_lid_matrix_t* const p_lmx = (osm_lid_matrix_t*)context; + + UNUSED_PARAM( index ); + memset( p_elem, OSM_NO_PATH, p_lmx->num_ports + 1); +} + +/********************************************************************** + **********************************************************************/ +void +osm_lid_matrix_clear( + IN osm_lid_matrix_t* const p_lmx ) +{ + cl_vector_apply_func( &p_lmx->lid_vec, + __osm_lid_matrix_vec_clear, p_lmx ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_lid_matrix_init( + IN osm_lid_matrix_t* const p_lmx, + IN const uint8_t num_ports ) +{ + cl_vector_t *p_vec; + cl_status_t status; + + CL_ASSERT( p_lmx ); + CL_ASSERT( num_ports ); + + p_lmx->num_ports = num_ports; + + p_vec = &p_lmx->lid_vec; + /* + Initialize the vector for the number of ports plus an + extra entry to hold the "least-hops" count for that LID. + */ + status = cl_vector_init( p_vec, + 0, /* min_size, */ + 1, /* grow_size */ + sizeof(uint8_t)*(num_ports + 1), /* element size */ + __osm_lid_matrix_vec_init, /* init function */ + NULL, /* destory func */ + p_lmx /* context */ + ); + + return( status ); +} + +/********************************************************************** + **********************************************************************/ +cl_status_t +osm_lid_matrix_set( + IN osm_lid_matrix_t* const p_lmx, + IN const uint16_t lid_ho, + IN const uint8_t port_num, + IN const uint8_t val ) +{ + uint8_t *p_port_array; + cl_status_t status; + + CL_ASSERT( port_num < p_lmx->num_ports ); + status = cl_vector_set_min_size( &p_lmx->lid_vec, lid_ho + 1 ); + if( status == CL_SUCCESS ) + { + p_port_array = (uint8_t *)cl_vector_get_ptr( &p_lmx->lid_vec, lid_ho ); + p_port_array[port_num] = val; + if( p_port_array[p_lmx->num_ports] > val ) + p_port_array[p_lmx->num_ports] = val; + } + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_fwd_rcv.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_fwd_rcv.c new file mode 100644 index 00000000..54f9dba7 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_fwd_rcv.c @@ -0,0 +1,181 @@ +/* + * 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: + * 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_mft_rcv_construct( + IN osm_mft_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mft_rcv_destroy( + IN osm_mft_rcv_t* const p_rcv ) +{ + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_mft_rcv_destroy ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mft_rcv_init( + IN osm_mft_rcv_t* const p_rcv, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_mft_rcv_init ); + + osm_mft_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mft_rcv_process( + IN const osm_mft_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ) +{ + 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( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_mft_rcv_process ); + + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_block = (uint16_t*)ib_smp_get_payload_ptr( p_smp ); + block_num = cl_ntoh32( p_smp->attr_mod ) & IB_MCAST_BLOCK_ID_MASK_HO; + position = (uint8_t)((cl_ntoh32( p_smp->attr_mod ) & + IB_MCAST_POSITION_MASK_HO) >> IB_MCAST_POSITION_SHIFT); + + /* + Acquire the switch object for this switch. + */ + p_mft_context = osm_madw_get_mft_context_ptr( p_madw ); + node_guid = p_mft_context->node_guid; + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_mft_rcv_process: " + "Setting MFT block %u, position %u" + "\n\t\t\t\tSwitch 0x%016" PRIx64 ", TID 0x%" PRIx64 "\n", + block_num, position, cl_ntoh64( node_guid ), + cl_ntoh64( p_smp->trans_id ) ); + } + + CL_PLOCK_EXCL_ACQUIRE( p_rcv->p_lock ); + p_sw = osm_get_switch_by_guid( p_rcv->p_subn, node_guid ); + + if( !p_sw ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mft_rcv_process: 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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mft_rcv_process: ERR 0802: " + "Setting MFT block failed (%s)" + "\n\t\t\t\tSwitch 0x%016" PRIx64 + ", block %u, position %u\n", + ib_get_err_str( status ), + cl_ntoh64( node_guid ), + block_num, position ); + } + } + + CL_PLOCK_RELEASE( p_rcv->p_lock ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_fwd_rcv_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_fwd_rcv_ctrl.c new file mode 100644 index 00000000..0a492180 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_fwd_rcv_ctrl.c @@ -0,0 +1,125 @@ +/* + * 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: + * Implementation of osm_mft_rcv_ctrl_t. + * This object represents the LFT Receive controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_mft_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_mft_rcv_process( ((osm_mft_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mft_rcv_ctrl_construct( + IN osm_mft_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_mft_rcv_ctrl_destroy( + IN osm_mft_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mft_rcv_ctrl_init( + IN osm_mft_rcv_ctrl_t* const p_ctrl, + IN osm_mft_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_mft_rcv_ctrl_init ); + + osm_mft_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_MFT, + __osm_mft_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_mft_rcv_ctrl_init: ERR 0901: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_mgr.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_mgr.c new file mode 100644 index 00000000..b40b64dc --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_mgr.c @@ -0,0 +1,1726 @@ +/* + * 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: + * Implementation of osm_mcast_mgr_t. + * This file implements the Multicast Manager object. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.9 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LINE_LENGTH 256 + +/********************************************************************** + **********************************************************************/ +typedef struct _osm_mcast_work_obj +{ + cl_list_item_t list_item; + osm_port_t* p_port; +} osm_mcast_work_obj_t; + +/********************************************************************** + **********************************************************************/ +static osm_mcast_work_obj_t* +__osm_mcast_work_obj_new( + IN const osm_port_t* const p_port ) +{ + /* + TO DO - get these objects from a lockpool. + */ + osm_mcast_work_obj_t* p_obj; + + /* + clean allocated memory to avoid assertion when trying to insert to + qlist. + see cl_qlist_insert_tail(): CL_ASSERT(p_list_item->p_list != p_list) + */ + p_obj = malloc( sizeof( *p_obj ) ); + if( p_obj ) + { + memset( p_obj, 0, sizeof( *p_obj ) ); + p_obj->p_port = (osm_port_t*)p_port; + } + + return( p_obj ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_mcast_work_obj_delete( + IN osm_mcast_work_obj_t* p_wobj ) +{ + free( p_wobj ); +} + +/********************************************************************** + Recursively remove nodes from the tree +**********************************************************************/ +static void +__osm_mcast_mgr_purge_tree_node( + IN osm_mtree_node_t* p_mtn ) +{ + uint8_t i; + + for( i = 0; i < p_mtn->max_children; i++ ) + { + if( p_mtn->child_array[i] && + (p_mtn->child_array[i] != OSM_MTREE_LEAF) ) + __osm_mcast_mgr_purge_tree_node( p_mtn->child_array[i] ); + + p_mtn->child_array[i] = NULL; + + } + + free( p_mtn ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_mcast_mgr_purge_tree( + IN osm_mcast_mgr_t* const p_mgr, + IN osm_mgrp_t* const p_mgrp ) +{ + OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_purge_tree ); + + if( p_mgrp->p_root ) + __osm_mcast_mgr_purge_tree_node( p_mgrp->p_root ); + + p_mgrp->p_root = NULL; + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static float +osm_mcast_mgr_compute_avg_hops( + osm_mcast_mgr_t* const p_mgr, + const osm_mgrp_t* const p_mgrp, + const osm_switch_t* const p_sw ) +{ + float avg_hops = 0; + uint32_t hops = 0; + uint32_t num_ports = 0; + uint16_t base_lid_ho; + const osm_port_t* p_port; + const osm_mcm_port_t* p_mcm_port; + const cl_qmap_t* p_mcm_tbl; + const cl_qmap_t* p_port_tbl; + + OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_compute_avg_hops ); + + p_mcm_tbl = &p_mgrp->mcm_port_tbl; + p_port_tbl = &p_mgr->p_subn->port_guid_tbl; + + /* + For each member of the multicast group, compute the + number of hops to its base LID. + */ + for( p_mcm_port = (osm_mcm_port_t*)cl_qmap_head( p_mcm_tbl ); + p_mcm_port != (osm_mcm_port_t*)cl_qmap_end( p_mcm_tbl ); + p_mcm_port = (osm_mcm_port_t*)cl_qmap_next(&p_mcm_port->map_item)) + { + /* + Acquire the port object for this port guid, then create + the new worker object to build the list. + */ + p_port = (osm_port_t*)cl_qmap_get( p_port_tbl, + ib_gid_get_guid( &p_mcm_port->port_gid ) ); + + if( p_port == (osm_port_t*)cl_qmap_end( p_port_tbl ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_mcast_mgr_compute_avg_hops: ERR 0A18: " + "No port object for port 0x%016" PRIx64 "\n", + cl_ntoh64( ib_gid_get_guid( &p_mcm_port->port_gid ) ) ); + continue; + } + + base_lid_ho = cl_ntoh16( osm_port_get_base_lid( p_port ) ); + hops += osm_switch_get_least_hops( p_sw, base_lid_ho ); + num_ports++; + } + + /* + We should be here if there aren't any ports in the group. + */ + CL_ASSERT( num_ports ); + + if( num_ports != 0 ) + { + avg_hops = (float)(hops / num_ports); + } + + OSM_LOG_EXIT( p_mgr->p_log ); + return( avg_hops ); +} + +/********************************************************************** + Calculate the maximal "min hops" from the given switch to any + of the group HCAs + **********************************************************************/ +static float +osm_mcast_mgr_compute_max_hops( + osm_mcast_mgr_t* const p_mgr, + const osm_mgrp_t* const p_mgrp, + const osm_switch_t* const p_sw ) +{ + uint32_t max_hops = 0; + uint32_t hops = 0; + uint16_t base_lid_ho; + const osm_port_t* p_port; + const osm_mcm_port_t* p_mcm_port; + const cl_qmap_t* p_mcm_tbl; + const cl_qmap_t* p_port_tbl; + + OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_compute_max_hops ); + + p_mcm_tbl = &p_mgrp->mcm_port_tbl; + p_port_tbl = &p_mgr->p_subn->port_guid_tbl; + + /* + For each member of the multicast group, compute the + number of hops to its base LID. + */ + for( p_mcm_port = (osm_mcm_port_t*)cl_qmap_head( p_mcm_tbl ); + p_mcm_port != (osm_mcm_port_t*)cl_qmap_end( p_mcm_tbl ); + p_mcm_port = (osm_mcm_port_t*)cl_qmap_next(&p_mcm_port->map_item)) + { + /* + Acquire the port object for this port guid, then create + the new worker object to build the list. + */ + p_port = (osm_port_t*)cl_qmap_get( + p_port_tbl, + ib_gid_get_guid( &p_mcm_port->port_gid ) ); + + if( p_port == (osm_port_t*)cl_qmap_end( p_port_tbl ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_mcast_mgr_compute_max_hops: ERR 0A1A: " + "No port object for port 0x%016" PRIx64 "\n", + cl_ntoh64( ib_gid_get_guid( &p_mcm_port->port_gid ) ) ); + continue; + } + + base_lid_ho = cl_ntoh16( osm_port_get_base_lid( p_port ) ); + hops = osm_switch_get_least_hops( p_sw, base_lid_ho ); + if (hops > max_hops) max_hops = hops; + } + + if( max_hops == 0 ) + { + /* + We should be here if there aren't any ports in the group. + */ + max_hops = 10001; /* see later - we use it to realize no hops */ + } + + OSM_LOG_EXIT( p_mgr->p_log ); + return(float)(max_hops); +} + +/********************************************************************** + This function attempts to locate the optimal switch for the + center of the spanning tree. The current algorithm chooses + a switch with the lowest average hop count to the members + of the multicast group. +**********************************************************************/ +static osm_switch_t* +__osm_mcast_mgr_find_optimal_switch( + osm_mcast_mgr_t* const p_mgr, + const osm_mgrp_t* const p_mgrp ) +{ + cl_qmap_t* p_sw_tbl; + const osm_switch_t* p_sw; + const osm_switch_t* p_best_sw = NULL; + float hops = 0; + float best_hops = 10000; /* any big # will do */ + uint64_t sw_guid_ho; +#ifdef OSM_VENDOR_INTF_ANAFA + boolean_t use_avg_hops = TRUE; /* anafa2 - bug hca on switch */ /* use max hops for root */ +#else + boolean_t use_avg_hops = FALSE; /* use max hops for root */ +#endif + + OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_find_optimal_switch ); + + p_sw_tbl = &p_mgr->p_subn->sw_guid_tbl; + + CL_ASSERT( !osm_mgrp_is_empty( p_mgrp ) ); + + for( p_sw = (osm_switch_t*)cl_qmap_head( p_sw_tbl ); + p_sw != (osm_switch_t*)cl_qmap_end( p_sw_tbl ); + p_sw = (osm_switch_t*)cl_qmap_next( &p_sw->map_item ) ) + { + if( !osm_switch_supports_mcast( p_sw ) ) + continue; + + if (use_avg_hops) + hops = osm_mcast_mgr_compute_avg_hops( p_mgr, p_mgrp, p_sw ); + else + hops = osm_mcast_mgr_compute_max_hops( p_mgr, p_mgrp, p_sw ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + sw_guid_ho = cl_ntoh64( osm_node_get_node_guid( + osm_switch_get_node_ptr( p_sw ) ) ); + + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_mcast_mgr_find_optimal_switch: " + "Switch 0x%016" PRIx64 ", hops = %f\n", + sw_guid_ho, hops ); + } + + if( hops < best_hops ) + { + p_best_sw = p_sw; + best_hops = hops; + } + } + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + if( p_best_sw ) + { + sw_guid_ho = cl_ntoh64( osm_node_get_node_guid( + osm_switch_get_node_ptr( p_best_sw ) ) ); + + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_mcast_mgr_find_optimal_switch: " + "Best switch is 0x%" PRIx64 ", hops = %f\n", + sw_guid_ho, best_hops ); + } + else + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_mcast_mgr_find_optimal_switch: " + "No multicast capable switches detected\n" ); + } + } + + OSM_LOG_EXIT( p_mgr->p_log ); + return( (osm_switch_t*)p_best_sw ); +} + +/********************************************************************** + This function returns the existing or optimal root swtich for the tree. +**********************************************************************/ +static osm_switch_t* +__osm_mcast_mgr_find_root_switch( + osm_mcast_mgr_t* const p_mgr, + const osm_mgrp_t* const p_mgrp ) +{ + const osm_switch_t* p_sw = NULL; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_find_root_switch ); + + /* + We always look for the best multicast tree root switch. + Otherwise since we always start with a a single join + the root will be always on the first switch attached to it. + - Very bad ... + */ + p_sw = __osm_mcast_mgr_find_optimal_switch( p_mgr, p_mgrp ); + + OSM_LOG_EXIT( p_mgr->p_log ); + return( (osm_switch_t*)p_sw ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcast_mgr_construct( + IN osm_mcast_mgr_t* const p_mgr ) +{ + memset( p_mgr, 0, sizeof(*p_mgr) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcast_mgr_destroy( + IN osm_mcast_mgr_t* const p_mgr ) +{ + CL_ASSERT( p_mgr ); + + OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_destroy ); + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mcast_mgr_init( + IN osm_mcast_mgr_t* const p_mgr, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_mcast_mgr_init ); + + CL_ASSERT( p_req ); + CL_ASSERT( p_subn ); + CL_ASSERT( p_lock ); + + osm_mcast_mgr_construct( p_mgr ); + + p_mgr->p_log = p_log; + p_mgr->p_subn = p_subn; + p_mgr->p_lock = p_lock; + p_mgr->p_req = p_req; + + OSM_LOG_EXIT( p_mgr->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static osm_signal_t +__osm_mcast_mgr_set_tbl( + IN osm_mcast_mgr_t* const p_mgr, + IN osm_switch_t* const p_sw ) +{ + osm_node_t* p_node; + osm_dr_path_t* p_path; + osm_madw_context_t mad_context; + ib_api_status_t status; + uint32_t block_id_ho = 0; + int16_t block_num = 0; + uint32_t position = 0; + uint32_t max_position; + osm_mcast_tbl_t* p_tbl; + ib_net16_t block[IB_MCAST_BLOCK_SIZE]; + osm_signal_t signal = OSM_SIGNAL_DONE; + + CL_ASSERT( p_mgr ); + + OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_set_tbl ); + + CL_ASSERT( p_sw ); + + p_node = osm_switch_get_node_ptr( p_sw ); + + CL_ASSERT( p_node ); + + p_path = osm_node_get_any_dr_path_ptr( p_node ); + + CL_ASSERT( p_path ); + + /* + Send multicast forwarding table blocks to the switch + as long as the switch indicates it has blocks needing + configuration. + */ + + mad_context.mft_context.node_guid = osm_node_get_node_guid( p_node ); + mad_context.mft_context.set_method = TRUE; + + p_tbl = osm_switch_get_mcast_tbl_ptr( p_sw ); + max_position = p_tbl->max_position; + + while( osm_mcast_tbl_get_block( p_tbl, block_num, + (uint8_t)position, block ) ) + { + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_mcast_mgr_set_tbl: " + "Writing MFT block 0x%X\n", block_id_ho ); + } + + block_id_ho = block_num + (position << 28); + + status = osm_req_set( p_mgr->p_req, + p_path, + (void*)block, + sizeof(block), + IB_MAD_ATTR_MCAST_FWD_TBL, + cl_hton32( block_id_ho ), + CL_DISP_MSGID_NONE, + &mad_context ); + + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_mcast_mgr_set_tbl: ERR 0A02: " + "Sending multicast fwd. tbl. block failed (%s)\n", + ib_get_err_str( status ) ); + } + + signal = OSM_SIGNAL_DONE_PENDING; + + if( ++position > max_position ) + { + position = 0; + block_num++; + } + } + + OSM_LOG_EXIT( p_mgr->p_log ); + return( signal ); +} + +/********************************************************************** + This is part of the recursive function to compute the paths in the + spanning tree that eminate from this switch. On input, the p_list + contains the group members that must be routed from this switch. +**********************************************************************/ +static void +__osm_mcast_mgr_subdivide( + osm_mcast_mgr_t* const p_mgr, + osm_mgrp_t* const p_mgrp, + osm_switch_t* const p_sw, + cl_qlist_t* const p_list, + cl_qlist_t* const list_array, + uint8_t const array_size ) +{ + uint8_t port_num; + uint16_t mlid_ho; + uint16_t lid_ho; + boolean_t ignore_existing; + osm_mcast_work_obj_t* p_wobj; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_subdivide ); + + mlid_ho = cl_ntoh16( osm_mgrp_get_mlid( p_mgrp ) ); + + /* + For Multicast Groups, we want not to count on previous + configurations - since we can easily generate a storm + by loops. + */ + ignore_existing = TRUE; + + /* + Subdivide the set of ports into non-overlapping subsets + that will be routed to other switches. + */ + while( (p_wobj = (osm_mcast_work_obj_t*)cl_qlist_remove_head( p_list )) != + (osm_mcast_work_obj_t*)cl_qlist_end( p_list ) ) + { + lid_ho = cl_ntoh16( osm_port_get_base_lid( p_wobj->p_port ) ); + + port_num = osm_switch_recommend_mcast_path( + p_sw, lid_ho, mlid_ho, ignore_existing ); + + if( port_num == OSM_NO_PATH ) + { + /* + This typically occurs if the switch does not support + multicast and the multicast tree must branch at this + switch. + */ + uint64_t node_guid_ho = cl_ntoh64( osm_node_get_node_guid( + osm_switch_get_node_ptr( p_sw ) ) ); + + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_mcast_mgr_subdivide: ERR 0A03: " + "Error routing MLID 0x%X through switch 0x%" PRIx64 "\n" + "\t\t\t\tNo multicast paths from this switch for port " + "with LID 0x%X\n", + mlid_ho, node_guid_ho, lid_ho ); + + __osm_mcast_work_obj_delete( p_wobj ); + continue; + } + + if( port_num > array_size ) + { + uint64_t node_guid_ho = cl_ntoh64( osm_node_get_node_guid( + osm_switch_get_node_ptr( p_sw ) ) ); + + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_mcast_mgr_subdivide: ERR 0A04: " + "Error routing MLID 0x%X through switch 0x%" PRIx64 "\n" + "\t\t\t\tNo multicast paths from this switch to port " + "with LID 0x%X\n", + mlid_ho, node_guid_ho, lid_ho ); + + __osm_mcast_work_obj_delete( p_wobj ); + + /* This is means OpenSM has a bug. */ + CL_ASSERT( FALSE ); + continue; + } + + cl_qlist_insert_tail( &list_array[port_num], &p_wobj->list_item ); + } + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_mcast_mgr_purge_list( + osm_mcast_mgr_t* const p_mgr, + cl_qlist_t* const p_list ) +{ + osm_mcast_work_obj_t* p_wobj; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_purge_list ); + + while( (p_wobj = (osm_mcast_work_obj_t*)cl_qlist_remove_head( p_list ) ) + != (osm_mcast_work_obj_t*)cl_qlist_end( p_list ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_mcast_mgr_purge_list: ERR 0A06: " + "Unable to route for port 0x%" PRIx64 "\n", + osm_port_get_guid( p_wobj->p_port ) ); + __osm_mcast_work_obj_delete( p_wobj ); + } + + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + This is the recursive function to compute the paths in the spanning + tree that emanate from this switch. On input, the p_list contains + the group members that must be routed from this switch. + + The function returns the newly created mtree node element. +**********************************************************************/ +static osm_mtree_node_t* +__osm_mcast_mgr_branch( + osm_mcast_mgr_t* const p_mgr, + osm_mgrp_t* const p_mgrp, + osm_switch_t* const p_sw, + cl_qlist_t* const p_list, + uint8_t depth, + uint8_t const upstream_port, + uint8_t* const p_max_depth ) +{ + uint8_t max_children; + osm_mtree_node_t* p_mtn = NULL; + cl_qlist_t* list_array = NULL; + uint8_t i; + ib_net64_t node_guid; + uint64_t node_guid_ho; + osm_mcast_work_obj_t* p_wobj; + cl_qlist_t* p_port_list; + size_t count; + uint16_t mlid_ho; + osm_mcast_tbl_t* p_tbl; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_branch ); + + CL_ASSERT( p_sw ); + CL_ASSERT( p_list ); + CL_ASSERT( p_max_depth ); + + node_guid = osm_node_get_node_guid( osm_switch_get_node_ptr( p_sw ) ); + node_guid_ho = cl_ntoh64( node_guid ); + mlid_ho = cl_ntoh16( osm_mgrp_get_mlid( p_mgrp ) ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_mcast_mgr_branch: " + "Routing MLID 0x%X through switch 0x%" PRIx64 "\n" + "\t\t\t\t%u nodes at depth %u\n", + mlid_ho, + node_guid_ho, + cl_qlist_count( p_list ), depth ); + } + + CL_ASSERT( cl_qlist_count( p_list ) > 0 ); + + depth++; + + if( depth > *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( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_mcast_mgr_branch: ERR 0A14: " + "Switch 0x%" PRIx64 " does not support multicast\n", + node_guid_ho ); + + /* + Deallocate all the work objects on this branch of the tree. + */ + __osm_mcast_mgr_purge_list( p_mgr, 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( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_mcast_mgr_branch: ERR 0A15: " + "Insufficient memory to build multicast tree\n" ); + + /* + Deallocate all the work objects on this branch of the tree. + */ + __osm_mcast_mgr_purge_list( p_mgr, 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( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_mcast_mgr_branch: ERR 0A16: " + "Unable to allocate list array\n" ); + __osm_mcast_mgr_purge_list( p_mgr, p_list ); + goto Exit; + } + + memset( list_array, 0, sizeof(cl_qlist_t) * max_children ); + + for( i = 0; i < max_children; i++ ) + cl_qlist_init( &list_array[i] ); + + __osm_mcast_mgr_subdivide( p_mgr, p_mgrp, p_sw, p_list, list_array, + max_children ); + + p_tbl = osm_switch_get_mcast_tbl_ptr( p_sw ); + + /* + Add the upstream port to the forwarding table unless + we're at the root of the spanning tree. + */ + if( depth > 1 ) + { + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_mcast_mgr_branch: " + "Adding upstream port 0x%X\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; + const 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. */ + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_mcast_mgr_branch: " + "Routing %zu destination(s) via switch port 0x%X\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 */ + continue; + + p_node = osm_switch_get_node_ptr( p_sw ); + p_remote_node = osm_node_get_remote_node( p_node, i, NULL ); + + 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 ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + + p_remote_physp = osm_physp_get_remote( p_physp ); + CL_ASSERT( p_remote_physp ); + CL_ASSERT( osm_physp_is_valid( p_remote_physp ) ); + + p_mtn->child_array[i] = __osm_mcast_mgr_branch( + p_mgr, p_mgrp, p_remote_node->sw, + p_port_list, depth, + osm_physp_get_port_num( p_remote_physp), + p_max_depth ); + } + else + { + /* + The neighbor node is not a switch, so this + must be a leaf. + */ + CL_ASSERT( count == 1 ); + + p_mtn->child_array[i] = OSM_MTREE_LEAF; + p_wobj = (osm_mcast_work_obj_t*)cl_qlist_remove_head( + p_port_list ); + + CL_ASSERT( cl_is_qlist_empty( p_port_list ) ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "__osm_mcast_mgr_branch: " + "Found leaf for port 0x%016" PRIx64 "\n" + "\t\t\t\ton switch port 0x%X\n", + cl_ntoh64( osm_port_get_guid( p_wobj->p_port ) ), i ); + } + + __osm_mcast_work_obj_delete( p_wobj ); + } + } + + free( list_array ); + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); + return( p_mtn ); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_mcast_mgr_build_spanning_tree( + osm_mcast_mgr_t* const p_mgr, + osm_mgrp_t* const p_mgrp ) +{ + const cl_qmap_t* p_mcm_tbl; + const cl_qmap_t* p_port_tbl; + const osm_port_t* p_port; + const osm_mcm_port_t* p_mcm_port; + uint32_t num_ports; + cl_qlist_t port_list; + osm_switch_t* p_sw; + osm_mcast_work_obj_t* p_wobj; + ib_api_status_t status = IB_SUCCESS; + uint8_t max_depth = 0; + uint32_t count; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_build_spanning_tree ); + + cl_qlist_init( &port_list ); + + /* + TO DO - for now, just blow away the old tree. + In the future we'll need to construct the tree based + on multicast forwarding table information if the user wants to + preserve existing multicast routes. + */ + __osm_mcast_mgr_purge_tree( p_mgr, p_mgrp ); + + p_mcm_tbl = &p_mgrp->mcm_port_tbl; + p_port_tbl = &p_mgr->p_subn->port_guid_tbl; + num_ports = cl_qmap_count( p_mcm_tbl ); + if( num_ports == 0 ) + { + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_mcast_mgr_build_spanning_tree: " + "MLID 0x%X has no members--nothing to do\n", + cl_ntoh16( osm_mgrp_get_mlid( p_mgrp ) ) ); + } + goto Exit; + } + + /* + This function builds the single spanning tree recursively. + At each stage, the ports to be reached are divided into + non-overlapping subsets of member ports that can be reached through + a given switch port. Construction then moves down each + branch, and the process starts again with each branch computing + for its own subset of the member ports. + + The maximum recursion depth is at worst the maximum hop count in the + subnet, which is spec limited to 64. + */ + + /* + Locate the switch around which to create the spanning + tree for this multicast group. + */ + p_sw = __osm_mcast_mgr_find_root_switch( p_mgr, p_mgrp ); + if( p_sw == NULL ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_mcast_mgr_build_spanning_tree: ERR 0A08: " + "Unable to locate a suitable switch for group 0x%X\n", + cl_ntoh16( osm_mgrp_get_mlid( p_mgrp ) )); + status = IB_ERROR; + goto Exit; + } + + /* + Build the first "subset" containing all member ports. + */ + for( p_mcm_port = (osm_mcm_port_t*)cl_qmap_head( p_mcm_tbl ); + p_mcm_port != (osm_mcm_port_t*)cl_qmap_end( p_mcm_tbl ); + p_mcm_port = (osm_mcm_port_t*)cl_qmap_next(&p_mcm_port->map_item)) + { + /* + Acquire the port object for this port guid, then create + the new worker object to build the list. + */ + p_port = (osm_port_t*)cl_qmap_get( p_port_tbl, + ib_gid_get_guid( &p_mcm_port->port_gid ) ); + + if( p_port == (osm_port_t*)cl_qmap_end( p_port_tbl ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_mcast_mgr_build_spanning_tree: ERR 0A09: " + "No port object for port 0x%016" PRIx64 "\n", + cl_ntoh64( ib_gid_get_guid( &p_mcm_port->port_gid ) ) ); + continue; + } + + p_wobj = __osm_mcast_work_obj_new( p_port ); + if( p_wobj == NULL ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "__osm_mcast_mgr_build_spanning_tree: ERR 0A10: " + "Insufficient memory to route port 0x%016" PRIx64 "\n", + cl_ntoh64( osm_port_get_guid( p_port ) ) ); + continue; + } + + cl_qlist_insert_tail( &port_list, &p_wobj->list_item ); + } + + count = cl_qlist_count( &port_list ); + p_mgrp->p_root = __osm_mcast_mgr_branch( p_mgr, p_mgrp, p_sw, + &port_list, 0, 0, &max_depth ); + + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "__osm_mcast_mgr_build_spanning_tree: " + "Configured MLID 0x%X for %u ports, max tree depth = %u\n", + cl_ntoh16( osm_mgrp_get_mlid( p_mgrp ) ), + count, max_depth ); + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); + return( status ); +} + +#if 0 +/* unused */ +/********************************************************************** + **********************************************************************/ +void +osm_mcast_mgr_set_table( + IN osm_mcast_mgr_t* const p_mgr, + IN const osm_mgrp_t* const p_mgrp, + IN const osm_mtree_node_t* const p_mtn ) +{ + uint8_t i; + uint8_t max_children; + osm_mtree_node_t* p_child_mtn; + uint16_t mlid_ho; + osm_mcast_tbl_t* p_tbl; + osm_switch_t* p_sw; + + OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_set_table ); + + mlid_ho = cl_ntoh16( osm_mgrp_get_mlid( p_mgrp ) ); + p_sw = osm_mtree_node_get_switch_ptr( p_mtn ); + + CL_ASSERT( p_sw ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_VERBOSE, + "osm_mcast_mgr_set_table: " + "Configuring MLID 0x%X on switch 0x%" PRIx64 "\n", + mlid_ho, osm_node_get_node_guid( + osm_switch_get_node_ptr( p_sw ) ) ); + } + + /* + 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( p_mgr->p_log ); +} +#endif + +/********************************************************************** + **********************************************************************/ +static void +__osm_mcast_mgr_clear( + IN osm_mcast_mgr_t* const p_mgr, + IN osm_mgrp_t* const p_mgrp ) +{ + osm_switch_t* p_sw; + cl_qmap_t* p_sw_tbl; + osm_mcast_tbl_t* p_mcast_tbl; + + OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_clear ); + + /* + Walk the switches and clear the routing entries for + this MLID. + */ + p_sw_tbl = &p_mgr->p_subn->sw_guid_tbl; + p_sw = (osm_switch_t*)cl_qmap_head( p_sw_tbl ); + while( p_sw != (osm_switch_t*)cl_qmap_end( p_sw_tbl ) ) + { + p_mcast_tbl = osm_switch_get_mcast_tbl_ptr( p_sw ); + osm_mcast_tbl_clear_mlid( p_mcast_tbl, cl_ntoh16(p_mgrp->mlid) ); + p_sw = (osm_switch_t*)cl_qmap_next( &p_sw->map_item ); + } + + OSM_LOG_EXIT( p_mgr->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( + IN osm_mcast_mgr_t* const p_mgr, + 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; + osm_switch_t* p_sw; + 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; + cl_qmap_t* p_port_tbl; + osm_mcast_tbl_t* p_mcast_tbl; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_process_single ); + + CL_ASSERT( mlid ); + CL_ASSERT( port_guid ); + + p_port_tbl = &p_mgr->p_subn->port_guid_tbl; + mlid_ho = cl_ntoh16( mlid ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_mcast_mgr_process_single: " + "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_port_t*)cl_qmap_get( p_port_tbl, port_guid ); + if( p_port == (osm_port_t*)cl_qmap_end( p_port_tbl ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_mcast_mgr_process_single: ERR 0A01: " + "Unable to acquire port object for 0x%" PRIx64 "\n", + cl_ntoh64( port_guid ) ); + status = IB_ERROR; + goto Exit; + } + + p_physp = osm_port_get_default_phys_ptr( p_port ); + if( p_physp == NULL ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_mcast_mgr_process_single: ERR 0A05: " + "Unable to acquire phsyical port object for 0x%" PRIx64 "\n", + cl_ntoh64( port_guid ) ); + status = IB_ERROR; + goto Exit; + } + + if( !osm_physp_is_valid( p_physp ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_mcast_mgr_process_single: ERR 0A07: " + "Unable to acquire valid physical 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( p_mgr->p_log, OSM_LOG_ERROR, + "osm_mcast_mgr_process_single: ERR 0A11: " + "Unable to acquire remote phsyical port object " + "for 0x%" PRIx64 "\n", + cl_ntoh64( port_guid ) ); + status = IB_ERROR; + goto Exit; + } + + if( !osm_physp_is_valid( p_remote_physp ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_mcast_mgr_process_single: ERR 0A21: " + "Unable to acquire valid remote physical 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( p_mgr->p_log, OSM_LOG_ERROR, + "osm_mcast_mgr_process_single: ERR 0A22: " + "Remote node not a switch node 0x%" PRIx64 "\n", + cl_ntoh64( sw_guid ) ); + status = IB_ERROR; + goto Exit; + } + + p_sw = p_remote_node->sw; + if( !p_sw ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_mcast_mgr_process_single: 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_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_sw ); + osm_mcast_tbl_set( p_mcast_tbl, mlid_ho, port_num ); + } + else + { + if( join_state & IB_JOIN_STATE_SEND_ONLY ) + { + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_mcast_mgr_process_single: " + "Success. Nothing to do for send" + "only member\n" ); + } + } + else + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_mcast_mgr_process_single: ERR 0A13: " + "Unknown join state 0x%X\n", join_state ); + status = IB_ERROR; + goto Exit; + } + } + } + else + { + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_mcast_mgr_process_single: " + "Unable to add port\n" ); + } + } + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); + return( status ); +} +#endif + +/********************************************************************** + lock must already be held on entry +**********************************************************************/ +static ib_api_status_t +osm_mcast_mgr_process_tree( + IN osm_mcast_mgr_t* const p_mgr, + IN osm_mgrp_t* const p_mgrp, + IN osm_mcast_req_type_t req_type, + ib_net64_t port_guid ) +{ + ib_api_status_t status = IB_SUCCESS; + ib_net16_t mlid; + boolean_t ui_mcast_fdb_assign_func_defined; + + OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_process_tree ); + + mlid = osm_mgrp_get_mlid( p_mgrp ); + + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_mcast_mgr_process_tree: " + "Processing multicast group 0x%X\n", cl_ntoh16( mlid )); + } + + /* + If there are no switches in the subnet, then we have nothing to do. + */ + if( cl_qmap_count( &p_mgr->p_subn->sw_guid_tbl ) == 0 ) + { + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_mcast_mgr_process_tree: " + "No switches in subnet. Nothing to do\n" ); + } + goto Exit; + } + + if (p_mgr->p_subn->opt.pfn_ui_mcast_fdb_assign) + ui_mcast_fdb_assign_func_defined = TRUE; + else + ui_mcast_fdb_assign_func_defined = FALSE; + + /* + Clear the multicast tables to start clean, then build + the spanning tree which sets the mcast table bits for each + port in the group. + We will clean the multicast tables if a ui_mcast function isn't + defined, or if such function is defined, but we got here + through a MC_CREATE request - this means we are creating a new + multicast group - clean all old data. + */ + if ( ui_mcast_fdb_assign_func_defined == FALSE || + req_type == OSM_MCAST_REQ_TYPE_CREATE ) + __osm_mcast_mgr_clear( p_mgr, p_mgrp ); + + /* If a UI function is defined, then we will call it here. + If not - the use the regular build spanning tree function */ + if ( ui_mcast_fdb_assign_func_defined == FALSE ) + { + status = __osm_mcast_mgr_build_spanning_tree( p_mgr, p_mgrp ); + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_mcast_mgr_process_tree: ERR 0A17: " + "Unable to create spanning tree (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + } + else + { + if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_mcast_mgr_process_tree: " + "Invoking UI function pfn_ui_mcast_fdb_assign\n"); + } + + p_mgr->p_subn->opt.pfn_ui_mcast_fdb_assign( + p_mgr->p_subn->opt.ui_mcast_fdb_assign_ctx, + mlid, req_type, port_guid ); + } + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static void +mcast_mgr_dump_sw_routes( + IN const osm_mcast_mgr_t* const p_mgr, + IN const osm_switch_t* const p_sw, + IN FILE *file ) +{ + 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]; + + OSM_LOG_ENTER( p_mgr->p_log, mcast_mgr_dump_sw_routes ); + + if( !osm_log_is_active( p_mgr->p_log, OSM_LOG_ROUTING ) ) + goto Exit; + + p_node = osm_switch_get_node_ptr( p_sw ); + + p_tbl = osm_switch_get_mcast_tbl_ptr( p_sw ); + + sprintf( sw_hdr, "\nSwitch 0x%016" PRIx64 "\n" + "LID : 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++; + } + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); +} + +/********************************************************************** + **********************************************************************/ +struct mcast_mgr_dump_context { + osm_mcast_mgr_t *p_mgr; + FILE *file; +}; + +static void +mcast_mgr_dump_table(cl_map_item_t *p_map_item, void *context) +{ + osm_switch_t *p_sw = (osm_switch_t *)p_map_item; + struct mcast_mgr_dump_context *cxt = context; + + mcast_mgr_dump_sw_routes(cxt->p_mgr, p_sw, cxt->file); +} + +static void +mcast_mgr_dump_mcast_routes(osm_mcast_mgr_t *p_mgr) +{ + char file_name[1024]; + struct mcast_mgr_dump_context dump_context; + FILE *file; + + if (!osm_log_is_active(p_mgr->p_log, OSM_LOG_ROUTING)) + return; + + snprintf(file_name, sizeof(file_name), "%s/%s", + p_mgr->p_subn->opt.dump_files_dir, "osm.mcfdbs"); + + file = fopen(file_name, "w"); + if (!file) { + osm_log(p_mgr->p_log, OSM_LOG_ERROR, + "mcast_dump_mcast_routes: ERR 0A18: " + "cannot create mcfdb file \'%s\': %s\n", + file_name, strerror(errno)); + return; + } + + dump_context.p_mgr = p_mgr; + dump_context.file = file; + + cl_qmap_apply_func(&p_mgr->p_subn->sw_guid_tbl, + mcast_mgr_dump_table, &dump_context); + + fclose(file); +} + +/********************************************************************** + Process the entire group. + + NOTE : The lock should be held externally! + **********************************************************************/ +static osm_signal_t +osm_mcast_mgr_process_mgrp( + IN osm_mcast_mgr_t* const p_mgr, + IN osm_mgrp_t* const p_mgrp, + IN osm_mcast_req_type_t req_type, + IN ib_net64_t port_guid ) +{ + osm_signal_t signal = OSM_SIGNAL_DONE; + ib_api_status_t status; + osm_switch_t* p_sw; + cl_qmap_t* p_sw_tbl; + boolean_t pending_transactions = FALSE; + + OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_process_mgrp ); + + p_sw_tbl = &p_mgr->p_subn->sw_guid_tbl; + + status = osm_mcast_mgr_process_tree( p_mgr, p_mgrp, req_type, port_guid ); + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_mcast_mgr_process_mgrp: ERR 0A19: " + "Unable to create spanning tree (%s)\n", + ib_get_err_str( status ) ); + + goto Exit; + } + + /* + Walk the switches and download the tables for each. + */ + p_sw = (osm_switch_t*)cl_qmap_head( p_sw_tbl ); + while( p_sw != (osm_switch_t*)cl_qmap_end( p_sw_tbl ) ) + { + signal = __osm_mcast_mgr_set_tbl( p_mgr, p_sw ); + if( signal == OSM_SIGNAL_DONE_PENDING ) + pending_transactions = TRUE; + + p_sw = (osm_switch_t*)cl_qmap_next( &p_sw->map_item ); + } + + mcast_mgr_dump_mcast_routes( p_mgr ); + + Exit: + OSM_LOG_EXIT( p_mgr->p_log ); + + if( pending_transactions == TRUE ) + return( OSM_SIGNAL_DONE_PENDING ); + else + return( OSM_SIGNAL_DONE ); +} + +/********************************************************************** + **********************************************************************/ +osm_signal_t +osm_mcast_mgr_process( + IN osm_mcast_mgr_t* const p_mgr ) +{ + osm_signal_t signal; + osm_switch_t* p_sw; + cl_qmap_t* p_sw_tbl; + cl_qmap_t* p_mcast_tbl; + osm_mgrp_t* p_mgrp; + ib_api_status_t status; + boolean_t pending_transactions = FALSE; + + OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_process ); + + p_sw_tbl = &p_mgr->p_subn->sw_guid_tbl; + + p_mcast_tbl = &p_mgr->p_subn->mgrp_mlid_tbl; + /* + While holding the lock, iterate over all the established + multicast groups, servicing each in turn. + + Then, download the multicast tables to the switches. + */ + CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock ); + + p_mgrp = (osm_mgrp_t*)cl_qmap_head( p_mcast_tbl ); + while( p_mgrp != (osm_mgrp_t*)cl_qmap_end( p_mcast_tbl ) ) + { + /* We reached here due to some change that caused a heavy sweep + of the subnet. Not due to a specific multicast request. + So the request type is subnet_change and the port guid is 0. */ + status = osm_mcast_mgr_process_tree( p_mgr, p_mgrp, + OSM_MCAST_REQ_TYPE_SUBNET_CHANGE, 0); + if( status != IB_SUCCESS ) + { + osm_log( p_mgr->p_log, OSM_LOG_ERROR, + "osm_mcast_mgr_process: ERR 0A20: " + "Unable to create spanning tree (%s)\n", + ib_get_err_str( status ) ); + } + + p_mgrp = (osm_mgrp_t*)cl_qmap_next( &p_mgrp->map_item ); + } + + /* + Walk the switches and download the tables for each. + */ + p_sw = (osm_switch_t*)cl_qmap_head( p_sw_tbl ); + while( p_sw != (osm_switch_t*)cl_qmap_end( p_sw_tbl ) ) + { + signal = __osm_mcast_mgr_set_tbl( p_mgr, p_sw ); + if( signal == OSM_SIGNAL_DONE_PENDING ) + pending_transactions = TRUE; + + p_sw = (osm_switch_t*)cl_qmap_next( &p_sw->map_item ); + } + + mcast_mgr_dump_mcast_routes( p_mgr ); + + CL_PLOCK_RELEASE( p_mgr->p_lock ); + + OSM_LOG_EXIT( p_mgr->p_log ); + + if( pending_transactions == TRUE ) + return( OSM_SIGNAL_DONE_PENDING ); + else + return( OSM_SIGNAL_DONE ); +} + +/********************************************************************** + **********************************************************************/ +static +osm_mgrp_t * +__get_mgrp_by_mlid( + IN osm_mcast_mgr_t* const p_mgr, + IN ib_net16_t const mlid) +{ + cl_map_item_t *map_item; + + map_item = cl_qmap_get(&p_mgr->p_subn->mgrp_mlid_tbl, mlid); + if(map_item == cl_qmap_end(&p_mgr->p_subn->mgrp_mlid_tbl)) + { + return NULL; + } + return (osm_mgrp_t *)map_item; +} + +/********************************************************************** + This is the function that is invoked during idle time to handle the + process request. Context1 is simply the osm_mcast_mgr_t*, Context2 + hold the mlid, port guid and action (join/leave/delete) required. + **********************************************************************/ +osm_signal_t +osm_mcast_mgr_process_mgrp_cb( + IN void* const Context1, + IN void* const Context2 ) +{ + osm_mcast_mgr_t* p_mgr = (osm_mcast_mgr_t*)Context1; + osm_mgrp_t* p_mgrp; + ib_net16_t mlid; + osm_signal_t signal = OSM_SIGNAL_DONE; + osm_mcast_mgr_ctxt_t* p_ctxt = (osm_mcast_mgr_ctxt_t*)Context2; + osm_mcast_req_type_t req_type = p_ctxt->req_type; + ib_net64_t port_guid = p_ctxt->port_guid; + + OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_process_mgrp_cb ); + + /* nice copy no warning on size diff */ + memcpy(&mlid, &p_ctxt->mlid, sizeof(mlid)); + + /* we can destroy the context now */ + free(p_ctxt); + + /* we need a lock to make sure the p_mgrp is not change other ways */ + CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock ); + p_mgrp = __get_mgrp_by_mlid( p_mgr, mlid); + + /* since we delayed the execution we prefer to pass the + mlid as the mgrp identifier and then find it or abort */ + + if (p_mgrp) + { + + /* if there was no change from the last time we processed the group + we can skip doing anything + */ + if ( p_mgrp->last_change_id == p_mgrp->last_tree_id) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_mcast_mgr_process_mgrp_cb: " + "Skip processing mgrp with lid:0x%X change id:%u\n", + cl_ntoh16(mlid), p_mgrp->last_change_id ); + } + else + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_mcast_mgr_process_mgrp_cb: " + "Processing mgrp with lid:0x%X change id:%u\n", + cl_ntoh16(mlid), p_mgrp->last_change_id ); + + signal = + osm_mcast_mgr_process_mgrp( p_mgr, p_mgrp, req_type, port_guid ); + p_mgrp->last_tree_id = p_mgrp->last_change_id; + } + + /* Remove MGRP only if osm_mcm_port_t count is 0 and + * Not a well known group + */ + if((0x0 == cl_qmap_count(&p_mgrp->mcm_port_tbl)) && + (p_mgrp->well_known == FALSE)) + { + osm_log( p_mgr->p_log, OSM_LOG_DEBUG, + "osm_mcast_mgr_process_mgrp_cb: " + "Destroying mgrp with lid:0x%X\n", + cl_ntoh16(mlid) ); + + /* Send a Report to any InformInfo registered for + Trap 67 : MCGroup delete */ + osm_mgrp_send_delete_notice( p_mgr->p_subn, p_mgr->p_log, p_mgrp ); + + cl_qmap_remove_item(&p_mgr->p_subn->mgrp_mlid_tbl, + (cl_map_item_t *)p_mgrp ); + + osm_mgrp_destroy(p_mgrp); + } + } + + CL_PLOCK_RELEASE( p_mgr->p_lock ); + OSM_LOG_EXIT( p_mgr->p_log ); + return signal; +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_tbl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_tbl.c new file mode 100644 index 00000000..bb175802 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcast_tbl.c @@ -0,0 +1,302 @@ +/* + * 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: + * Implementation of osm_mcast_tbl_t. + * This object represents an multicast forwarding table. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mcast_tbl_init( + IN osm_mcast_tbl_t* const p_tbl, + IN uint8_t const num_ports, + IN uint16_t const capacity ) +{ + CL_ASSERT( p_tbl ); + CL_ASSERT( num_ports ); + + memset( p_tbl, 0, sizeof(*p_tbl) ); + + p_tbl->max_block_in_use = -1; + + if( capacity == 0 ) + { + /* + This switch apparently doesn't support multicast. + Everything is initialized to zero already, so return. + */ + return( IB_SUCCESS ); + } + + p_tbl->num_entries = capacity; + p_tbl->num_ports = num_ports; + p_tbl->max_position = (uint8_t)((ROUNDUP( num_ports, IB_MCAST_MASK_SIZE) / + IB_MCAST_MASK_SIZE) - 1); + + p_tbl->max_block = (uint16_t)((ROUNDUP( p_tbl->num_entries, + IB_MCAST_BLOCK_SIZE ) / IB_MCAST_BLOCK_SIZE) - 1); + + p_tbl->max_mlid_ho = (uint16_t)(IB_LID_MCAST_START_HO + capacity); + + /* + The number of bytes needed in the mask table is: + The (maximum bit mask 'position' + 1) times the + number of bytes in each bit mask times the + number of MLIDs supported by the table. + + We must always allocate the array with the maximum position + since it is (and must be) defined that way the table structure + in order to create a pointer to a two dimensional array. + */ + p_tbl->p_mask_tbl = malloc( p_tbl->num_entries * + (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8 ); + + if( p_tbl->p_mask_tbl == NULL ) + return( IB_INSUFFICIENT_MEMORY ); + + memset(p_tbl->p_mask_tbl, 0, + p_tbl->num_entries * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8 ); + return( IB_SUCCESS ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcast_tbl_destroy( + IN osm_mcast_tbl_t* const p_tbl ) +{ + free( p_tbl->p_mask_tbl ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcast_tbl_set( + IN osm_mcast_tbl_t* const p_tbl, + IN const uint16_t mlid_ho, + IN const uint8_t port ) +{ + uintn_t mlid_offset; + uintn_t mask_offset; + uintn_t bit_mask; + int16_t block_num; + + CL_ASSERT( p_tbl ); + CL_ASSERT( mlid_ho >= IB_LID_MCAST_START_HO ); + CL_ASSERT( mlid_ho <= p_tbl->max_mlid_ho ); + CL_ASSERT( p_tbl->p_mask_tbl ); + + mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; + mask_offset = port / IB_MCAST_MASK_SIZE; + bit_mask = cl_ntoh16( (uint16_t)( 1 << (port % IB_MCAST_MASK_SIZE) ) ); + (*p_tbl->p_mask_tbl)[mlid_offset][mask_offset] |= bit_mask; + + block_num = (int16_t)(mlid_offset / IB_MCAST_BLOCK_SIZE); + + if( block_num > p_tbl->max_block_in_use ) + p_tbl->max_block_in_use = (uint16_t)block_num; +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_mcast_tbl_is_port( + IN const osm_mcast_tbl_t* const p_tbl, + IN const uint16_t mlid_ho, + IN const uint8_t port_num ) +{ + uintn_t mlid_offset; + uintn_t mask_offset; + uintn_t bit_mask; + + CL_ASSERT( p_tbl ); + + if( p_tbl->p_mask_tbl ) + { + CL_ASSERT( port_num <= (p_tbl->max_position + 1) * IB_MCAST_MASK_SIZE ); + CL_ASSERT( mlid_ho >= IB_LID_MCAST_START_HO ); + CL_ASSERT( mlid_ho <= p_tbl->max_mlid_ho ); + + mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; + mask_offset = port_num / IB_MCAST_MASK_SIZE; + bit_mask = cl_ntoh16( + (uint16_t)( 1 << (port_num % IB_MCAST_MASK_SIZE) ) ); + return( ((*p_tbl->p_mask_tbl)[mlid_offset][mask_offset] & bit_mask) == + bit_mask ); + } + + return( FALSE ); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_mcast_tbl_is_any_port( + IN const osm_mcast_tbl_t* const p_tbl, + IN const uint16_t mlid_ho ) +{ + uintn_t mlid_offset; + uint8_t position; + uint16_t result = 0; + + CL_ASSERT( p_tbl ); + + if( p_tbl->p_mask_tbl ) + { + CL_ASSERT( mlid_ho >= IB_LID_MCAST_START_HO ); + CL_ASSERT( mlid_ho <= p_tbl->max_mlid_ho ); + + mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; + + for( position = 0; position <= p_tbl->max_position; position++ ) + result |= (*p_tbl->p_mask_tbl)[mlid_offset][position]; + } + + return( result != 0 ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mcast_tbl_set_block( + IN osm_mcast_tbl_t* const p_tbl, + IN const ib_net16_t* const p_block, + IN const int16_t block_num, + IN const uint8_t position ) +{ + uint32_t i; + uint16_t mlid_start_ho; + + CL_ASSERT( p_tbl ); + CL_ASSERT( p_block ); + + if( block_num > p_tbl->max_block ) + return( IB_INVALID_PARAMETER ); + + if( position > p_tbl->max_position ) + return( IB_INVALID_PARAMETER ); + + mlid_start_ho = (uint16_t)(block_num * IB_MCAST_BLOCK_SIZE); + + if( mlid_start_ho + IB_MCAST_BLOCK_SIZE > p_tbl->max_mlid_ho ) + return( IB_INVALID_PARAMETER ); + + for( i = 0; i < IB_MCAST_BLOCK_SIZE; i++ ) + (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position] = p_block[i]; + + if( block_num > p_tbl->max_block_in_use ) + p_tbl->max_block_in_use = (uint16_t)block_num; + + return( IB_SUCCESS ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcast_tbl_clear_mlid( + IN osm_mcast_tbl_t* const p_tbl, + IN const uint16_t mlid_ho ) +{ + uint8_t i; + uintn_t mlid_offset; + + CL_ASSERT( p_tbl ); + CL_ASSERT( mlid_ho >= IB_LID_MCAST_START_HO ); + + if( p_tbl->p_mask_tbl && (mlid_ho <= p_tbl->max_mlid_ho) ) + { + mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; + for( i = 0; i <= p_tbl->max_position; i++ ) + (*p_tbl->p_mask_tbl)[mlid_offset][i] = 0; + } +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_mcast_tbl_get_block( + IN osm_mcast_tbl_t* const p_tbl, + IN int16_t const block_num, + IN uint8_t const position, + OUT ib_net16_t* const p_block ) +{ + uint32_t i; + uint16_t mlid_start_ho; + + CL_ASSERT( p_tbl ); + CL_ASSERT( p_block ); + + if( block_num > p_tbl->max_block_in_use ) + return( FALSE ); + + if( position > p_tbl->max_position ) + { + /* + Caller shouldn't do this for efficiency's sake... + */ + memset( p_block, 0, IB_SMP_DATA_SIZE ); + return( TRUE ); + } + + mlid_start_ho = (uint16_t)(block_num * IB_MCAST_BLOCK_SIZE); + + if( mlid_start_ho + IB_MCAST_BLOCK_SIZE > p_tbl->max_mlid_ho ) + return( IB_INVALID_PARAMETER ); + + for( i = 0; i < IB_MCAST_BLOCK_SIZE; i++ ) + p_block[i] = (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position]; + + return( TRUE ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcm_info.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcm_info.c new file mode 100644 index 00000000..47eeb2e6 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcm_info.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF 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 osm_mcm_info_t. + * This object represents a Multicast Forwarding Information object. + * This object is part of the OpenSM family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_mcm_info_destroy( + IN osm_mcm_info_t* const p_mcm ) +{ + CL_ASSERT( p_mcm ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcm_info_init( + IN osm_mcm_info_t* const p_mcm, + IN const ib_net16_t mlid ) +{ + CL_ASSERT( p_mcm ); + p_mcm->mlid = mlid; +} + +/********************************************************************** + **********************************************************************/ +osm_mcm_info_t* +osm_mcm_info_new( + IN const ib_net16_t mlid ) +{ + osm_mcm_info_t* p_mcm; + + p_mcm = (osm_mcm_info_t*)malloc( sizeof(*p_mcm) ); + if( p_mcm ) + { + memset(p_mcm, 0, sizeof(*p_mcm) ); + osm_mcm_info_init( p_mcm, mlid ); + } + + return( p_mcm ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcm_info_delete( + IN osm_mcm_info_t* const p_mcm ) +{ + osm_mcm_info_destroy( p_mcm ); + free( p_mcm ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcm_port.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcm_port.c new file mode 100644 index 00000000..af15ef4b --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mcm_port.c @@ -0,0 +1,127 @@ +/* + * 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: + * 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. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_mcm_port_construct( + IN osm_mcm_port_t* const p_mcm ) +{ + memset( p_mcm, 0, sizeof(*p_mcm) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcm_port_destroy( + IN osm_mcm_port_t* const p_mcm ) +{ + /* + Nothing to do? + */ + UNUSED_PARAM( p_mcm ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcm_port_init( + IN osm_mcm_port_t* const p_mcm, + IN const ib_gid_t* const p_port_gid, + IN const uint8_t scope_state, + IN const boolean_t proxy_join ) +{ + CL_ASSERT( p_mcm ); + CL_ASSERT( p_port_gid ); + CL_ASSERT( scope_state ); + + osm_mcm_port_construct( p_mcm ); + p_mcm->port_gid = *p_port_gid; + p_mcm->scope_state = scope_state; + p_mcm->proxy_join = proxy_join; +} + +/********************************************************************** + **********************************************************************/ +osm_mcm_port_t* +osm_mcm_port_new( + IN const ib_gid_t* const p_port_gid, + IN const uint8_t scope_state, + IN const boolean_t proxy_join ) +{ + osm_mcm_port_t* p_mcm; + + p_mcm = malloc( sizeof(*p_mcm) ); + if( p_mcm ) + { + osm_mcm_port_init( p_mcm, p_port_gid, + scope_state, proxy_join ); + } + + return( p_mcm ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcm_port_delete( + IN osm_mcm_port_t* const p_mcm ) +{ + CL_ASSERT( p_mcm ); + + osm_mcm_port_destroy( p_mcm ); + free( p_mcm ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_mtree.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mtree.c new file mode 100644 index 00000000..256ec281 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_mtree.c @@ -0,0 +1,137 @@ +/* + * 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: + * Implementation of osm_mtree_node_t. + * This file implements the Multicast Tree object. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_mtree_node_init( + IN osm_mtree_node_t* const p_mtn, + IN const osm_switch_t* const p_sw ) +{ + uint32_t i; + + CL_ASSERT( p_mtn ); + CL_ASSERT( p_sw ); + + osm_mtree_node_construct( p_mtn ); + + p_mtn->p_sw = (osm_switch_t*)p_sw; + p_mtn->max_children = osm_switch_get_num_ports( p_sw ); + + for( i = 0; i < p_mtn->max_children; i++ ) + p_mtn->child_array[i] = NULL; +} + +/********************************************************************** + **********************************************************************/ +osm_mtree_node_t* +osm_mtree_node_new( + IN const osm_switch_t* const p_sw ) +{ + osm_mtree_node_t *p_mtn; + + p_mtn = malloc( sizeof(osm_mtree_node_t) + + sizeof(void*) * (osm_switch_get_num_ports( p_sw ) - 1) ); + + if( p_mtn != NULL ) + osm_mtree_node_init( p_mtn, p_sw ); + + return( p_mtn ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mtree_destroy( + IN osm_mtree_node_t *p_mtn ) +{ + uint32_t i; + + if (p_mtn == NULL) + return; + + if ( p_mtn->child_array != NULL ) + for (i = 0 ; i< p_mtn->max_children; i++ ) + if ( (p_mtn->child_array[i] != NULL) && + (p_mtn->child_array[i] != OSM_MTREE_LEAF) ) + osm_mtree_destroy(p_mtn->child_array[i]); + + free( p_mtn ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_mtree_dump( + IN osm_mtree_node_t *p_mtn ) +{ + uint32_t i; + + if (p_mtn == NULL) + return; + + printf("GUID:0x%016" PRIx64 " max_children:%u\n", + cl_ntoh64(p_mtn->p_sw->p_node->node_info.node_guid), + p_mtn->max_children ); + if ( p_mtn->child_array != NULL ) + { + for (i = 0 ; i< p_mtn->max_children; i++ ) + { + printf("i=%d\n", i); + if ( (p_mtn->child_array[i] != NULL) && (p_mtn->child_array[i] != OSM_MTREE_LEAF) ) + __osm_mtree_dump(p_mtn->child_array[i]); + } + } +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_multicast.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_multicast.c new file mode 100644 index 00000000..b12bcbe3 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_multicast.c @@ -0,0 +1,403 @@ +/* + * 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: + * Implementation of multicast functions. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +/* osm_mcast_req_type_t values converted to test for easier printing. */ +const char* osm_mcast_req_type_str[] = +{ + "OSM_MCAST_REQ_TYPE_CREATE", + "OSM_MCAST_REQ_TYPE_JOIN", + "OSM_MCAST_REQ_TYPE_LEAVE", + "OSM_MCAST_REQ_TYPE_SUBNET_CHANGE" +}; + +const char* +osm_get_mcast_req_type_str( + IN osm_mcast_req_type_t req_type ) +{ + if ( req_type > OSM_MCAST_REQ_TYPE_SUBNET_CHANGE ) + req_type = OSM_MCAST_REQ_TYPE_SUBNET_CHANGE; + return( osm_mcast_req_type_str[req_type] ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mgrp_construct( + IN osm_mgrp_t* const p_mgrp ) +{ + memset( p_mgrp, 0, sizeof(*p_mgrp) ); + cl_qmap_init( &p_mgrp->mcm_port_tbl ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mgrp_destroy( + IN osm_mgrp_t* const p_mgrp ) +{ + osm_mcm_port_t *p_mcm_port; + osm_mcm_port_t *p_next_mcm_port; + + CL_ASSERT(p_mgrp); + + p_next_mcm_port = (osm_mcm_port_t*)cl_qmap_head( &p_mgrp->mcm_port_tbl ); + while( p_next_mcm_port != (osm_mcm_port_t*)cl_qmap_end( &p_mgrp->mcm_port_tbl ) ) + { + p_mcm_port = p_next_mcm_port; + p_next_mcm_port = (osm_mcm_port_t*)cl_qmap_next( &p_mcm_port->map_item ); + osm_mcm_port_delete( p_mcm_port ); + } + /* destroy the mtree_node structure */ + osm_mtree_destroy(p_mgrp->p_root); + + free(p_mgrp); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mgrp_init( + IN osm_mgrp_t* const p_mgrp, + IN const ib_net16_t mlid ) +{ + CL_ASSERT( p_mgrp ); + CL_ASSERT( cl_ntoh16( mlid ) >= IB_LID_MCAST_START_HO ); + + osm_mgrp_construct( p_mgrp ); + p_mgrp->mlid = mlid; + p_mgrp->last_change_id = 0; + p_mgrp->last_tree_id = 0; + p_mgrp->to_be_deleted = FALSE; +} + +/********************************************************************** + **********************************************************************/ +osm_mgrp_t* +osm_mgrp_new( + IN const ib_net16_t mlid ) +{ + osm_mgrp_t* p_mgrp; + + p_mgrp = (osm_mgrp_t*)malloc( sizeof(*p_mgrp) ); + if( p_mgrp ) + osm_mgrp_init( p_mgrp, mlid ); + + return( p_mgrp ); +} + +/********************************************************************** + **********************************************************************/ +osm_mcm_port_t* +osm_mgrp_add_port( + IN osm_mgrp_t* const p_mgrp, + IN const ib_gid_t* const p_port_gid, + IN const uint8_t join_state, + IN boolean_t proxy_join ) +{ + ib_net64_t port_guid; + osm_mcm_port_t *p_mcm_port; + cl_map_item_t *prev_item; + uint8_t prev_join_state; + uint8_t prev_scope; + + p_mcm_port = osm_mcm_port_new( p_port_gid, join_state, proxy_join ); + if( p_mcm_port ) + { + port_guid = p_port_gid->unicast.interface_id; + + /* + prev_item = cl_qmap_insert(...) + Pointer to the item in the map with the specified key. If insertion + was successful, this is the pointer to the item. If an item with the + specified key already exists in the map, the pointer to that item is + returned. + */ + prev_item = cl_qmap_insert( &p_mgrp->mcm_port_tbl, + port_guid, &p_mcm_port->map_item ); + + /* if already exists - revert the insertion and only update join state */ + if( prev_item != &p_mcm_port->map_item ) + { + + osm_mcm_port_delete( p_mcm_port ); + p_mcm_port =(osm_mcm_port_t *) prev_item; + + /* + o15.0.1.11 + Join state of the end port should be the or of the + previous setting with the current one + */ + ib_member_get_scope_state(p_mcm_port->scope_state, &prev_scope, &prev_join_state); + p_mcm_port->scope_state = + ib_member_set_scope_state(prev_scope, prev_join_state | join_state); + + } + else + { + /* track the fact we modified the group ports */ + p_mgrp->last_change_id++; + } + } + + return( p_mcm_port ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mgrp_remove_port( + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_mgrp_t* const p_mgrp, + IN const ib_net64_t port_guid ) +{ + cl_map_item_t *p_map_item; + + CL_ASSERT(p_mgrp); + + p_map_item = cl_qmap_get( &p_mgrp->mcm_port_tbl, port_guid ); + + if( p_map_item != cl_qmap_end( &p_mgrp->mcm_port_tbl ) ) + { + cl_qmap_remove_item( &p_mgrp->mcm_port_tbl, + p_map_item ); + osm_mcm_port_delete((osm_mcm_port_t*)p_map_item); + + /* track the fact we modified the group */ + p_mgrp->last_change_id++; + } + + /* + no more ports so the group will be deleted after re-route + but only if it is not a well known group and not already deleted + */ + if ((cl_is_qmap_empty( &p_mgrp->mcm_port_tbl )) && + (p_mgrp->well_known == FALSE) && + (p_mgrp->to_be_deleted == FALSE)) + { + p_mgrp->to_be_deleted = TRUE; + + /* Send a Report to any InformInfo registered for + Trap 67 : MCGroup delete */ + osm_mgrp_send_delete_notice( p_subn, p_log, p_mgrp ); + } +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_mgrp_is_port_present( + IN const osm_mgrp_t* const p_mgrp, + IN const ib_net64_t port_guid, + OUT osm_mcm_port_t ** const pp_mcm_port ) +{ + cl_map_item_t *p_map_item; + + CL_ASSERT(p_mgrp); + + p_map_item = cl_qmap_get(&p_mgrp->mcm_port_tbl, + port_guid); + + if (p_map_item != cl_qmap_end(&p_mgrp->mcm_port_tbl)) + { + if (pp_mcm_port) + *pp_mcm_port = (osm_mcm_port_t *)p_map_item; + return TRUE; + } + if (pp_mcm_port) + *pp_mcm_port = NULL; + return FALSE; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_mgrp_apply_func_sub( + const osm_mgrp_t* const p_mgrp, + const osm_mtree_node_t* const p_mtn, + osm_mgrp_func_t p_func, + void* context ) +{ + uint8_t i = 0; + uint8_t max_children; + osm_mtree_node_t* p_child_mtn; + + /* + Call the user, then recurse. + */ + p_func( p_mgrp, p_mtn, context ); + + max_children = osm_mtree_node_get_max_children( p_mtn ); + for( i = 0; i < max_children; i++ ) + { + p_child_mtn = osm_mtree_node_get_child( p_mtn, i ); + if( p_child_mtn ) + __osm_mgrp_apply_func_sub( p_mgrp, p_child_mtn, p_func, context ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_mgrp_apply_func( + const osm_mgrp_t* const p_mgrp, + osm_mgrp_func_t p_func, + void* context ) +{ + osm_mtree_node_t* p_mtn; + + CL_ASSERT( p_mgrp ); + CL_ASSERT( p_func ); + + p_mtn = p_mgrp->p_root; + + if( p_mtn ) + __osm_mgrp_apply_func_sub( p_mgrp, p_mtn, p_func, context ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mgrp_send_delete_notice( + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_mgrp_t *p_mgrp ) +{ + ib_mad_notice_attr_t notice; + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_mgrp_send_delete_notice ); + + /* prepare the needed info */ + + /* 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 */ + notice.g_or_v.generic.trap_num = CL_HTON16(67); /* delete of mcg */ + /* The sm_base_lid is saved in network order already. */ + notice.issuer_lid = p_subn->sm_base_lid; + /* following o14-12.1.11 and table 120 p726 */ + /* we need to provide the MGID */ + memcpy(&(notice.data_details.ntc_64_67.gid), + &(p_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 = p_subn->opt.subnet_prefix; + notice.issuer_gid.unicast.interface_id = p_subn->sm_port_guid; + + status = osm_report_notice(p_log, p_subn, ¬ice); + if( status != IB_SUCCESS ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_mgrp_send_delete_notice: ERR 7601: " + "Error sending trap reports (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mgrp_send_create_notice( + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_mgrp_t *p_mgrp ) +{ + ib_mad_notice_attr_t notice; + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_mgrp_send_create_notice ); + + /* prepare the needed info */ + + /* details of the notice */ + 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(66); /* create of mcg */ + /* The sm_base_lid is saved in network order already. */ + notice.issuer_lid = p_subn->sm_base_lid; + /* following o14-12.1.11 and table 120 p726 */ + /* we need to provide the MGID */ + memcpy(&(notice.data_details.ntc_64_67.gid), + &(p_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 = p_subn->opt.subnet_prefix; + notice.issuer_gid.unicast.interface_id = p_subn->sm_port_guid; + + status = osm_report_notice(p_log, p_subn, ¬ice); + if( status != IB_SUCCESS ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_mgrp_send_create_notice: ERR 7602: " + "Error sending trap reports (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_node.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_node.c new file mode 100644 index 00000000..064c1db5 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_node.c @@ -0,0 +1,335 @@ +/* + * 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: + * Implementation of osm_node_t. + * This object represents an Infiniband Node. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_node_init_physp( + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ) +{ + osm_physp_t *p_physp; + ib_net64_t port_guid; + ib_smp_t *p_smp; + ib_node_info_t *p_ni; + uint8_t port_num; + + CL_ASSERT( p_node ); + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + + CL_ASSERT( p_smp->attr_id == IB_MAD_ATTR_NODE_INFO ); + + p_ni = (ib_node_info_t*)ib_smp_get_payload_ptr( p_smp ); + port_guid = p_ni->port_guid; + port_num = ib_node_info_get_local_port_num( p_ni ); + + CL_ASSERT( port_num < p_node->physp_tbl_size ); + + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + + osm_physp_init( p_physp, port_guid, port_num, p_node, + osm_madw_get_bind_handle( p_madw ), + p_smp->hop_count, p_smp->initial_path ); +} + +/********************************************************************** + **********************************************************************/ +osm_node_t* +osm_node_new( + IN const osm_madw_t* const p_madw ) +{ + osm_node_t *p_node; + ib_smp_t *p_smp; + ib_node_info_t *p_ni; + uint8_t i; + uint32_t size; + + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + + CL_ASSERT( p_smp->attr_id == IB_MAD_ATTR_NODE_INFO ); + + p_ni = (ib_node_info_t*)ib_smp_get_payload_ptr( p_smp ); + + /* + The node object already contains one physical port object. + Therefore, subtract 1 from the number of physical ports + used by the switch. This is not done for CA's since they + need to occupy 1 more physp than they physically have since + we still reserve room for a "port 0". + */ + size = p_ni->num_ports; + + p_node = malloc( sizeof(*p_node) + sizeof(osm_physp_t) * size ); + if( p_node != 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 HCA's 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( osm_node_get_physp_ptr( p_node, i ) ); + + osm_node_init_physp( p_node, p_madw ); + } + + return( p_node ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_node_destroy( + IN osm_node_t *p_node ) +{ + uint16_t i; + + /* Cleanup all PhysPorts */ + if( p_node != NULL ) + { + /* + Cleanup all physports + */ + for( i = 0; i < p_node->physp_tbl_size; i++ ) + { + osm_physp_t *p_physp = osm_node_get_physp_ptr( p_node, i ); + if (p_physp) + osm_physp_destroy( p_physp ); + } + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_node_delete( + IN OUT osm_node_t** const p_node ) +{ + osm_node_destroy( *p_node ); + free( *p_node ); + *p_node = NULL; +} + +/********************************************************************** + **********************************************************************/ +void +osm_node_link( + IN osm_node_t* const p_node, + IN const uint8_t port_num, + IN osm_node_t* const p_remote_node, + IN const uint8_t remote_port_num ) +{ + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + + CL_ASSERT( port_num < p_node->physp_tbl_size ); + CL_ASSERT( remote_port_num < p_remote_node->physp_tbl_size ); + + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + p_remote_physp = osm_node_get_physp_ptr( p_remote_node, + remote_port_num ); + + if (p_physp->p_remote_physp) + p_physp->p_remote_physp->p_remote_physp = NULL; + if (p_remote_physp->p_remote_physp) + p_remote_physp->p_remote_physp->p_remote_physp = NULL; + + osm_physp_link( p_physp, p_remote_physp ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_node_unlink( + IN osm_node_t* const p_node, + IN const uint8_t port_num, + IN osm_node_t* const p_remote_node, + IN const uint8_t remote_port_num ) +{ + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + + CL_ASSERT( port_num < p_node->physp_tbl_size ); + CL_ASSERT( remote_port_num < p_remote_node->physp_tbl_size ); + + if( osm_node_link_exists( p_node, port_num, + p_remote_node, remote_port_num ) ) + { + + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + p_remote_physp = osm_node_get_physp_ptr( p_remote_node, + remote_port_num ); + + osm_physp_unlink( p_physp, p_remote_physp ); + } +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_node_link_exists( + IN osm_node_t* const p_node, + IN const uint8_t port_num, + IN osm_node_t* const p_remote_node, + IN const uint8_t remote_port_num ) +{ + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + + CL_ASSERT( port_num < p_node->physp_tbl_size ); + CL_ASSERT( remote_port_num < p_remote_node->physp_tbl_size ); + + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + p_remote_physp = osm_node_get_physp_ptr( p_remote_node, + remote_port_num ); + + return( osm_physp_link_exists( p_physp, p_remote_physp ) ); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_node_link_has_valid_ports( + IN osm_node_t* const p_node, + IN const uint8_t port_num, + IN osm_node_t* const p_remote_node, + IN const uint8_t remote_port_num ) +{ + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + + CL_ASSERT( port_num < p_node->physp_tbl_size ); + CL_ASSERT( remote_port_num < p_remote_node->physp_tbl_size ); + + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + p_remote_physp = osm_node_get_physp_ptr( p_remote_node, + remote_port_num ); + + return( osm_physp_is_valid( p_physp ) && + osm_physp_is_valid( p_remote_physp ) ); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_node_has_any_link( + IN osm_node_t* const p_node, + IN const uint8_t port_num ) +{ + osm_physp_t *p_physp; + CL_ASSERT( port_num < p_node->physp_tbl_size ); + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + return( osm_physp_has_any_link( p_physp ) ); +} + +/********************************************************************** + **********************************************************************/ +osm_node_t* +osm_node_get_remote_node( + IN const osm_node_t* const p_node, + IN const uint8_t port_num, + OUT uint8_t *p_remote_port_num ) +{ + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + + if( !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 const osm_node_t* const p_node, + IN const uint32_t port_num ) +{ + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + CL_ASSERT( port_num < p_node->physp_tbl_size ); + + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + if( osm_physp_is_valid( 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-1/ulp/opensm/user/opensm/osm_node_desc_rcv.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_node_desc_rcv.c new file mode 100644 index 00000000..d3e8cfbd --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_node_desc_rcv.c @@ -0,0 +1,182 @@ +/* + * 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: + * Implementation of osm_nd_rcv_t. + * This object represents the NodeDescription Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_nd_rcv_process_nd( + IN const osm_nd_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN const ib_node_desc_t* const p_nd ) +{ + char desc[IB_NODE_DESCRIPTION_SIZE + 1]; + OSM_LOG_ENTER( p_rcv->p_log, __osm_nd_rcv_process_nd ); + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) ) + { + memcpy( desc, p_nd, sizeof(*p_nd) ); + /* Guarantee null termination before printing. */ + desc[IB_NODE_DESCRIPTION_SIZE] = '\0'; + + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_nd_rcv_process_nd: " + "Node 0x%" PRIx64 "\n\t\t\t\tDescription = %s\n", + cl_ntoh64( osm_node_get_node_guid( p_node )), desc ); + } + + memcpy( &p_node->node_desc.description, p_nd, sizeof(*p_nd) ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_nd_rcv_construct( + IN osm_nd_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_nd_rcv_destroy( + IN osm_nd_rcv_t* const p_rcv ) +{ + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_nd_rcv_destroy ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_nd_rcv_init( + IN osm_nd_rcv_t* const p_rcv, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_nd_rcv_init ); + + osm_nd_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_nd_rcv_process( + IN const osm_nd_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ) +{ + cl_qmap_t *p_guid_tbl; + ib_node_desc_t *p_nd; + ib_smp_t *p_smp; + osm_node_t *p_node; + ib_net64_t node_guid; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_nd_rcv_process ); + + CL_ASSERT( p_madw ); + + p_guid_tbl = &p_rcv->p_subn->node_guid_tbl; + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_nd = (ib_node_desc_t*)ib_smp_get_payload_ptr( p_smp ); + + /* + Acquire the node object and add the node description. + */ + + node_guid = osm_madw_get_nd_context_ptr( p_madw )->node_guid; + CL_PLOCK_EXCL_ACQUIRE( p_rcv->p_lock ); + p_node = (osm_node_t*)cl_qmap_get( p_guid_tbl, node_guid ); + + if( p_node == (osm_node_t*)cl_qmap_end( p_guid_tbl) ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_nd_rcv_process: ERR 0B01: " + "NodeDescription received for nonexistent node " + "0x%" PRIx64 "\n", cl_ntoh64(node_guid) ); + } + else + { + __osm_nd_rcv_process_nd( p_rcv, p_node, p_nd ); + } + + CL_PLOCK_RELEASE( p_rcv->p_lock ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_node_desc_rcv_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_node_desc_rcv_ctrl.c new file mode 100644 index 00000000..f038e7b2 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_node_desc_rcv_ctrl.c @@ -0,0 +1,127 @@ +/* + * 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: + * Implementation of osm_nd_rcv_ctrl_t. + * This object represents the NodeDescription request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_nd_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_nd_rcv_process( ((osm_nd_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_nd_rcv_ctrl_construct( + IN osm_nd_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_nd_rcv_ctrl_destroy( + IN osm_nd_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_nd_rcv_ctrl_init( + IN osm_nd_rcv_ctrl_t* const p_ctrl, + IN osm_nd_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_nd_rcv_ctrl_init ); + + osm_nd_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_NODE_DESC, + __osm_nd_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_nd_rcv_ctrl_init: ERR 0C01: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_node_info_rcv.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_node_info_rcv.c new file mode 100755 index 00000000..76151f2c --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_node_info_rcv.c @@ -0,0 +1,1090 @@ +/* + * 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: + * Implementation of osm_ni_rcv_t. + * This object represents the NodeInfo Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.9 $ + */ + +#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 + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_set_links( + IN const osm_ni_rcv_t* const p_rcv, + osm_node_t* p_node, + const uint8_t port_num, + const osm_ni_context_t* const p_ni_context ) +{ + cl_qmap_t *p_guid_tbl; + osm_node_t *p_neighbor_node; + osm_node_t *p_old_neighbor_node; + uint8_t old_neighbor_port_num; + osm_physp_t *p_physp, *p_old_physp; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_ni_rcv_set_links ); + + /* + 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 ) + { + p_guid_tbl = &p_rcv->p_subn->node_guid_tbl; + p_neighbor_node = (osm_node_t*)cl_qmap_get( p_guid_tbl, + p_ni_context->node_guid ); + if( p_neighbor_node == (osm_node_t*)cl_qmap_end( p_guid_tbl ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_set_links: ERR 0D10: " + "Unexpected removal of neighbor node " + "0x%" PRIx64 "\n", + cl_ntoh64( p_ni_context->node_guid ) ); + } + else + { + /* + We have seen this neighbor node before, but we might + not have seen this port on the neighbor node before. + We should not set links to an uninitialized port on the + neighbor, so check validity up front. If it's not + valid, do nothing, since we'll see this link again + when we probe the neighbor. + */ + if( osm_node_link_has_valid_ports( p_node, port_num, + p_neighbor_node, p_ni_context->port_num ) ) + { + if( osm_node_link_exists( p_node, port_num, + p_neighbor_node, p_ni_context->port_num ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_ni_rcv_set_links: " + "Link already exists\n" ); + } + else + { + if( osm_node_has_any_link( p_node, port_num ) && + p_rcv->p_subn->force_immediate_heavy_sweep == FALSE ) + { + /* + Uh oh... + This means that we found 2 nodes with the same guid, + or a 12x link with lane reversal that is not configured correctly. + If the force_immediate_heavy_sweep == TRUE, then this might be a case + of port being moved (causing trap 128), and thus rediscovered. + In this case, just continue. There will be another heavy sweep + immediately after, when the subnet is stable again. + */ + char line[BUF_SIZE]; + char dr_new_path[BUF_SIZE]; + char dr_old_path[BUF_SIZE]; + uint32_t i; + osm_dr_path_t *p_path = NULL, *p_old_path = NULL; + + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + sprintf( dr_new_path, "no_path_available" ); + if (p_physp) + { + p_path = osm_physp_get_dr_path_ptr( p_physp ); + if ( p_path ) + { + sprintf( dr_new_path, "new path:" ); + for (i = 0; i <= p_path->hop_count; i++ ) + { + sprintf( line, "[%X]", p_path->path[i] ); + strcat( dr_new_path, line ); + } + } + } + + p_old_neighbor_node = osm_node_get_remote_node( + p_node, port_num, &old_neighbor_port_num ); + p_old_physp = osm_node_get_physp_ptr( + p_old_neighbor_node, + old_neighbor_port_num); + sprintf( dr_old_path, "no_path_available" ); + if (p_old_physp) + { + p_old_path = osm_physp_get_dr_path_ptr( p_old_physp ); + if ( p_old_path ) + { + sprintf( dr_old_path, "old_path:" ); + for (i = 0; i <= p_old_path->hop_count; i++ ) + { + sprintf( line, "[%X]", p_old_path->path[i] ); + strcat( dr_old_path, line ); + } + } + } + + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_set_links: ERR 0D01: " + "Found duplicated guids or 12x link " + "with lane reversal badly configured.\n" + "Overriding existing link to:" + "node 0x%" PRIx64 ", port number 0x%X connected to:\n" + "\t\t\t\told node 0x%" PRIx64 ", " + "port number 0x%X %s\n" + "\t\t\t\tnew node 0x%" PRIx64 ", " + "port number 0x%X %s\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + port_num, + cl_ntoh64( osm_node_get_node_guid( + p_old_neighbor_node ) ), + old_neighbor_port_num , + dr_old_path, + cl_ntoh64( p_ni_context->node_guid ), + p_ni_context->port_num, + dr_new_path + ); + + osm_log( p_rcv->p_log, OSM_LOG_SYS, + "FATAL: duplicated guids or 12x lane reversal\n"); + + if ( p_rcv->p_subn->opt.exit_on_fatal == TRUE ) + { + osm_log( p_rcv->p_log, OSM_LOG_SYS, "Exiting\n"); + exit( 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)) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_set_links: ERR 0D18: " + "Duplicate GUID found by link from a port to itself:" + "node 0x%" PRIx64 ", port number 0x%X\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + port_num ); + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + if (p_physp) + osm_dump_dr_path(p_rcv->p_log, + osm_physp_get_dr_path_ptr(p_physp), + OSM_LOG_ERROR); + + osm_log( p_rcv->p_log, OSM_LOG_SYS, + "Errors on subnet. Duplicate GUID found " + "by link from a port to itself. " + "See osm log for more details\n"); + + if ( p_rcv->p_subn->opt.exit_on_fatal == TRUE ) + exit( 1 ); + } + else + { + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_ni_rcv_set_links: " + "Creating new link between: " + "\n\t\t\t\tnode 0x%" PRIx64 ", " + "port number 0x%X and" + "\n\t\t\t\tnode 0x%" PRIx64 ", " + "port number 0x%X\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + port_num, + cl_ntoh64( p_ni_context->node_guid ), + p_ni_context->port_num ); + } + + CL_ASSERT( osm_node_get_node_guid( p_neighbor_node ) == + p_ni_context->node_guid ); + + osm_node_link( p_node, port_num, p_neighbor_node, + p_ni_context->port_num ); + } + } + } + } + } + else + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_ni_rcv_set_links: " + "Nothing to link for our own node 0x%" PRIx64 "\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) ) ); + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_new_node( + IN const osm_ni_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ) +{ + ib_api_status_t status = IB_SUCCESS; + osm_madw_context_t context; + osm_physp_t *p_physp; + ib_node_info_t *p_ni; + ib_smp_t *p_smp; + uint8_t port_num; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_ni_rcv_process_new_node ); + + CL_ASSERT( p_node ); + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_ni = (ib_node_info_t*)ib_smp_get_payload_ptr( p_smp ); + 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 ); + + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + CL_ASSERT( osm_madw_get_bind_handle( p_madw ) == + osm_dr_path_get_bind_handle( + osm_physp_get_dr_path_ptr( p_physp ) ) ); + + context.pi_context.node_guid = p_ni->node_guid; + context.pi_context.port_guid = p_ni->port_guid; + context.pi_context.set_method = FALSE; + context.pi_context.update_master_sm_base_lid = FALSE; + context.pi_context.ignore_errors = FALSE; + context.pi_context.light_sweep = FALSE; + context.pi_context.active_transition = FALSE; + + status = osm_req_get( p_rcv->p_gen_req, + osm_physp_get_dr_path_ptr( p_physp ), + IB_MAD_ATTR_PORT_INFO, + cl_hton32( port_num ), + CL_DISP_MSGID_NONE, + &context ); + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_new_node: ERR 0D02: " + "Failure initiating PortInfo request (%s)\n", + ib_get_err_str(status)); + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_get_node_desc( + IN const osm_ni_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ) +{ + ib_api_status_t status = IB_SUCCESS; + osm_madw_context_t context; + osm_physp_t *p_physp; + ib_node_info_t *p_ni; + ib_smp_t *p_smp; + uint8_t port_num; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_ni_rcv_get_node_desc ); + + CL_ASSERT( p_node ); + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_ni = (ib_node_info_t*)ib_smp_get_payload_ptr( p_smp ); + 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 ); + + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + CL_ASSERT( osm_madw_get_bind_handle( p_madw ) == + osm_dr_path_get_bind_handle( + osm_physp_get_dr_path_ptr( p_physp ) ) ); + + context.nd_context.node_guid = osm_node_get_node_guid( p_node ); + + status = osm_req_get( p_rcv->p_gen_req, + 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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_get_node_desc: ERR 0D03: " + "Failure initiating NodeDescription request (%s)\n", + ib_get_err_str(status)); + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_new_ca_or_router( + IN const osm_ni_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ) +{ + OSM_LOG_ENTER( p_rcv->p_log, __osm_ni_rcv_process_new_ca_or_router ); + + __osm_ni_rcv_process_new_node( p_rcv, 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 ) + { + p_rcv->p_subn->sm_port_guid = p_node->node_info.port_guid; + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_existing_ca_or_router( + IN const osm_ni_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ) +{ + ib_node_info_t *p_ni; + ib_smp_t *p_smp; + osm_port_t *p_port; + osm_port_t *p_port_check; + cl_qmap_t *p_guid_tbl; + osm_madw_context_t context; + uint8_t port_num; + osm_physp_t *p_physp; + ib_api_status_t status; + osm_dr_path_t *p_dr_path; + osm_bind_handle_t h_bind; + cl_status_t cl_status; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_ni_rcv_process_existing_ca_or_router ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_ni = (ib_node_info_t*)ib_smp_get_payload_ptr( p_smp ); + port_num = ib_node_info_get_local_port_num( p_ni ); + p_guid_tbl = &p_rcv->p_subn->port_guid_tbl; + 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_port_t*)cl_qmap_get( p_guid_tbl, p_ni->port_guid ); + + if( p_port == (osm_port_t*)cl_qmap_end( p_guid_tbl ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_ni_rcv_process_existing_ca_or_router: " + "Creating new port object with GUID 0x%" PRIx64 "\n", + cl_ntoh64( p_ni->port_guid ) ); + + osm_node_init_physp( p_node, p_madw ); + + p_port = osm_port_new( p_ni, p_node ); + if( p_port == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_existing_ca_or_router: 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( p_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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_existing_ca_or_router: 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. + Add it to the new_ports_list - 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 ( p_rcv->p_subn->sm_state == IB_SMINFO_STATE_MASTER ) + { + cl_status = cl_list_insert_tail( &p_rcv->p_subn->new_ports_list, p_port ); + if( cl_status != CL_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_existing_ca_or_router: ERR 0D08: " + "Error %s adding to list\n", + CL_STATUS_MSG( cl_status ) ); + osm_port_delete( &p_port ); + goto Exit; + } + else + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_ni_rcv_process_existing_ca_or_router: " + "Adding port GUID:0x%016" PRIx64 " to new_ports_list\n", + cl_ntoh64(osm_node_get_node_guid( p_port->p_node )) ); + } + } + + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + } + else + { + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + + CL_ASSERT( p_physp ); + + if ( !osm_physp_is_valid( p_physp ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_existing_ca_or_router: ERR 0D19: " + "Invalid physical port. Aborting discovery\n"); + goto Exit; + } + + /* + Update the DR Path to the port, + in case the old one is no longer available. + */ + p_dr_path = osm_physp_get_dr_path_ptr( p_physp ); + + osm_dr_path_init( p_dr_path, h_bind, p_smp->hop_count, + p_smp->initial_path ); + } + + context.pi_context.node_guid = p_ni->node_guid; + context.pi_context.port_guid = p_ni->port_guid; + context.pi_context.set_method = FALSE; + context.pi_context.update_master_sm_base_lid = FALSE; + context.pi_context.ignore_errors = FALSE; + context.pi_context.light_sweep = FALSE; + + status = osm_req_get( p_rcv->p_gen_req, + osm_physp_get_dr_path_ptr( p_physp ), + IB_MAD_ATTR_PORT_INFO, + cl_hton32( port_num ), + CL_DISP_MSGID_NONE, + &context ); + + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_existing_ca_or_router: ERR 0D13: " + "Failure initiating PortInfo request (%s)\n", + ib_get_err_str(status)); + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_ni_rcv_process_switch( + IN const osm_ni_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ) +{ + ib_api_status_t status = IB_SUCCESS; + osm_madw_context_t context; + osm_dr_path_t dr_path; + ib_smp_t *p_smp; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_ni_rcv_process_switch ); + + CL_ASSERT( p_node ); + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + + osm_dr_path_init( &dr_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( p_rcv->p_gen_req, + &dr_path, + IB_MAD_ATTR_SWITCH_INFO, + 0, + CL_DISP_MSGID_NONE, + &context ); + if( status != IB_SUCCESS ) + { + /* continue despite error */ + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_switch: ERR 0D06: " + "Failure initiating SwitchInfo request (%s)\n", + ib_get_err_str( status ) ); + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_existing_switch( + IN const osm_ni_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ) +{ + OSM_LOG_ENTER( p_rcv->p_log, __osm_ni_rcv_process_existing_switch ); + + /* + 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( osm_node_discovery_count_get( p_node ) == 1 ) + __osm_ni_rcv_process_switch( p_rcv, p_node, p_madw ); + else + { + /* Make sure we have SwitchInfo on this node */ + if( !p_node->sw || osm_switch_discovery_count_get( p_node->sw ) == 0 ) + { + /* we don't have the SwitchInfo - retry to get it */ + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_ni_rcv_process_existing_switch: " + "Retry to get SwitchInfo on node GUID:0x%" + PRIx64 "\n", cl_ntoh64(osm_node_get_node_guid(p_node)) ); + __osm_ni_rcv_process_switch( p_rcv, p_node, p_madw ); + } + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_new_switch( + IN const osm_ni_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ) +{ + OSM_LOG_ENTER( p_rcv->p_log, __osm_ni_rcv_process_new_switch ); + + __osm_ni_rcv_process_switch( p_rcv, 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 ) + { + p_rcv->p_subn->sm_port_guid = p_node->node_info.port_guid; + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + The plock must NOT be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_new( + IN const osm_ni_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + osm_node_t *p_node; + osm_node_t *p_node_check; + osm_port_t *p_port; + osm_port_t *p_port_check; + osm_router_t *p_rtr = NULL; + osm_router_t *p_rtr_check; + cl_qmap_t *p_node_guid_tbl; + cl_qmap_t *p_port_guid_tbl; + 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; + cl_status_t status; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_ni_rcv_process_new ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_ni = (ib_node_info_t*)ib_smp_get_payload_ptr( p_smp ); + p_ni_context = osm_madw_get_ni_context_ptr( p_madw ); + port_num = ib_node_info_get_local_port_num( p_ni ); + + osm_dump_smp_dr_path( p_rcv->p_log, p_smp, OSM_LOG_VERBOSE ); + + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_ni_rcv_process_new: " + "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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_new: 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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_new: ERR 0D14: " + "Unable to create new port object\n" ); + osm_node_delete( &p_node ); + goto Exit; + } + + /* If there were RouterInfo or other router attribute, + this would be elsewhere */ + if ( p_ni->node_type == IB_NODE_TYPE_ROUTER ) + { + p_rtr = osm_router_new( p_port ); + if ( p_rtr == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_new: ERR 0D1A: " + "Unable to create new router object\n" ); + } + } + + /* + Add the new port object to the database. + */ + p_port_guid_tbl = &p_rcv->p_subn->port_guid_tbl; + p_port_check = (osm_port_t*)cl_qmap_insert( p_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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_new: ERR 0D15: " + "Duplicate Port GUID 0x%" PRIx64 "! Found by the two directed routes:\n", + cl_ntoh64( p_ni->port_guid ) ); + osm_dump_dr_path(p_rcv->p_log, + osm_physp_get_dr_path_ptr( + osm_port_get_default_phys_ptr ( p_port) ), + OSM_LOG_ERROR); + osm_dump_dr_path(p_rcv->p_log, + osm_physp_get_dr_path_ptr( + osm_port_get_default_phys_ptr ( p_port_check) ), + OSM_LOG_ERROR); + if ( p_rtr ) + osm_router_delete( &p_rtr ); + 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. + Add it to the new_ports_list - 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 ( p_rcv->p_subn->sm_state == IB_SMINFO_STATE_MASTER ) + { + status = cl_list_insert_tail( &p_rcv->p_subn->new_ports_list, p_port ); + if( status != CL_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_new: ERR 0D05: " + "Error %s adding to new_ports_list\n", + CL_STATUS_MSG( status ) ); + if ( p_rtr ) + osm_router_delete( &p_rtr ); + osm_port_delete( &p_port ); + osm_node_delete( &p_node ); + goto Exit; + } + else + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_ni_rcv_process_new: " + "Adding port GUID:0x%016" PRIx64 " to new_ports_list\n", + cl_ntoh64( osm_node_get_node_guid( p_port->p_node ) ) ); + } + } + + if ( p_rtr && p_ni->node_type == IB_NODE_TYPE_ROUTER ) + { + p_rtr_guid_tbl = &p_rcv->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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_new: ERR 0D1B: " + "Unable to add port GUID:0x%016" PRIx64 " to router table\n", + cl_ntoh64( p_ni->port_guid ) ); + } + } + + p_node_guid_tbl = &p_rcv->p_subn->node_guid_tbl; + p_node_check = (osm_node_t*)cl_qmap_insert( p_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( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_ni_rcv_process_new: " + "Discovery race detected at node 0x%" PRIx64 "\n", + cl_ntoh64( p_ni->node_guid ) ); + osm_node_delete( &p_node ); + p_node = p_node_check; + __osm_ni_rcv_set_links( p_rcv, p_node, port_num, p_ni_context ); + goto Exit; + } + else + __osm_ni_rcv_set_links( p_rcv, p_node, port_num, p_ni_context ); + + osm_node_discovery_count_inc( p_node ); + __osm_ni_rcv_get_node_desc( p_rcv, p_node, p_madw ); + + switch( p_ni->node_type ) + { + case IB_NODE_TYPE_CA: + case IB_NODE_TYPE_ROUTER: + __osm_ni_rcv_process_new_ca_or_router( p_rcv, p_node, p_madw ); + break; + case IB_NODE_TYPE_SWITCH: + __osm_ni_rcv_process_new_switch( p_rcv, p_node, p_madw ); + break; + default: + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_new: 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( p_rcv->p_log ); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_existing( + IN const osm_ni_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN const osm_madw_t* const p_madw ) +{ + ib_node_info_t *p_ni; + ib_smp_t *p_smp; + osm_ni_context_t *p_ni_context; + uint8_t port_num; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_ni_rcv_process_existing ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_ni = (ib_node_info_t*)ib_smp_get_payload_ptr( p_smp ); + p_ni_context = osm_madw_get_ni_context_ptr( p_madw ); + port_num = ib_node_info_get_local_port_num( p_ni ); + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_ni_rcv_process_existing: " + "Rediscovered %s node 0x%" PRIx64 + "\n\t\t\t\tTID 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 ), + osm_node_discovery_count_get( p_node ) ); + } + + /* + If we haven't already encountered this existing node + on this particular sweep, then process further. + */ + osm_node_discovery_count_inc( p_node ); + + switch( p_ni->node_type ) + { + case IB_NODE_TYPE_CA: + case IB_NODE_TYPE_ROUTER: + __osm_ni_rcv_process_existing_ca_or_router( p_rcv, p_node, p_madw ); + break; + + case IB_NODE_TYPE_SWITCH: + __osm_ni_rcv_process_existing_switch( p_rcv, p_node, p_madw ); + break; + + default: + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_ni_rcv_process_existing: ERR 0D09: " + "Unknown node type %u with GUID 0x%" PRIx64 "\n", + p_ni->node_type, cl_ntoh64( p_ni->node_guid ) ); + break; + } + + __osm_ni_rcv_set_links( p_rcv, p_node, port_num, p_ni_context ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_ni_rcv_construct( + IN osm_ni_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_ni_rcv_destroy( + IN osm_ni_rcv_t* const p_rcv ) +{ + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_ni_rcv_destroy ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_ni_rcv_init( + IN osm_ni_rcv_t* const p_rcv, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_state_mgr_t* const p_state_mgr, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_ni_rcv_init ); + + osm_ni_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_gen_req = p_req; + p_rcv->p_state_mgr = p_state_mgr; + + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_ni_rcv_process( + IN const osm_ni_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ) +{ + cl_qmap_t *p_guid_tbl; + ib_node_info_t *p_ni; + ib_smp_t *p_smp; + osm_node_t *p_node; + boolean_t process_new_flag = FALSE; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_ni_rcv_process ); + + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_ni = (ib_node_info_t*)ib_smp_get_payload_ptr( p_smp ); + + CL_ASSERT( p_smp->attr_id == IB_MAD_ATTR_NODE_INFO ); + + if (p_ni->node_guid == 0) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_ni_rcv_process: ERR 0D16: " + "Got Zero Node GUID! Found on the directed route:\n"); + osm_dump_smp_dr_path(p_rcv->p_log, p_smp, OSM_LOG_ERROR); + goto Exit; + } + + if (p_ni->port_guid == 0) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_ni_rcv_process: ERR 0D17: " + "Got Zero Port GUID! Found on the directed route:\n"); + osm_dump_smp_dr_path(p_rcv->p_log, p_smp, OSM_LOG_ERROR); + goto Exit; + } + + p_guid_tbl = &p_rcv->p_subn->node_guid_tbl; + + /* + Determine if this node has already been discovered, + and process accordingly. + During processing of this node, hold the shared lock. + */ + + CL_PLOCK_EXCL_ACQUIRE( p_rcv->p_lock ); + p_node = (osm_node_t*)cl_qmap_get( p_guid_tbl, p_ni->node_guid ); + + osm_dump_node_info( p_rcv->p_log, p_ni, OSM_LOG_DEBUG ); + + if( p_node == (osm_node_t*)cl_qmap_end(p_guid_tbl) ) + { + __osm_ni_rcv_process_new( p_rcv, p_madw ); + process_new_flag = TRUE; + } + else + __osm_ni_rcv_process_existing( p_rcv, p_node, p_madw ); + + CL_PLOCK_RELEASE( p_rcv->p_lock ); + + /* + * If we processed a new node - need to signal to the state_mgr that + * change detected. BUT - we cannot call the osm_state_mgr_process + * from within the lock of p_rcv->p_lock (can cause a deadlock). + */ + if ( process_new_flag ) + osm_state_mgr_process( p_rcv->p_state_mgr, OSM_SIGNAL_CHANGE_DETECTED ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_node_info_rcv_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_node_info_rcv_ctrl.c new file mode 100644 index 00000000..8633dd3e --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_node_info_rcv_ctrl.c @@ -0,0 +1,127 @@ +/* + * 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: + * Implementation of osm_ni_rcv_ctrl_t. + * This object represents the NodeInfo request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_ni_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_ni_rcv_process( ((osm_ni_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_ni_rcv_ctrl_construct( + IN osm_ni_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_ni_rcv_ctrl_destroy( + IN osm_ni_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_ni_rcv_ctrl_init( + IN osm_ni_rcv_ctrl_t* const p_ctrl, + IN osm_ni_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_ni_rcv_ctrl_init ); + + osm_ni_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_NODE_INFO, + __osm_ni_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_ni_rcv_ctrl_init: ERR 0E01: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_opensm.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_opensm.c new file mode 100644 index 00000000..e80d6c34 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_opensm.c @@ -0,0 +1,320 @@ +/* + * 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: + * Implementation of osm_opensm_t. + * This object represents the opensm super object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct routing_engine_module { + const char *name; + int (*setup)(osm_opensm_t *p_osm); +}; + +extern int osm_ucast_updn_setup(osm_opensm_t *p_osm); +extern int osm_ucast_file_setup(osm_opensm_t *p_osm); +extern int osm_ucast_ftree_setup(osm_opensm_t *p_osm); + +static int osm_ucast_null_setup(osm_opensm_t *p_osm); + +const static struct routing_engine_module routing_modules[] = { + { "null", osm_ucast_null_setup }, + { "updn", osm_ucast_updn_setup }, + { "file", osm_ucast_file_setup }, + { "ftree", osm_ucast_ftree_setup }, + { NULL, NULL } +}; + +static int setup_routing_engine(osm_opensm_t *p_osm, const char *name) +{ + const struct routing_engine_module *r; + + for (r = routing_modules; r->name && *r->name; r++) { + if(!strcmp(r->name, name)) { + p_osm->routing_engine.name = r->name; + if (r->setup(p_osm)) { + osm_log(&p_osm->log, OSM_LOG_VERBOSE, + "setup_routing_engine: setup of routing" + " engine \'%s\' failed\n", name); + return -2; + } + osm_log (&p_osm->log, OSM_LOG_DEBUG, + "setup_routing_engine: " + "\'%s\' routing engine set up\n", + p_osm->routing_engine.name); + return 0; + } + } + return -1; +} + +static int osm_ucast_null_setup(osm_opensm_t *p_osm) +{ + osm_log(&p_osm->log, OSM_LOG_VERBOSE, + "osm_ucast_null_setup: nothing yet - " + "will use default routing engine\n"); + return 0; +} + +/********************************************************************** + **********************************************************************/ +void +osm_opensm_construct( + IN osm_opensm_t * const p_osm ) +{ + memset( p_osm, 0, sizeof( *p_osm ) ); + 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 ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_opensm_destroy( + IN osm_opensm_t * const p_osm ) +{ + + /* in case of shutdown through exit proc - no ^C */ + osm_exit_flag = TRUE; + + /* + * First of all - Clear the is_sm bit. + */ + if( p_osm->sm.mad_ctrl.h_bind ) + osm_vendor_set_sm( p_osm->sm.mad_ctrl.h_bind, FALSE ); + + /* 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 */ + if (p_osm->routing_engine.delete) + p_osm->routing_engine.delete(p_osm->routing_engine.context); + osm_sa_destroy( &p_osm->sa ); + osm_sm_destroy( &p_osm->sm ); + 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 ); + + cl_plock_destroy( &p_osm->lock ); + + osm_log_destroy( &p_osm->log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_opensm_init( + IN osm_opensm_t * const p_osm, + IN const osm_subn_opt_t * const p_opt ) +{ + ib_api_status_t status; + + /* Can't use log macros here, since we're initializing the log. */ + osm_opensm_construct( p_osm ); + + status = osm_log_init_v2( &p_osm->log, p_opt->force_log_flush, + p_opt->log_flags, p_opt->log_file, + p_opt->log_max_size, p_opt->accum_log_file ); + if( status != IB_SUCCESS ) + return ( status ); + + /* If there is a log level defined - add the OSM_VERSION to it. */ + osm_log( &p_osm->log, + osm_log_get_level( &p_osm->log ) & ( OSM_LOG_SYS ^ 0xFF ), "%s\n", + OSM_VERSION ); + /* Write the OSM_VERSION to the SYS_LOG */ + osm_log( &p_osm->log, OSM_LOG_SYS, "%s\n", OSM_VERSION ); /* Format Waived */ + + osm_log( &p_osm->log, OSM_LOG_FUNCS, "osm_opensm_init: [\n" ); /* Format Waived */ + + status = cl_plock_init( &p_osm->lock ); + if( status != IB_SUCCESS ) + goto Exit; + + if( p_opt->single_thread ) + { + osm_log( &p_osm->log, OSM_LOG_INFO, + "osm_opensm_init: 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, &p_osm->log ); + 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, + &p_osm->subn, &p_osm->disp, &p_osm->lock ); + 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; + + if( p_opt->routing_engine_name && + setup_routing_engine(p_osm, p_opt->routing_engine_name)) { + osm_log( &p_osm->log, OSM_LOG_VERBOSE, + "osm_opensm_init: cannot find or setup routing engine" + " \'%s\'. Default will be used instead\n", + p_opt->routing_engine_name); + goto Exit; + } + + Exit: + osm_log( &p_osm->log, OSM_LOG_FUNCS, "osm_opensm_init: ]\n" ); /* Format Waived */ + return ( status ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_opensm_bind( + IN osm_opensm_t * const p_osm, + IN const ib_net64_t guid ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( &p_osm->log, osm_opensm_bind ); + + 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; + Exit: + OSM_LOG_EXIT( &p_osm->log ); + return ( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey.c new file mode 100644 index 00000000..49edbdf6 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey.c @@ -0,0 +1,547 @@ +/* + * 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: + * Implementation of opensm pkey manipulation functions. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.1 $ + */ + +#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) + memset(p_pkey_block, 0, sizeof(ib_pkey_table_t)); + cl_ptr_vector_set( &p_pkey_tbl->blocks, block, p_pkey_block ); + } + + /* sets the block values */ + memcpy( p_pkey_block, p_tbl, sizeof(ib_pkey_table_t) ); + + /* + NOTE: as the spec does not require uniqueness of PKeys in + tables there is no other way but to refresh the entire keys map. + + Moreover, if the same key exists but with full membership it should have + precedence on the key with limited membership ! + */ + cl_map_remove_all( &p_pkey_tbl->keys ); + + for (b = 0; b < cl_ptr_vector_get_size( &p_pkey_tbl->blocks ); b++) + { + + p_pkey_block = cl_ptr_vector_get( &p_pkey_tbl->blocks, b ); + if (! p_pkey_block) + continue; + + for (i = 0; i < IB_NUM_PKEY_ELEMENTS_IN_BLOCK; i++) + { + pkey = p_pkey_block->pkey_entry[i]; + if (ib_pkey_is_invalid(pkey)) + continue; + + /* + ignore the PKey Full Member bit in the key but store + the pointer to the table element as the map value + */ + p_prev_pkey = + cl_map_get( &p_pkey_tbl->keys, ib_pkey_get_base(pkey)); + + /* we only insert if no previous or it is not full member */ + if ((p_prev_pkey == NULL) || + (cl_ntoh16(*p_prev_pkey) < cl_ntoh16(pkey))) + cl_map_insert( &p_pkey_tbl->keys, + ib_pkey_get_base(pkey), + &(p_pkey_block->pkey_entry[i]) + ); + } + } + return(IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +/* + Store the given pkey in the "new" blocks array. + Also, make sure the regular block exists. +*/ +ib_api_status_t +osm_pkey_tbl_set_new_entry( + IN osm_pkey_tbl_t *p_pkey_tbl, + IN uint16_t block_idx, + IN uint8_t pkey_idx, + IN uint16_t pkey) +{ + ib_pkey_table_t *p_block; + + if (!(p_block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_idx))) { + p_block = (ib_pkey_table_t *)malloc(sizeof(ib_pkey_table_t)); + if (!p_block) + return(IB_ERROR); + memset(p_block, 0, sizeof(ib_pkey_table_t)); + cl_ptr_vector_set(&p_pkey_tbl->new_blocks, block_idx, p_block); + } + + p_block->pkey_entry[pkey_idx] = pkey; + if (p_pkey_tbl->used_blocks <= block_idx) + p_pkey_tbl->used_blocks = block_idx + 1; + + return(IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_pkey_find_next_free_entry( + IN osm_pkey_tbl_t *p_pkey_tbl, + OUT uint16_t *p_block_idx, + OUT uint8_t *p_pkey_idx) +{ + ib_pkey_table_t *p_new_block; + + CL_ASSERT(p_block_idx); + CL_ASSERT(p_pkey_idx); + + while (*p_block_idx < p_pkey_tbl->max_blocks) + { + if (*p_pkey_idx > IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) + { + *p_pkey_idx = 0; + (*p_block_idx)++; + if (*p_block_idx >= p_pkey_tbl->max_blocks) + return FALSE; + } + + p_new_block = osm_pkey_tbl_new_block_get(p_pkey_tbl, *p_block_idx); + + if (!p_new_block || + ib_pkey_is_invalid(p_new_block->pkey_entry[*p_pkey_idx])) + return TRUE; + else + (*p_pkey_idx)++; + } + return FALSE; +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pkey_tbl_get_block_and_idx( + IN osm_pkey_tbl_t *p_pkey_tbl, + IN uint16_t *p_pkey, + OUT uint16_t *p_block_idx, + OUT uint8_t *p_pkey_idx) +{ + uint16_t num_of_blocks; + uint16_t block_index; + ib_pkey_table_t *block; + + CL_ASSERT( p_block_idx != NULL ); + CL_ASSERT( p_pkey_idx != NULL ); + + num_of_blocks = (uint16_t)cl_ptr_vector_get_size( &p_pkey_tbl->blocks ); + for (block_index = 0; block_index < num_of_blocks; block_index++) + { + block = osm_pkey_tbl_block_get(p_pkey_tbl, block_index); + if ((block->pkey_entry <= p_pkey) && + (p_pkey < block->pkey_entry + IB_NUM_PKEY_ELEMENTS_IN_BLOCK)) + { + *p_block_idx = block_index; + *p_pkey_idx = (uint8_t)(p_pkey - block->pkey_entry); + return(IB_SUCCESS); + } + } + return(IB_NOT_FOUND); +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +__osm_match_pkey ( + IN const ib_net16_t *pkey1, + IN const ib_net16_t *pkey2 ) +{ + + /* if both pkeys are not full member - this is not a match */ + if (!(ib_pkey_is_full_member(*pkey1) || ib_pkey_is_full_member(*pkey2))) + return(FALSE); + + /* compare if the bases are the same. if they are - then + this is a match */ + if (ib_pkey_get_base(*pkey1) != ib_pkey_get_base(*pkey2)) + return(FALSE); + + return(TRUE); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_physp_share_this_pkey( + IN const osm_physp_t* const p_physp1, + IN const osm_physp_t* const p_physp2, + IN const ib_net16_t pkey ) +{ + ib_net16_t *pkey1, *pkey2; + + pkey1 = cl_map_get( &(osm_physp_get_pkey_tbl(p_physp1))->keys, + ib_pkey_get_base(pkey)); + pkey2 = cl_map_get( &(osm_physp_get_pkey_tbl(p_physp2))->keys, + ib_pkey_get_base(pkey)); + return (pkey1 && pkey2 && __osm_match_pkey(pkey1, pkey2)); +} + +/********************************************************************** + **********************************************************************/ +ib_net16_t +osm_physp_find_common_pkey( + IN const osm_physp_t* const p_physp1, + IN const osm_physp_t* const p_physp2 ) +{ + ib_net16_t *pkey1, *pkey2; + uint64_t pkey1_base, pkey2_base; + const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2; + cl_map_iterator_t map_iter1, map_iter2; + + pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp1); + pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp2); + + map_iter1 = cl_map_head(&pkey_tbl1->keys); + map_iter2 = cl_map_head(&pkey_tbl2->keys); + + /* we rely on the fact the map are sorted by pkey */ + while ( (map_iter1 != cl_map_end( &pkey_tbl1->keys )) && + (map_iter2 != cl_map_end( &pkey_tbl2->keys ))) + { + pkey1 = (ib_net16_t *)cl_map_obj( map_iter1 ); + pkey2 = (ib_net16_t *)cl_map_obj( map_iter2 ); + + if (__osm_match_pkey(pkey1, pkey2)) + return *pkey1; + + /* advance the lower value if they are not equal */ + pkey1_base = cl_map_key( map_iter1 ); + pkey2_base = cl_map_key( map_iter2 ); + if (pkey2_base == pkey1_base) + { + map_iter1 = cl_map_next( map_iter1 ); + map_iter2 = cl_map_next( map_iter2 ); + } + else if (pkey2_base < pkey1_base) + map_iter2 = cl_map_next( map_iter2 ); + else + map_iter1 = cl_map_next( map_iter1 ); + } + + return 0; +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_physp_share_pkey( + IN osm_log_t* p_log, + IN const osm_physp_t* const p_physp_1, + IN const osm_physp_t* const p_physp_2 ) +{ + const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2; + + if (p_physp_1 == p_physp_2) + return TRUE; + + pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp_1); + pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp_2); + + /* + The spec: 10.9.2 does not require each phys port to have PKey Table. + So actually if it does not, we need to use the default port instead. + + HACK: meanwhile we will ignore the check + */ + if (cl_is_map_empty(&pkey_tbl1->keys) || cl_is_map_empty(&pkey_tbl2->keys)) + return TRUE; + + return !ib_pkey_is_invalid(osm_physp_find_common_pkey(p_physp_1, p_physp_2)); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_port_share_pkey( + IN osm_log_t* p_log, + IN const osm_port_t* const p_port_1, + IN const osm_port_t* const p_port_2 ) { + + osm_physp_t *p_physp1, *p_physp2; + boolean_t ret; + + OSM_LOG_ENTER( p_log, osm_port_share_pkey ); + + if (!p_port_1 || !p_port_2) + { + ret = FALSE; + goto Exit; + } + + p_physp1 = osm_port_get_default_phys_ptr(p_port_1); + p_physp2 = osm_port_get_default_phys_ptr(p_port_2); + + 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_lid_share_pkey( + IN osm_log_t* p_log, + IN const osm_subn_t * const p_subn, + IN const ib_net16_t lid1, + IN const uint8_t port_num1, + IN const ib_net16_t lid2, + IN const uint8_t port_num2 ) { + + osm_physp_t *p_physp1, *p_physp2; + osm_port_t *p_port1, *p_port2; + osm_node_t *p_node1, *p_node2; + const cl_ptr_vector_t* const p_port_lid_tbl = &(p_subn->port_lid_tbl); + + OSM_LOG_ENTER( p_log, osm_lid_share_pkey ); + + p_port1 = cl_ptr_vector_get(p_port_lid_tbl, lid1); + p_port2 = cl_ptr_vector_get(p_port_lid_tbl, lid2); + + p_node1 = p_port1->p_node; + p_node2 = p_port2->p_node; + + if (osm_node_get_type( p_node1 ) == IB_NODE_TYPE_SWITCH) + { + p_physp1 = osm_node_get_physp_ptr( p_node1, port_num1 ); + } + else + { + p_physp1 = osm_port_get_default_phys_ptr(p_port1); + } + + if (osm_node_get_type( p_node2 ) == IB_NODE_TYPE_SWITCH) + { + p_physp2 = osm_node_get_physp_ptr( p_node2, port_num2 ); + } + else + { + p_physp2 = osm_port_get_default_phys_ptr(p_port2); + } + + return(osm_physp_share_pkey(p_log, p_physp1, p_physp2)); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_physp_has_pkey( + IN osm_log_t* p_log, + IN const ib_net16_t pkey, + IN const osm_physp_t* const p_physp ) { + + ib_net16_t *p_pkey, pkey_base; + const osm_pkey_tbl_t *pkey_tbl; + boolean_t res = FALSE; + + OSM_LOG_ENTER( p_log, osm_physp_has_pkey ); + + osm_log( p_log, OSM_LOG_DEBUG, + "osm_physp_has_pkey: " + "Search for PKey: 0x%4x\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, + "osm_physp_has_pkey: " + "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, + "osm_physp_has_pkey: " + "PKey 0x%04x was found\n", cl_ntoh16(pkey)); + } + else + { + osm_log( p_log, OSM_LOG_DEBUG, + "osm_physp_has_pkey: " + "PKey 0x%04x was not found\n", cl_ntoh16(pkey)); + } + + Exit: + OSM_LOG_EXIT( p_log ); + return res; +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey_mgr.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey_mgr.c new file mode 100644 index 00000000..a03f7a4b --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey_mgr.c @@ -0,0 +1,596 @@ +/* + * 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: + * Implementation of the P_Key Manager (Partititon Manager). + * This is part of the OpenSM. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#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 const osm_req_t *p_req, + 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 = osm_physp_get_mod_pkey_tbl( p_physp ); + p_pending = (osm_pending_pkey_t *)malloc( sizeof( osm_pending_pkey_t ) ); + if (!p_pending) + { + osm_log( p_log, OSM_LOG_ERROR, + "pkey_mgr_process_physical_port: 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, + "pkey_mgr_process_physical_port: ERR 0503: " + "Failed to obtain P_Key 0x%04x block and index for node " + "0x%016" PRIx64 " port %u\n", + ib_pkey_get_base( pkey ), + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + osm_physp_get_port_num( p_physp ) ); + return; + } + cl_qlist_insert_head( &p_pkey_tbl->pending, (cl_list_item_t*)p_pending ); + stat = "updated"; + } + + osm_log( p_log, OSM_LOG_DEBUG, + "pkey_mgr_process_physical_port: " + "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, + const osm_req_t *p_req, + 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 && osm_physp_is_valid( p_physp ) ) + pkey_mgr_process_physical_port( p_log, p_req, pkey, p_physp ); + } +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +pkey_mgr_update_pkey_entry( + IN const osm_req_t *p_req, + 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( p_req, osm_physp_get_dr_path_ptr( p_physp ), + ( uint8_t * ) block, sizeof( *block ), + IB_MAD_ATTR_P_KEY_TABLE, + cl_hton32( attr_mod ), CL_DISP_MSGID_NONE, &context ); +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +pkey_mgr_enforce_partition( + IN osm_log_t *p_log, + IN const osm_req_t *p_req, + IN const 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; + + if (!(p_pi = osm_physp_get_port_info_ptr( p_physp ))) + { + osm_log( p_log, OSM_LOG_ERROR, + "pkey_mgr_enforce_partition: ERR 0507: " + "No port info for " + "node 0x%016" PRIx64 " port %u\n", + cl_ntoh64( + osm_node_get_node_guid( + osm_physp_get_node_ptr( p_physp ))), + osm_physp_get_port_num( p_physp ) ); + return FALSE; + } + + if ((p_pi->vl_enforce & 0xc) == (0xc)*(enforce == TRUE)) + { + osm_log( p_log, OSM_LOG_DEBUG, + "pkey_mgr_enforce_partition: " + "No need to update PortInfo for " + "node 0x%016" PRIx64 " port %u\n", + cl_ntoh64( + osm_node_get_node_guid( + osm_physp_get_node_ptr( p_physp ))), + osm_physp_get_port_num( p_physp ) ); + return FALSE; + } + + memset( payload, 0, IB_SMP_DATA_SIZE ); + memcpy( payload, p_pi, sizeof(ib_port_info_t) ); + + p_pi = (ib_port_info_t*)payload; + if (enforce == TRUE) + p_pi->vl_enforce |= 0xc; + else + p_pi->vl_enforce &= ~0xc; + p_pi->state_info2 = 0; + ib_port_info_set_port_state( p_pi, IB_LINK_NO_CHANGE ); + + context.pi_context.node_guid = + osm_node_get_node_guid( osm_physp_get_node_ptr( p_physp ) ); + context.pi_context.port_guid = osm_physp_get_port_guid( p_physp ); + context.pi_context.set_method = TRUE; + context.pi_context.update_master_sm_base_lid = FALSE; + context.pi_context.ignore_errors = FALSE; + context.pi_context.light_sweep = FALSE; + context.pi_context.active_transition = FALSE; + + status = osm_req_set( p_req, 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, + "pkey_mgr_enforce_partition: ERR 0511: " + "Failed to set PortInfo for " + "node 0x%016" PRIx64 " port %u\n", + cl_ntoh64( + osm_node_get_node_guid( + osm_physp_get_node_ptr( p_physp ))), + osm_physp_get_port_num( p_physp ) ); + return FALSE; + } + else + { + osm_log( p_log, OSM_LOG_DEBUG, + "pkey_mgr_enforce_partition: " + "Set PortInfo for " + "node 0x%016" PRIx64 " port %u\n", + cl_ntoh64( + osm_node_get_node_guid( + osm_physp_get_node_ptr( p_physp ))), + osm_physp_get_port_num( p_physp ) ); + return TRUE; + } +} + +/********************************************************************** + **********************************************************************/ +static boolean_t pkey_mgr_update_port( + osm_log_t *p_log, + osm_req_t *p_req, + const osm_port_t * const p_port ) +{ + osm_physp_t *p_physp; + osm_node_t *p_node; + ib_pkey_table_t *block, *new_block; + osm_pkey_tbl_t *p_pkey_tbl; + uint16_t block_index; + uint8_t pkey_index; + uint16_t last_free_block_index = 0; + uint8_t last_free_pkey_index = 0; + uint16_t num_of_blocks; + uint16_t max_num_of_blocks; + ib_api_status_t status; + boolean_t ret_val = FALSE; + osm_pending_pkey_t *p_pending; + boolean_t found; + ib_pkey_table_t empty_block; + + memset(&empty_block, 0, sizeof(ib_pkey_table_t)); + + p_physp = osm_port_get_default_phys_ptr( p_port ); + if ( !osm_physp_is_valid( p_physp ) ) + return FALSE; + + p_node = osm_physp_get_node_ptr( p_physp ); + p_pkey_tbl = osm_physp_get_mod_pkey_tbl( p_physp ); + num_of_blocks = osm_pkey_tbl_get_num_blocks( p_pkey_tbl ); + max_num_of_blocks = pkey_mgr_get_physp_max_blocks( p_req->p_subn, p_physp ); + if ( p_pkey_tbl->max_blocks > max_num_of_blocks ) + { + osm_log( p_log, OSM_LOG_INFO, + "pkey_mgr_update_port: " + "Max number of blocks reduced from %u to %u " + "for node 0x%016" PRIx64 " port %u\n", + p_pkey_tbl->max_blocks, max_num_of_blocks, + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + osm_physp_get_port_num( p_physp ) ); + } + p_pkey_tbl->max_blocks = max_num_of_blocks; + + osm_pkey_tbl_init_new_blocks( p_pkey_tbl ); + p_pkey_tbl->used_blocks = 0; + + /* + process every pending pkey in order - + first must be "updated" last are "new" + */ + p_pending = (osm_pending_pkey_t *)cl_qlist_remove_head( &p_pkey_tbl->pending ); + while ( p_pending != (osm_pending_pkey_t *)cl_qlist_end( &p_pkey_tbl->pending )) + { + if (p_pending->is_new == FALSE) + { + block_index = p_pending->block; + pkey_index = p_pending->index; + found = TRUE; + } + else + { + found = osm_pkey_find_next_free_entry( p_pkey_tbl, + &last_free_block_index, + &last_free_pkey_index ); + if (!found) + { + osm_log( p_log, OSM_LOG_ERROR, + "pkey_mgr_update_port: ERR 0504: " + "Failed to find empty space for new pkey 0x%04x " + "for node 0x%016" PRIx64 " port %u\n", + cl_ntoh16( p_pending->pkey ), + cl_ntoh64( osm_node_get_node_guid( p_node )), + osm_physp_get_port_num( p_physp ) ); + } + else + { + block_index = last_free_block_index; + pkey_index = last_free_pkey_index++; + } + } + + if (found) + { + if (IB_SUCCESS != osm_pkey_tbl_set_new_entry( p_pkey_tbl, block_index, + pkey_index, p_pending->pkey )) + { + osm_log( p_log, OSM_LOG_ERROR, + "pkey_mgr_update_port: ERR 0505: " + "Failed to set PKey 0x%04x in block %u idx %u " + "for node 0x%016" PRIx64 " port %u\n", + p_pending->pkey, block_index, pkey_index, + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + osm_physp_get_port_num( p_physp ) ); + } + } + + free(p_pending); + p_pending = (osm_pending_pkey_t *)cl_qlist_remove_head( &p_pkey_tbl->pending ); + } + + /* now look for changes and store */ + for (block_index = 0; block_index < num_of_blocks; block_index++) + { + block = osm_pkey_tbl_block_get( p_pkey_tbl, block_index ); + new_block = osm_pkey_tbl_new_block_get( p_pkey_tbl, block_index ); + if (!new_block) + new_block = &empty_block; + if (block && !memcmp( new_block, block, sizeof( *block ) )) + continue; + + status = pkey_mgr_update_pkey_entry( p_req, p_physp, new_block, block_index ); + if (status == IB_SUCCESS) + { + osm_log( p_log, OSM_LOG_DEBUG, + "pkey_mgr_update_port: " + "Updated " + "pkey table block %d for node 0x%016" PRIx64 " port %u\n", + block_index, + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + osm_physp_get_port_num( p_physp ) ); + ret_val = TRUE; + } + else + { + osm_log( p_log, OSM_LOG_ERROR, + "pkey_mgr_update_port: ERR 0506: " + "pkey_mgr_update_pkey_entry() failed to update " + "pkey table block %d for node 0x%016" PRIx64 " port %u\n", + block_index, + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + osm_physp_get_port_num( p_physp ) ); + } + } + + return ret_val; +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +pkey_mgr_update_peer_port( + osm_log_t *p_log, + const osm_req_t *p_req, + const osm_subn_t *p_subn, + const osm_port_t * const p_port, + boolean_t enforce ) +{ + osm_physp_t *p_physp, *peer; + osm_node_t *p_node; + ib_pkey_table_t *block, *peer_block; + const osm_pkey_tbl_t *p_pkey_tbl; + osm_pkey_tbl_t *p_peer_pkey_tbl; + uint16_t block_index; + uint16_t num_of_blocks; + uint16_t peer_max_blocks; + ib_api_status_t status = IB_SUCCESS; + boolean_t ret_val = FALSE; + boolean_t port_info_set = FALSE; + ib_pkey_table_t empty_block; + + memset(&empty_block, 0, sizeof(ib_pkey_table_t)); + + p_physp = osm_port_get_default_phys_ptr( p_port ); + if (!osm_physp_is_valid( p_physp )) + return FALSE; + peer = osm_physp_get_remote( p_physp ); + if ( !peer || !osm_physp_is_valid( peer ) ) + return FALSE; + p_node = osm_physp_get_node_ptr( peer ); + if ( !p_node->sw || !p_node->sw->switch_info.enforce_cap ) + return FALSE; + + p_pkey_tbl = osm_physp_get_pkey_tbl( p_physp ); + p_peer_pkey_tbl = osm_physp_get_mod_pkey_tbl( peer ); + 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, + "pkey_mgr_update_peer_port: ERR 0508: " + "Not enough pkey entries (%u < %u) on switch 0x%016" PRIx64 + " port %u. Clearing Enforcement bit\n", + peer_max_blocks, num_of_blocks, + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + osm_physp_get_port_num( peer ) ); + enforce = FALSE; + } + + if ( pkey_mgr_enforce_partition( p_log, p_req, peer, enforce ) ) + port_info_set = TRUE; + + if (enforce == FALSE) + return port_info_set; + + p_peer_pkey_tbl->used_blocks = p_pkey_tbl->used_blocks; + for (block_index = 0; block_index < p_pkey_tbl->used_blocks; block_index++) + { + block = osm_pkey_tbl_new_block_get( p_pkey_tbl, block_index ); + if (!block) + block = &empty_block; + + peer_block = osm_pkey_tbl_block_get( p_peer_pkey_tbl, block_index ); + if ( !peer_block || memcmp( peer_block, block, sizeof( *peer_block ) ) ) + { + status = pkey_mgr_update_pkey_entry( p_req, peer, block, block_index ); + if ( status == IB_SUCCESS ) + ret_val = TRUE; + else + osm_log( p_log, OSM_LOG_ERROR, + "pkey_mgr_update_peer_port: ERR 0509: " + "pkey_mgr_update_pkey_entry() failed to update " + "pkey table block %d for node 0x%016" PRIx64 + " port %u\n", + block_index, + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + osm_physp_get_port_num( peer ) ); + } + } + + if ( (ret_val == TRUE) && osm_log_is_active( p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_log, OSM_LOG_DEBUG, + "pkey_mgr_update_peer_port: " + "Pkey table was updated for node 0x%016" PRIx64 + " port %u\n", + cl_ntoh64( osm_node_get_node_guid( p_node ) ), + osm_physp_get_port_num( peer ) ); + } + + if (port_info_set) + return TRUE; + return ret_val; +} + +/********************************************************************** + **********************************************************************/ +osm_signal_t +osm_pkey_mgr_process( + IN osm_opensm_t *p_osm ) +{ + cl_qmap_t *p_tbl; + cl_map_item_t *p_next; + osm_prtn_t *p_prtn; + osm_port_t *p_port; + osm_signal_t signal = OSM_SIGNAL_DONE; + osm_node_t *p_node; + + CL_ASSERT( p_osm ); + + OSM_LOG_ENTER( &p_osm->log, osm_pkey_mgr_process ); + + 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, + "osm_pkey_mgr_process: ERR 0510: " + "osm_prtn_make_partitions() failed\n" ); + goto _err; + } + + /* populate the pending pkey entries by scanning all partitions */ + p_tbl = &p_osm->subn.prtn_pkey_tbl; + p_next = cl_qmap_head( p_tbl ); + while ( p_next != cl_qmap_end( p_tbl ) ) + { + p_prtn = ( osm_prtn_t * ) p_next; + p_next = cl_qmap_next( p_next ); + pkey_mgr_process_partition_table( &p_osm->log, &p_osm->sm.req, + p_prtn, FALSE ); + pkey_mgr_process_partition_table( &p_osm->log, &p_osm->sm.req, + 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.req, p_port ) ) + signal = OSM_SIGNAL_DONE_PENDING; + p_node = osm_port_get_parent_node( p_port ); + if ( ( osm_node_get_type( p_node ) != IB_NODE_TYPE_SWITCH ) && + pkey_mgr_update_peer_port( &p_osm->log, &p_osm->sm.req, + &p_osm->subn, p_port, + !p_osm->subn.opt.no_partition_enforcement ) ) + signal = OSM_SIGNAL_DONE_PENDING; + } + + _err: + CL_PLOCK_RELEASE( &p_osm->lock ); + OSM_LOG_EXIT( &p_osm->log ); + return ( signal ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey_rcv.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey_rcv.c new file mode 100644 index 00000000..47cbac6e --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey_rcv.c @@ -0,0 +1,220 @@ +/* + * 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$ + */ + + + +#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_pkey_rcv_construct( + IN osm_pkey_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pkey_rcv_destroy( + IN osm_pkey_rcv_t* const p_rcv ) +{ + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_pkey_rcv_destroy ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pkey_rcv_init( + IN osm_pkey_rcv_t* const p_rcv, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_pkey_rcv_init ); + + osm_pkey_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_req = p_req; + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +/* + * WE MIGHT ONLY RECEIVE GET or SET responses + */ +void +osm_pkey_rcv_process( + IN const osm_pkey_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ) +{ + cl_qmap_t *p_guid_tbl; + 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( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_pkey_rcv_process ); + + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + + p_context = osm_madw_get_pkey_context_ptr( p_madw ); + p_pkey_tbl = (ib_pkey_table_t*)ib_smp_get_payload_ptr( p_smp ); + + port_guid = p_context->port_guid; + node_guid = p_context->node_guid; + + CL_ASSERT( p_smp->attr_id == IB_MAD_ATTR_P_KEY_TABLE ); + + p_guid_tbl = &p_rcv->p_subn->port_guid_tbl; + cl_plock_excl_acquire( p_rcv->p_lock ); + p_port = (osm_port_t*)cl_qmap_get( p_guid_tbl, port_guid ); + + if( p_port == (osm_port_t*)cl_qmap_end( p_guid_tbl) ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pkey_rcv_process: 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 = osm_port_get_parent_node( p_port ); + 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 = osm_port_get_default_phys_ptr(p_port); + port_num = p_port->default_port_num; + } + + CL_ASSERT( p_physp ); + + /* + We do not mind if this is a result of a set or get - all we want is to + update the subnet. + */ + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_pkey_rcv_process: " + "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( !osm_physp_is_valid( p_physp ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pkey_rcv_process: ERR 4807: " + "Got invalid port number 0x%X\n", + port_num ); + goto Exit; + } + + osm_dump_pkey_block( p_rcv->p_log, + port_guid, block_num, + port_num, p_pkey_tbl, + OSM_LOG_DEBUG ); + + osm_physp_set_pkey_tbl( p_rcv->p_log, p_rcv->p_subn, + p_physp, p_pkey_tbl, block_num ); + + Exit: + cl_plock_release( p_rcv->p_lock ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey_rcv_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey_rcv_ctrl.c new file mode 100644 index 00000000..ca7fe0ad --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_pkey_rcv_ctrl.c @@ -0,0 +1,116 @@ +/* + * 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$ + */ + + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +static void +__osm_pkey_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_pkey_rcv_process( ((osm_pkey_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pkey_rcv_ctrl_construct( + IN osm_pkey_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_pkey_rcv_ctrl_destroy( + IN osm_pkey_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pkey_rcv_ctrl_init( + IN osm_pkey_rcv_ctrl_t* const p_ctrl, + IN osm_pkey_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_pkey_rcv_ctrl_init ); + + osm_pkey_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + + + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_PKEY, + __osm_pkey_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_pkey_rcv_ctrl_init: ERR 4901: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_port.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_port.c new file mode 100644 index 00000000..9afd2e4c --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_port.c @@ -0,0 +1,936 @@ +/* + * 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: + * Implementation of osm_physp_t. + * This object represents an Infiniband Port. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_physp_construct( + IN osm_physp_t* const p_physp ) +{ + memset( p_physp, 0, sizeof(*p_physp) ); + osm_dr_path_construct( &p_physp->dr_path ); + cl_ptr_vector_construct( &p_physp->slvl_by_port ); + osm_pkey_tbl_construct( &p_physp->pkeys ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_physp_destroy( + IN osm_physp_t* const p_physp ) +{ + size_t num_slvl, i; + + /* the physp might be un-initialized */ + if (p_physp->port_guid) + { + /* free the SL2VL Tables */ + num_slvl = cl_ptr_vector_get_size(&p_physp->slvl_by_port); + for (i = 0; i < num_slvl; i++) + free(cl_ptr_vector_get(&p_physp->slvl_by_port, i)); + cl_ptr_vector_destroy(&p_physp->slvl_by_port); + + /* free the P_Key Tables */ + osm_pkey_tbl_destroy( &p_physp->pkeys ); + + memset( p_physp, 0, sizeof(*p_physp) ); + osm_dr_path_construct( &p_physp->dr_path ); /* clear dr_path */ + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_physp_init( + IN osm_physp_t* const p_physp, + IN const ib_net64_t port_guid, + IN const uint8_t port_num, + IN const struct _osm_node* const p_node, + IN const osm_bind_handle_t h_bind, + IN const uint8_t hop_count, + IN const uint8_t* const p_initial_path ) +{ + uint16_t num_slvl, i; + ib_slvl_table_t *p_slvl; + + CL_ASSERT( p_node ); + + osm_physp_construct( p_physp ); + p_physp->port_guid = port_guid; + p_physp->port_num = port_num; + p_physp->healthy = TRUE; + p_physp->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) + 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_destroy( + IN osm_port_t* const p_port ) +{ + /* cleanup all mcm recs attached */ + osm_port_remove_all_mgrp( p_port ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_port_init( + IN osm_port_t* const p_port, + IN const ib_node_info_t* p_ni, + IN const osm_node_t* const p_parent_node ) +{ + uint32_t port_index; + ib_net64_t port_guid; + osm_physp_t *p_physp; + uint32_t size; + + CL_ASSERT( p_port ); + CL_ASSERT( p_ni ); + CL_ASSERT( p_parent_node ); + + osm_port_construct( p_port ); + + p_port->p_node = (struct _osm_node *)p_parent_node; + port_guid = p_ni->port_guid; + p_port->guid = port_guid; + + /* + See comment in port_new for info about this... + */ + size = p_ni->num_ports; + + p_port->physp_tbl_size = (uint8_t)(size + 1); + + /* + Get the pointers to the physical node objects "owned" by this + logical port GUID. + For switches, all the ports are owned; for HCA's and routers, + only the singular part that has this GUID is owned. + */ + p_port->default_port_num = 0xFF; + for( port_index = 0; port_index < p_port->physp_tbl_size; port_index++ ) + { + p_physp = osm_node_get_physp_ptr( p_parent_node, port_index ); + if( osm_physp_is_valid( p_physp ) && + port_guid == osm_physp_get_port_guid( p_physp ) ) + { + p_port->tbl[port_index] = p_physp; + /* + Because much of the PortInfo data is only valid + for port 0 on switches, try to keep the lowest + possible value of default_port_num. + */ + if( port_index < p_port->default_port_num ) + p_port->default_port_num = (uint8_t)port_index; + } + else + p_port->tbl[port_index] = NULL; + } + + CL_ASSERT( p_port->default_port_num < 0xFF ); +} + +/********************************************************************** + **********************************************************************/ +osm_port_t* +osm_port_new( + IN const ib_node_info_t* p_ni, + IN const osm_node_t* const p_parent_node ) +{ + osm_port_t* p_port; + uint32_t size; + + /* + The port object already contains one physical port object pointer. + 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 pointer than they physically have since + we still reserve room for a "port 0". + */ + size = p_ni->num_ports; + + p_port = malloc( sizeof(*p_port) + sizeof(void *) * size ); + if( p_port != NULL ) + { + memset( p_port, 0, sizeof(*p_port) + sizeof(void *) * size ); + osm_port_init( p_port, p_ni, p_parent_node ); + } + + return( p_port ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_port_get_lid_range_ho( + IN const osm_port_t* const p_port, + IN uint16_t* const p_min_lid, + IN uint16_t* const p_max_lid ) +{ + uint8_t lmc; + + *p_min_lid = cl_ntoh16( osm_port_get_base_lid( p_port ) ); + lmc = osm_port_get_lmc( p_port ); + *p_max_lid = (uint16_t)(*p_min_lid + (1 << lmc) - 1); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_get_port_by_base_lid( + IN const osm_subn_t* const p_subn, + IN const ib_net16_t lid, + IN OUT const osm_port_t** const pp_port ) +{ + ib_api_status_t status; + uint16_t base_lid; + uint8_t lmc; + + *pp_port = NULL; + + /* Loop on lmc from 0 up through max LMC possible */ + for (lmc = 0; lmc <= IB_PORT_LMC_MAX; lmc++) + { + /* Calculate a base LID assuming this is the real LMC */ + base_lid = cl_ntoh16(lid) & ~((1 << lmc) - 1); + + /* Look for a match */ + status = cl_ptr_vector_at( &p_subn->port_lid_tbl, + base_lid, + (void**)pp_port ); + if ((status == CL_SUCCESS) && (*pp_port != NULL)) + { + /* Determine if base LID "tested" is the real base LID */ + /* This is true if the LMC "tested" is the port's actual LMC */ + if (lmc == osm_port_get_lmc( *pp_port ) ) + { + status = IB_SUCCESS; + goto Found; + } + } + } + *pp_port = NULL; + status = IB_NOT_FOUND; + + Found: + return status; +} + +/********************************************************************** + **********************************************************************/ +void +osm_port_add_new_physp( + IN osm_port_t* const p_port, + IN const uint8_t port_num ) +{ + osm_node_t *p_node; + osm_physp_t *p_physp; + + CL_ASSERT( port_num < p_port->physp_tbl_size ); + + p_node = p_port->p_node; + CL_ASSERT( p_node ); + + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + CL_ASSERT( osm_physp_get_port_guid( p_physp ) == p_port->guid ); + p_port->tbl[port_num] = p_physp; + + /* + For switches, we generally want to use Port 0, which is + the management port as the default Physical Port. + The LID value in the PortInfo for example, is only valid + for port 0 on switches. + */ + if( !osm_physp_is_valid( p_port->tbl[p_port->default_port_num] ) ) + { + p_port->default_port_num = port_num; + } + else + { + if( port_num < p_port->default_port_num ) + { + p_port->default_port_num = port_num; + } + } +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_port_add_mgrp( + IN osm_port_t* const p_port, + IN const ib_net16_t mlid ) +{ + ib_api_status_t status = IB_SUCCESS; + osm_mcm_info_t *p_mcm; + + p_mcm = osm_mcm_info_new( mlid ); + if( p_mcm ) + cl_qlist_insert_tail( &p_port->mcm_list, (cl_list_item_t*)p_mcm ); + else + status = IB_INSUFFICIENT_MEMORY; + + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static cl_status_t +__osm_port_mgrp_find_func( + IN const cl_list_item_t* const p_list_item, + IN void* context ) +{ + if( *((ib_net16_t*)context) == ((osm_mcm_info_t*)p_list_item)->mlid ) + return( CL_SUCCESS ); + else + return( CL_NOT_FOUND ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_port_remove_mgrp( + IN osm_port_t* const p_port, + IN const ib_net16_t mlid ) +{ + cl_list_item_t *p_mcm; + + p_mcm = cl_qlist_find_from_head( &p_port->mcm_list, + __osm_port_mgrp_find_func, &mlid ); + + if( p_mcm != cl_qlist_end( &p_port->mcm_list ) ) + { + cl_qlist_remove_item( &p_port->mcm_list, p_mcm ); + osm_mcm_info_delete( (osm_mcm_info_t*)p_mcm ); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_port_remove_all_mgrp( + IN osm_port_t* const p_port ) +{ + cl_list_item_t *p_mcm; + + p_mcm = cl_qlist_remove_head( &p_port->mcm_list ); + while( p_mcm != cl_qlist_end( &p_port->mcm_list ) ) + { + osm_mcm_info_delete( (osm_mcm_info_t*)p_mcm ); + p_mcm = cl_qlist_remove_head( &p_port->mcm_list ); + } +} + +/********************************************************************** + **********************************************************************/ +uint8_t +osm_physp_calc_link_mtu( + IN osm_log_t* p_log, + IN const osm_physp_t* p_physp ) +{ + const ib_port_info_t* p_old_pi; + const ib_port_info_t* p_remote_pi; + const osm_physp_t* p_remote_physp; + uint8_t mtu; + uint8_t remote_mtu; + + OSM_LOG_ENTER( p_log, osm_physp_calc_link_mtu ); + p_old_pi = osm_physp_get_port_info_ptr( p_physp ); + + /* use the available MTU */ + mtu = ib_port_info_get_mtu_cap( p_old_pi ); + + p_remote_physp = osm_physp_get_remote( p_physp ); + if( p_remote_physp && osm_physp_is_valid( p_remote_physp ) ) + { + p_remote_pi = osm_physp_get_port_info_ptr( p_remote_physp ); + remote_mtu = ib_port_info_get_mtu_cap( p_remote_pi ); + + if( osm_log_is_active( p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_log, OSM_LOG_DEBUG, + "osm_physp_calc_link_mtu: " + "Remote port 0x%016" PRIx64 " port# = 0x%X : " + "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; + + if( osm_log_is_active( p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_log, OSM_LOG_VERBOSE, + "osm_physp_calc_link_mtu: " + "MTU 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 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 ); + } + } + } + + if( mtu == 0 ) + { + osm_log( p_log, OSM_LOG_DEBUG, + "osm_physp_calc_link_mtu: 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 ib_port_info_t* p_old_pi; + const ib_port_info_t* p_remote_pi; + const osm_physp_t* p_remote_physp; + uint8_t op_vls; + uint8_t remote_op_vls; + + OSM_LOG_ENTER( p_log, osm_physp_calc_link_op_vls ); + p_old_pi = osm_physp_get_port_info_ptr( p_physp ); + + /* use the available VL CAP */ + op_vls = ib_port_info_get_vl_cap(p_old_pi); + + p_remote_physp = osm_physp_get_remote( p_physp ); + if( p_remote_physp && osm_physp_is_valid( p_remote_physp ) ) + { + p_remote_pi = osm_physp_get_port_info_ptr( p_remote_physp ); + remote_op_vls = ib_port_info_get_vl_cap(p_remote_pi); + + if( osm_log_is_active( p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_log, OSM_LOG_DEBUG, + "osm_physp_calc_link_op_vls: " + "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; + + if( osm_log_is_active( p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_log, OSM_LOG_VERBOSE, + "osm_physp_calc_link_op_vls: " + "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 ); + } + } + } + + /* support user limitation of max_op_vls */ + if (op_vls > p_subn->opt.max_op_vls) + op_vls = p_subn->opt.max_op_vls; + + if( op_vls == 0 ) + { + osm_log( p_log, OSM_LOG_DEBUG, + "osm_physp_calc_link_op_vls: ERR 4102: " + "Invalid OP_VLS = 0. Forcing correction to 1 (VL0)\n" ); + op_vls = 1; + } + + OSM_LOG_EXIT( p_log ); + return(op_vls); +} + +inline +uint64_t +__osm_ptr_to_key(void const *p) +{ + uint64_t k = 0; + + memcpy(&k, p, sizeof(void *)); + return k; +} + +inline +void * +__osm_key_to_ptr(uint64_t k) +{ + void *p = 0; + + memcpy(&p, &k, sizeof(void *)); + return p; +} + +/********************************************************************** + Traverse the fabric from the SM node following the DR path given and + add every phys port traversed to the map. Avoid tracking the first and + last phys ports (going into the first switch and into the target port). + **********************************************************************/ +cl_status_t +__osm_physp_get_dr_physp_set( + IN osm_log_t* p_log, + IN osm_subn_t const *p_subn, + IN osm_dr_path_t const *p_path, + OUT cl_map_t* p_physp_map) +{ + osm_port_t *p_port; + osm_physp_t *p_physp; + osm_node_t *p_node; + uint8_t hop; + cl_status_t status = CL_SUCCESS; + + OSM_LOG_ENTER( p_log, __osm_physp_get_dr_physp_set ); + + /* 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, + "__osm_physp_get_dr_nodes_set: 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 = osm_port_get_parent_node(p_port); + + /* + 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]); + + /* we track the ports we go out along the path */ + if (hop > 1) + cl_map_insert(p_physp_map, __osm_ptr_to_key(p_physp), NULL); + + osm_log( p_log, OSM_LOG_DEBUG, + "__osm_physp_get_dr_nodes_set: " + "Traversed through node: 0x%016" PRIx64 + " port:%u\n", + cl_ntoh64(p_node->node_info.node_guid), + p_path->path[hop]); + + /* make sure we got a valid port and it has a remote port */ + if (!(p_physp && osm_physp_is_valid( p_physp ))) + { + osm_log( p_log, OSM_LOG_ERROR, + "__osm_physp_get_dr_nodes_set: ERR 4104: " + "DR Traversal stopped on invalid port at hop:%u\n", + hop); + status = CL_ERROR; + goto Exit; + } + + if (! (p_physp = osm_physp_get_remote(p_physp))) + { + osm_log( p_log, OSM_LOG_ERROR, + "__osm_physp_get_dr_nodes_set: 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; +} + +/********************************************************************** + **********************************************************************/ +void +__osm_physp_update_new_dr_path( + IN osm_physp_t const *p_dest_physp, + IN cl_map_t *p_visited_map, + IN osm_bind_handle_t *h_bind ) +{ + cl_list_t tmpPortsList; + osm_physp_t *p_physp, *p_src_physp = NULL; + uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX]; + uint8_t i = 0; + osm_dr_path_t *p_dr_path; + + cl_list_construct( &tmpPortsList ); + cl_list_init( &tmpPortsList, 10 ); + + cl_list_insert_head( &tmpPortsList, p_dest_physp ); + /* get the output port where we need to come from */ + p_physp = (osm_physp_t*)cl_map_get( p_visited_map, + __osm_ptr_to_key(p_dest_physp) ); + while ( p_physp != NULL ) + { + cl_list_insert_head( &tmpPortsList, p_physp ); + /* get the input port through where we reached the output port */ + p_src_physp = p_physp; + p_physp = (osm_physp_t*)cl_map_get( p_visited_map, + __osm_ptr_to_key(p_physp) ); + /* if we reached a null p_physp - this means we are at the begining + of the path. Break. */ + if ( p_physp == NULL ) + break; + /* get the output port */ + p_physp = (osm_physp_t*)cl_map_get( p_visited_map, + __osm_ptr_to_key(p_physp) ); + } + + memset( path_array, 0, sizeof(path_array) ); + p_physp = (osm_physp_t*)cl_list_remove_head( &tmpPortsList ); + while ( p_physp != NULL ) + { + i++; + path_array[i] = p_physp->port_num; + p_physp = (osm_physp_t*)cl_list_remove_head( &tmpPortsList ); + } + if (p_src_physp) + { + p_dr_path = osm_physp_get_dr_path_ptr( p_src_physp ); + osm_dr_path_init( p_dr_path, h_bind, i, path_array ); + } + + cl_list_destroy( &tmpPortsList ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_physp_replace_dr_path_with_alternate_dr_path( + IN osm_log_t *p_log, + IN osm_subn_t const *p_subn, + IN osm_physp_t const *p_dest_physp, + IN osm_bind_handle_t *h_bind + ) +{ + cl_map_t physp_map; + cl_map_t visited_map; + osm_dr_path_t * p_dr_path; + cl_list_t *p_currPortsList; + cl_list_t *p_nextPortsList; + cl_qmap_t const *p_port_tbl; + 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; + + /* + initialize the map of all port participating in current dr path + not including first and last switches + */ + cl_map_construct( &physp_map ); + cl_map_init( &physp_map, 4 ); + cl_map_construct( &visited_map ); + cl_map_init( &visited_map, 4 ); + p_dr_path = osm_physp_get_dr_path_ptr( p_dest_physp ); + __osm_physp_get_dr_physp_set(p_log, p_subn, p_dr_path, &physp_map); + + /* + BFS from OSM port until we find the target physp but avoid + going through mapped ports + */ + p_nextPortsList = (cl_list_t*)malloc(sizeof(cl_list_t)); + cl_list_construct( p_nextPortsList ); + cl_list_init( p_nextPortsList, 10 ); + + p_port_tbl = &p_subn->port_guid_tbl; + port_guid = p_subn->sm_port_guid; + + CL_ASSERT( port_guid ); + + p_port = (osm_port_t*)cl_qmap_get( p_port_tbl, port_guid ); + + if( p_port == (osm_port_t*)cl_qmap_end( p_port_tbl ) ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_physp_replace_dr_path_with_alternate_dr_path: 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 = osm_port_get_default_phys_ptr( p_port ); + + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( 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)); + 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. The port is a valid port + 3. This is not the port we came from + 4. The port is not in the physp_map + 5. This port haven't been visited before + */ + if ( p_remote_physp && + osm_physp_is_valid ( p_remote_physp ) && + p_remote_physp != p_physp && + cl_map_get( &physp_map, __osm_ptr_to_key(p_remote_physp)) == NULL && + cl_map_get( &visited_map, __osm_ptr_to_key(p_remote_physp)) == NULL ) + { + /* Insert the port into the visited_map, and save its source port */ + cl_map_insert( &visited_map, __osm_ptr_to_key(p_remote_physp), p_physp ); + + /* Is this the p_dest_physp? */ + if ( p_remote_physp == p_dest_physp ) + { + /* update the new dr path */ + __osm_physp_update_new_dr_path( p_dest_physp, &visited_map, h_bind ); + reached_dest = TRUE; + break; + } + + /* add the p_remote_physp to the nextPortsList */ + cl_list_insert_tail( p_nextPortsList, p_remote_physp ); + next_list_is_full = TRUE; + } + } + + p_physp = (osm_physp_t*)cl_list_remove_head( p_currPortsList ); + if ( reached_dest == TRUE ) + { + /* free the rest of the currPortsList */ + while ( p_physp != NULL ) + p_physp = (osm_physp_t*)cl_list_remove_head( p_currPortsList ); + /* free the nextPortsList, if items were added to it */ + p_physp = (osm_physp_t*)cl_list_remove_head( p_nextPortsList ); + while ( p_physp != NULL ) + p_physp = (osm_physp_t*)cl_list_remove_head( p_nextPortsList ); + next_list_is_full = FALSE; + } + } + cl_list_destroy( p_currPortsList ); + free(p_currPortsList); + } + + /* cleanup */ + Exit: + cl_list_destroy( p_nextPortsList ); + free( p_nextPortsList ); + cl_map_destroy( &physp_map ); + cl_map_destroy( &visited_map ); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_link_is_healthy( + IN const osm_physp_t* const p_physp ) +{ + osm_physp_t* p_remote_physp; + CL_ASSERT( p_physp ); + p_remote_physp = p_physp->p_remote_physp; + if (p_remote_physp != NULL && osm_physp_is_valid(p_remote_physp) ) + return( (p_physp->healthy)&(p_remote_physp->healthy) ); + /* the other side is not known - consider the link as healthy */ + return(TRUE); +} + +/********************************************************************** + **********************************************************************/ +void +osm_physp_set_pkey_tbl( + IN osm_log_t* p_log, + IN const osm_subn_t* p_subn, + IN osm_physp_t* const p_physp, + IN ib_pkey_table_t *p_pkey_tbl, + IN uint16_t block_num ) +{ + uint16_t max_blocks; + + CL_ASSERT( p_pkey_tbl ); + 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. + */ + if (!p_physp->p_node->sw || p_physp->port_num == 0 ) + { + /* + The maximum blocks is defined in the node info: partition cap for CA, + routers 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, + "osm_physp_set_pkey_tbl: ERR 4108: " + "Got illegal set for block number:%u " + "For GUID: %" PRIx64 " port number:0x%X\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-1/ulp/opensm/user/opensm/osm_port_info_rcv.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_port_info_rcv.c new file mode 100644 index 00000000..0b4c3462 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_port_info_rcv.c @@ -0,0 +1,870 @@ +/* + * 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: + * Implementation of osm_pi_rcv_t. + * This object represents the PortInfo Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.8 $ + */ + +#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 +__osm_pi_rcv_set_sm( + IN const osm_pi_rcv_t* const p_rcv, + IN osm_physp_t* const p_physp ) +{ + osm_bind_handle_t h_bind; + osm_dr_path_t *p_dr_path; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_set_sm ); + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pi_rcv_set_sm: " + "Setting 'IS_SM' bit in port attributes\n" ); + } + + p_dr_path = osm_physp_get_dr_path_ptr( p_physp ); + h_bind = osm_dr_path_get_bind_handle( p_dr_path ); + /* + The 'IS_SM' bit isn't already set, so set it. + */ + osm_vendor_set_sm( h_bind, TRUE ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pi_rcv_process_endport( + IN const osm_pi_rcv_t* const p_rcv, + IN osm_physp_t* const p_physp, + IN const ib_port_info_t* const p_pi ) +{ + osm_madw_context_t context; + ib_api_status_t status; + ib_net64_t port_guid; + uint8_t rate, mtu; + cl_qmap_t* p_sm_tbl; + osm_remote_sm_t* p_sm; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_process_endport ); + + 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 < p_rcv->p_subn->min_ca_mtu) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_pi_rcv_process_endport: " + "Setting endport minimal MTU to:%u defined by port:0x%" + PRIx64 "\n", + mtu, + cl_ntoh64( port_guid ) ); + p_rcv->p_subn->min_ca_mtu = mtu; + } + + rate = ib_port_info_compute_rate( p_pi ); + if (rate < p_rcv->p_subn->min_ca_rate) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_pi_rcv_process_endport: " + "Setting endport minimal rate to:%u defined by port:0x%" + PRIx64 "\n", + rate, + cl_ntoh64( port_guid ) ); + p_rcv->p_subn->min_ca_rate = rate; + } + } + + if( port_guid == p_rcv->p_subn->sm_port_guid ) + { + /* + We received the PortInfo for our own port. + */ + if( !(p_pi->capability_mask & IB_PORT_CAP_IS_SM ) ) + { + /* + Set the IS_SM bit to indicate our port hosts an SM. + */ + __osm_pi_rcv_set_sm( p_rcv, p_physp ); + } + } + else + { + /* + 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_tbl = &p_rcv->p_subn->sm_guid_tbl; + 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( p_pi->capability_mask & IB_PORT_CAP_IS_SM ) + { + if( p_rcv->p_subn->opt.ignore_other_sm ) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_pi_rcv_process_endport: " + "Ignoring SM on port 0x%" PRIx64 "\n", + cl_ntoh64( port_guid ) ); + } + else + { + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_pi_rcv_process_endport: " + "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; + status = osm_req_get( p_rcv->p_req, + 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( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pi_rcv_process_endport: ERR 0F05: " + "Failure requesting SMInfo (%s)\n", + ib_get_err_str( status ) ); + } + } + } + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_pi_rcv_process_switch_port( + IN const osm_pi_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN osm_physp_t* const p_physp, + IN const ib_port_info_t* const p_pi ) +{ + ib_api_status_t status = IB_SUCCESS; + osm_madw_context_t context; + osm_physp_t *p_remote_physp; + osm_node_t *p_remote_node; + ib_net16_t orig_lid; + uint8_t port_num; + uint8_t remote_port_num; + osm_dr_path_t path; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_process_switch_port ); + + /* + 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 in on the switch, + and we got switchInfo of our local switch. Do not continue + probing through the switch. */ + if( port_num != 0 && p_rcv->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 && osm_physp_is_valid( 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( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_pi_rcv_process_switch_port: " + "Unlinking local node 0x%" PRIx64 ", port 0x%X" + "\n\t\t\t\tand remote node 0x%" PRIx64 + ", port 0x%X\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 ); + + osm_node_unlink( p_node, (uint8_t)port_num, + p_remote_node, (uint8_t)remote_port_num ); + + } + break; + + case IB_LINK_INIT: + case IB_LINK_ARMED: + case IB_LINK_ACTIVE: + /* + To avoid looping forever, only probe the port if it + is NOT the port that responded to the SMP. + + Request node info from the other end of this link: + 1) Copy the current path from the parent node. + 2) Extend the path to the next hop thru this port. + 3) Request node info with the new path + + */ + if( p_pi->local_port_num != osm_physp_get_port_num( p_physp ) ) + { + path = *osm_physp_get_dr_path_ptr( p_physp ); + + osm_dr_path_extend( &path, osm_physp_get_port_num( p_physp ) ); + + 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( p_rcv->p_req, + &path, + IB_MAD_ATTR_NODE_INFO, + 0, + CL_DISP_MSGID_NONE, + &context ); + + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pi_rcv_process_switch_port: ERR 0F02: " + "Failure initiating NodeInfo request (%s)\n", + ib_get_err_str(status) ); + } + } + else + { + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_pi_rcv_process_switch_port: " + "Skipping SMP responder port 0x%X\n", + p_pi->local_port_num ); + } + } + break; + + default: + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pi_rcv_process_switch_port: ERR 0F03: " + "Unknown link state = %u, port = 0x%X\n", + ib_port_info_get_port_state( p_pi ), + p_pi->local_port_num ); + break; + } + } + + /* + Update the PortInfo attribute. + */ + osm_physp_set_port_info( p_physp, p_pi ); + + if (port_num == 0) + { + /* This is switch management port 0 */ + if ( ( orig_lid = osm_physp_trim_base_lid_to_valid_range( p_physp ) ) ) + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pi_rcv_process_switch_port: ERR 0F04: " + "Invalid base LID 0x%x corrected\n", + cl_ntoh16( orig_lid ) ); + /* Determine if base switch port 0 */ + if (p_node->sw && + !ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info)) + { + /* PortState is not used on BSP0 but just in case it is DOWN */ + p_physp->port_info = *p_pi; + } + __osm_pi_rcv_process_endport(p_rcv, p_physp, p_pi); + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pi_rcv_process_ca_port( + IN const osm_pi_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN osm_physp_t* const p_physp, + IN const ib_port_info_t* const p_pi ) +{ + ib_net16_t orig_lid; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_process_ca_port ); + + UNUSED_PARAM( p_node ); + + osm_physp_set_port_info( p_physp, p_pi ); + + if ( (orig_lid = osm_physp_trim_base_lid_to_valid_range( p_physp ) ) ) + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pi_rcv_process_ca_port: ERR 0F08: " + "Invalid base LID 0x%x corrected\n", + cl_ntoh16 ( orig_lid ) ); + + __osm_pi_rcv_process_endport(p_rcv, p_physp, p_pi); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pi_rcv_process_router_port( + IN const osm_pi_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN osm_physp_t* const p_physp, + IN const ib_port_info_t* const p_pi ) +{ + ib_net16_t orig_lid; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_process_router_port ); + + UNUSED_PARAM( p_node ); + + /* + Update the PortInfo attribute. + */ + osm_physp_set_port_info( p_physp, p_pi ); + + if ( (orig_lid = osm_physp_trim_base_lid_to_valid_range( p_physp ) ) ) + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_pi_rcv_process_router_port: ERR 0F09: " + "Invalid base LID 0x%x corrected\n", + cl_ntoh16 ( orig_lid) ); + + __osm_pi_rcv_process_endport(p_rcv, p_physp, p_pi); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +#define IBM_VENDOR_ID (0x5076) +/********************************************************************** + **********************************************************************/ +void osm_pkey_get_tables( + IN osm_log_t *p_log, + IN osm_req_t *p_req, + IN osm_subn_t* const p_subn, + IN osm_node_t* const p_node, + IN osm_physp_t* const p_physp ) { + + osm_madw_context_t context; + ib_api_status_t status; + osm_dr_path_t path; + uint8_t port_num; + uint16_t block_num, max_blocks; + uint32_t attr_mod_ho; + + OSM_LOG_ENTER( p_log, osm_pkey_get_tables ); + + 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( p_req, + &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, + "osm_physp_has_pkey: ERR 0F12: " + "Failure initiating PKeyTable request (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + } + + Exit: + OSM_LOG_EXIT( p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pi_rcv_get_pkey_slvl_vla_tables( + IN const osm_pi_rcv_t* const p_rcv, + IN osm_node_t* const p_node, + IN osm_physp_t* const p_physp ) +{ + OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_get_pkey_slvl_vla_tables ); + + osm_pkey_get_tables( p_rcv->p_log, p_rcv->p_req, p_rcv->p_subn, + p_node, p_physp ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pi_rcv_construct( + IN osm_pi_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pi_rcv_destroy( + IN osm_pi_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_pi_rcv_destroy ); + + CL_ASSERT( p_rcv ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pi_rcv_init( + IN osm_pi_rcv_t* const p_rcv, + IN osm_req_t* const p_req, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_state_mgr_t* const p_state_mgr, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + OSM_LOG_ENTER( p_log, osm_pi_rcv_init ); + + osm_pi_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_req = p_req; + p_rcv->p_state_mgr = p_state_mgr; + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pi_rcv_process_set( + IN const osm_pi_rcv_t* const p_rcv, + IN osm_port_t* const p_port, + IN const uint8_t port_num, + IN osm_madw_t* const p_madw ) +{ + osm_physp_t *p_physp; + osm_node_t *p_node; + 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( p_rcv->p_log, osm_pi_rcv_process_set ); + + p_context = osm_madw_get_pi_context_ptr( p_madw ); + + p_physp = osm_port_get_phys_ptr( p_port, port_num ); + CL_ASSERT( p_physp ); + CL_ASSERT( osm_physp_is_valid( p_physp ) ); + + port_guid = osm_physp_get_port_guid( p_physp ); + p_node = osm_port_get_parent_node( p_port ); + CL_ASSERT( p_node ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_pi = (ib_port_info_t*)ib_smp_get_payload_ptr( p_smp ); + + /* check for error */ + if (!p_context->ignore_errors && (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( p_rcv->p_log, OSM_LOG_INFO, + "osm_pi_rcv_process_set: " + "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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pi_rcv_process_set: ERR 0F10: " + "Received error status for SetResp()\n"); + } + osm_dump_port_info( + p_rcv->p_log, + osm_node_get_node_guid( p_node ), + port_guid, + port_num, + p_pi, + level); + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_pi_rcv_process_set: " + "Received logical SetResp() for GUID 0x%" PRIx64 + ", port num 0x%X" + "\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 ); + + /* We got a PortInfoSetResp - set the got_set_resp flag to TRUE */ + p_physp->got_set_resp = TRUE; + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pi_rcv_process( + IN const osm_pi_rcv_t* const p_rcv, + IN osm_madw_t* const p_madw ) +{ + cl_qmap_t *p_guid_tbl; + ib_port_info_t *p_pi; + ib_smp_t *p_smp; + osm_port_t *p_port; + osm_physp_t *p_physp; + osm_dr_path_t *p_dr_path; + osm_node_t *p_node; + osm_pi_context_t *p_context; + ib_net64_t port_guid; + ib_net64_t node_guid; + uint8_t port_num; + + OSM_LOG_ENTER( p_rcv->p_log, osm_pi_rcv_process ); + + CL_ASSERT( p_rcv ); + CL_ASSERT( p_madw ); + + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_context = osm_madw_get_pi_context_ptr( p_madw ); + p_pi = (ib_port_info_t*)ib_smp_get_payload_ptr( p_smp ); + + CL_ASSERT( p_smp->attr_id == IB_MAD_ATTR_PORT_INFO ); + + /* 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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_pi_rcv_process: " + "Client reregister received on response\n"); + ib_port_info_set_client_rereg( p_pi, 0 ); + } + + 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( p_rcv->p_log, + node_guid, port_guid, port_num, p_pi, + OSM_LOG_DEBUG ); + + /* + 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( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_pi_rcv_process: " + "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 ) ); + osm_state_mgr_process( p_rcv->p_state_mgr, + OSM_SIGNAL_CHANGE_DETECTED ); + goto Exit; + } + + p_guid_tbl = &p_rcv->p_subn->port_guid_tbl; + CL_PLOCK_EXCL_ACQUIRE( p_rcv->p_lock ); + p_port = (osm_port_t*)cl_qmap_get( p_guid_tbl, port_guid ); + + if( p_port == (osm_port_t*)cl_qmap_end( p_guid_tbl) ) + { + CL_PLOCK_RELEASE( p_rcv->p_lock ); + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pi_rcv_process: 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; + } + + /* + If we were setting the PortInfo, then receiving + this attribute was not part of sweeping the subnet. + In this case, just update the PortInfo attribute. + + In an unfortunate blunder, the IB spec defines the + return method for Set() as a GetResp(). Thus, we can't + use the method (what would have been SetResp()) to determine + our course of action. So, we have to carry this extra + boolean around to determine if we were doing Get() or Set(). + */ + if( p_context->set_method ) + { + osm_pi_rcv_process_set( p_rcv, p_port, port_num, p_madw ); + } + else + { + osm_port_discovery_count_inc( p_port ); + + /* + This PortInfo arrived because we did a Get() method, + most likely due to a subnet sweep in progress. + */ + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_pi_rcv_process: " + "Discovered port num 0x%X 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_node = osm_port_get_parent_node( p_port ); + p_physp = osm_node_get_physp_ptr( p_node, port_num ); + + CL_ASSERT( p_node ); + CL_ASSERT( p_physp ); + + /* + Determine if we encountered a new Physical Port. + If so, initialize the new Physical Port then + continue processing as normal. + */ + if( !osm_physp_is_valid( p_physp ) ) + { + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_pi_rcv_process: " + "Initializing port number 0x%X\n", + port_num ); + } + + osm_physp_init( p_physp, + port_guid, + port_num, + p_node, + osm_madw_get_bind_handle( p_madw ), + p_smp->hop_count, + p_smp->initial_path ); + + osm_port_add_new_physp( p_port, port_num ); + } + else + { + /* + Update the directed route path to this port + in case the old path is no longer usable. + */ + p_dr_path = osm_physp_get_dr_path_ptr( p_physp ); + osm_dr_path_init( p_dr_path, + osm_madw_get_bind_handle( p_madw ), + p_smp->hop_count, p_smp->initial_path ); + } + + /* + Check if the update_sm_base_lid in the context is TRUE. + If it is - then update the master_sm_base_lid of the variable + in the subnet. + */ + if (p_context->update_master_sm_base_lid == TRUE) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_pi_rcv_process: " + "update_master_sm is TRUE. " + "Updating master_sm_base_lid to:%u\n", + p_pi->master_sm_base_lid ); + + p_rcv->p_subn->master_sm_base_lid = p_pi->master_sm_base_lid; + } + + switch( osm_node_get_type( p_node ) ) + { + case IB_NODE_TYPE_CA: + __osm_pi_rcv_process_ca_port( p_rcv, + p_node, p_physp, p_pi ); + break; + case IB_NODE_TYPE_ROUTER: + __osm_pi_rcv_process_router_port( p_rcv, + p_node, p_physp, p_pi ); + break; + case IB_NODE_TYPE_SWITCH: + __osm_pi_rcv_process_switch_port( p_rcv, + p_node, p_physp, p_pi ); + break; + default: + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_pi_rcv_process: 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. + */ + __osm_pi_rcv_get_pkey_slvl_vla_tables( p_rcv, p_node, p_physp ); + + } + + CL_PLOCK_RELEASE( p_rcv->p_lock ); + + Exit: + /* + Release the lock before jumping here!! + */ + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_port_info_rcv_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_port_info_rcv_ctrl.c new file mode 100644 index 00000000..ff6a8a1c --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_port_info_rcv_ctrl.c @@ -0,0 +1,128 @@ +/* + * 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: + * Implementation of osm_pi_rcv_ctrl_t. + * This object represents the PortInfo request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_pi_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_pi_rcv_process( ((osm_pi_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pi_rcv_ctrl_construct( + IN osm_pi_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_pi_rcv_ctrl_destroy( + IN osm_pi_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pi_rcv_ctrl_init( + IN osm_pi_rcv_ctrl_t* const p_ctrl, + IN osm_pi_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_pi_rcv_ctrl_init ); + + osm_pi_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_PORT_INFO, + __osm_pi_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_pi_rcv_ctrl_init: ERR 1001: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_prtn.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_prtn.c new file mode 100644 index 00000000..4440553d --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_prtn.c @@ -0,0 +1,399 @@ +/* + * 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: + * Implementation of osm_prtn_t. + * This object represents an IBA partition. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision$ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int osm_prtn_config_parse_file(osm_log_t * const p_log, + osm_subn_t * const p_subn, + const char *file_name); + +static uint16_t global_pkey_counter; + +osm_prtn_t* osm_prtn_new( + IN const char *name, + IN const uint16_t pkey ) +{ + osm_prtn_t *p = malloc(sizeof(*p)); + if (!p) + return NULL; + + memset(p, 0, sizeof(*p)); + p->pkey = pkey; + p->sl = OSM_DEFAULT_SL; + cl_map_construct(&p->full_guid_tbl); + cl_map_init(&p->full_guid_tbl, 32); + cl_map_construct(&p->part_guid_tbl); + cl_map_init(&p->part_guid_tbl, 32); + + if (name && *name) + strncpy(p->name, name, sizeof(p->name)); + else + snprintf(p->name, sizeof(p->name), "%04x", cl_ntoh16(pkey)); + + return p; +} + +void osm_prtn_delete( + IN OUT osm_prtn_t** const pp_prtn ) +{ + osm_prtn_t *p = *pp_prtn; + + cl_map_remove_all(&p->full_guid_tbl); + cl_map_destroy(&p->full_guid_tbl); + cl_map_remove_all(&p->part_guid_tbl); + cl_map_destroy(&p->part_guid_tbl); + free(p); + *pp_prtn = NULL; +} + +ib_api_status_t osm_prtn_add_port(osm_log_t *p_log, osm_subn_t *p_subn, + osm_prtn_t *p, ib_net64_t guid, boolean_t full) +{ + cl_qmap_t *p_port_tbl = &p_subn->port_guid_tbl; + 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_port_t *)cl_qmap_get(p_port_tbl, guid); + if (!p_port || p_port == (osm_port_t *)cl_qmap_end(p_port_tbl)) { + osm_log(p_log, OSM_LOG_VERBOSE, "osm_prtn_add_port: " + "port 0x%" PRIx64 " not found\n", + cl_ntoh64(guid)); + return status; + } + + p_physp = osm_port_get_default_phys_ptr(p_port); + if (!p_physp) { + osm_log(p_log, OSM_LOG_VERBOSE, "osm_prtn_add_port: " + "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, "osm_prtn_add_port: " + "port 0x%" PRIx64 " already in " + "partition \'%s\' (0x%04x). Will overwrite\n", + cl_ntoh64(guid), p->name, cl_ntoh16(p->pkey)); + } + + p_tbl = (full == TRUE) ? &p->full_guid_tbl : &p->part_guid_tbl ; + + if (cl_map_insert(p_tbl, guid, p_physp) == NULL) + return IB_INSUFFICIENT_MEMORY; + + return status; +} + +ib_api_status_t osm_prtn_add_all(osm_log_t *p_log, osm_subn_t *p_subn, + osm_prtn_t *p, boolean_t full) +{ + cl_qmap_t *p_port_tbl = &p_subn->port_guid_tbl; + cl_map_item_t *p_item; + osm_port_t *p_port; + ib_api_status_t status = IB_SUCCESS; + + p_item = cl_qmap_head(p_port_tbl); + while (p_item != cl_qmap_end(p_port_tbl)) { + p_port = (osm_port_t *)p_item; + p_item = cl_qmap_next(p_item); + status = osm_prtn_add_port(p_log, p_subn, p, + osm_port_get_guid(p_port), full); + if (status != IB_SUCCESS) + goto _err; + } + + _err: + return status; +} + +static const ib_gid_t osm_ipoib_mgid = { + { + 0xff, /* multicast field */ + 0x12, /* non-permanent bit, link local scope */ + 0x40, 0x1b, /* IPv4 signature */ + 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ + 0xff, 0xff, 0xff, 0xff, /* 32 bit IPv4 broadcast address */ + }, +}; + +/* + * HACK: Until TS resolves their noncompliant join compmask, + * we have to pre-define the MGID + */ +static const ib_gid_t osm_ts_ipoib_mgid = { + { + 0xff, /* multicast field */ + 0x12, /* non-permanent bit, link local scope */ + 0x40, 0x1b, /* IPv4 signature */ + 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ + 0x00, 0x00, 0x00, 0x01, /* 32 bit IPv4 broadcast address */ + }, +}; + +ib_api_status_t osm_prtn_add_mcgroup(osm_log_t *p_log, + osm_subn_t *p_subn, osm_prtn_t *p, + unsigned is_ipoib, 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 ts_scope; + + pkey = p->pkey | cl_hton16(0x8000); + + 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 = OSM_DEFAULT_SUBNET_TIMEOUT; + mc_rec.sl_flow_hop = ib_member_set_sl_flow_hop(p->sl, 0, 0); + /* Scope in MCMemberRecord needs to be consistent with MGID */ + mc_rec.scope_state = ib_member_set_scope_state(scope ? scope : OSM_DEFAULT_MGRP_SCOPE, MC_FULL_MEMBER); + ib_mgid_set_scope(&mc_rec.mgid, scope ? scope : OSM_DEFAULT_MGRP_SCOPE); + + /* don't update rate, mtu, scope */ + comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL + | IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL + | IB_MCR_COMPMASK_SCOPE; + status = osm_mcmr_rcv_find_or_create_new_mgrp(&p_sa->mcmr_rcv, + comp_mask, &mc_rec, &p_mgrp); + if (!p_mgrp || status != IB_SUCCESS) + osm_log( p_log, OSM_LOG_ERROR, + "osm_prtn_add_mcgroup: " + "Failed to create MC group with pkey 0x%04x\n", + cl_ntoh16(pkey)); + if (p_mgrp) + p_mgrp->well_known = TRUE; + + /* 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 needs to be consistent with MGID */ + ts_scope = ib_mgid_get_scope(&osm_ts_ipoib_mgid); /* get scope from MGID */ + mc_rec.scope_state = ib_member_set_scope_state(ts_scope, MC_FULL_MEMBER); + status = osm_mcmr_rcv_find_or_create_new_mgrp(&p_sa->mcmr_rcv, + comp_mask, &mc_rec, &p_mgrp); + if (p_mgrp) + p_mgrp->well_known = TRUE; + + 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; +} + +static osm_prtn_t *find_prtn_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 = find_prtn_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, + "osm_prtn_make_new: 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, + "osm_prtn_make_new: Duplicated partition" + " definition: \'%s\' (0x%04x) prev name \'%s\'" + ". Will use it\n", + name, cl_ntoh16(pkey), p_check->name); + osm_prtn_delete(&p); + p = p_check; + } + + return p; +} + +static ib_api_status_t osm_prtn_make_default(osm_log_t * const p_log, + osm_subn_t * const p_subn, + boolean_t no_config) +{ + ib_api_status_t status = IB_UNKNOWN_ERROR; + osm_prtn_t *p; + + p = osm_prtn_make_new(p_log, p_subn, "Default", IB_DEFAULT_PARTIAL_PKEY); + if (!p) + goto _err; + status = osm_prtn_add_all(p_log, p_subn, p, no_config); + if (status != IB_SUCCESS) + goto _err; + cl_map_remove(&p->part_guid_tbl, p_subn->sm_port_guid); + status = osm_prtn_add_port(p_log, p_subn, p, p_subn->sm_port_guid, TRUE); + + if (no_config) + osm_prtn_add_mcgroup(p_log, p_subn, p, 1, 0, 0, 0); + + _err: + return status; +} + +ib_api_status_t osm_prtn_make_partitions(osm_log_t * const p_log, + osm_subn_t * const p_subn) +{ + struct stat statbuf; + const char *file_name; + boolean_t is_config = TRUE; + ib_api_status_t status = IB_SUCCESS; + cl_map_item_t *p_next; + osm_prtn_t *p; + + file_name = p_subn->opt.partition_config_file ? + p_subn->opt.partition_config_file : + "/etc/osm-partitions.conf"; + if (stat(file_name, &statbuf)) + is_config = FALSE; + + /* clean up current port maps */ + p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl); + while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) { + p = (osm_prtn_t *)p_next; + p_next = cl_qmap_next(&p->map_item); + cl_map_remove_all(&p->part_guid_tbl); + cl_map_remove_all(&p->full_guid_tbl); + } + + global_pkey_counter = 0; + + status = osm_prtn_make_default(p_log, p_subn, !is_config); + if (status != IB_SUCCESS) + goto _err; + + if (is_config && osm_prtn_config_parse_file(p_log, p_subn, file_name)) { + osm_log(p_log, OSM_LOG_VERBOSE, + "osm_prtn_make_partitions: 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-1/ulp/opensm/user/opensm/osm_prtn_config.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_prtn_config.c new file mode 100644 index 00000000..3d4411b2 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_prtn_config.c @@ -0,0 +1,447 @@ +/* + * 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: + * Implementation of opensm partition management configuration + * + * Environment: + * Linux User Mode + * + * $Revision$ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if __WORDSIZE == 64 +#define STRTO_IB_NET64(str, end, base) strtoul(str, end, base) +#else +#define STRTO_IB_NET64(str, end, base) strtoull(str, end, base) +#endif + +/* + */ +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; +}; + +extern osm_prtn_t *osm_prtn_make_new(osm_log_t *p_log, osm_subn_t *p_subn, + const char *name, uint16_t pkey); +extern ib_api_status_t osm_prtn_add_all(osm_log_t *p_log, + osm_subn_t *p_subn, + osm_prtn_t *p, boolean_t full); +extern ib_api_status_t osm_prtn_add_port(osm_log_t *p_log, + osm_subn_t *p_subn, osm_prtn_t *p, + ib_net64_t guid, boolean_t full); +extern ib_api_status_t osm_prtn_add_mcgroup(osm_log_t *p_log, + osm_subn_t *p_subn, osm_prtn_t *p, + unsigned is_ipoib, 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; + + 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.no_qos) { + if (conf->sl != OSM_DEFAULT_SL) { + osm_log(conf->p_log, OSM_LOG_ERROR, + "partition_create: Overriding SL %d to default SL %d on partition %s as QoS 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) + osm_prtn_add_mcgroup(conf->p_log, conf->p_subn, conf->p_prtn, + conf->is_ipoib, (uint8_t)conf->rate, + (uint8_t)conf->mtu, (uint8_t)conf->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)) { + if (!val || (conf->scope = strtoul(val, NULL, 0)) == 0) + osm_log(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "flag \'scope\' requires valid value" + " - skipped\n", lineno); + } else if (!strncmp(flag, "sl", len)) { + unsigned sl; + char *end; + + if (!val || !*val || (sl = strtoul(val, &end, 0)) > 15 || + (*end && !isspace(*end))) + osm_log(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "flag \'sl\' requires valid value" + " - skipped\n", lineno); + else + conf->sl = sl; + } else { + 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 = FALSE; + + if (!name || !*name || !strncmp(name, "NONE", strlen(name))) + return 0; + + if (flag) { + if (!strncmp(flag, "full", strlen(flag))) + full = TRUE; + else if (strncmp(flag, "limited", strlen(flag))) { + osm_log(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "unrecognized port flag \'%s\'." + " Assume \'limited\'\n", lineno, flag); + } + } + + if (!strncmp(name, "ALL", strlen(name))) { + return osm_prtn_add_all(conf->p_log, conf->p_subn, p, + full) == IB_SUCCESS ? 0 : -1; + } else if (!strncmp(name, "SELF", strlen(name))) { + guid = cl_ntoh64(conf->p_subn->sm_port_guid); + } else { + char *end; + guid = STRTO_IB_NET64(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; + 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, + "osm_prtn_config_parse_file: " + "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-1/ulp/opensm/user/opensm/osm_qos.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_qos.c new file mode 100644 index 00000000..fe3b9534 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_qos.c @@ -0,0 +1,451 @@ +/* + * 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: + * Implementation of OpenSM QoS infrastructure primitives + * + * Environment: + * Linux User Mode + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#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_req_t * p_req, + osm_physp_t * p, + uint8_t port_num, + 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; + ib_port_info_t *p_pi; + unsigned vl_mask, i; + + if (!(p_pi = osm_physp_get_port_info_ptr(p))) + return IB_ERROR; + + vl_mask = (1 << (ib_port_info_get_op_vls(p_pi) - 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 (!memcmp(&p->vl_arb[block_num], &block, + block_length * sizeof(block.vl_entry[0]))) + return IB_SUCCESS; + + context.vla_context.node_guid = + osm_node_get_node_guid(osm_physp_get_node_ptr(p)); + context.vla_context.port_guid = osm_physp_get_port_guid(p); + context.vla_context.set_method = TRUE; + attr_mod = ((block_num + 1) << 16) | port_num; + + return osm_req_set(p_req, osm_physp_get_dr_path_ptr(p), + (uint8_t *) & block, sizeof(block), + IB_MAD_ATTR_VL_ARBITRATION, + cl_hton32(attr_mod), CL_DISP_MSGID_NONE, &context); +} + +static ib_api_status_t vlarb_update(osm_req_t * p_req, + osm_physp_t * p, uint8_t port_num, + const struct qos_config *qcfg) +{ + ib_api_status_t status = IB_SUCCESS; + ib_port_info_t *p_pi; + unsigned len; + + if (!(p_pi = osm_physp_get_port_info_ptr(p))) + return IB_ERROR; + + 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(p_req, p, port_num, + &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(p_req, p, port_num, + &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(p_req, p, port_num, + &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(p_req, p, port_num, + &qcfg->vlarb_high[1], + len, 3)) != IB_SUCCESS) + return status; + } + + return status; +} + +static ib_api_status_t sl2vl_update_table(osm_req_t * p_req, + osm_physp_t * p, uint8_t in_port, + uint8_t out_port, + const ib_slvl_table_t * sl2vl_table) +{ + osm_madw_context_t context; + ib_slvl_table_t tbl, *p_tbl; + osm_node_t *p_node = osm_physp_get_node_ptr(p); + uint32_t attr_mod; + ib_port_info_t *p_pi; + unsigned vl_mask; + uint8_t vl1, vl2; + int i; + + if (!(p_pi = osm_physp_get_port_info_ptr(p))) + return IB_ERROR; + + vl_mask = (1 << (ib_port_info_get_op_vls(p_pi) - 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 ; + } + + p_tbl = osm_physp_get_slvl_tbl(p, in_port); + if (p_tbl && !memcmp(p_tbl, &tbl, sizeof(tbl))) + return IB_SUCCESS; + + context.slvl_context.node_guid = osm_node_get_node_guid(p_node); + context.slvl_context.port_guid = osm_physp_get_port_guid(p); + context.slvl_context.set_method = TRUE; + attr_mod = in_port << 8 | out_port; + return osm_req_set(p_req, osm_physp_get_dr_path_ptr(p), + (uint8_t *) & tbl, sizeof(tbl), + IB_MAD_ATTR_SLVL_TABLE, + cl_hton32(attr_mod), CL_DISP_MSGID_NONE, &context); +} + +static ib_api_status_t sl2vl_update(osm_req_t * p_req, osm_port_t * p_port, + osm_physp_t * p, uint8_t port_num, + const struct qos_config *qcfg) +{ + ib_api_status_t status; + uint8_t i, num_ports; + ib_port_info_t *p_pi = osm_physp_get_port_info_ptr(p); + osm_physp_t *p_physp; + + if (!p_pi) + return IB_ERROR; + + if (osm_node_get_type(osm_physp_get_node_ptr(p)) == IB_NODE_TYPE_SWITCH) { + if (ib_port_info_get_vl_cap(p_pi) == 1) { + /* Check port 0's capability mask */ + p_physp = osm_port_get_default_phys_ptr(p_port); + p_pi = osm_physp_get_port_info_ptr(p_physp); + if (!(p_pi->capability_mask & IB_PORT_CAP_HAS_SL_MAP)) + return IB_SUCCESS; + } + num_ports = osm_node_get_num_physp(osm_physp_get_node_ptr(p)); + } else { + if (!(p_pi->capability_mask & IB_PORT_CAP_HAS_SL_MAP)) + return IB_SUCCESS; + num_ports = 1; + } + + for (i = 0; i < num_ports; i++) { + status = + sl2vl_update_table(p_req, p, i, port_num, &qcfg->sl2vl); + if (status != IB_SUCCESS) + return status; + } + + return IB_SUCCESS; +} + +static ib_api_status_t vl_high_limit_update(osm_req_t * p_req, + osm_physp_t * p, + const struct qos_config *qcfg) +{ + uint8_t payload[IB_SMP_DATA_SIZE]; + osm_madw_context_t context; + ib_port_info_t *p_pi; + + if (!(p_pi = osm_physp_get_port_info_ptr(p))) + return IB_ERROR; + + if (p_pi->vl_high_limit == qcfg->vl_high_limit) + return IB_SUCCESS; + + memset(payload, 0, IB_SMP_DATA_SIZE); + memcpy(payload, p_pi, sizeof(ib_port_info_t)); + + p_pi = (ib_port_info_t *) payload; + ib_port_info_set_state_no_change(p_pi); + + p_pi->vl_high_limit = qcfg->vl_high_limit; + + context.pi_context.node_guid = + osm_node_get_node_guid(osm_physp_get_node_ptr(p)); + context.pi_context.port_guid = osm_physp_get_port_guid(p); + context.pi_context.set_method = TRUE; + context.pi_context.update_master_sm_base_lid = FALSE; + context.pi_context.ignore_errors = FALSE; + context.pi_context.light_sweep = FALSE; + context.pi_context.active_transition = FALSE; + + return osm_req_set(p_req, 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 ib_api_status_t qos_physp_setup(osm_log_t * p_log, osm_req_t * p_req, + osm_port_t * p_port, osm_physp_t * p, + uint8_t port_num, + const struct qos_config *qcfg) +{ + ib_api_status_t status; + + /* OpVLs should be ok at this moment - just use it */ + + /* setup VL high limit */ + status = vl_high_limit_update(p_req, p, qcfg); + if (status != IB_SUCCESS) { + osm_log(p_log, OSM_LOG_ERROR, + "qos_physp_setup: ERR 6201 : " + "failed to update VLHighLimit " + "for port %" PRIx64 " #%d\n", + cl_ntoh64(p->port_guid), port_num); + return status; + } + + /* setup VLArbitration */ + status = vlarb_update(p_req, p, port_num, qcfg); + if (status != IB_SUCCESS) { + osm_log(p_log, OSM_LOG_ERROR, + "qos_physp_setup: ERR 6202 : " + "failed to update VLArbitration tables " + "for port %" PRIx64 " #%d\n", + cl_ntoh64(p->port_guid), port_num); + return status; + } + + /* setup SL2VL tables */ + status = sl2vl_update(p_req, p_port, p, port_num, qcfg); + if (status != IB_SUCCESS) { + osm_log(p_log, OSM_LOG_ERROR, + "qos_physp_setup: ERR 6203 : " + "failed to update SL2VLMapping tables " + "for port %" PRIx64 " #%d\n", + cl_ntoh64(p->port_guid), port_num); + return status; + } + + return IB_SUCCESS; +} + +osm_signal_t osm_qos_setup(osm_opensm_t * p_osm) +{ + struct qos_config ca_config, sw0_config, swe_config, rtr_config; + struct qos_config *cfg; + cl_qmap_t *p_tbl; + cl_map_item_t *p_next; + osm_port_t *p_port; + uint32_t num_physp; + osm_physp_t *p_physp; + osm_node_t *p_node; + ib_api_status_t status; + uint8_t i; + + if (p_osm->subn.opt.no_qos) + return OSM_SIGNAL_DONE; + + OSM_LOG_ENTER(&p_osm->log, osm_qos_setup); + + 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); + + p_tbl = &p_osm->subn.port_guid_tbl; + p_next = cl_qmap_head(p_tbl); + while (p_next != cl_qmap_end(p_tbl)) { + p_port = (osm_port_t *) p_next; + p_next = cl_qmap_next(p_next); + + p_node = p_port->p_node; + if (p_node->sw) { + num_physp = osm_port_get_num_physp(p_port); + for (i = 1; i < num_physp; i++) { + p_physp = osm_port_get_phys_ptr(p_port, i); + if (!p_physp || !osm_physp_is_valid(p_physp)) + continue; + status = + qos_physp_setup(&p_osm->log, &p_osm->sm.req, + p_port, p_physp, i, &swe_config); + } + /* skip base port 0 */ + if (!ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info)) + continue; + + cfg = &sw0_config; + } else if (osm_node_get_type(p_node) == IB_NODE_TYPE_ROUTER) + cfg = &rtr_config; + else + cfg = &ca_config; + + p_physp = osm_port_get_default_phys_ptr(p_port); + if (!osm_physp_is_valid(p_physp)) + continue; + + status = qos_physp_setup(&p_osm->log, &p_osm->sm.req, + p_port, p_physp, 0, cfg); + } + + cl_plock_release(&p_osm->lock); + OSM_LOG_EXIT(&p_osm->log); + + return OSM_SIGNAL_DONE; +} + +/* + * QoS config stuff + */ +static int parse_one_unsigned(char *str, char delim, unsigned *val) +{ + char *end; + *val = strtoul(str, &end, 0); + if (*end) + end++; + return (int)(end - str); +} + +static int parse_vlarb_entry(char *str, ib_vl_arb_element_t * e) +{ + unsigned val; + char *p = str; + p += parse_one_unsigned(p, ':', &val); + e->vl = val % 15; + p += parse_one_unsigned(p, ',', &val); + e->weight = (uint8_t)val; + return (int)(p - str); +} + +static int parse_sl2vl_entry(char *str, uint8_t * raw) +{ + unsigned val1, val2; + char *p = str; + p += parse_one_unsigned(p, ',', &val1); + p += parse_one_unsigned(p, ',', &val2); + *raw = (val1 << 4) | (val2 & 0xf); + return (int)(p - str); +} + +static void qos_build_config(struct qos_config *cfg, + osm_qos_options_t * opt, osm_qos_options_t * dflt) +{ + int i; + char *p; + + memset(cfg, 0, sizeof(*cfg)); + + cfg->max_vls = opt->max_vls > 0 ? opt->max_vls : dflt->max_vls; + cfg->vl_high_limit = (uint8_t)opt->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-1/ulp/opensm/user/opensm/osm_remote_sm.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_remote_sm.c new file mode 100644 index 00000000..4b0cefeb --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_remote_sm.c @@ -0,0 +1,90 @@ +/* + * 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: + * Implementation of osm_sm_t. + * This object represents the remote SM object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_remote_sm_construct( + IN osm_remote_sm_t* const p_sm ) +{ + memset( p_sm, 0, sizeof(*p_sm) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_remote_sm_destroy( + IN osm_remote_sm_t* const p_sm ) +{ + memset( p_sm, 0, sizeof(*p_sm) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_remote_sm_init( + IN osm_remote_sm_t* const p_sm, + IN const osm_port_t* const p_port, + IN const ib_sm_info_t* const p_smi ) +{ + CL_ASSERT( p_sm ); + CL_ASSERT( p_port ); + + osm_remote_sm_construct( p_sm ); + + p_sm->p_port = p_port; + p_sm->smi = *p_smi; + return; +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_req.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_req.c new file mode 100644 index 00000000..f428315f --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_req.c @@ -0,0 +1,298 @@ +/* + * 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: + * Implementation of osm_req_t. + * This object represents the generic attribute requester. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.6 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_req_construct( + IN osm_req_t* const p_req ) +{ + CL_ASSERT( p_req ); + + memset( p_req, 0, sizeof(*p_req) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_req_destroy( + IN osm_req_t* const p_req ) +{ + CL_ASSERT( p_req ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_req_init( + IN osm_req_t* const p_req, + IN osm_mad_pool_t* const p_pool, + IN osm_vl15_t* const p_vl15, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN atomic32_t* const p_sm_trans_id ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_req_init ); + + osm_req_construct( p_req ); + p_req->p_log = p_log; + + p_req->p_pool = p_pool; + p_req->p_vl15 = p_vl15; + p_req->p_subn = p_subn; + p_req->p_sm_trans_id = p_sm_trans_id; + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + The plock MAY or MAY NOT be held before calling this function. +**********************************************************************/ +ib_api_status_t +osm_req_get( + IN const osm_req_t* const p_req, + IN const osm_dr_path_t* const p_path, + IN const uint16_t attr_id, + IN const uint32_t attr_mod, + IN const cl_disp_msgid_t err_msg, + IN const osm_madw_context_t* const p_context ) +{ + osm_madw_t *p_madw; + ib_api_status_t status = IB_SUCCESS; + ib_net64_t tid; + + CL_ASSERT( p_req ); + + OSM_LOG_ENTER( p_req->p_log, osm_req_get ); + + 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( + p_req->p_pool, + p_path->h_bind, + MAD_BLOCK_SIZE, + NULL ); + + if( p_madw == NULL ) + { + osm_log( p_req->p_log, OSM_LOG_ERROR, + "osm_req_get: ERR 1101: " + "Unable to acquire MAD\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + tid = cl_hton64( (uint64_t)cl_atomic_inc( p_req->p_sm_trans_id ) ); + + if( osm_log_is_active( p_req->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_req->p_log, OSM_LOG_DEBUG, + "osm_req_get: " + "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, + p_req->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( p_req->p_vl15, p_madw ); + + Exit: + OSM_LOG_EXIT( p_req->p_log ); + return( status ); +} + +/********************************************************************** + The plock MAY or MAY NOT be held before calling this function. +**********************************************************************/ +ib_api_status_t +osm_req_set( + IN const osm_req_t* const p_req, + IN const osm_dr_path_t* const p_path, + IN const uint8_t* const p_payload, + IN const size_t payload_size, + IN const uint16_t attr_id, + IN const uint32_t attr_mod, + IN const cl_disp_msgid_t err_msg, + IN const osm_madw_context_t* const p_context ) +{ + osm_madw_t *p_madw; + ib_api_status_t status = IB_SUCCESS; + ib_net64_t tid; + + CL_ASSERT( p_req ); + + OSM_LOG_ENTER( p_req->p_log, osm_req_set ); + + 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( + p_req->p_pool, + p_path->h_bind, + MAD_BLOCK_SIZE, + NULL ); + + if( p_madw == NULL ) + { + osm_log( p_req->p_log, OSM_LOG_ERROR, + "osm_req_set: ERR 1102: " + "Unable to acquire MAD\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + tid = cl_hton64( (uint64_t)cl_atomic_inc( p_req->p_sm_trans_id ) ); + + if( osm_log_is_active( p_req->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_req->p_log, OSM_LOG_DEBUG, + "osm_req_set: " + "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, + p_req->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( p_req->p_vl15, p_madw ); + + Exit: + OSM_LOG_EXIT( p_req->p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_req_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_req_ctrl.c new file mode 100644 index 00000000..97274389 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_req_ctrl.c @@ -0,0 +1,136 @@ +/* + * 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: + * Implementation of osm_req_ctrl_t. + * This object represents the request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_req_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_req_get( ((osm_req_ctrl_t*)context)->p_req, + (&((osm_attrib_req_t*)p_data)->path), + ((osm_attrib_req_t*)p_data)->attrib_id, + ((osm_attrib_req_t*)p_data)->attrib_mod, + ((osm_attrib_req_t*)p_data)->err_msg, + (&((osm_attrib_req_t*)p_data)->context) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_req_ctrl_construct( + IN osm_req_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_req_ctrl_destroy( + IN osm_req_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_req_ctrl_init( + IN osm_req_ctrl_t* const p_ctrl, + IN osm_req_t* const p_req, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_req_ctrl_init ); + + osm_req_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + + p_ctrl->p_disp = p_disp; + p_ctrl->p_req = p_req; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_REQ, + __osm_req_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_req_ctrl_init: ERR 1202: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_resp.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_resp.c new file mode 100644 index 00000000..aff8198a --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_resp.c @@ -0,0 +1,227 @@ +/* + * 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: + * Implementation of osm_resp_t. + * This object represents the generic attribute responder. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_resp_construct( + IN osm_resp_t* const p_resp ) +{ + memset( p_resp, 0, sizeof(*p_resp) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_resp_destroy( + IN osm_resp_t* const p_resp ) +{ + CL_ASSERT( p_resp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_resp_init( + IN osm_resp_t* const p_resp, + IN osm_mad_pool_t* const p_pool, + IN osm_vl15_t* const p_vl15, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_resp_init ); + + osm_resp_construct( p_resp ); + + p_resp->p_log = p_log; + p_resp->p_pool = p_pool; + p_resp->p_vl15 = p_vl15; + p_resp->p_subn = p_subn; + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_resp_make_resp_smp( + IN const osm_resp_t* const p_resp, + IN const ib_smp_t* const p_src_smp, + IN const ib_net16_t status, + IN const uint8_t* const p_payload, + OUT ib_smp_t* const p_dest_smp ) +{ + OSM_LOG_ENTER( p_resp->p_log, osm_resp_make_resp_smp ); + + 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( p_resp->p_log, OSM_LOG_ERROR, + "osm_resp_make_resp_smp: 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( p_resp->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_resp_send( + IN const osm_resp_t* const p_resp, + IN const osm_madw_t* const p_req_madw, + IN const ib_net16_t mad_status, + IN const uint8_t* const p_payload ) +{ + const ib_smp_t* p_req_smp; + ib_smp_t* p_smp; + osm_madw_t* p_madw; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_resp->p_log, osm_resp_send ); + + 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( + p_resp->p_pool, + osm_madw_get_bind_handle( p_req_madw ), + MAD_BLOCK_SIZE, + NULL ); + + if( p_madw == NULL ) + { + osm_log( p_resp->p_log, OSM_LOG_ERROR, + "osm_resp_send: ERR 1301: " + "Unable to acquire MAD\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* + Copy the request smp to the response smp, then just + update the necessary fields. + */ + p_smp = osm_madw_get_smp_ptr( p_madw ); + p_req_smp = osm_madw_get_smp_ptr( p_req_madw ); + osm_resp_make_resp_smp( p_resp, 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; + + if( osm_log_is_active( p_resp->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_resp->p_log, OSM_LOG_DEBUG, + "osm_resp_send: " + "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( p_resp->p_vl15, p_madw ); + + Exit: + OSM_LOG_EXIT( p_resp->p_log ); + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_router.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_router.c new file mode 100644 index 00000000..0f478b65 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_router.c @@ -0,0 +1,124 @@ +/* + * 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: + * Implementation of osm_router_t. + * This object represents an Infiniband router. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_router_construct( + IN osm_router_t* const p_rtr ) +{ + CL_ASSERT( p_rtr ); + memset( p_rtr, 0, sizeof(*p_rtr) ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_router_init( + IN osm_router_t* const p_rtr, + IN osm_port_t* const p_port ) +{ + ib_api_status_t status = IB_SUCCESS; + + CL_ASSERT( p_rtr ); + CL_ASSERT( p_port ); + + osm_router_construct( p_rtr ); + + p_rtr->p_port = p_port; + + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_router_destroy( + IN osm_router_t* const p_rtr ) +{ +} + +/********************************************************************** + **********************************************************************/ +void +osm_router_delete( + IN OUT osm_router_t** const pp_rtr ) +{ + osm_router_destroy( *pp_rtr ); + free( *pp_rtr ); + *pp_rtr = NULL; +} + +/********************************************************************** + **********************************************************************/ +osm_router_t* +osm_router_new( + IN osm_port_t* const p_port ) +{ + ib_api_status_t status; + osm_router_t *p_rtr; + + p_rtr = (osm_router_t*)malloc( sizeof(*p_rtr) ); + if( p_rtr ) + { + memset( p_rtr, 0, sizeof(*p_rtr) ); + status = osm_router_init( p_rtr, p_port ); + if( status != IB_SUCCESS ) + osm_router_delete( &p_rtr ); + } + + return( p_rtr ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa.c new file mode 100644 index 00000000..3512cb27 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa.c @@ -0,0 +1,1207 @@ +/* + * 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: + * Implementation of osm_sa_t. + * This object represents the Subnet Administration object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.14 $ + */ + +#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 + +#define OSM_SA_INITIAL_TID_VALUE 0xabc + +/********************************************************************** + **********************************************************************/ +void +osm_sa_construct( + IN osm_sa_t* const p_sa ) +{ + memset( p_sa, 0, sizeof(*p_sa) ); + p_sa->state = OSM_SA_STATE_INIT; + p_sa->sa_trans_id = OSM_SA_INITIAL_TID_VALUE; + + osm_sa_mad_ctrl_construct( &p_sa->mad_ctrl ); + osm_sa_resp_construct( &p_sa->resp ); + + osm_nr_rcv_construct( &p_sa->nr_rcv); + osm_nr_rcv_ctrl_construct( &p_sa->nr_rcv_ctrl ); + + osm_pir_rcv_construct( &p_sa->pir_rcv ); + osm_pir_rcv_ctrl_construct( &p_sa->pir_rcv_ctrl ); + + osm_gir_rcv_construct( &p_sa->gir_rcv ); + osm_gir_rcv_ctrl_construct( &p_sa->gir_rcv_ctrl ); + + osm_lr_rcv_construct( &p_sa->lr_rcv ); + osm_lr_rcv_ctrl_construct( &p_sa->lr_rcv_ctrl ); + + osm_pr_rcv_construct( &p_sa->pr_rcv ); + osm_pr_rcv_ctrl_construct( &p_sa->pr_rcv_ctrl ); + +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + osm_mpr_rcv_construct( &p_sa->mpr_rcv ); + osm_mpr_rcv_ctrl_construct( &p_sa->mpr_rcv_ctrl ); +#endif + + osm_smir_rcv_construct( &p_sa->smir_rcv ); + osm_smir_ctrl_construct( &p_sa->smir_ctrl ); + + osm_mcmr_rcv_construct(&p_sa->mcmr_rcv ); + osm_mcmr_rcv_ctrl_construct(&p_sa->mcmr_rcv_ctlr); + + osm_sr_rcv_construct( &p_sa->sr_rcv ); + osm_sr_rcv_ctrl_construct( &p_sa->sr_rcv_ctrl ); + + osm_infr_rcv_construct( &p_sa->infr_rcv ); + osm_infr_rcv_ctrl_construct( &p_sa->infr_rcv_ctrl ); + + osm_vlarb_rec_rcv_construct( &p_sa->vlarb_rec_rcv ); + osm_vlarb_rec_rcv_ctrl_construct( &p_sa->vlarb_rec_rcv_ctrl ); + + osm_slvl_rec_rcv_construct( &p_sa->slvl_rec_rcv ); + osm_slvl_rec_rcv_ctrl_construct( &p_sa->slvl_rec_rcv_ctrl ); + + osm_pkey_rec_rcv_construct( &p_sa->pkey_rec_rcv ); + osm_pkey_rec_rcv_ctrl_construct( &p_sa->pkey_rec_rcv_ctrl ); + + osm_lftr_rcv_construct( &p_sa->lftr_rcv ); + osm_lftr_rcv_ctrl_construct( &p_sa->lftr_rcv_ctrl ); + + osm_sir_rcv_construct( &p_sa->sir_rcv ); + osm_sir_rcv_ctrl_construct( &p_sa->sir_rcv_ctrl ); + + osm_mftr_rcv_construct( &p_sa->mftr_rcv ); + osm_mftr_rcv_ctrl_construct( &p_sa->mftr_rcv_ctrl ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sa_shutdown( + IN osm_sa_t* const p_sa ) +{ + ib_api_status_t status; + OSM_LOG_ENTER( p_sa->p_log, osm_sa_shutdown ); + + /* unbind from the mad service */ + status = osm_sa_mad_ctrl_unbind( &p_sa->mad_ctrl ); + + /* remove any registered dispatcher message */ + osm_nr_rcv_ctrl_destroy( &p_sa->nr_rcv_ctrl ); + osm_pir_rcv_ctrl_destroy( &p_sa->pir_rcv_ctrl ); + osm_gir_rcv_ctrl_destroy( &p_sa->gir_rcv_ctrl ); + osm_lr_rcv_ctrl_destroy( &p_sa->lr_rcv_ctrl ); + osm_pr_rcv_ctrl_destroy( &p_sa->pr_rcv_ctrl ); +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + osm_mpr_rcv_ctrl_destroy( &p_sa->mpr_rcv_ctrl ); +#endif + osm_smir_ctrl_destroy( &p_sa->smir_ctrl ); + osm_mcmr_rcv_ctrl_destroy( &p_sa->mcmr_rcv_ctlr); + osm_sr_rcv_ctrl_destroy( &p_sa->sr_rcv_ctrl ); + osm_infr_rcv_ctrl_destroy( &p_sa->infr_rcv_ctrl ); + osm_vlarb_rec_rcv_ctrl_destroy( &p_sa->vlarb_rec_rcv_ctrl ); + osm_slvl_rec_rcv_ctrl_destroy( &p_sa->slvl_rec_rcv_ctrl ); + osm_pkey_rec_rcv_ctrl_destroy( &p_sa->pkey_rec_rcv_ctrl ); + osm_lftr_rcv_ctrl_destroy( &p_sa->lftr_rcv_ctrl ); + osm_sir_rcv_ctrl_destroy( &p_sa->sir_rcv_ctrl ); + osm_mftr_rcv_ctrl_destroy( &p_sa->mftr_rcv_ctrl ); + osm_sa_mad_ctrl_destroy( &p_sa->mad_ctrl ); + + OSM_LOG_EXIT( p_sa->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_sa_destroy( + IN osm_sa_t* const p_sa ) +{ + OSM_LOG_ENTER( p_sa->p_log, osm_sa_destroy ); + + p_sa->state = OSM_SA_STATE_INIT; + + osm_nr_rcv_destroy( &p_sa->nr_rcv ); + osm_pir_rcv_destroy( &p_sa->pir_rcv ); + osm_gir_rcv_destroy( &p_sa->gir_rcv ); + osm_lr_rcv_destroy( &p_sa->lr_rcv ); + osm_pr_rcv_destroy( &p_sa->pr_rcv ); +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + osm_mpr_rcv_destroy( &p_sa->mpr_rcv ); +#endif + osm_smir_rcv_destroy( &p_sa->smir_rcv ); + osm_mcmr_rcv_destroy(&p_sa->mcmr_rcv); + osm_sr_rcv_destroy( &p_sa->sr_rcv ); + osm_infr_rcv_destroy( &p_sa->infr_rcv ); + osm_vlarb_rec_rcv_destroy( &p_sa->vlarb_rec_rcv ); + osm_slvl_rec_rcv_destroy( &p_sa->slvl_rec_rcv ); + osm_pkey_rec_rcv_destroy( &p_sa->pkey_rec_rcv ); + osm_lftr_rcv_destroy( &p_sa->lftr_rcv ); + osm_sir_rcv_destroy( &p_sa->sir_rcv ); + osm_mftr_rcv_destroy( &p_sa->mftr_rcv ); + osm_sa_resp_destroy( &p_sa->resp ); + + OSM_LOG_EXIT( p_sa->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sa_init( + IN osm_sm_t* const p_sm, + IN osm_sa_t* const p_sa, + IN osm_subn_t* const p_subn, + IN osm_vendor_t* const p_vendor, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_log_t* const p_log, + IN osm_stats_t* const p_stats, + IN cl_dispatcher_t* const p_disp, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_sa_init ); + + 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_resp_init(&p_sa->resp, + p_sa->p_mad_pool, + p_log); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_sa_mad_ctrl_init( + &p_sa->mad_ctrl, + &p_sa->resp, + p_sa->p_mad_pool, + p_sa->p_vendor, + p_subn, + p_log, + p_stats, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_cpi_rcv_init( + &p_sa->cpi_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_cpi_rcv_ctrl_init( + &p_sa->cpi_rcv_ctrl, + &p_sa->cpi_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_nr_rcv_init( + &p_sa->nr_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_nr_rcv_ctrl_init( + &p_sa->nr_rcv_ctrl, + &p_sa->nr_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_pir_rcv_init( + &p_sa->pir_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_pir_rcv_ctrl_init( + &p_sa->pir_rcv_ctrl, + &p_sa->pir_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_gir_rcv_init( + &p_sa->gir_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_gir_rcv_ctrl_init( + &p_sa->gir_rcv_ctrl, + &p_sa->gir_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_lr_rcv_init( + &p_sa->lr_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_lr_rcv_ctrl_init( + &p_sa->lr_rcv_ctrl, + &p_sa->lr_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_pr_rcv_init( + &p_sa->pr_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_pr_rcv_ctrl_init( + &p_sa->pr_rcv_ctrl, + &p_sa->pr_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + status = osm_mpr_rcv_init( + &p_sa->mpr_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_mpr_rcv_ctrl_init( + &p_sa->mpr_rcv_ctrl, + &p_sa->mpr_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; +#endif + + status = osm_smir_rcv_init( + &p_sa->smir_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_stats, + p_log, + p_lock ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_smir_ctrl_init( + &p_sa->smir_ctrl, + &p_sa->smir_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_mcmr_rcv_init( + p_sm, + &p_sa->mcmr_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_mcmr_rcv_ctrl_init( + &p_sa->mcmr_rcv_ctlr, + &p_sa->mcmr_rcv, + p_log, + p_disp); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_sr_rcv_init( + &p_sa->sr_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_sr_rcv_ctrl_init( + &p_sa->sr_rcv_ctrl, + &p_sa->sr_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_infr_rcv_init( + &p_sa->infr_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_infr_rcv_ctrl_init( + &p_sa->infr_rcv_ctrl, + &p_sa->infr_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_vlarb_rec_rcv_init( + &p_sa->vlarb_rec_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_vlarb_rec_rcv_ctrl_init( + &p_sa->vlarb_rec_rcv_ctrl, + &p_sa->vlarb_rec_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_slvl_rec_rcv_init( + &p_sa->slvl_rec_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_slvl_rec_rcv_ctrl_init( + &p_sa->slvl_rec_rcv_ctrl, + &p_sa->slvl_rec_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_pkey_rec_rcv_init( + &p_sa->pkey_rec_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_pkey_rec_rcv_ctrl_init( + &p_sa->pkey_rec_rcv_ctrl, + &p_sa->pkey_rec_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_lftr_rcv_init( + &p_sa->lftr_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_lftr_rcv_ctrl_init( + &p_sa->lftr_rcv_ctrl, + &p_sa->lftr_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_sir_rcv_init( + &p_sa->sir_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_sir_rcv_ctrl_init( + &p_sa->sir_rcv_ctrl, + &p_sa->sir_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_mftr_rcv_init( + &p_sa->mftr_rcv, + &p_sa->resp, + p_sa->p_mad_pool, + p_subn, + p_log, + p_lock); + if( status != IB_SUCCESS ) + goto Exit; + + status = osm_mftr_rcv_ctrl_init( + &p_sa->mftr_rcv_ctrl, + &p_sa->mftr_rcv, + p_log, + p_disp ); + if( status != IB_SUCCESS ) + goto Exit; + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sa_bind( + IN osm_sa_t* const p_sa, + IN const ib_net64_t port_guid ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_sa->p_log, osm_sa_bind ); + + status = osm_sa_mad_ctrl_bind( + &p_sa->mad_ctrl, port_guid ); + + OSM_LOG_EXIT( p_sa->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +/* + * 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, + "opensm_dump_to_file: ERR 0000: " + "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(cl_map_item_t *p_map_item, 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; + osm_mgrp_t *p_mgrp = (osm_mgrp_t *)p_map_item; + + 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=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_node_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), + cl_ntoh16(p_infr->report_addr.addr_type.gsi.pkey), + 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; + + dump_context.p_osm = p_osm; + dump_context.file = file; + osm_log(&p_osm->log, OSM_LOG_DEBUG, "sa_dump_all_sa: Dump multicast:\n"); + cl_plock_acquire(&p_osm->lock); + cl_qmap_apply_func(&p_osm->subn.mgrp_mlid_tbl, + sa_dump_one_mgrp, &dump_context); + osm_log(&p_osm->log, OSM_LOG_DEBUG, "sa_dump_all_sa: 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, "sa_dump_all_sa: Dump services:\n"); + cl_qlist_apply_func(&p_osm->subn.sa_sr_list, + sa_dump_one_service, &dump_context); + cl_plock_release(&p_osm->lock); +} + +int osm_sa_db_file_dump(osm_opensm_t *p_osm) +{ + return opensm_dump_to_file(p_osm, "opensm-sa.dump", sa_dump_all_sa); +} + +/* + * SA DB Loader + * + */ + +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; + cl_map_item_t *p_next; + osm_mgrp_t *p_mgrp; + + cl_plock_excl_acquire(&p_osm->lock); + + if ((p_next = cl_qmap_get(&p_osm->subn.mgrp_mlid_tbl, mlid)) != + cl_qmap_end(&p_osm->subn.mgrp_mlid_tbl)) { + p_mgrp = (osm_mgrp_t *)p_next; + if (!memcmp(&p_mgrp->mcmember_rec.mgid, &p_mcm_rec->mgid, + sizeof(ib_gid_t))) { + osm_log(&p_osm->log, OSM_LOG_DEBUG, + "load_mcgroup: mgrp %04x is already here.", + cl_ntoh16(mlid)); + goto _out; + } + osm_log(&p_osm->log, OSM_LOG_VERBOSE, + "load_mcgroup: 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.mcmr_rcv, + comp_mask, p_mcm_rec, + &p_mgrp) != IB_SUCCESS || + !p_mgrp || p_mgrp->mlid != mlid) { + osm_log(&p_osm->log, OSM_LOG_ERROR, + "load_mcgroup: 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, + "load_svcr ServiceRecord already exists.\n"); + goto _out; + } + + if (!(p_svcr = osm_svcr_new(sr))) { + osm_log(&p_osm->log, OSM_LOG_ERROR, + "load_svcr: 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, + "load_svcr: 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_rcv.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.p_infr_rcv = &p_osm->sa.infr_rcv; + /* 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, + "load_infr: InformInfo Record already exists\n"); + goto _out; + } + + if (!(p_infr = osm_infr_new(&infr))) { + osm_log(&p_osm->log, OSM_LOG_ERROR, + "load_infr: cannot allocate new infr struct\n"); + ret = -1; + goto _out; + } + + osm_log(&p_osm->log, OSM_LOG_DEBUG, + "load_infr: 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) \ +int unpack_##name##x(char *p, uint##x##_t *val_ptr) \ +{ \ + char *q; \ + unsigned long long num; \ + num = strtoull(p, &q, 16); \ + if (num > ~((uint##x##_t)0x0) \ + || q == p || (!isspace(*q) && *q != ':')) { \ + *val_ptr = 0; \ + return -1; \ + } \ + *val_ptr = cl_hton##x((uint##x##_t)num); \ + return (int)(q - p); \ +} + +#define cl_hton8(x) (x) + +UNPACK_FUNC(net,8); +UNPACK_FUNC(net,16); +UNPACK_FUNC(net,32); +UNPACK_FUNC(net,64); + +static int unpack_string(char *p, uint8_t *buf, unsigned len) +{ + char *q = p; + char delim = ' '; + + if (*q == '\'' || *q == '\"') + delim = *q++; + while (--len && *q && *q != delim) + *buf++ = *q++; + *buf = '\0'; + if (*q == delim && delim != ' ') + q++; + return (int)(q - p); +} + +static int unpack_string64(char *p, uint8_t *buf) +{ + return unpack_string(p, buf, 64); +} + +#define PARSE_AHEAD(p, x, name, val_ptr) { int _ret; \ + p = strstr(p, name); \ + if (!p) { \ + osm_log(&p_osm->log, OSM_LOG_ERROR, \ + "PARSE ERROR: %s:%u: cannot find \"%s\" string\n", \ + file_name, lineno, (name)); \ + ret = -2; \ + goto _error; \ + } \ + p += strlen(name); \ + _ret = unpack_##x(p, (val_ptr)); \ + if (_ret < 0) { \ + osm_log(&p_osm->log, OSM_LOG_ERROR, \ + "PARSE ERROR: %s:%u: cannot parse "#x" value " \ + "after \"%s\"\n", file_name, lineno, (name)); \ + ret = _ret; \ + goto _error; \ + } \ + p += _ret; \ +} + +int osm_sa_db_file_load(osm_opensm_t *p_osm) +{ + char line[1024]; + char *file_name; + FILE *file; + int ret = 0; + osm_mgrp_t *p_mgrp = NULL; + unsigned rereg_clients = 0; + unsigned lineno; + + file_name = p_osm->subn.opt.sa_db_file; + if (!file_name) { + osm_log(&p_osm->log, OSM_LOG_VERBOSE, + "osm_sa_db_file_load: 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, + "osm_sa_db_file_load: ERR 0000: " + "cannot open sa db file \'%s\'. " + "Skip restoring\n", file_name); + return -1; + } + + lineno = 0; + + while (fgets(line, sizeof(line) - 1, file) != NULL) { + char *p; + uint8_t val; + + lineno++; + + p = line; + while (isspace(*p)) + p++; + + if (*p == '#') + continue; + + if (!strncmp(p, "MC Group", 8)) { + ib_member_rec_t mcm_rec; + ib_net16_t mlid; + unsigned well_known = 0; + + p_mgrp = NULL; + memset(&mcm_rec, 0, sizeof(mcm_rec)); + + PARSE_AHEAD(p, net16, " 0x", &mlid); + if(strstr(p, "well known")) + well_known = 1; + PARSE_AHEAD(p, net64, " mgid=0x", + &mcm_rec.mgid.unicast.prefix); + PARSE_AHEAD(p, net64, ":0x", + &mcm_rec.mgid.unicast.interface_id); + PARSE_AHEAD(p, net64, " port_gid=0x", + &mcm_rec.port_gid.unicast.prefix); + PARSE_AHEAD(p, net64, ":0x", + &mcm_rec.port_gid.unicast.interface_id); + PARSE_AHEAD(p, net32, " qkey=0x", &mcm_rec.qkey); + PARSE_AHEAD(p, net16, " mlid=0x", &mcm_rec.mlid); + PARSE_AHEAD(p, net8, " mtu=0x", &mcm_rec.mtu); + PARSE_AHEAD(p, net8, " tclass=0x", &mcm_rec.tclass); + PARSE_AHEAD(p, net16, " pkey=0x", &mcm_rec.pkey); + PARSE_AHEAD(p, net8, " rate=0x", &mcm_rec.rate); + PARSE_AHEAD(p, net8, " pkt_life=0x", &mcm_rec.pkt_life); + PARSE_AHEAD(p, net32, " sl_flow_hop=0x", + &mcm_rec.sl_flow_hop); + PARSE_AHEAD(p, net8, " scope_state=0x", + &mcm_rec.scope_state); + PARSE_AHEAD(p, net8, " proxy_join=0x", &val); + mcm_rec.proxy_join = val; + + p_mgrp = load_mcgroup(p_osm, mlid, &mcm_rec, + well_known); + if (!p_mgrp) + rereg_clients = 1; + } + else if (p_mgrp && !strncmp(p, "mcm_port", 8)) { + ib_gid_t port_gid; + ib_net64_t guid; + uint8_t scope_state; + boolean_t proxy_join; + + PARSE_AHEAD(p, net64, " port_gid=0x", + &port_gid.unicast.prefix); + PARSE_AHEAD(p, net64, ":0x", + &port_gid.unicast.interface_id); + PARSE_AHEAD(p, net8, " scope_state=0x", &scope_state); + PARSE_AHEAD(p, net8, " proxy_join=0x", &val); + proxy_join = val; + + guid = port_gid.unicast.interface_id; + if (cl_qmap_get(&p_mgrp->mcm_port_tbl, + port_gid.unicast.interface_id) == + cl_qmap_end(&p_mgrp->mcm_port_tbl)) + osm_mgrp_add_port(p_mgrp, &port_gid, + scope_state, proxy_join); + } + else if (!strncmp(p, "Service Record:", 15)) { + ib_service_record_t s_rec; + uint32_t modified_time, lease_period; + + p_mgrp = NULL; + memset(&s_rec, 0, sizeof(s_rec)); + + PARSE_AHEAD(p, net64, " id=0x", &s_rec.service_id); + PARSE_AHEAD(p, net64, " gid=0x", + &s_rec.service_gid.unicast.prefix); + PARSE_AHEAD(p, net64, ":0x", + &s_rec.service_gid.unicast.interface_id); + PARSE_AHEAD(p, net16, " pkey=0x", &s_rec.service_pkey); + PARSE_AHEAD(p, net32, " lease=0x", &s_rec.service_lease); + PARSE_AHEAD(p, net64, " key=0x", + (ib_net64_t *)(&s_rec.service_key[0])); + PARSE_AHEAD(p, net64, ":0x", + (ib_net64_t *)(&s_rec.service_key[8])); + PARSE_AHEAD(p, string64, " name=", s_rec.service_name); + PARSE_AHEAD(p, net64, " data8=0x", + (ib_net64_t *)(&s_rec.service_data8[0])); + PARSE_AHEAD(p, net64, ":0x", + (ib_net64_t *)(&s_rec.service_data8[8])); + PARSE_AHEAD(p, net64, " data16=0x", + (ib_net64_t *)(&s_rec.service_data16[0])); + PARSE_AHEAD(p, net64, ":0x", + (ib_net64_t *)(&s_rec.service_data16[4])); + PARSE_AHEAD(p, net64, " data32=0x", + (ib_net64_t *)(&s_rec.service_data32[0])); + PARSE_AHEAD(p, net64, ":0x", + (ib_net64_t *)(&s_rec.service_data32[2])); + PARSE_AHEAD(p, net64, " data64=0x", &s_rec.service_data64[0]); + PARSE_AHEAD(p, net64, ":0x", &s_rec.service_data64[1]); + PARSE_AHEAD(p, net32, " modified_time=0x", + &modified_time); + PARSE_AHEAD(p, net32, " lease_period=0x", + &lease_period); + + if (load_svcr(p_osm, &s_rec, cl_ntoh32(modified_time), + cl_ntoh32(lease_period))) + rereg_clients = 1; + } + else if (!strncmp(p, "InformInfo Record:", 18)) { + ib_inform_info_record_t i_rec; + osm_mad_addr_t rep_addr; + + 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=0x", + &rep_addr.addr_type.gsi.pkey); + PARSE_AHEAD(p, net8, " sl=0x", + &rep_addr.addr_type.gsi.service_level); + + if (load_infr(p_osm, &i_rec, &rep_addr)) + rereg_clients = 1; + } + } + + if (!rereg_clients) + p_osm->subn.opt.no_clients_rereg = TRUE; + + _error: + fclose(file); + return ret; +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_class_port_info.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_class_port_info.c new file mode 100644 index 00000000..eb812798 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_class_port_info.c @@ -0,0 +1,280 @@ +/* + * 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: + * Implementation of osm_cpi_rcv_t. + * This object represents the ClassPortInfo Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.8 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#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) */ +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 }; + +/********************************************************************** + **********************************************************************/ +void +osm_cpi_rcv_construct( + IN osm_cpi_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_cpi_rcv_destroy( + IN osm_cpi_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_cpi_rcv_destroy ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_cpi_rcv_init( + IN osm_cpi_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_cpi_rcv_init ); + + osm_cpi_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_cpi_rcv_respond( + IN osm_cpi_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + osm_madw_t* p_resp_madw; + const ib_sa_mad_t* p_sa_mad; + ib_sa_mad_t* p_resp_sa_mad; + ib_class_port_info_t *p_resp_cpi; + ib_api_status_t status; + ib_gid_t zero_gid; + uint8_t rtv; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_cpi_rcv_respond ); + + 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( p_rcv->p_mad_pool, + p_madw->h_bind, + MAD_BLOCK_SIZE, + &p_madw->mad_addr ); + if( !p_resp_madw ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_cpi_rcv_respond: 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 (p_rcv->p_subn->opt.transaction_timeout > __msecs_to_rtv_table[MAX_MSECS_TO_RTV]) + rtv = MAX_MSECS_TO_RTV - 1; + else + { + for (rtv = 0; rtv < MAX_MSECS_TO_RTV; rtv++) { + if (p_rcv->p_subn->opt.transaction_timeout <= __msecs_to_rtv_table[rtv]) + break; + } + } + rtv += 8; + p_resp_cpi->cap_mask2_resp_time = 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 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 (p_rcv->p_subn->opt.no_multicast_option != TRUE) + 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( p_rcv->p_log, OSM_LOG_FRAMES ) ) + osm_dump_sa_mad( p_rcv->p_log, p_resp_sa_mad, OSM_LOG_FRAMES ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + if( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_cpi_rcv_respond: ERR 1409: " + "Unable to send MAD (%s)\n", ib_get_err_str( status ) ); + /* osm_mad_pool_put( p_rcv->p_mad_pool, p_resp_madw ); */ + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + * This code actually handles the call + **********************************************************************/ +void +osm_cpi_rcv_process( + IN osm_cpi_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_path_rec_t* p_pr; + const ib_sa_mad_t* p_sa_mad; + + OSM_LOG_ENTER( p_rcv->p_log, osm_cpi_rcv_process ); + + 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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_cpi_rcv_process: ERR 1403: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_sa_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad ); + + CL_ASSERT( p_sa_mad->attr_id == IB_MAD_ATTR_CLASS_PORT_INFO ); + + /* + CLASS PORT INFO does not really look on the SMDB - no lock required. + */ + + __osm_cpi_rcv_respond( p_rcv, p_madw); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_class_port_info_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_class_port_info_ctrl.c new file mode 100644 index 00000000..dbd55dca --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_class_port_info_ctrl.c @@ -0,0 +1,126 @@ +/* + * 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: + * Implementation of osm_pr_rcv_ctrl_t. + * This object represents the ClassPortInfo request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.3 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_cpi_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_cpi_rcv_process( ((osm_cpi_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_cpi_rcv_ctrl_construct( + IN osm_cpi_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_cpi_rcv_ctrl_destroy( + IN osm_cpi_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_cpi_rcv_ctrl_init( + IN osm_cpi_rcv_ctrl_t* const p_ctrl, + IN osm_cpi_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_cpi_rcv_ctrl_init ); + + osm_cpi_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_CLASS_PORT_INFO, + __osm_cpi_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_cpi_rcv_ctrl_init: ERR 1501: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_guidinfo_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_guidinfo_record.c new file mode 100644 index 00000000..2c0bce9f --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_guidinfo_record.c @@ -0,0 +1,611 @@ +/* + * 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: + * Implementation of osm_gir_rcv_t. + * This object represents the GUIDInfoRecord Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_GIR_RCV_POOL_MIN_SIZE 32 +#define OSM_GIR_RCV_POOL_GROW_SIZE 32 + +typedef struct _osm_gir_item +{ + cl_pool_item_t pool_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_gir_rcv_t* p_rcv; + const osm_physp_t* p_req_physp; +} osm_gir_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void +osm_gir_rcv_construct( + IN osm_gir_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_gir_rcv_destroy( + IN osm_gir_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_gir_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_gir_rcv_init( + IN osm_gir_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN const osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_gir_rcv_init ); + + osm_gir_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + status = cl_qlock_pool_init( &p_rcv->pool, + OSM_GIR_RCV_POOL_MIN_SIZE, + 0, + OSM_GIR_RCV_POOL_GROW_SIZE, + sizeof(osm_gir_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_gir_rcv_new_gir( + IN osm_gir_rcv_t* const p_rcv, + IN const osm_node_t* const p_node, + IN cl_qlist_t* const p_list, + IN ib_net64_t const match_port_guid, + IN ib_net16_t const match_lid, + IN const osm_physp_t* const p_req_physp, + IN uint8_t const block_num ) +{ + osm_gir_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_gir_rcv_new_gir ); + + p_rec_item = (osm_gir_item_t*)cl_qlock_pool_get( &p_rcv->pool ); + if( p_rec_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_gir_rcv_new_gir: ERR 5102: " + "cl_qlock_pool_get failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_gir_rcv_new_gir: " + "New GUIDInfoRecord: lid 0x%X, block num %d\n", + cl_ntoh16( match_lid ), block_num ); + } + + memset( &p_rec_item->rec, 0, sizeof( p_rec_item->rec ) ); + + 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, (cl_list_item_t*)&p_rec_item->pool_item ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sa_gir_create_gir( + IN osm_gir_rcv_t* const p_rcv, + IN const osm_node_t* const p_node, + IN cl_qlist_t* const p_list, + IN ib_net64_t const match_port_guid, + IN ib_net16_t const match_lid, + IN const osm_physp_t* const p_req_physp, + IN uint8_t const 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; + const ib_port_info_t* p_pi; + uint8_t block_num, start_block_num, end_block_num, num_blocks; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_gir_create_gir ); + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_gir_create_gir: " + "Looking for GUIDRecord with LID: 0x%X 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( !osm_physp_is_valid( 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( p_rcv->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; + + p_pi = osm_physp_get_port_info_ptr( p_physp ); + + /* + 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_pi->guid_cap == 0 ) + continue; + + num_blocks = p_pi->guid_cap / 8; + if ( p_pi->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. + */ + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_gir_create_gir: " + "Comparing LID: 0x%X <= 0x%X <= 0x%X\n", + base_lid_ho, match_lid_ho, max_lid_ho + ); + } + + if ( match_lid_ho < base_lid_ho || match_lid_ho > max_lid_ho ) + continue; + } + + for (block_num = start_block_num; block_num <= end_block_num; block_num++) + __osm_gir_rcv_new_gir( p_rcv, p_node, p_list, + port_guid, cl_ntoh16(base_lid_ho), + p_physp, block_num ); + + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +__osm_sa_gir_by_comp_mask_cb( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + const osm_gir_search_ctxt_t* const p_ctxt = (osm_gir_search_ctxt_t *)context; + const 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_gir_rcv_t* const p_rcv = p_ctxt->p_rcv; + 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->p_rcv->p_log, __osm_sa_gir_by_comp_mask_cb); + + if( comp_mask & IB_GIR_COMPMASK_LID ) + match_lid = p_rcvd_rec->lid; + + if( comp_mask & IB_GIR_COMPMASK_BLOCKNUM ) + match_block_num = p_rcvd_rec->block_num; + + p_comp_gi = &p_rcvd_rec->guid_info; + /* Different rule for block 0 v. other blocks */ + if( comp_mask & IB_GIR_COMPMASK_GID0 ) + { + if ( !p_rcvd_rec->block_num ) + match_port_guid = osm_physp_get_port_guid( p_req_physp ); + if ( p_comp_gi->guid[0] != match_port_guid ) + goto Exit; + } + + if( comp_mask & IB_GIR_COMPMASK_GID1 ) + { + if ( p_comp_gi->guid[1] != 0) + goto Exit; + } + + if( comp_mask & IB_GIR_COMPMASK_GID2 ) + { + if ( p_comp_gi->guid[2] != 0) + goto Exit; + } + + if( comp_mask & IB_GIR_COMPMASK_GID3 ) + { + if ( p_comp_gi->guid[3] != 0) + goto Exit; + } + + if( comp_mask & IB_GIR_COMPMASK_GID4 ) + { + if ( p_comp_gi->guid[4] != 0) + goto Exit; + } + + if( comp_mask & IB_GIR_COMPMASK_GID5 ) + { + if ( p_comp_gi->guid[5] != 0) + goto Exit; + } + + if( comp_mask & IB_GIR_COMPMASK_GID6 ) + { + if ( p_comp_gi->guid[6] != 0) + goto Exit; + } + + if( comp_mask & IB_GIR_COMPMASK_GID7 ) + { + if ( p_comp_gi->guid[7] != 0) + goto Exit; + } + + __osm_sa_gir_create_gir( p_rcv, p_node, p_ctxt->p_list, + match_port_guid, match_lid, p_req_physp, + match_block_num ); + + Exit: + OSM_LOG_EXIT( p_ctxt->p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_gir_rcv_process( + IN osm_gir_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_sa_mad_t* p_rcvd_mad; + const ib_guidinfo_record_t* p_rcvd_rec; + cl_qlist_t rec_list; + osm_madw_t* p_resp_madw; + ib_sa_mad_t* p_resp_sa_mad; + ib_guidinfo_record_t* p_resp_rec; + uint32_t num_rec, pre_trim_num_rec; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t trim_num_rec; +#endif + uint32_t i; + osm_gir_search_ctxt_t context; + osm_gir_item_t* p_rec_item; + ib_api_status_t status; + osm_physp_t* p_req_physp; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_gir_rcv_process ); + + 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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_gir_rcv_process: ERR 5105: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_rcvd_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_gir_rcv_process: ERR 5104: " + "Cannot find requester physical port\n" ); + goto Exit; + } + + if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + osm_dump_guidinfo_record( p_rcv->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.p_rcv = p_rcv; + context.p_req_physp = p_req_physp; + + cl_plock_acquire( p_rcv->p_lock ); + + cl_qmap_apply_func( &p_rcv->p_subn->node_guid_tbl, + __osm_sa_gir_by_comp_mask_cb, + &context ); + + cl_plock_release( p_rcv->p_lock ); + + num_rec = cl_qlist_count( &rec_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if (p_rcvd_mad->method == IB_MAD_METHOD_GET) + { + if (num_rec == 0) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + if (num_rec > 1) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_gir_rcv_process: ERR 5103: " + "Got more than one record for SubnAdmGet (%u)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS ); + + /* need to set the mem free ... */ + p_rec_item = (osm_gir_item_t*)cl_qlist_remove_head( &rec_list ); + while( p_rec_item != (osm_gir_item_t*)cl_qlist_end( &rec_list ) ) + { + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_rec_item = (osm_gir_item_t*)cl_qlist_remove_head( &rec_list ); + } + + goto Exit; + } + } + + pre_trim_num_rec = num_rec; +#ifndef VENDOR_RMPP_SUPPORT + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_guidinfo_record_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_gir_rcv_process: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_gir_rcv_process: " + "Returning %u records\n", num_rec ); + + if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0)) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_guidinfo_record_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + + if( !p_resp_madw ) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_gir_rcv_process: ERR 5106: " + "osm_mad_pool_get failed\n" ); + + for( i = 0; i < num_rec; i++ ) + { + p_rec_item = (osm_gir_item_t*)cl_qlist_remove_head( &rec_list ); + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES ); + goto Exit; + } + + p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_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( p_resp_sa_mad, p_rcvd_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; + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_guidinfo_record_t) ); + + p_resp_rec = (ib_guidinfo_record_t*) + ib_sa_mad_get_payload_ptr( p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + for( i = 0; i < pre_trim_num_rec; i++ ) + { + p_rec_item = (osm_gir_item_t*)cl_qlist_remove_head( &rec_list ); + /* copy only if not trimmed */ + if (i < num_rec) + { + *p_resp_rec = p_rec_item->rec; + } + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_resp_rec++; + } + + CL_ASSERT( cl_is_qlist_empty( &rec_list ) ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE); + if (status != IB_SUCCESS) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_gir_rcv_process: ERR 5107: " + "osm_vendor_send status = %s\n", + ib_get_err_str(status)); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_guidinfo_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_guidinfo_record_ctrl.c new file mode 100644 index 00000000..6e0b9e20 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_guidinfo_record_ctrl.c @@ -0,0 +1,124 @@ +/* + * 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: + * Implementation of osm_gir_rcv_ctrl_t. + * This object represents the GUIDInfoRecord request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_gir_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_gir_rcv_process( ((osm_gir_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_gir_rcv_ctrl_construct( + IN osm_gir_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_gir_rcv_ctrl_destroy( + IN osm_gir_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_gir_rcv_ctrl_init( + IN osm_gir_rcv_ctrl_t* const p_ctrl, + IN osm_gir_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_gir_rcv_ctrl_init ); + + osm_gir_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_GUIDINFO_RECORD, + __osm_gir_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_gir_rcv_ctrl_init: ERR 5201: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_informinfo.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_informinfo.c new file mode 100644 index 00000000..56619130 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_informinfo.c @@ -0,0 +1,922 @@ +/* + * 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: + * Implementation of osm_infr_rcv_t. + * This object represents the InformInfo Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.8 $ + */ + +#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 + +#define OSM_IIR_RCV_POOL_MIN_SIZE 32 +#define OSM_IIR_RCV_POOL_GROW_SIZE 32 + +typedef struct _osm_iir_item +{ + cl_pool_item_t pool_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_infr_rcv_t* p_rcv; + osm_physp_t* p_req_physp; +} osm_iir_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void +osm_infr_rcv_construct( + IN osm_infr_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_infr_rcv_destroy( + IN osm_infr_rcv_t* const p_rcv ) +{ + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_infr_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_infr_rcv_init( + IN osm_infr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_ERROR; + + OSM_LOG_ENTER( p_log, osm_infr_rcv_init ); + + osm_infr_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + status = cl_qlock_pool_init( &p_rcv->pool, + OSM_IIR_RCV_POOL_MIN_SIZE, + 0, + OSM_IIR_RCV_POOL_GROW_SIZE, + sizeof(osm_iir_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** +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_infr_rcv_t* const p_rcv, + IN osm_infr_t* p_infr_rec ) +{ + boolean_t valid = TRUE; + osm_physp_t* p_requester_physp; + osm_port_t* p_port; + osm_physp_t* p_physp; + ib_net64_t portguid; + ib_net16_t lid_range_begin; + ib_net16_t lid_range_end; + ib_net16_t lid; + const cl_ptr_vector_t* p_tbl; + ib_gid_t zero_gid; + + OSM_LOG_ENTER( p_rcv->p_log, __validate_ports_access_rights ); + + /* get the requester physp from the request address */ + p_requester_physp = osm_get_physp_by_mad_addr( p_rcv->p_log, + p_rcv->p_subn, + &p_infr_rec->report_addr ); + + memset( &zero_gid, 0, sizeof(zero_gid) ); + if ( memcmp (&(p_infr_rec->inform_record.inform_info.gid), + &zero_gid, sizeof(ib_gid_t) ) ) + { + /* a gid is defined */ + portguid = p_infr_rec->inform_record.inform_info.gid.unicast.interface_id; + + p_port = osm_get_port_by_guid( p_rcv->p_subn, portguid ); + + if ( p_port == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__validate_ports_access_rights: ERR 4301: " + "Invalid port guid: 0x%016" PRIx64 "\n", + cl_ntoh64(portguid) ); + valid = FALSE; + goto Exit; + } + + /* get the destination InformInfo physical port */ + p_physp = osm_port_get_default_phys_ptr(p_port); + + /* make sure that the requester and destination port can access each other + according to the current partitioning. */ + if (! osm_physp_share_pkey( p_rcv->p_log, p_physp, p_requester_physp)) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_ports_access_rights: " + "port and requester don't share pkey\n" ); + valid = FALSE; + goto Exit; + } + } + else + { + /* gid is zero - check if LID range is defined */ + lid_range_begin = cl_ntoh16(p_infr_rec->inform_record.inform_info.lid_range_begin); + /* if lid is 0xFFFF - meaning all endports managed by the manager */ + if ( lid_range_begin == 0xFFFF ) + goto Exit; + + lid_range_end = cl_ntoh16(p_infr_rec->inform_record.inform_info.lid_range_end); + + /* lid_range_end is set to zero if no range desired. In this case - + just make it equal to the lid_range_begin. */ + if (lid_range_end == 0) + lid_range_end = lid_range_begin; + + /* go over all defined lids within the range and make sure that the + requester port can access them according to current partitioning. */ + for ( lid = lid_range_begin; lid <= lid_range_end; lid++ ) + { + p_tbl = &p_rcv->p_subn->port_lid_tbl; + if ( cl_ptr_vector_get_size( p_tbl ) > lid ) + { + p_port = cl_ptr_vector_get( p_tbl, lid ); + } + else + { + /* lid requested is out of range */ + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__validate_ports_access_rights: ERR 4302: " + "Given LID (0x%X) is out of range:0x%X\n", + lid, cl_ptr_vector_get_size(p_tbl) ); + valid = FALSE; + goto Exit; + } + if ( p_port == NULL ) + continue; + + p_physp = osm_port_get_default_phys_ptr(p_port); + /* make sure that the requester and destination port can access + each other according to the current partitioning. */ + if (! osm_physp_share_pkey( p_rcv->p_log, p_physp, p_requester_physp)) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_ports_access_rights: " + "port and requester don't share pkey\n" ); + valid = FALSE; + goto Exit; + } + } + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return valid; +} + +/********************************************************************** + **********************************************************************/ +static +boolean_t +__validate_infr( + IN osm_infr_rcv_t* const p_rcv, + IN osm_infr_t* p_infr_rec ) +{ + boolean_t valid = TRUE; + + OSM_LOG_ENTER( p_rcv->p_log, __validate_infr ); + + valid = __validate_ports_access_rights( p_rcv, p_infr_rec ); + if (!valid) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_infr: " + "Invalid Access for InformInfo\n" ); + valid = FALSE; + } + + OSM_LOG_EXIT( p_rcv->p_log ); + return valid; +} + +/********************************************************************** +o13-12.1.1: Confirm a valid request for event subscription by responding +with an InformInfo attribute that is a copy of the data in the +Set(InformInfo) request. +**********************************************************************/ +static void +__osm_infr_rcv_respond( + IN osm_infr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + osm_madw_t* p_resp_madw; + const ib_sa_mad_t* p_sa_mad; + ib_sa_mad_t* p_resp_sa_mad; + ib_inform_info_t* p_resp_infr; + ib_api_status_t status; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_infr_rcv_respond ); + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_infr_rcv_respond: " + "Generating successful InformInfo response\n"); + } + + /* + Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + MAD_BLOCK_SIZE, + &p_madw->mad_addr ); + if ( !p_resp_madw ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_infr_rcv_respond: ERR 4303: " + "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 ); + + /* copy the request InformInfo */ + memcpy( p_resp_sa_mad, p_sa_mad, MAD_BLOCK_SIZE ); + p_resp_sa_mad->method = IB_MAD_METHOD_GET_RESP; + /* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */ + p_resp_sa_mad->sm_key = 0; + + p_resp_infr = (ib_inform_info_t*)ib_sa_mad_get_payload_ptr( p_resp_sa_mad ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + + if ( status != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_infr_rcv_respond: ERR 4304: " + "Unable to send MAD (%s)\n", ib_get_err_str( status ) ); + /* osm_mad_pool_put( p_rcv->p_mad_pool, p_resp_madw ); */ + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_inform_info_rec_by_comp_mask( + IN osm_infr_rcv_t* const p_rcv, + IN const osm_infr_t* const p_infr, + osm_iir_search_ctxt_t* const p_ctxt ) +{ + const ib_inform_info_record_t* p_rcvd_rec = NULL; + ib_net64_t comp_mask; + ib_net64_t portguid; + osm_port_t * p_subscriber_port; + osm_physp_t * p_subscriber_physp; + const osm_physp_t* p_req_physp; + osm_iir_item_t* p_rec_item; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_sa_inform_info_rec_by_comp_mask ); + + 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) + { + if (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) + { + if (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( p_rcv->p_subn, portguid ); + if ( p_subscriber_port == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sa_inform_info_rec_by_comp_mask: ERR 430D: " + "Invalid subscriber port guid: 0x%016" PRIx64 "\n", + cl_ntoh64(portguid) ); + goto Exit; + } + + /* get the subscriber InformInfo physical port */ + p_subscriber_physp = osm_port_get_default_phys_ptr(p_subscriber_port); + /* make sure that the requester and subscriber port can access each other + according to the current partitioning. */ + if (! osm_physp_share_pkey( p_rcv->p_log, p_req_physp, p_subscriber_physp )) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_sa_inform_info_rec_by_comp_mask: " + "requester and subscriber ports don't share pkey\n" ); + goto Exit; + } + + p_rec_item = (osm_iir_item_t*)cl_qlock_pool_get( &p_rcv->pool ); + if( p_rec_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_sa_inform_info_rec_by_comp_mask: ERR 430E: " + "cl_qlock_pool_get failed\n" ); + goto Exit; + } + + memcpy((void *)&p_rec_item->rec, (void *)&p_infr->inform_record, sizeof(ib_inform_info_record_t)); + cl_qlist_insert_tail( p_ctxt->p_list, (cl_list_item_t*)&p_rec_item->pool_item ); + +Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_inform_info_rec_by_comp_mask_cb( + IN cl_list_item_t* const p_list_item, + IN void* context ) +{ + const osm_infr_t* const p_infr = (osm_infr_t *)p_list_item; + osm_iir_search_ctxt_t* const p_ctxt = (osm_iir_search_ctxt_t *)context; + + __osm_sa_inform_info_rec_by_comp_mask( p_ctxt->p_rcv, p_infr, p_ctxt ); +} + +/********************************************************************** +Received a Get(InformInfoRecord) or GetTable(InformInfoRecord) MAD +**********************************************************************/ +static void +osm_infr_rcv_process_get_method( + IN osm_infr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + ib_sa_mad_t* p_rcvd_mad; + const ib_inform_info_record_t* p_rcvd_rec; + ib_inform_info_record_t* p_resp_rec; + cl_qlist_t rec_list; + osm_madw_t* p_resp_madw; + ib_sa_mad_t* p_resp_sa_mad; + uint32_t num_rec, pre_trim_num_rec; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t trim_num_rec; +#endif + uint32_t i, j; + osm_iir_search_ctxt_t context; + osm_iir_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + osm_physp_t* p_req_physp; + + OSM_LOG_ENTER( p_rcv->p_log, osm_infr_rcv_process_get_method ); + + 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(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_infr_rcv_process_get_method: ERR 4309: " + "Cannot find requester physical port\n" ); + goto Exit; + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + osm_dump_inform_info_record( p_rcv->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.p_rcv = p_rcv; + context.p_req_physp = p_req_physp; + + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_infr_rcv_process_get_method: " + "Query Subscriber GID:0x%016" PRIx64 " : 0x%016" PRIx64 "(%02X) Enum:0x%X(%02X)\n", + cl_ntoh64(p_rcvd_rec->subscriber_gid.unicast.prefix), + cl_ntoh64(p_rcvd_rec->subscriber_gid.unicast.interface_id), + (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( p_rcv->p_lock ); + + cl_qlist_apply_func( &p_rcv->p_subn->sa_infr_list, + __osm_sa_inform_info_rec_by_comp_mask_cb, + &context ); + + cl_plock_release( p_rcv->p_lock ); + + num_rec = cl_qlist_count( &rec_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if (p_rcvd_mad->method == IB_MAD_METHOD_GET) + { + if (num_rec == 0) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + if (num_rec > 1) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_infr_rcv_process_get_method: ERR 430A: " + "More than one record for SubnAdmGet (%u)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS); + + /* need to set the mem free ... */ + p_rec_item = (osm_iir_item_t*)cl_qlist_remove_head( &rec_list ); + while( p_rec_item != (osm_iir_item_t*)cl_qlist_end( &rec_list ) ) + { + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_rec_item = (osm_iir_item_t*)cl_qlist_remove_head( &rec_list ); + } + + goto Exit; + } + } + + pre_trim_num_rec = num_rec; +#ifndef VENDOR_RMPP_SUPPORT + /* we limit the number of records to a single packet */ + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_inform_info_record_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_infr_rcv_process_get_method: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_infr_rcv_process_get_method: " + "Returning %u records\n", num_rec ); + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_inform_info_record_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + + if( !p_resp_madw ) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_infr_rcv_process_get_method: ERR 430B: " + "osm_mad_pool_get failed\n" ); + + for( i = 0; i < num_rec; i++ ) + { + p_rec_item = (osm_iir_item_t*)cl_qlist_remove_head( &rec_list ); + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_NO_RESOURCES ); + + goto Exit; + } + + p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_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( p_resp_sa_mad, p_rcvd_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; + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_inform_info_record_t) ); + + p_resp_rec = (ib_inform_info_record_t*)ib_sa_mad_get_payload_ptr( p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + for( i = 0; i < pre_trim_num_rec; i++ ) + { + p_rec_item = (osm_iir_item_t*)cl_qlist_remove_head( &rec_list ); + /* copy only if not trimmed */ + if (i < num_rec) + { + *p_resp_rec = p_rec_item->rec; + /* clear reserved and pad fields in InformInfoRecord */ + for (j = 0; j < 6; j++) + p_resp_rec->reserved[j] = 0; + for (j = 0; j < 4; j++) + p_resp_rec->pad[j] = 0; + } + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_resp_rec++; + } + + CL_ASSERT( cl_is_qlist_empty( &rec_list ) ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + if (status != IB_SUCCESS) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_infr_rcv_process_get_method: ERR 430C: " + "osm_vendor_send status = %s\n", + ib_get_err_str(status)); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************* +Received a Set(InformInfo) MAD +**********************************************************************/ +static void +osm_infr_rcv_process_set_method( + IN osm_infr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + ib_sa_mad_t *p_sa_mad; + ib_inform_info_t *p_recvd_inform_info; + osm_infr_t inform_info_rec; /* actual inform record to be stored for reports */ + osm_infr_t *p_infr; + ib_net32_t qpn; + uint8_t resp_time_val; + ib_api_status_t res; + + OSM_LOG_ENTER( p_rcv->p_log, osm_infr_rcv_process_set_method ); + + 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( p_rcv->p_log, OSM_LOG_DEBUG ) ) + osm_dump_inform_info( p_rcv->p_log, p_recvd_inform_info, OSM_LOG_DEBUG ); +#endif + + /* Grab the lock */ + cl_plock_excl_acquire( p_rcv->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.p_infr_rcv = p_rcv; + + /* update the subscriber GID according to mad address */ + res = osm_get_gid_by_mad_addr( + p_rcv->p_log, + p_rcv->p_subn, + &p_madw->mad_addr, + &inform_info_rec.inform_record.subscriber_gid ); + if ( res != IB_SUCCESS ) + { + cl_plock_release( p_rcv->p_lock ); + + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_infr_rcv_process_set_method: ERR 4308 " + "Subscribe Request from unknown LID: 0x%04X\n", + cl_ntoh16(p_madw->mad_addr.dest_lid) + ); + osm_sa_send_error( p_rcv->p_resp, 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( p_rcv->p_lock ); + + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_infr_rcv_process_set_method: ERR 4308 " + "Invalid subscribe: %d\n", + p_recvd_inform_info->subscribe + ); + osm_sa_send_error( p_rcv->p_resp, 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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_infr_rcv_process_set_method: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_infr_rcv_process_set_method: " + "UnSubscribe Request with QPN: 0x%06X\n", + cl_ntoh32(qpn) + ); + } + + /* If record exists with matching InformInfo */ + p_infr = osm_infr_get_by_rec( p_rcv->p_subn, p_rcv->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( p_rcv, &inform_info_rec ) != TRUE ) + { + cl_plock_release( p_rcv->p_lock ); + + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_infr_rcv_process_set_method: 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( p_rcv->p_resp, 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( p_rcv->p_lock ); + + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_infr_rcv_process_set_method: 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( p_rcv->p_resp, 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( p_rcv->p_subn, p_rcv->p_log, p_infr ); + } + else + { + /* Update the old instance of the osm_infr_t object */ + p_infr->inform_record = inform_info_rec.inform_record; + } + } + else + { + /* We got an UnSubscribe request */ + if (p_infr == NULL) + { + cl_plock_release( p_rcv->p_lock ); + + /* No Such Item - So Error */ + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_infr_rcv_process_set_method: 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( p_rcv->p_resp, 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( p_rcv->p_subn, p_rcv->p_log, p_infr ); + } + } + + cl_plock_release( p_rcv->p_lock ); + + /* send the success response */ + __osm_infr_rcv_respond( p_rcv, p_madw ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************* +**********************************************************************/ +void +osm_infr_rcv_process( + IN osm_infr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + ib_sa_mad_t *p_sa_mad; + + OSM_LOG_ENTER( p_rcv->p_log, osm_infr_rcv_process ); + + 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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_infr_rcv_process: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_sa_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + osm_infr_rcv_process_set_method( p_rcv, p_madw ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************* +**********************************************************************/ +void +osm_infir_rcv_process( + IN osm_infr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + ib_sa_mad_t *p_sa_mad; + + OSM_LOG_ENTER( p_rcv->p_log, osm_infr_rcv_process ); + + 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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_infir_rcv_process: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_sa_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + osm_infr_rcv_process_get_method( p_rcv, p_madw ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_informinfo_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_informinfo_ctrl.c new file mode 100644 index 00000000..94760b6e --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_informinfo_ctrl.c @@ -0,0 +1,154 @@ +/* + * 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: + * Implementation of osm_infr_rcv_ctrl_t. + * This object represents the InformInfo set request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +static void +__osm_infr_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_infr_rcv_process( ((osm_infr_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_infir_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_infir_rcv_process( ((osm_infr_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_infr_rcv_ctrl_construct( + IN osm_infr_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; + p_ctrl->h_disp2 = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_infr_rcv_ctrl_destroy( + IN osm_infr_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp2 ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_infr_rcv_ctrl_init( + IN osm_infr_rcv_ctrl_t* const p_ctrl, + IN osm_infr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_infr_rcv_ctrl_init ); + + osm_infr_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_INFORM_INFO, + __osm_infr_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_infr_rcv_ctrl_init: ERR 1701: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + p_ctrl->h_disp2 = cl_disp_register( + p_disp, + OSM_MSG_MAD_INFORM_INFO_RECORD, + __osm_infir_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp2 == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_infr_rcv_ctrl_init: ERR 1702: " + "Dispatcher registration failed\n" ); + cl_disp_unregister( p_ctrl->h_disp ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_lft_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_lft_record.c new file mode 100644 index 00000000..8034febe --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_lft_record.c @@ -0,0 +1,515 @@ +/* + * 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: + * Implementation of osm_lftr_rcv_t. + * This object represents the LinearForwardingTable Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_LFTR_RCV_POOL_MIN_SIZE 32 +#define OSM_LFTR_RCV_POOL_GROW_SIZE 32 + +typedef struct _osm_lftr_item +{ + cl_pool_item_t pool_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_lftr_rcv_t* p_rcv; + const osm_physp_t* p_req_physp; +} osm_lftr_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void +osm_lftr_rcv_construct( + IN osm_lftr_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_lftr_rcv_destroy( + IN osm_lftr_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_lftr_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_lftr_rcv_init( + IN osm_lftr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status; + + OSM_LOG_ENTER( p_log, osm_lftr_rcv_init ); + + osm_lftr_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + status = cl_qlock_pool_init( &p_rcv->pool, + OSM_LFTR_RCV_POOL_MIN_SIZE, + 0, + OSM_LFTR_RCV_POOL_GROW_SIZE, + sizeof(osm_lftr_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_lftr_rcv_new_lftr( + IN osm_lftr_rcv_t* const p_rcv, + IN const osm_switch_t* const p_sw, + IN cl_qlist_t* const p_list, + IN ib_net16_t const lid, + IN ib_net16_t const block ) +{ + osm_lftr_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_lftr_rcv_new_lftr ); + + p_rec_item = (osm_lftr_item_t*)cl_qlock_pool_get( &p_rcv->pool ); + if( p_rec_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_lftr_rcv_new_lftr: ERR 4402: " + "cl_qlock_pool_get failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_lftr_rcv_new_lftr: " + "New LinearForwardingTable: sw 0x%016" PRIx64 + "\n\t\t\t\tblock 0x%02X lid 0x%02X\n", + cl_ntoh64( osm_node_get_node_guid( p_sw->p_node ) ), + cl_ntoh16( block ), cl_ntoh16( lid ) + ); + } + + memset( &p_rec_item->rec, 0, sizeof(ib_lft_record_t) ); + + p_rec_item->rec.lid = lid; + p_rec_item->rec.block_num = block; + + /* copy the lft block */ + osm_switch_get_fwd_tbl_block( p_sw, cl_ntoh16(block), p_rec_item->rec.lft ); + + cl_qlist_insert_tail( p_list, (cl_list_item_t*)&p_rec_item->pool_item ); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static osm_port_t* +__osm_lftr_get_port_by_guid( + IN osm_lftr_rcv_t* const p_rcv, + IN uint64_t port_guid ) +{ + osm_port_t* p_port; + + CL_PLOCK_ACQUIRE(p_rcv->p_lock); + + p_port = (osm_port_t *)cl_qmap_get(&p_rcv->p_subn->port_guid_tbl, + port_guid); + if (p_port == (osm_port_t *)cl_qmap_end(&p_rcv->p_subn->port_guid_tbl)) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_lftr_get_port_by_guid ERR 4404: " + "Invalid port GUID 0x%016" PRIx64 "\n", + port_guid ); + p_port = NULL; + } + + CL_PLOCK_RELEASE(p_rcv->p_lock); + return p_port; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_lftr_rcv_by_comp_mask( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + const osm_lftr_search_ctxt_t* const p_ctxt = + (osm_lftr_search_ctxt_t *)context; + const osm_switch_t* const p_sw = (osm_switch_t*)p_map_item; + const ib_lft_record_t* const p_rcvd_rec = p_ctxt->p_rcvd_rec; + osm_lftr_rcv_t* const p_rcv = p_ctxt->p_rcv; + 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_lftr_get_port_by_guid( p_rcv, p_sw->p_node->node_info.port_guid ); + if (! p_port) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_lftr_rcv_by_comp_mask: 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 = osm_port_get_default_phys_ptr( p_port ); + if (! p_physp) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_lftr_rcv_by_comp_mask: 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( p_rcv->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( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_lftr_rcv_by_comp_mask: " + "Comparing lid:0x%02X to port lid range: 0x%02X .. 0x%02X\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 */ + if( comp_mask & IB_LFTR_COMPMASK_BLOCK ) + { + max_block = min_block = cl_ntoh16(p_rcvd_rec->block_num); + } + else + { + /* use as many blocks as "in use" */ + min_block = 0; + max_block = osm_switch_get_max_block_id_in_use(p_sw); + } + + /* so we can add these blocks one by one ... */ + for (block = min_block; block <= max_block; block++) + __osm_lftr_rcv_new_lftr( p_rcv, p_sw, p_ctxt->p_list, + osm_port_get_base_lid(p_port), + cl_hton16(block) ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_lftr_rcv_process( + IN osm_lftr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_sa_mad_t* p_rcvd_mad; + const ib_lft_record_t* p_rcvd_rec; + ib_lft_record_t* p_resp_rec; + cl_qlist_t rec_list; + osm_madw_t* p_resp_madw; + ib_sa_mad_t* p_resp_sa_mad; + uint32_t num_rec, pre_trim_num_rec; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t trim_num_rec; +#endif + uint32_t i; + osm_lftr_search_ctxt_t context; + osm_lftr_item_t* p_rec_item; + ib_api_status_t status = IB_SUCCESS; + osm_physp_t* p_req_physp; + + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_lftr_rcv_process ); + + 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( p_rcv->p_log, OSM_LOG_ERROR, + "osm_lftr_rcv_process: ERR 4408: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_rcvd_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_lftr_rcv_process: 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.p_rcv = p_rcv; + context.p_req_physp = p_req_physp; + + cl_plock_acquire( p_rcv->p_lock ); + + /* Go over all switches */ + cl_qmap_apply_func( &p_rcv->p_subn->sw_guid_tbl, + __osm_lftr_rcv_by_comp_mask, + &context ); + + cl_plock_release( p_rcv->p_lock ); + + num_rec = cl_qlist_count( &rec_list ); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if (p_rcvd_mad->method == IB_MAD_METHOD_GET) + { + if (num_rec == 0) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + if (num_rec > 1) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_lftr_rcv_process: ERR 4409: " + "Got more than one record for SubnAdmGet (%u)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS); + + /* need to set the mem free ... */ + p_rec_item = (osm_lftr_item_t*)cl_qlist_remove_head( &rec_list ); + while( p_rec_item != (osm_lftr_item_t*)cl_qlist_end( &rec_list ) ) + { + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_rec_item = (osm_lftr_item_t*)cl_qlist_remove_head( &rec_list ); + } + + goto Exit; + } + } + + pre_trim_num_rec = num_rec; +#ifndef VENDOR_RMPP_SUPPORT + /* we limit the number of records to a single packet */ + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_lft_record_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "osm_lftr_rcv_process: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "osm_lftr_rcv_process: " + "Returning %u records\n", num_rec ); + + if ((p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) && + (num_rec == 0)) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_lft_record_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + + if( !p_resp_madw ) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_lftr_rcv_process: ERR 4410: " + "osm_mad_pool_get failed\n" ); + + for( i = 0; i < num_rec; i++ ) + { + p_rec_item = (osm_lftr_item_t*)cl_qlist_remove_head( &rec_list ); + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + } + + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_NO_RESOURCES ); + + goto Exit; + } + + p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_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( p_resp_sa_mad, p_rcvd_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; + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_lft_record_t) ); + + p_resp_rec = (ib_lft_record_t*)ib_sa_mad_get_payload_ptr( p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + for( i = 0; i < pre_trim_num_rec; i++ ) + { + p_rec_item = (osm_lftr_item_t*)cl_qlist_remove_head( &rec_list ); + /* copy only if not trimmed */ + if (i < num_rec) + { + *p_resp_rec = p_rec_item->rec; + } + cl_qlock_pool_put( &p_rcv->pool, &p_rec_item->pool_item ); + p_resp_rec++; + } + + CL_ASSERT( cl_is_qlist_empty( &rec_list ) ); + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + if (status != IB_SUCCESS) + { + osm_log(p_rcv->p_log, OSM_LOG_ERROR, + "osm_lftr_rcv_process: ERR 4411: " + "osm_vendor_send status = %s\n", + ib_get_err_str(status)); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_lft_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_lft_record_ctrl.c new file mode 100644 index 00000000..c39efe2d --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_lft_record_ctrl.c @@ -0,0 +1,124 @@ +/* + * 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: + * Implementation of osm_lftr_rcv_ctrl_t. + * This object represents the LinearForwardingTable request controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_lftr_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_lftr_rcv_process( ((osm_lftr_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_lftr_rcv_ctrl_construct( + IN osm_lftr_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_lftr_rcv_ctrl_destroy( + IN osm_lftr_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_lftr_rcv_ctrl_init( + IN osm_lftr_rcv_ctrl_t* const p_ctrl, + IN osm_lftr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_lftr_rcv_ctrl_init ); + + osm_lftr_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_LFT_RECORD, + __osm_lftr_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_lftr_rcv_ctrl_init: ERR 4501: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_link_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_link_record.c new file mode 100644 index 00000000..8e242b08 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_link_record.c @@ -0,0 +1,777 @@ +/* + * 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: + * Implementation of osm_lr_rcv_t. + * This object represents the LinkRecord Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.8 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_LR_RCV_POOL_MIN_SIZE 64 +#define OSM_LR_RCV_POOL_GROW_SIZE 64 + +typedef struct _osm_lr_item +{ + cl_pool_item_t pool_item; + ib_link_record_t link_rec; +} osm_lr_item_t; + +/********************************************************************** + **********************************************************************/ +void +osm_lr_rcv_construct( + IN osm_lr_rcv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->lr_pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_lr_rcv_destroy( + IN osm_lr_rcv_t* const p_rcv ) +{ + OSM_LOG_ENTER( p_rcv->p_log, osm_lr_rcv_destroy ); + cl_qlock_pool_destroy( &p_rcv->lr_pool ); + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_lr_rcv_init( + IN osm_lr_rcv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_lr_rcv_init ); + + osm_lr_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + + status = cl_qlock_pool_init( &p_rcv->lr_pool, + OSM_LR_RCV_POOL_MIN_SIZE, + 0, + OSM_LR_RCV_POOL_GROW_SIZE, + sizeof(osm_lr_item_t), + NULL, NULL, NULL ); + + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_lr_rcv_build_physp_link( + IN osm_lr_rcv_t* const p_rcv, + IN const ib_net16_t from_lid, + IN const ib_net16_t to_lid, + IN const uint8_t from_port, + IN const uint8_t to_port, + IN cl_qlist_t* p_list ) +{ + osm_lr_item_t* p_lr_item; + + p_lr_item = (osm_lr_item_t*)cl_qlock_pool_get( &p_rcv->lr_pool ); + if( p_lr_item == NULL ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_lr_rcv_build_physp_link: ERR 1801: " + "Unable to acquire link record\n" + "\t\t\t\tFrom port 0x%u\n" + "\t\t\t\tTo port 0x%u\n" + "\t\t\t\tFrom lid 0x%X\n" + "\t\t\t\tTo lid 0x%X\n", + from_port, to_port, + cl_ntoh16(from_lid), + cl_ntoh16(to_lid) ); + return; + } + + 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, (cl_list_item_t*)&p_lr_item->pool_item ); +} + +/********************************************************************** + **********************************************************************/ +static void +__get_base_lid( + IN const osm_physp_t* p_physp, + OUT uint16_t * p_base_lid ) +{ + if(p_physp->p_node->node_info.node_type == IB_NODE_TYPE_SWITCH) + { + *p_base_lid = + cl_ntoh16( + osm_physp_get_base_lid( + osm_node_get_physp_ptr(p_physp->p_node, 0)) + ); + } + else + { + *p_base_lid = + cl_ntoh16(osm_physp_get_base_lid(p_physp)); + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_lr_rcv_get_physp_link( + IN osm_lr_rcv_t* const p_rcv, + IN const ib_link_record_t* const p_lr, + IN const osm_physp_t* p_src_physp, + IN const osm_physp_t* p_dest_physp, + IN const ib_net64_t comp_mask, + IN cl_qlist_t* const p_list, + IN const osm_physp_t* p_req_physp ) +{ + uint8_t src_port_num; + uint8_t dest_port_num; + ib_net16_t from_base_lid_ho; + ib_net16_t to_base_lid_ho; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_lr_rcv_get_physp_link ); + + /* + If only one end of the link is specified, determine + the other side. + */ + if( p_src_physp ) + { + if( !osm_physp_is_valid( p_src_physp ) ) + goto Exit; + + if( p_dest_physp ) + { + if( !osm_physp_is_valid( p_dest_physp ) ) + goto Exit; + /* + 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; + + if( !osm_physp_is_valid( p_dest_physp ) ) + goto Exit; + } + } + else + { + if( p_dest_physp ) + { + if( !osm_physp_is_valid( p_dest_physp ) ) + goto Exit; + + 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 */ + } + + CL_ASSERT( p_src_physp ); + CL_ASSERT( p_dest_physp ); + CL_ASSERT( osm_physp_is_valid( p_src_physp ) ); + CL_ASSERT( osm_physp_is_valid( p_dest_physp ) ); + + /* 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(p_rcv->p_log, p_src_physp, p_dest_physp)) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_lr_rcv_get_physp_link: " + "Source and Dest PhysPorts do not share PKey\n"); + goto Exit; + } + if (! osm_physp_share_pkey(p_rcv->p_log, p_src_physp, p_req_physp)) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_lr_rcv_get_physp_link: " + "Source and Requester PhysPorts do not share PKey\n"); + goto Exit; + } + if (! osm_physp_share_pkey(p_rcv->p_log, p_req_physp, p_dest_physp) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_lr_rcv_get_physp_link: " + "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; + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_lr_rcv_get_physp_link: " + "Acquiring link record\n" + "\t\t\t\tsrc port 0x%" PRIx64 " (port 0x%X)" + ", dest port 0x%" PRIx64 " (port 0x%X)\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 ); + } + + __get_base_lid(p_src_physp, &from_base_lid_ho); + __get_base_lid(p_dest_physp, &to_base_lid_ho); + + __osm_lr_rcv_build_physp_link(p_rcv, cl_ntoh16(from_base_lid_ho), + cl_ntoh16(to_base_lid_ho), + src_port_num, dest_port_num, p_list); + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_lr_rcv_get_port_links( + IN osm_lr_rcv_t* const p_rcv, + IN const ib_link_record_t* const p_lr, + IN const osm_port_t* p_src_port, + IN const osm_port_t* p_dest_port, + IN const ib_net64_t comp_mask, + IN cl_qlist_t* const p_list, + IN const osm_physp_t* p_req_physp ) +{ + const osm_physp_t* p_src_physp; + const osm_physp_t* p_dest_physp; + const cl_qmap_t* p_port_tbl; + uint8_t port_num; + uint8_t num_ports; + uint8_t dest_num_ports; + uint8_t dest_port_num; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_lr_rcv_get_port_links ); + + 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_port_get_num_physp( p_src_port ); + dest_num_ports = osm_port_get_num_physp( p_dest_port ); + for( port_num = 1; port_num < num_ports; port_num++ ) + { + p_src_physp = osm_port_get_phys_ptr( p_src_port, port_num ); + for( dest_port_num = 1; dest_port_num < dest_num_ports; + dest_port_num++ ) + { + p_dest_physp = osm_port_get_phys_ptr( p_dest_port, + dest_port_num ); + /* both physical ports should be with data */ + if (p_src_physp && p_dest_physp) + __osm_lr_rcv_get_physp_link( p_rcv, 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->physp_tbl_size) + { + p_src_physp = osm_port_get_phys_ptr( p_src_port, port_num ); + if (p_src_physp) + __osm_lr_rcv_get_physp_link( p_rcv, p_lr, p_src_physp, + NULL, comp_mask, p_list, + p_req_physp ); + } + } + else + { + num_ports = osm_port_get_num_physp( p_src_port ); + for( port_num = 1; port_num < num_ports; port_num++ ) + { + p_src_physp = osm_port_get_phys_ptr( p_src_port, port_num ); + if (p_src_physp) + __osm_lr_rcv_get_physp_link( p_rcv, 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->physp_tbl_size ) + { + p_dest_physp = osm_port_get_phys_ptr( + p_dest_port, port_num ); + if (p_dest_physp) + __osm_lr_rcv_get_physp_link( p_rcv, p_lr, NULL, + p_dest_physp, comp_mask, + p_list, p_req_physp ); + } + } + else + { + num_ports = osm_port_get_num_physp( p_dest_port ); + for( port_num = 1; port_num < num_ports; port_num++ ) + { + p_dest_physp = osm_port_get_phys_ptr( + p_dest_port, port_num ); + if (p_dest_physp) + __osm_lr_rcv_get_physp_link( p_rcv, p_lr, NULL, + p_dest_physp, comp_mask, + p_list, p_req_physp ); + } + } + } + else + { + /* + Process the world (recurse once back into this function). + */ + p_port_tbl = &p_rcv->p_subn->port_guid_tbl; + p_src_port = (osm_port_t*)cl_qmap_head( p_port_tbl ); + + while( p_src_port != (osm_port_t*)cl_qmap_end( p_port_tbl ) ) + { + __osm_lr_rcv_get_port_links( p_rcv, p_lr, p_src_port, + NULL, comp_mask, p_list, + p_req_physp ); + + p_src_port = (osm_port_t*)cl_qmap_next( + &p_src_port->map_item ); + } + } + } + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + Returns the SA status to return to the client. + **********************************************************************/ +static ib_net16_t +__osm_lr_rcv_get_end_points( + IN osm_lr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + OUT const osm_port_t** const pp_src_port, + OUT const osm_port_t** const pp_dest_port ) +{ + const ib_link_record_t* p_lr; + const ib_sa_mad_t* p_sa_mad; + ib_net64_t comp_mask; + ib_api_status_t status; + ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_lr_rcv_get_end_points ); + + /* + Determine what fields are valid and then get a pointer + to the source and destination port objects, if possible. + */ + p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw ); + p_lr = (ib_link_record_t*)ib_sa_mad_get_payload_ptr( p_sa_mad ); + + comp_mask = p_sa_mad->comp_mask; + *pp_src_port = NULL; + *pp_dest_port = NULL; + + if( p_sa_mad->comp_mask & IB_LR_COMPMASK_FROM_LID ) + { + status = osm_get_port_by_base_lid( p_rcv->p_subn, + p_lr->from_lid, + pp_src_port ); + + if( (status != IB_SUCCESS) || (*pp_src_port == NULL) ) + { + /* + This 'error' is the client's fault (bad lid) so + don't enter it as an error in our own log. + Return an error response to the client. + */ + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_lr_rcv_get_end_points: " + "No source port with LID = 0x%X\n", + cl_ntoh16( p_lr->from_lid ) ); + + sa_status = IB_SA_MAD_STATUS_NO_RECORDS; + goto Exit; + } + } + + if( p_sa_mad->comp_mask & IB_LR_COMPMASK_TO_LID ) + { + status = osm_get_port_by_base_lid( p_rcv->p_subn, + p_lr->to_lid, + pp_dest_port ); + + if( (status != IB_SUCCESS) || (*pp_dest_port == NULL) ) + { + /* + This 'error' is the client's fault (bad lid) so + don't enter it as an error in our own log. + Return an error response to the client. + */ + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_lr_rcv_get_end_points: " + "No dest port with LID = 0x%X\n", + cl_ntoh16( p_lr->to_lid ) ); + + sa_status = IB_SA_MAD_STATUS_NO_RECORDS; + goto Exit; + } + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return( sa_status ); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_lr_rcv_respond( + IN osm_lr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + IN cl_qlist_t* const p_list ) +{ + osm_madw_t* p_resp_madw; + const ib_sa_mad_t* p_sa_mad; + ib_sa_mad_t* p_resp_sa_mad; + size_t num_rec, num_copied; +#ifndef VENDOR_RMPP_SUPPORT + size_t trim_num_rec; +#endif + ib_link_record_t* p_resp_lr; + ib_api_status_t status; + osm_lr_item_t* p_lr_item; + const ib_sa_mad_t* p_rcvd_mad = osm_madw_get_sa_mad_ptr( p_madw ); + + OSM_LOG_ENTER( p_rcv->p_log, __osm_lr_rcv_respond ); + + num_rec = cl_qlist_count( p_list ); + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error ! + */ + if ( (p_rcvd_mad->method == IB_MAD_METHOD_GET) && + (num_rec > 1)) { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_lr_rcv_respond: ERR 1806: " + "Got more than one record for SubnAdmGet (%zu)\n", + num_rec ); + osm_sa_send_error( p_rcv->p_resp, p_madw, + IB_SA_MAD_STATUS_TOO_MANY_RECORDS ); + + /* need to set the mem free ... */ + p_lr_item = (osm_lr_item_t*)cl_qlist_remove_head( p_list ); + while( p_lr_item != (osm_lr_item_t*)cl_qlist_end( p_list ) ) + { + cl_qlock_pool_put( &p_rcv->lr_pool, &p_lr_item->pool_item ); + p_lr_item = (osm_lr_item_t*)cl_qlist_remove_head( p_list ); + } + + goto Exit; + } + +#ifndef VENDOR_RMPP_SUPPORT + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_link_record_t); + if (trim_num_rec < num_rec) + { + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__osm_lr_rcv_respond: " + "Number of records:%u trimmed to:%u to fit in one MAD\n", + num_rec, trim_num_rec ); + num_rec = trim_num_rec; + } +#endif + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__osm_lr_rcv_respond: " + "Generating response with %zu records", num_rec ); + } + + /* + Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, + p_madw->h_bind, + num_rec * sizeof(ib_link_record_t) + IB_SA_MAD_HDR_SIZE, + &p_madw->mad_addr ); + if( !p_resp_madw ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_lr_rcv_respond: ERR 1802: " + "Unable to allocate MAD\n" ); + /* Release the quick pool items */ + p_lr_item = (osm_lr_item_t*)cl_qlist_remove_head( p_list ); + while( p_lr_item != (osm_lr_item_t*)cl_qlist_end( p_list ) ) + { + cl_qlock_pool_put( &p_rcv->lr_pool, &p_lr_item->pool_item ); + p_lr_item = (osm_lr_item_t*)cl_qlist_remove_head( p_list ); + } + + 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 ); + + /* Copy the header from the request to response */ + memcpy( p_resp_sa_mad, p_sa_mad, IB_SA_MAD_HDR_SIZE ); + p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK; + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_link_record_t) ); + /* C15-0.1.5 - always return SM_Key = 0 (table table 185 p 884) */ + p_resp_sa_mad->sm_key = 0; + +#ifndef VENDOR_RMPP_SUPPORT + /* we support only one packet RMPP - so we will set the first and + last flags for gettable */ + if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + { + p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_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 (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + p_resp_lr = (ib_link_record_t*)ib_sa_mad_get_payload_ptr( p_resp_sa_mad ); + + if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0)) + { + p_resp_sa_mad->status = IB_SA_MAD_STATUS_NO_RECORDS; + memset( p_resp_lr, 0, sizeof(*p_resp_lr) ); + } + else + { + p_lr_item = (osm_lr_item_t*)cl_qlist_remove_head( p_list ); + /* we need to track the number of copied items so we can + * stop the copy - but clear them all + */ + num_copied = 0; + while( p_lr_item != (osm_lr_item_t*)cl_qlist_end( p_list ) ) + { + /* Copy the Link Records from the list into the MAD */ + /* only if we did not go over the mad size (since we might trimmed it) */ + if (num_copied < num_rec) + { + *p_resp_lr = p_lr_item->link_rec; + num_copied++; + } + cl_qlock_pool_put( &p_rcv->lr_pool, &p_lr_item->pool_item ); + p_resp_lr++; + p_lr_item = (osm_lr_item_t*)cl_qlist_remove_head( p_list ); + } + } + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + if (status != IB_SUCCESS) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_lr_rcv_respond: ERR 1803: " + "Unable to send MAD (%s)\n", ib_get_err_str( status ) ); + /* osm_mad_pool_put( p_rcv->p_mad_pool, p_resp_madw ); */ + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_lr_rcv_process( + IN osm_lr_rcv_t* const p_rcv, + IN const osm_madw_t* const p_madw ) +{ + const ib_link_record_t* p_lr; + const ib_sa_mad_t* p_sa_mad; + const osm_port_t* p_src_port; + const osm_port_t* p_dest_port; + cl_qlist_t lr_list; + ib_net16_t sa_status; + osm_physp_t* p_req_physp; + + OSM_LOG_ENTER( p_rcv->p_log, osm_lr_rcv_process ); + + CL_ASSERT( p_madw ); + + p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw ); + p_lr = (ib_link_record_t*)ib_sa_mad_get_payload_ptr( p_sa_mad ); + + CL_ASSERT( p_sa_mad->attr_id == IB_MAD_ATTR_LINK_RECORD ); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if ( (p_sa_mad->method != IB_MAD_METHOD_GET) && + (p_sa_mad->method != IB_MAD_METHOD_GETTABLE)) { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_lr_rcv_process: ERR 1804: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str( p_sa_mad->method ) ); + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR ); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(p_rcv->p_log, + p_rcv->p_subn, + osm_madw_get_mad_addr_ptr(p_madw) ); + if (p_req_physp == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_lr_rcv_process: ERR 1805: " + "Cannot find requester physical port\n" ); + goto Exit; + } + + if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) ) + osm_dump_link_record( p_rcv->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( p_rcv->p_lock ); + + sa_status = __osm_lr_rcv_get_end_points( p_rcv, p_madw, + &p_src_port, &p_dest_port ); + + if( sa_status == IB_SA_MAD_STATUS_SUCCESS ) + { + __osm_lr_rcv_get_port_links( p_rcv, p_lr, p_src_port, p_dest_port, + p_sa_mad->comp_mask, &lr_list, p_req_physp ); + } + + cl_plock_release( p_rcv->p_lock ); + + if( (cl_qlist_count( &lr_list ) == 0) && + (p_sa_mad->method == IB_MAD_METHOD_GET) ) + { + osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS ); + goto Exit; + } + + __osm_lr_rcv_respond( p_rcv, p_madw, &lr_list ); + + Exit: + + OSM_LOG_EXIT( p_rcv->p_log ); +} + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_link_record_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_link_record_ctrl.c new file mode 100644 index 00000000..ee517abf --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_link_record_ctrl.c @@ -0,0 +1,128 @@ +/* + * 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: + * Implementation of osm_lr_rcv_ctrl_t. + * This object represents the link record controller object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.5 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +__osm_lr_rcv_ctrl_disp_callback( + IN void *context, + IN void *p_data ) +{ + /* ignore return status when invoked via the dispatcher */ + osm_lr_rcv_process( ((osm_lr_rcv_ctrl_t*)context)->p_rcv, + (osm_madw_t*)p_data ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_lr_rcv_ctrl_construct( + IN osm_lr_rcv_ctrl_t* const p_ctrl ) +{ + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_lr_rcv_ctrl_destroy( + IN osm_lr_rcv_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_lr_rcv_ctrl_init( + IN osm_lr_rcv_ctrl_t* const p_ctrl, + IN osm_lr_rcv_t* const p_rcv, + IN osm_log_t* const p_log, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_lr_rcv_ctrl_init ); + + osm_lr_rcv_ctrl_construct( p_ctrl ); + p_ctrl->p_log = p_log; + p_ctrl->p_rcv = p_rcv; + p_ctrl->p_disp = p_disp; + + p_ctrl->h_disp = cl_disp_register( + p_disp, + OSM_MSG_MAD_LINK_RECORD, + __osm_lr_rcv_ctrl_disp_callback, + p_ctrl ); + + if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE ) + { + osm_log( p_log, OSM_LOG_ERROR, + "osm_lr_rcv_ctrl_init: ERR 1901: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + + + diff --git a/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mad_ctrl.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mad_ctrl.c new file mode 100644 index 00000000..55c10f8e --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mad_ctrl.c @@ -0,0 +1,651 @@ +/* + * 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: + * Implementation of osm_sa_mad_ctrl_t. + * This object is part of the SA object. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.7 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/****f* opensm: SA/__osm_sa_mad_ctrl_disp_done_callback + * NAME + * __osm_sa_mad_ctrl_disp_done_callback + * + * DESCRIPTION + * This function is the Dispatcher callback that indicates + * a received MAD has been processed by the recipient. + * + * SYNOPSIS + */ +static void +__osm_sa_mad_ctrl_disp_done_callback( + IN void* context, + IN void* p_data ) +{ + osm_sa_mad_ctrl_t* const p_ctrl = (osm_sa_mad_ctrl_t*)context; + osm_madw_t* const p_madw = (osm_madw_t*)p_data; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sa_mad_ctrl_disp_done_callback ); + + CL_ASSERT( p_madw ); + /* + Return the MAD & wrapper to the pool. + */ + osm_mad_pool_put( p_ctrl->p_mad_pool, p_madw ); + OSM_LOG_EXIT( p_ctrl->p_log ); +} +/************/ + +/****f* opensm: SA/__osm_sa_mad_ctrl_process + * NAME + * __osm_sa_mad_ctrl_process + * + * DESCRIPTION + * This function handles known methods for received MADs. + * + * SYNOPSIS + */ +static void +__osm_sa_mad_ctrl_process( + IN osm_sa_mad_ctrl_t* const p_ctrl, + IN osm_madw_t *p_madw ) +{ + ib_sa_mad_t* p_sa_mad; + cl_status_t status; + cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE; + uint64_t last_dispatched_msg_queue_time_msec; + uint32_t num_messages; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sa_mad_ctrl_process ); + + /* + 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, + "__osm_sa_mad_ctrl_process: " + /* "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, + "__osm_sa_mad_ctrl_process: 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, + "__osm_sa_mad_ctrl_process: " + "Posting Dispatcher message %s\n", + osm_get_disp_msg_str( msg_id ) ); + + status = cl_disp_post( p_ctrl->h_disp, + msg_id, + p_madw, + __osm_sa_mad_ctrl_disp_done_callback, + p_ctrl ); + + if( status != CL_SUCCESS ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sa_mad_ctrl_process: ERR 1A02: " + "Dispatcher post message failed (%s) for attribute = 0x%X\n", + CL_STATUS_MSG( status ), + cl_ntoh16( p_sa_mad->attr_id ) ); + + osm_mad_pool_put( p_ctrl->p_mad_pool, p_madw ); + goto Exit; + } + } + else + { + /* + There is an unknown MAD attribute type for which there is + no recipient. Simply retire the MAD here. + */ + osm_mad_pool_put( p_ctrl->p_mad_pool, p_madw ); + } + + Exit: + OSM_LOG_EXIT( p_ctrl->p_log ); +} +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* opensm: SA/__osm_sa_mad_ctrl_rcv_callback + * NAME + * __osm_sa_mad_ctrl_rcv_callback + * + * DESCRIPTION + * This is the callback from the transport layer for received MADs. + * + * SYNOPSIS + */ +static void +__osm_sa_mad_ctrl_rcv_callback( + IN osm_madw_t *p_madw, + IN void *bind_context, + IN osm_madw_t *p_req_madw ) +{ + osm_sa_mad_ctrl_t* p_ctrl = (osm_sa_mad_ctrl_t*)bind_context; + ib_sa_mad_t* p_sa_mad; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sa_mad_ctrl_rcv_callback ); + + CL_ASSERT( p_madw ); + + /* + A MAD was received from the wire, possibly in response to a request. + */ + cl_atomic_inc( &p_ctrl->p_stats->qp1_mads_rcvd ); + + if( osm_log_is_active( p_ctrl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_DEBUG, + "__osm_sa_mad_ctrl_rcv_callback: " + "%u QP1 MADs received\n", + p_ctrl->p_stats->qp1_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 ) + { + osm_log( p_ctrl->p_log, OSM_LOG_VERBOSE, + "__osm_sa_mad_ctrl_rcv_callback: " + "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 ) + { + osm_log( p_ctrl->p_log, OSM_LOG_VERBOSE, + "__osm_sa_mad_ctrl_rcv_callback: " + "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.sm_key)) { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sa_mad_ctrl_rcv_callback: 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.sm_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, + "__osm_sa_mad_ctrl_rcv_callback: " + "Received Report Repress. Retiring the transaction\n"); + + if (p_req_madw) + osm_mad_pool_put( p_ctrl->p_mad_pool, p_req_madw ); + osm_mad_pool_put( p_ctrl->p_mad_pool, p_madw ); + + break; + + case IB_MAD_METHOD_GET: + case IB_MAD_METHOD_GETTABLE: +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + case IB_MAD_METHOD_GETMULTI: +#endif + case IB_MAD_METHOD_SET: + case IB_MAD_METHOD_DELETE: + __osm_sa_mad_ctrl_process( p_ctrl, p_madw ); + break; + + default: + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sa_mad_ctrl_rcv_callback: ERR 1A05: " + "Unsupported method = 0x%X\n", + p_sa_mad->method ); + osm_mad_pool_put( p_ctrl->p_mad_pool, p_madw ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_ctrl->p_log ); +} +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* opensm: SA/__osm_sa_mad_ctrl_send_err_callback + * NAME + * __osm_sa_mad_ctrl_send_err_callback + * + * DESCRIPTION + * This is the callback from the transport layer for send errors + * on MADs that were expecting a response. + * + * SYNOPSIS + */ +void +__osm_sa_mad_ctrl_send_err_callback( + IN void *bind_context, + IN osm_madw_t *p_madw ) +{ + osm_sa_mad_ctrl_t* p_ctrl = (osm_sa_mad_ctrl_t*)bind_context; + cl_status_t status; + + OSM_LOG_ENTER( p_ctrl->p_log, __osm_sa_mad_ctrl_send_err_callback ); + + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sa_mad_ctrl_send_err_callback: ERR 1A06: " + "MAD transaction completed in error\n" ); + + /* + We should never be here since the SA never originates a request. + Unless we generated a Report(Notice) + */ + + CL_ASSERT( p_madw ); + + /* + An error occurred. No response was received to a request MAD. + Retire the original request MAD. + */ + + osm_dump_sa_mad(p_ctrl->p_log, osm_madw_get_sa_mad_ptr( p_madw ), + OSM_LOG_ERROR ); + + /* __osm_sm_mad_ctrl_update_wire_stats( p_ctrl ); */ + + if( osm_madw_get_err_msg( p_madw ) != CL_DISP_MSGID_NONE ) + { + if( osm_log_is_active( p_ctrl->p_log, OSM_LOG_DEBUG ) ) + { + osm_log( p_ctrl->p_log, OSM_LOG_DEBUG, + "__osm_sa_mad_ctrl_send_err_callback: " + "Posting Dispatcher message %s\n", + osm_get_disp_msg_str( osm_madw_get_err_msg( p_madw ) ) ); + } + + status = cl_disp_post( p_ctrl->h_disp, + osm_madw_get_err_msg( p_madw ), + p_madw, + __osm_sa_mad_ctrl_disp_done_callback, + p_ctrl ); + if( status != CL_SUCCESS ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "__osm_sa_mad_ctrl_send_err_callback: ERR 1A07: " + "Dispatcher post message failed (%s)\n", + CL_STATUS_MSG( status ) ); + } + } + else + { + /* + No error message was provided, just retire the MAD. + */ + osm_mad_pool_put( p_ctrl->p_mad_pool, p_madw ); + } + + OSM_LOG_EXIT( p_ctrl->p_log ); +} +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/********************************************************************** + **********************************************************************/ +void +osm_sa_mad_ctrl_construct( + IN osm_sa_mad_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + memset( p_ctrl, 0, sizeof(*p_ctrl) ); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void +osm_sa_mad_ctrl_destroy( + IN osm_sa_mad_ctrl_t* const p_ctrl ) +{ + CL_ASSERT( p_ctrl ); + cl_disp_unregister( p_ctrl->h_disp ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sa_mad_ctrl_init( + IN osm_sa_mad_ctrl_t* const p_ctrl, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_vendor_t* const p_vendor, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN osm_stats_t* const p_stats, + IN cl_dispatcher_t* const p_disp ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_sa_mad_ctrl_init ); + + osm_sa_mad_ctrl_construct( p_ctrl ); + + 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->p_resp = p_resp; + + 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, + "osm_sa_mad_ctrl_init: ERR 1A08: " + "Dispatcher registration failed\n" ); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sa_mad_ctrl_bind( + IN osm_sa_mad_ctrl_t* const p_ctrl, + IN const ib_net64_t port_guid ) +{ + osm_bind_info_t bind_info; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_ctrl->p_log, osm_sa_mad_ctrl_bind ); + + if( p_ctrl->h_bind != OSM_BIND_INVALID_HANDLE ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "osm_sa_mad_ctrl_bind: ERR 1A09: " + "Multiple binds not allowed\n" ); + status = IB_ERROR; + goto Exit; + } + + bind_info.class_version = 2; + bind_info.is_responder = TRUE; + bind_info.is_report_processor = FALSE; + bind_info.is_trap_processor = FALSE; + bind_info.mad_class = IB_MCLASS_SUBN_ADM; + bind_info.port_guid = port_guid; + bind_info.recv_q_size = OSM_SM_DEFAULT_QP1_RCV_SIZE; + bind_info.send_q_size = OSM_SM_DEFAULT_QP1_SEND_SIZE; + + osm_log( p_ctrl->p_log, OSM_LOG_VERBOSE, + "osm_sa_mad_ctrl_bind: " + "Binding to port GUID 0x%" PRIx64 "\n", + cl_ntoh64( port_guid ) ); + + p_ctrl->h_bind = osm_vendor_bind( p_ctrl->p_vendor, + &bind_info, + p_ctrl->p_mad_pool, + __osm_sa_mad_ctrl_rcv_callback, + __osm_sa_mad_ctrl_send_err_callback, + p_ctrl ); + + if( p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE ) + { + status = IB_ERROR; + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "osm_sa_mad_ctrl_bind: ERR 1A10: " + "Vendor specific bind failed (%s)\n", + ib_get_err_str(status) ); + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_ctrl->p_log ); + return( status ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sa_mad_ctrl_unbind( + IN osm_sa_mad_ctrl_t* const p_ctrl) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_ctrl->p_log, osm_sa_mad_ctrl_unbind ); + + if( p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE ) + { + osm_log( p_ctrl->p_log, OSM_LOG_ERROR, + "osm_sa_mad_ctrl_unbind: 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-1/ulp/opensm/user/opensm/osm_sa_mcmember_record.c b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mcmember_record.c new file mode 100644 index 00000000..e5875d12 --- /dev/null +++ b/branches/WOF2-1/ulp/opensm/user/opensm/osm_sa_mcmember_record.c @@ -0,0 +1,2383 @@ +/* + * 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: + * Implementation of osm_mcmr_recv_t. + * This object represents the MCMemberRecord Receiver object. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.15 $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_MCMR_RCV_POOL_MIN_SIZE 32 +#define OSM_MCMR_RCV_POOL_GROW_SIZE 32 + +typedef struct _osm_mcmr_item +{ + cl_pool_item_t pool_item; + ib_member_rec_t rec; +} osm_mcmr_item_t; + +typedef struct osm_sa_mcmr_search_ctxt { + const ib_member_rec_t *p_mcmember_rec; + osm_mgrp_t *p_mgrp; + osm_mcmr_recv_t *p_rcv; + cl_qlist_t *p_list; /* hold results */ + ib_net64_t comp_mask; + const osm_physp_t* p_req_physp; + boolean_t trusted_req; +} osm_sa_mcmr_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void +osm_mcmr_rcv_construct( + IN osm_mcmr_recv_t* const p_rcv ) +{ + memset( p_rcv, 0, sizeof(*p_rcv) ); + cl_qlock_pool_construct( &p_rcv->pool ); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcmr_rcv_destroy( + IN osm_mcmr_recv_t* const p_rcv ) +{ + CL_ASSERT( p_rcv ); + + OSM_LOG_ENTER( p_rcv->p_log, osm_mcmr_rcv_destroy ); + + cl_qlock_pool_destroy( &p_rcv->pool ); + + OSM_LOG_EXIT( p_rcv->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mcmr_rcv_init( + IN osm_sm_t * const p_sm, + IN osm_mcmr_recv_t* const p_rcv, + IN osm_sa_resp_t* const p_resp, + IN osm_mad_pool_t* const p_mad_pool, + IN osm_subn_t* const p_subn, + IN osm_log_t* const p_log, + IN cl_plock_t* const p_lock ) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER( p_log, osm_mcmr_rcv_init ); + + osm_mcmr_rcv_construct( p_rcv ); + + p_rcv->p_log = p_log; + p_rcv->p_subn = p_subn; + p_rcv->p_sm = p_sm; + p_rcv->p_lock = p_lock; + p_rcv->p_resp = p_resp; + p_rcv->p_mad_pool = p_mad_pool; + p_rcv->mlid_ho = 0xC000; + + status = cl_qlock_pool_init( &p_rcv->pool, + OSM_MCMR_RCV_POOL_MIN_SIZE, + 0, + OSM_MCMR_RCV_POOL_GROW_SIZE, + sizeof(osm_mcmr_item_t), + NULL, NULL, NULL ); + if (status != CL_SUCCESS) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "osm_mcmr_rcv_init: ERR 1B02: " + "qlock pool init failed (%d)\n", + status ); + } + OSM_LOG_EXIT( p_rcv->p_log ); + return( status ); +} + +/********************************************************************** + A search function that compares the given mgrp with the search context + if there is a match by mgid the p_mgrp is copied to the search context + p_mgrp component + + Inputs: + p_map_item - which is part of a mgrp object + context - points to the osm_sa_mcmr_search_ctxt_t including the mgid + looked for and the result p_mgrp +**********************************************************************/ +static void +__search_mgrp_by_mgid( + IN cl_map_item_t* const p_map_item, + IN void* context ) +{ + osm_mgrp_t* p_mgrp = (osm_mgrp_t*)p_map_item; + osm_sa_mcmr_search_ctxt_t *p_ctxt = (osm_sa_mcmr_search_ctxt_t *) context; + const ib_member_rec_t *p_recvd_mcmember_rec; + osm_mcmr_recv_t *p_rcv; + + p_recvd_mcmember_rec = p_ctxt->p_mcmember_rec; + p_rcv = p_ctxt->p_rcv; + + /* ignore groups marked for deletion */ + if (p_mgrp->to_be_deleted) + return; + + /* compare entire MGID so different scope will not sneak in for + the same MGID */ + if (memcmp(&p_mgrp->mcmember_rec.mgid, + &p_recvd_mcmember_rec->mgid, + sizeof(ib_gid_t))) + return; + + if (p_ctxt->p_mgrp) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__search_mgrp_by_mgid: ERR 1B03: " + "Multiple MC groups for same MGID\n" ); + return; + } + + p_ctxt->p_mgrp = p_mgrp; + +} + +/********************************************************************** + Look for a MGRP in the mgrp_mlid_tbl by mlid +**********************************************************************/ +static osm_mgrp_t * +__get_mgrp_by_mlid( + IN osm_mcmr_recv_t* const p_rcv, + IN ib_net16_t const mlid) +{ + cl_map_item_t *map_item; + + map_item = cl_qmap_get(&p_rcv->p_subn->mgrp_mlid_tbl, mlid); + if (map_item == cl_qmap_end(&p_rcv->p_subn->mgrp_mlid_tbl)) + { + return NULL; + } + return (osm_mgrp_t *)map_item; + +} + +/********************************************************************** +Look for a MGRP in the mgrp_mlid_tbl by mgid +***********************************************************************/ +static ib_api_status_t +__get_mgrp_by_mgid( + IN osm_mcmr_recv_t* const p_rcv, + IN ib_member_rec_t* p_recvd_mcmember_rec, + OUT osm_mgrp_t **pp_mgrp) +{ + osm_sa_mcmr_search_ctxt_t mcmr_search_context; + + mcmr_search_context.p_mcmember_rec = p_recvd_mcmember_rec; + mcmr_search_context.p_rcv = p_rcv; + mcmr_search_context.p_mgrp = NULL; + + cl_qmap_apply_func( &p_rcv->p_subn->mgrp_mlid_tbl, + __search_mgrp_by_mgid, + &mcmr_search_context); + + if (mcmr_search_context.p_mgrp == NULL) + { + return IB_NOT_FOUND; + } + + *pp_mgrp = mcmr_search_context.p_mgrp; + return IB_SUCCESS; +} + +/********************************************************************* +Copy certain fields between two mcmember records +used during the process of join request to copy data from the mgrp to the +port record. +**********************************************************************/ +static inline void +__copy_from_create_mc_rec( + IN ib_member_rec_t * const dest, + IN const ib_member_rec_t *const src) +{ + dest->qkey = src->qkey; + dest->mlid = src->mlid; + dest->tclass = src->tclass; + dest->pkey = src->pkey; + dest->sl_flow_hop = src->sl_flow_hop; + dest->mtu = src->mtu; + dest->rate = src->rate; + dest->pkt_life = src->pkt_life; +} + +/********************************************************************* +Return an mlid to the pool of free mlids. +But this implementation is not a pool - it is simply scanning through +the MGRP database for unused mlids... +*********************************************************************/ +static void +__free_mlid( + IN osm_mcmr_recv_t* const p_rcv, + IN uint16_t mlid) +{ + UNUSED_PARAM(p_rcv); + UNUSED_PARAM(mlid); +} + +/********************************************************************* +Get a new unused mlid by scanning all the used ones in the subnet. +TODO: Implement a more scalable - O(1) solution based on pool of +available mlids. +**********************************************************************/ +static ib_net16_t +__get_new_mlid( + IN osm_mcmr_recv_t* const p_rcv, + IN ib_net16_t requested_mlid) +{ + osm_subn_t *p_subn = p_rcv->p_subn; + osm_mgrp_t *p_mgrp; + uint8_t *used_mlids_array; + uint16_t idx; + uint16_t mlid; /* the result */ + uint16_t max_num_mlids; + + OSM_LOG_ENTER(p_rcv->p_log, __get_new_mlid); + + if (requested_mlid && cl_ntoh16(requested_mlid) >= IB_LID_MCAST_START_HO && + cl_ntoh16(requested_mlid) < p_subn->max_multicast_lid_ho && + cl_qmap_get(&p_subn->mgrp_mlid_tbl, requested_mlid) == + cl_qmap_end(&p_subn->mgrp_mlid_tbl) ) { + mlid = cl_ntoh16(requested_mlid); + goto Exit; + } + + /* If MCGroups table empty, first return the min mlid */ + p_mgrp = (osm_mgrp_t*)cl_qmap_head( &p_subn->mgrp_mlid_tbl ); + if (p_mgrp == (osm_mgrp_t*)cl_qmap_end( &p_subn->mgrp_mlid_tbl )) + { + mlid = IB_LID_MCAST_START_HO; + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__get_new_mlid: " + "No multicast groups found using minimal mlid:0x%04X\n", + mlid ); + goto Exit; + } + + max_num_mlids = + p_rcv->p_subn->max_multicast_lid_ho - IB_LID_MCAST_START_HO; + + /* track all used mlids in the array (by mlid index) */ + used_mlids_array = + (uint8_t *)malloc(sizeof(uint8_t)*max_num_mlids); + if (used_mlids_array) + memset(used_mlids_array, 0, sizeof(uint8_t)*max_num_mlids); + if (!used_mlids_array) + return 0; + + /* scan all available multicast groups in the DB and fill in the table */ + while( p_mgrp != (osm_mgrp_t*)cl_qmap_end( &p_subn->mgrp_mlid_tbl ) ) + { + /* ignore mgrps marked for deletion */ + if (p_mgrp->to_be_deleted == FALSE) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__get_new_mlid: " + "Found mgrp with lid:0x%X MGID: 0x%016" PRIx64 " : " + "0x%016" PRIx64 "\n", + cl_ntoh16( p_mgrp->mlid), + cl_ntoh64( p_mgrp->mcmember_rec.mgid.unicast.prefix ), + cl_ntoh64( p_mgrp->mcmember_rec.mgid.unicast.interface_id ) ); + + /* Map in table */ + if (cl_ntoh16(p_mgrp->mlid) > p_rcv->p_subn->max_multicast_lid_ho) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__get_new_mlid: ERR 1B27: " + "Found mgrp with mlid:0x%04X > max allowed mlid:0x%04X\n", + cl_ntoh16(p_mgrp->mlid), + max_num_mlids + IB_LID_MCAST_START_HO ); + } + else + { + used_mlids_array[cl_ntoh16(p_mgrp->mlid) - IB_LID_MCAST_START_HO] = 1; + } + } + p_mgrp = (osm_mgrp_t*)cl_qmap_next( &p_mgrp->map_item ); + } + + /* Find "mlid holes" in the mgrp table */ + for (idx = 0; + (idx < max_num_mlids) && (used_mlids_array[idx] == 1); + idx++); + + /* did it go above the maximal mlid allowed */ + if ( idx < max_num_mlids ) + { + mlid = idx + IB_LID_MCAST_START_HO; + osm_log( p_rcv->p_log, OSM_LOG_VERBOSE, + "__get_new_mlid: " + "Found available mlid:0x%04X at idx:%u\n", + mlid, idx ); + } + else + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__get_new_mlid: ERR 1B23: " + "All available:%u mlids are taken\n", + max_num_mlids ); + mlid = 0; + } + + free(used_mlids_array); + + Exit: + OSM_LOG_EXIT(p_rcv->p_log); + return cl_hton16(mlid); +} + +/********************************************************************* +This procedure is only invoked to cleanup an INTERMEDIATE mgrp. +If there is only one port on the mgrp it means that the current +request was the only member and the group is not really needed. So we +silently drop it. Since it was an intermediate group no need to +re-route it. +**********************************************************************/ +static void +__cleanup_mgrp( + IN osm_mcmr_recv_t* const p_rcv, + IN ib_net16_t const mlid) +{ + osm_mgrp_t *p_mgrp; + + p_mgrp = __get_mgrp_by_mlid(p_rcv, mlid); + if(p_mgrp) + { + /* Remove MGRP only if osm_mcm_port_t count is 0 and + * Not a well known group + */ + if(cl_is_qmap_empty(&p_mgrp->mcm_port_tbl) && + (p_mgrp->well_known == FALSE)) + { + cl_qmap_remove_item(&p_rcv->p_subn->mgrp_mlid_tbl, + (cl_map_item_t *)p_mgrp ); + osm_mgrp_destroy(p_mgrp); + } + } +} + +/********************************************************************* +Add a port to the group. Calculating its PROXY_JOIN by the Port and +requester gids. +**********************************************************************/ +static ib_api_status_t +__add_new_mgrp_port( + IN osm_mcmr_recv_t *p_rcv, + IN osm_mgrp_t *p_mgrp, + IN ib_member_rec_t *p_recvd_mcmember_rec, + IN osm_mad_addr_t *p_mad_addr, + OUT osm_mcm_port_t **pp_mcmr_port) +{ + boolean_t proxy_join; + ib_gid_t requester_gid; + ib_api_status_t res; + + /* set the proxy_join if the requester gid is not identical to the + joined gid */ + res = osm_get_gid_by_mad_addr( p_rcv->p_log, + p_rcv->p_subn, + p_mad_addr, &requester_gid ); + if ( res != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__add_new_mgrp_port: ERR 1B29: " + "Could not find GID for requester\n" ); + + return IB_INVALID_PARAMETER; + } + + if (!memcmp(&p_recvd_mcmember_rec->port_gid, &requester_gid, + sizeof(ib_gid_t))) + { + proxy_join = FALSE; + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__add_new_mgrp_port: " + "Create new port with proxy_join FALSE\n" ); + } + else + { + /* The port is not the one specified in PortGID. + The check that the requester is in the same partition as + the PortGID is done before - just need to update the proxy_join. */ + proxy_join = TRUE; + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__add_new_mgrp_port: " + "Create new port with proxy_join TRUE\n" ); + } + + *pp_mcmr_port = osm_mgrp_add_port( p_mgrp, + &p_recvd_mcmember_rec->port_gid, + p_recvd_mcmember_rec->scope_state, + proxy_join ); + if(*pp_mcmr_port == NULL) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__add_new_mgrp_port: ERR 1B06: " + "osm_mgrp_add_port failed\n" ); + + return IB_INSUFFICIENT_MEMORY; + } + + return IB_SUCCESS; +} + +/********************************************************************** + **********************************************************************/ +static inline boolean_t +__check_join_comp_mask(ib_net64_t comp_mask) +{ + return( (comp_mask & JOIN_MC_COMP_MASK) == JOIN_MC_COMP_MASK ); +} + +/********************************************************************** + **********************************************************************/ +static inline boolean_t +__check_create_comp_mask(ib_net64_t comp_mask, + ib_member_rec_t *p_recvd_mcmember_rec) +{ + return( + ((comp_mask & REQUIRED_MC_CREATE_COMP_MASK) == REQUIRED_MC_CREATE_COMP_MASK) + ); +} + +/********************************************************************** +Generate the response MAD +**********************************************************************/ +static void +__osm_mcmr_rcv_respond( + IN const osm_mcmr_recv_t* const p_rcv, + IN const osm_madw_t* const p_madw, + IN ib_member_rec_t *p_mcmember_rec ) +{ + osm_madw_t *p_resp_madw; + ib_sa_mad_t *p_sa_mad, *p_resp_sa_mad; + ib_member_rec_t *p_resp_mcmember_rec; + ib_api_status_t status; + + OSM_LOG_ENTER( p_rcv->p_log, __osm_mcmr_rcv_respond ); + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get(p_rcv->p_mad_pool, + p_madw->h_bind, + sizeof(ib_member_rec_t)+IB_SA_MAD_HDR_SIZE, + osm_madw_get_mad_addr_ptr(p_madw) ); + if ( !p_resp_madw ) + { + goto Exit; + } + + p_resp_sa_mad = (ib_sa_mad_t*)p_resp_madw->p_mad; + p_sa_mad = (ib_sa_mad_t*)p_madw->p_mad; + /* Copy the MAD header back into the response mad */ + memcpy(p_resp_sa_mad, p_sa_mad, IB_SA_MAD_HDR_SIZE); + /* based on the current method decide about the response: */ + if ((p_resp_sa_mad->method == IB_MAD_METHOD_GET) || + (p_resp_sa_mad->method == IB_MAD_METHOD_SET)) { + p_resp_sa_mad->method = IB_MAD_METHOD_GET_RESP; + } + else if (p_resp_sa_mad->method == IB_MAD_METHOD_DELETE) { + p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK; + } + else + { + CL_ASSERT( p_resp_sa_mad->method == 0); + } + + /* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */ + p_resp_sa_mad->sm_key = 0; + + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + p_resp_sa_mad->attr_offset = + ib_get_attr_offset( sizeof(ib_member_rec_t) ); + p_resp_mcmember_rec = (ib_member_rec_t*)&p_resp_sa_mad->data; + + *p_resp_mcmember_rec = *p_mcmember_rec; + + /* Fill in the mtu, rate, and packet lifetime selectors */ + p_resp_mcmember_rec->mtu &= 0x3f; + p_resp_mcmember_rec->mtu |= 2<<6; /* exactly */ + p_resp_mcmember_rec->rate &= 0x3f; + p_resp_mcmember_rec->rate |= 2<<6; /* exactly */ + p_resp_mcmember_rec->pkt_life &= 0x3f; + p_resp_mcmember_rec->pkt_life |= 2<<6; /* exactly */ + + status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE ); + + if(status != IB_SUCCESS) + { + osm_log( p_rcv->p_log, OSM_LOG_ERROR, + "__osm_mcmr_rcv_respond: ERR 1B07: " + "Unable to send MAD (%s) for TID <0x%"PRIx64">\n", + ib_get_err_str( status ), + p_resp_sa_mad->trans_id ); + } + + Exit: + OSM_LOG_EXIT( p_rcv->p_log ); + return; +} + +/********************************************************************* +In joining an existing group, or when querying the mc groups, +we make sure the following components provided match: MTU and RATE +HACK: Currently we ignore the PKT_LIFETIME field. +**********************************************************************/ +static boolean_t +__validate_more_comp_fields( + osm_log_t *p_log, + const osm_mgrp_t *p_mgrp, + const ib_member_rec_t *p_recvd_mcmember_rec, + ib_net64_t comp_mask) +{ + uint8_t mtu_sel; + uint8_t mtu_required; + uint8_t mtu_mgrp; + uint8_t rate_sel; + uint8_t rate_required; + uint8_t rate_mgrp; + + if ( comp_mask & IB_MCR_COMPMASK_MTU_SEL) + { + mtu_sel = (uint8_t)(p_recvd_mcmember_rec->mtu >> 6); + /* Clearing last 2 bits */ + mtu_required = (uint8_t)(p_recvd_mcmember_rec->mtu & 0x3F); + mtu_mgrp = (uint8_t)(p_mgrp->mcmember_rec.mtu & 0x3F); + switch (mtu_sel) + { + case 0: /* Greater than MTU specified */ + if(mtu_mgrp <= mtu_required) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__validate_more_comp_fields: " + "Requested MTU %x is not greater than %x\n", + mtu_mgrp, mtu_required ); + return FALSE; + } + break; + case 1: /* Less than MTU specified */ + if(mtu_mgrp >= mtu_required) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__validate_more_comp_fields: " + "Requested MTU %x is not less than %x\n", + mtu_mgrp, mtu_required ); + return FALSE; + } + break; + case 2: /* Exactly MTU specified */ + if(mtu_mgrp != mtu_required) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__validate_more_comp_fields: " + "Requested MTU %x is not equal to %x\n", + mtu_mgrp, mtu_required ); + return FALSE; + } + break; + default: + break; + } + } + + /* what about rate ? */ + if ( comp_mask & IB_MCR_COMPMASK_RATE_SEL) + { + rate_sel = (uint8_t)(p_recvd_mcmember_rec->rate >> 6); + /* Clearing last 2 bits */ + rate_required = (uint8_t)(p_recvd_mcmember_rec->rate & 0x3F); + rate_mgrp = (uint8_t)(p_mgrp->mcmember_rec.rate & 0x3F); + switch (rate_sel) + { + case 0: /* Greater than RATE specified */ + if(rate_mgrp <= rate_required) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__validate_more_comp_fields: " + "Requested RATE %x is not greater than %x\n", + rate_mgrp, rate_required ); + return FALSE; + } + break; + case 1: /* Less than RATE specified */ + if(rate_mgrp >= rate_required) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__validate_more_comp_fields: " + "Requested RATE %x is not less than %x\n", + rate_mgrp, rate_required ); + return FALSE; + } + break; + case 2: /* Exactly RATE specified */ + if(rate_mgrp != rate_required) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__validate_more_comp_fields: " + "Requested RATE %x is not equal to %x\n", + rate_mgrp, rate_required ); + return FALSE; + } + break; + default: + break; + } + } + + return TRUE; +} + +/********************************************************************* +In joining an existing group, we make sure the following components +are physically realizable: MTU and RATE +**********************************************************************/ +static boolean_t +__validate_port_caps( + osm_log_t * const p_log, + const osm_mgrp_t *p_mgrp, + const osm_physp_t *p_physp) +{ + ib_port_info_t *p_pi; + uint8_t mtu_required; + uint8_t mtu_mgrp; + uint8_t rate_required; + uint8_t rate_mgrp; + + p_pi = osm_physp_get_port_info_ptr(p_physp); + if (!p_pi) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__validate_port_caps: " + "Cannot get Port's 0x%016" PRIx64 " PortInfo\n", + cl_ntoh64( osm_physp_get_port_guid(p_physp) ) ); + return FALSE; + } + + mtu_required = ib_port_info_get_mtu_cap(p_pi); + mtu_mgrp = (uint8_t)(p_mgrp->mcmember_rec.mtu & 0x3F); + if (mtu_required < mtu_mgrp) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__validate_port_caps: " + "Port's MTU %x is less than %x\n", + mtu_required, mtu_mgrp ); + return FALSE; + } + + rate_required = ib_port_info_compute_rate(p_pi); + rate_mgrp = (uint8_t)(p_mgrp->mcmember_rec.rate & 0x3F); + if (rate_required < rate_mgrp) + { + osm_log( p_log, OSM_LOG_DEBUG, + "__validate_port_caps: " + "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_mcmr_recv_t* const p_rcv, + IN osm_mgrp_t* p_mgrp, + IN osm_mad_addr_t* p_mad_addr, + IN ib_member_rec_t* p_recvd_mcmember_rec, + OUT osm_mcm_port_t **pp_mcm_port) +{ + ib_net64_t portguid; + ib_gid_t request_gid; + osm_physp_t* p_request_physp; + ib_api_status_t res; + + portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id; + + *pp_mcm_port = NULL; + + /* o15-0.2.1: If this is a new port being added - nothing to check */ + if (!osm_mgrp_is_port_present(p_mgrp, portguid, pp_mcm_port)) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_modify: " + "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(p_rcv->p_log, + p_rcv->p_subn, + p_mad_addr, + &request_gid); + + if ( res != IB_SUCCESS ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_modify: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_modify: " + "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(p_rcv->p_log, + p_rcv->p_subn, + p_mad_addr); + if (p_request_physp == NULL) + return FALSE; + + if (!osm_physp_has_pkey(p_rcv->p_log, p_mgrp->mcmember_rec.pkey, + p_request_physp)) + { + /* the request port is not part of the partition for this mgrp */ + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_modify: " + "ProxyJoin but port not in partition. stored:0x%016"PRIx64 + " request:0x%016"PRIx64"\n", + cl_ntoh64((*pp_mcm_port)->port_gid.unicast.interface_id), + cl_ntoh64(p_mad_addr->addr_type.gsi.grh_info.src_gid.unicast.interface_id) + ); + return FALSE; + } + } + return TRUE; +} + +/********************************************************************** + **********************************************************************/ +/* + * Check legality of the requested MGID DELETE + * o15-0.1.14 = VALID DELETE: + * To be a valid delete MAD needs to: + * 1 the MADs PortGID and MGID components match the PortGID and + * MGID of a stored MCMemberRecord; + * 2 the MADs JoinState component contains at least one bit set to 1 + * in the same position as that stored MCMemberRecords JoinState + * has a bit set to 1, + * i.e., the logical AND of the two JoinState components + * is not all zeros; + * 3 the MADs JoinState component does not have some bits set + * which are not set in the stored MCMemberRecords JoinState component; + * 4 either the stored MCMemberRecord:ProxyJoin is reset (0), and the + * MADs source is the stored PortGID; + * OR + * the stored MCMemberRecord:ProxyJoin is set (1), (see o15- + * 0.1.2:); and the MADs source is a member of the partition indicated + * by the stored MCMemberRecord:P_Key. + */ +static boolean_t +__validate_delete(IN osm_mcmr_recv_t* const p_rcv, + IN osm_mgrp_t *p_mgrp, + IN osm_mad_addr_t* p_mad_addr, + IN ib_member_rec_t* p_recvd_mcmember_rec, + OUT osm_mcm_port_t **pp_mcm_port) +{ + ib_net64_t portguid; + + portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id; + + *pp_mcm_port = NULL; + + /* 1 */ + if (!osm_mgrp_is_port_present(p_mgrp, portguid, pp_mcm_port)) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_delete: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_delete: " + "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( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_delete: " + "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( p_rcv, p_mgrp, p_mad_addr, p_recvd_mcmember_rec, + pp_mcm_port ) == FALSE ) + { + osm_log( p_rcv->p_log, OSM_LOG_DEBUG, + "__validate_delete: " + "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,,,,

+  +