From 55fade3816cd1b85fd8a6fbfae27fcbb61e7bd95 Mon Sep 17 00:00:00 2001 From: tzachid Date: Tue, 23 Jun 2009 15:58:00 +0000 Subject: [PATCH] [eth6] Add first version of ipoib NDIS 6.0 driver. Signed off by: xalex@mellanox.co.il git-svn-id: svn://openib.tc.cornell.edu/gen1@2263 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86 --- trunk/ulp/ipoib/kernel6/SOURCES | 59 + trunk/ulp/ipoib/kernel6/ipoib.cdf | 13 + trunk/ulp/ipoib/kernel6/ipoib.rc | 48 + trunk/ulp/ipoib/kernel6/ipoib32-xp.cdf | 10 + trunk/ulp/ipoib/kernel6/ipoib32.cdf | 11 + trunk/ulp/ipoib/kernel6/ipoib_adapter.c | 1632 ++++ trunk/ulp/ipoib/kernel6/ipoib_adapter.h | 483 + trunk/ulp/ipoib/kernel6/ipoib_cm.c | 0 trunk/ulp/ipoib/kernel6/ipoib_debug.h | 303 + trunk/ulp/ipoib/kernel6/ipoib_driver.c | 4057 ++++++++ trunk/ulp/ipoib/kernel6/ipoib_driver.h | 162 + trunk/ulp/ipoib/kernel6/ipoib_endpoint.c | 1170 +++ trunk/ulp/ipoib/kernel6/ipoib_endpoint.h | 257 + trunk/ulp/ipoib/kernel6/ipoib_ibat.c | 666 ++ trunk/ulp/ipoib/kernel6/ipoib_ibat.h | 45 + trunk/ulp/ipoib/kernel6/ipoib_log.mc | 334 + trunk/ulp/ipoib/kernel6/ipoib_port.c | 8098 ++++++++++++++++ trunk/ulp/ipoib/kernel6/ipoib_port.h | 827 ++ trunk/ulp/ipoib/kernel6/ipoib_xfr_mgr.c | 74 + trunk/ulp/ipoib/kernel6/ipoib_xfr_mgr.h | 513 ++ trunk/ulp/ipoib/kernel6/makefile | 7 + trunk/ulp/ipoib/kernel6/makefile.inc | 17 + trunk/ulp/ipoib/kernel6/netipoib-xp32.inf | 280 + trunk/ulp/ipoib/kernel6/netipoib.inx | 295 + trunk/ulp/ipoib/kernel6/offload.h | 47 + trunk/ulp/ipoib_NDIS6_CM/dirs | 2 + trunk/ulp/ipoib_NDIS6_CM/ip_stats.h | 150 + trunk/ulp/ipoib_NDIS6_CM/kernel/SOURCES | 59 + trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib.cdf | 13 + trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib.rc | 48 + trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib32.cdf | 11 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.c | 1642 ++++ .../ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h | 483 + trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h | 303 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.c | 4708 ++++++++++ .../ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.h | 166 + .../ipoib_NDIS6_CM/kernel/ipoib_endpoint.c | 1170 +++ .../ipoib_NDIS6_CM/kernel/ipoib_endpoint.h | 257 + trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.c | 693 ++ trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.h | 45 + trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc | 334 + trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.c | 8123 +++++++++++++++++ trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h | 827 ++ .../ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.c | 74 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.h | 513 ++ trunk/ulp/ipoib_NDIS6_CM/kernel/makefile | 7 + trunk/ulp/ipoib_NDIS6_CM/kernel/makefile.inc | 17 + trunk/ulp/ipoib_NDIS6_CM/kernel/netipoib.inx | 295 + trunk/ulp/ipoib_NDIS6_CM/kernel/offload.h | 47 + 49 files changed, 39395 insertions(+) create mode 100644 trunk/ulp/ipoib/kernel6/SOURCES create mode 100644 trunk/ulp/ipoib/kernel6/ipoib.cdf create mode 100644 trunk/ulp/ipoib/kernel6/ipoib.rc create mode 100644 trunk/ulp/ipoib/kernel6/ipoib32-xp.cdf create mode 100644 trunk/ulp/ipoib/kernel6/ipoib32.cdf create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_adapter.c create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_adapter.h create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_cm.c create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_debug.h create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_driver.c create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_driver.h create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_endpoint.c create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_endpoint.h create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_ibat.c create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_ibat.h create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_log.mc create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_port.c create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_port.h create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_xfr_mgr.c create mode 100644 trunk/ulp/ipoib/kernel6/ipoib_xfr_mgr.h create mode 100644 trunk/ulp/ipoib/kernel6/makefile create mode 100644 trunk/ulp/ipoib/kernel6/makefile.inc create mode 100644 trunk/ulp/ipoib/kernel6/netipoib-xp32.inf create mode 100644 trunk/ulp/ipoib/kernel6/netipoib.inx create mode 100644 trunk/ulp/ipoib/kernel6/offload.h create mode 100644 trunk/ulp/ipoib_NDIS6_CM/dirs create mode 100644 trunk/ulp/ipoib_NDIS6_CM/ip_stats.h create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/SOURCES create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib.cdf create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib.rc create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib32.cdf create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.c create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.c create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.h create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.c create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.h create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.c create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.h create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.c create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.c create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.h create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/makefile create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/makefile.inc create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/netipoib.inx create mode 100644 trunk/ulp/ipoib_NDIS6_CM/kernel/offload.h diff --git a/trunk/ulp/ipoib/kernel6/SOURCES b/trunk/ulp/ipoib/kernel6/SOURCES new file mode 100644 index 00000000..a528904b --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib.cdf b/trunk/ulp/ipoib/kernel6/ipoib.cdf new file mode 100644 index 00000000..eb21da98 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib.rc b/trunk/ulp/ipoib/kernel6/ipoib.rc new file mode 100644 index 00000000..330f19e7 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib32-xp.cdf b/trunk/ulp/ipoib/kernel6/ipoib32-xp.cdf new file mode 100644 index 00000000..faf8ea6f --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib32.cdf b/trunk/ulp/ipoib/kernel6/ipoib32.cdf new file mode 100644 index 00000000..50225ba6 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_adapter.c b/trunk/ulp/ipoib/kernel6/ipoib_adapter.c new file mode 100644 index 00000000..78eff263 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_adapter.h b/trunk/ulp/ipoib/kernel6/ipoib_adapter.h new file mode 100644 index 00000000..f8ab4c47 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_cm.c b/trunk/ulp/ipoib/kernel6/ipoib_cm.c new file mode 100644 index 00000000..e69de29b diff --git a/trunk/ulp/ipoib/kernel6/ipoib_debug.h b/trunk/ulp/ipoib/kernel6/ipoib_debug.h new file mode 100644 index 00000000..69ec3c5a --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_driver.c b/trunk/ulp/ipoib/kernel6/ipoib_driver.c new file mode 100644 index 00000000..95d67cdf --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_driver.h b/trunk/ulp/ipoib/kernel6/ipoib_driver.h new file mode 100644 index 00000000..5ba79d91 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_endpoint.c b/trunk/ulp/ipoib/kernel6/ipoib_endpoint.c new file mode 100644 index 00000000..1e82e5a5 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_endpoint.h b/trunk/ulp/ipoib/kernel6/ipoib_endpoint.h new file mode 100644 index 00000000..547d4652 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_ibat.c b/trunk/ulp/ipoib/kernel6/ipoib_ibat.c new file mode 100644 index 00000000..ba89e00f --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_ibat.h b/trunk/ulp/ipoib/kernel6/ipoib_ibat.h new file mode 100644 index 00000000..efcb0a6b --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_log.mc b/trunk/ulp/ipoib/kernel6/ipoib_log.mc new file mode 100644 index 00000000..bb7d1c1d --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_port.c b/trunk/ulp/ipoib/kernel6/ipoib_port.c new file mode 100644 index 00000000..da57d2cc --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_port.h b/trunk/ulp/ipoib/kernel6/ipoib_port.h new file mode 100644 index 00000000..602389b5 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_xfr_mgr.c b/trunk/ulp/ipoib/kernel6/ipoib_xfr_mgr.c new file mode 100644 index 00000000..ce0650f1 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/ipoib_xfr_mgr.h b/trunk/ulp/ipoib/kernel6/ipoib_xfr_mgr.h new file mode 100644 index 00000000..9e38b609 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/makefile b/trunk/ulp/ipoib/kernel6/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/makefile.inc b/trunk/ulp/ipoib/kernel6/makefile.inc new file mode 100644 index 00000000..4f29f500 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/netipoib-xp32.inf b/trunk/ulp/ipoib/kernel6/netipoib-xp32.inf new file mode 100644 index 00000000..fd29521f --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/netipoib.inx b/trunk/ulp/ipoib/kernel6/netipoib.inx new file mode 100644 index 00000000..ca3126b5 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib/kernel6/offload.h b/trunk/ulp/ipoib/kernel6/offload.h new file mode 100644 index 00000000..de696c6a --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/dirs b/trunk/ulp/ipoib_NDIS6_CM/dirs new file mode 100644 index 00000000..ed41dcf4 --- /dev/null +++ b/trunk/ulp/ipoib_NDIS6_CM/dirs @@ -0,0 +1,2 @@ +DIRS=\ + kernel diff --git a/trunk/ulp/ipoib_NDIS6_CM/ip_stats.h b/trunk/ulp/ipoib_NDIS6_CM/ip_stats.h new file mode 100644 index 00000000..2f93e41c --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/kernel/SOURCES b/trunk/ulp/ipoib_NDIS6_CM/kernel/SOURCES new file mode 100644 index 00000000..a528904b --- /dev/null +++ b/trunk/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.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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib.cdf b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib.cdf new file mode 100644 index 00000000..eb21da98 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib.rc b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib.rc new file mode 100644 index 00000000..330f19e7 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib32.cdf b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib32.cdf new file mode 100644 index 00000000..50225ba6 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.c b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.c new file mode 100644 index 00000000..92747097 --- /dev/null +++ b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.c @@ -0,0 +1,1642 @@ +/* + * 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 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 ) + { +ASSERT(FALSE); +//return 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 ) + { + 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, 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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h new file mode 100644 index 00000000..2254f399 --- /dev/null +++ b/trunk/ulp/ipoib_NDIS6_CM/kernel/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 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 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 40000000000 + +#endif /* _IPOIB_ADAPTER_H_ */ diff --git a/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h new file mode 100644 index 00000000..69ec3c5a --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.c b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.c new file mode 100644 index 00000000..0bc3ebd5 --- /dev/null +++ b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.c @@ -0,0 +1,4708 @@ +/* + * 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); + +} + + + +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 +*/ +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 = 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; +} + + + +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(MiniportDriverContext, 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; + //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 ) + { + 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 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 ) + { + 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 = 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 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( 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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.h b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.h new file mode 100644 index 00000000..0e3b7f28 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.c b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.c new file mode 100644 index 00000000..1e82e5a5 --- /dev/null +++ b/trunk/ulp/ipoib_NDIS6_CM/kernel/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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.h b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.h new file mode 100644 index 00000000..547d4652 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.c b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.c new file mode 100644 index 00000000..a7703665 --- /dev/null +++ b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.c @@ -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 = 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() +{ + 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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.h b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.h new file mode 100644 index 00000000..efcb0a6b --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc new file mode 100644 index 00000000..bb7d1c1d --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.c b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.c new file mode 100644 index 00000000..89e1a0c0 --- /dev/null +++ b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.c @@ -0,0 +1,8123 @@ +/* + * 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. */ +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] ); + 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 = 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 ); + + 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 = 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 = + 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 = 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 + ) +{ + 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; + + mss = (p_lso_info->LsoV1Transmit.MSS | p_lso_info->LsoV2Transmit.MSS); + //TODO: first check params.lso, and thereafter calculate LSO + if( p_port->p_adapter->params.lso && 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); +#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 = 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; +//#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; + } + + /* 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 ); + + 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, 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", (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 ); +} + +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 ) ); + 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*)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 = 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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h new file mode 100644 index 00000000..602389b5 --- /dev/null +++ b/trunk/ulp/ipoib_NDIS6_CM/kernel/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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.c b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.c new file mode 100644 index 00000000..ce0650f1 --- /dev/null +++ b/trunk/ulp/ipoib_NDIS6_CM/kernel/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/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.h b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.h new file mode 100644 index 00000000..9e38b609 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/kernel/makefile b/trunk/ulp/ipoib_NDIS6_CM/kernel/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/kernel/makefile.inc b/trunk/ulp/ipoib_NDIS6_CM/kernel/makefile.inc new file mode 100644 index 00000000..4f29f500 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/kernel/netipoib.inx b/trunk/ulp/ipoib_NDIS6_CM/kernel/netipoib.inx new file mode 100644 index 00000000..ca3126b5 --- /dev/null +++ b/trunk/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/trunk/ulp/ipoib_NDIS6_CM/kernel/offload.h b/trunk/ulp/ipoib_NDIS6_CM/kernel/offload.h new file mode 100644 index 00000000..de696c6a --- /dev/null +++ b/trunk/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; + + -- 2.46.0