--- /dev/null
+DIRS=\\r
+ kernel\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+#ifndef _IP_STATS_H_\r
+#define _IP_STATS_H_\r
+\r
+\r
+#include <complib/cl_types.h>\r
+\r
+\r
+/****s* IB Network Drivers/ip_data_stats_t\r
+* NAME\r
+* ip_data_stats_t\r
+*\r
+* DESCRIPTION\r
+* Defines data transfer statistic information for an IP device.\r
+*\r
+* SYNOPSIS\r
+*/\r
+typedef struct _ip_data_stats\r
+{\r
+ uint64_t bytes;\r
+ uint64_t frames;\r
+\r
+} ip_data_stats_t;\r
+/*\r
+* FIELDS\r
+* bytes\r
+* Total number of bytes transfered.\r
+*\r
+* frames\r
+* Total number of frames transfered.\r
+*\r
+* SEE ALSO\r
+* IPoIB, INIC, ip_comp_stats_t, ip_stats_t\r
+*********/\r
+\r
+\r
+/****s* IB Network Drivers/ip_comp_stats_t\r
+* NAME\r
+* ip_comp_stats_t\r
+*\r
+* DESCRIPTION\r
+* Defines transfer completion statistic information for an IP device.\r
+*\r
+* SYNOPSIS\r
+*/\r
+typedef struct _ip_comp_stats\r
+{\r
+ uint64_t success;\r
+ uint64_t error;\r
+ uint64_t dropped;\r
+\r
+} ip_comp_stats_t;\r
+/*\r
+* FIELDS\r
+* success\r
+* Total number of requests transfered successfully.\r
+*\r
+* error\r
+* Total number of requests that failed being transfered.\r
+*\r
+* dropped\r
+* Total number of requests that were dropped.\r
+*\r
+* SEE ALSO\r
+* IPoIB, INIC, ip_data_stats_t, ip_stats_t\r
+*********/\r
+\r
+\r
+/****s* IB Network Drivers/ip_stats_t\r
+* NAME\r
+* ip_stats_t\r
+*\r
+* DESCRIPTION\r
+* Defines statistic information for an IP device.\r
+*\r
+* SYNOPSIS\r
+*/\r
+typedef struct _ip_stats\r
+{\r
+ ip_comp_stats_t comp;\r
+ ip_data_stats_t ucast;\r
+ ip_data_stats_t bcast;\r
+ ip_data_stats_t mcast;\r
+\r
+} ip_stats_t;\r
+/*\r
+* FIELDS\r
+* comp\r
+* Request completion statistics.\r
+*\r
+* ucast\r
+* Data statistics for unicast packets\r
+*\r
+* bcast\r
+* Data statistics for broadcast packets\r
+*\r
+* mcast\r
+* Data statistics for multicast packets\r
+*\r
+* SEE ALSO\r
+* IPoIB, INIC, ip_data_stats_t, ip_comp_stats_t\r
+*********/\r
+\r
+\r
+typedef enum _ip_stat_sel\r
+{\r
+ IP_STAT_SUCCESS,\r
+ IP_STAT_ERROR,\r
+ IP_STAT_DROPPED,\r
+ IP_STAT_UCAST_BYTES,\r
+ IP_STAT_UCAST_FRAMES,\r
+ IP_STAT_BCAST_BYTES,\r
+ IP_STAT_BCAST_FRAMES,\r
+ IP_STAT_MCAST_BYTES,\r
+ IP_STAT_MCAST_FRAMES\r
+\r
+} ip_stat_sel_t;\r
+\r
+#endif /* _IP_STATS_H_ */\r
--- /dev/null
+TARGETNAME=ipoib\r
+TARGETPATH=..\..\..\bin\kernel\obj$(BUILD_ALT_DIR)\r
+TARGETTYPE=DRIVER\r
+\r
+\r
+!if $(FREEBUILD)\r
+ENABLE_EVENT_TRACING=1\r
+!else\r
+#ENABLE_EVENT_TRACING=1\r
+!endif\r
+\r
+\r
+SOURCES= ipoib_log.mc \\r
+ ipoib.rc \\r
+ ipoib_driver.c \\r
+ ipoib_adapter.c \\r
+ ipoib_endpoint.c \\r
+ ipoib_port.c \\r
+ ipoib_ibat.c\r
+\r
+INCLUDES=..;..\..\..\inc;..\..\..\inc\kernel;\r
+\r
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DNDIS_WDM=1 \\r
+ -DDEPRECATE_DDK_FUNCTIONS -DNDIS51_MINIPORT -DNEED_CL_OBJ -DBINARY_COMPATIBLE=0\r
+\r
+TARGETLIBS= \\r
+ $(TARGETPATH)\*\complib.lib \\r
+ $(DDK_LIB_PATH)\ndis.lib\r
+\r
+!if !defined(DDK_TARGET_OS) || "$(DDK_TARGET_OS)"=="Win2K"\r
+#\r
+# The driver is built in the Win2K build environment\r
+# - use the library version of safe strings \r
+#\r
+TARGETLIBS= $(TARGETLIBS) $(DDK_LIB_PATH)\ntstrsafe.lib\r
+!endif\r
+\r
+!IFDEF ENABLE_EVENT_TRACING\r
+\r
+C_DEFINES = $(C_DEFINES) -DEVENT_TRACING\r
+\r
+RUN_WPP = $(SOURCES) -km -ext: .c .h .C .H \\r
+ -scan:ipoib_debug.h \\r
+ -func:IPOIB_PRINT(LEVEL,FLAGS,(MSG,...)) \\r
+ -func:IPOIB_PRINT_EXIT(LEVEL,FLAGS,(MSG,...))\r
+!ENDIF\r
+\r
+MSC_WARNING_LEVEL= /W4\r
--- /dev/null
+[CatalogHeader]\r
+Name=ipoib.cat\r
+PublicVersion=0x0000001\r
+EncodingType=0x00010001\r
+CATATTR1=0x10010001:OSAttr:2:6.0\r
+[CatalogFiles]\r
+<hash>netipoib.inf=netipoib.inf\r
+<hash>ipoib.sys=ipoib.sys\r
+<hash>ibwsd.dll=ibwsd.dll\r
+<hash>ibwsd32.dll=ibwsd32.dll\r
+\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+#include <oib_ver.h>\r
+\r
+#define VER_FILETYPE VFT_DRV\r
+#define VER_FILESUBTYPE VFT2_UNKNOWN\r
+\r
+#ifdef _DEBUG_\r
+#define VER_FILEDESCRIPTION_STR "IP over InfiniBand NDIS Miniport (Debug)"\r
+#else\r
+#define VER_FILEDESCRIPTION_STR "IP over InfiniBand NDIS Miniport"\r
+#endif\r
+\r
+#define VER_INTERNALNAME_STR "ipoib.sys"\r
+#define VER_ORIGINALFILENAME_STR "ipoib.sys"\r
+\r
+#include <common.ver>\r
+#include "ipoib_log.rc"\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ * Copyright (c) 2006 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+\r
+#include "ipoib_adapter.h"\r
+#include "ipoib_port.h"\r
+#include "ipoib_driver.h"\r
+#include "ipoib_debug.h"\r
+\r
+#if defined(EVENT_TRACING)\r
+#ifdef offsetof\r
+#undef offsetof\r
+#endif\r
+#include "ipoib_adapter.tmh"\r
+#endif\r
+\r
+\r
+#define ITEM_POOL_START 16\r
+#define ITEM_POOL_GROW 16\r
+\r
+\r
+/* IB Link speeds in 100bps */\r
+#define ONE_X_IN_100BPS 25000000\r
+#define FOUR_X_IN_100BPS 100000000\r
+#define TWELVE_X_IN_100BPS 300000000\r
+\r
+\r
+/* Declarations */\r
+static void\r
+adapter_construct(\r
+ IN ipoib_adapter_t* const p_adapter );\r
+\r
+\r
+static ib_api_status_t\r
+adapter_init(\r
+ IN ipoib_adapter_t* const p_adapter );\r
+\r
+\r
+static void\r
+__adapter_destroying(\r
+ IN cl_obj_t* const p_obj );\r
+\r
+\r
+static void\r
+__adapter_cleanup(\r
+ IN cl_obj_t* const p_obj );\r
+\r
+\r
+static void\r
+__adapter_free(\r
+ IN cl_obj_t* const p_obj );\r
+\r
+\r
+static ib_api_status_t\r
+__ipoib_pnp_reg(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN ib_pnp_class_t flags );\r
+\r
+\r
+static void\r
+__ipoib_pnp_dereg(\r
+ IN void* context );\r
+\r
+\r
+static void\r
+__ipoib_adapter_reset(\r
+ IN void* context);\r
+\r
+\r
+static ib_api_status_t\r
+__ipoib_pnp_cb(\r
+ IN ib_pnp_rec_t *p_pnp_rec );\r
+\r
+\r
+void\r
+ipoib_join_mcast(\r
+ IN ipoib_adapter_t* const p_adapter );\r
+\r
+\r
+/* Leaves all mcast groups when port goes down. */\r
+static void\r
+ipoib_clear_mcast(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+NDIS_STATUS\r
+ipoib_get_adapter_guids(\r
+ IN NDIS_HANDLE* const h_adapter,\r
+ IN OUT ipoib_adapter_t *p_adapter );\r
+\r
+NDIS_STATUS\r
+ipoib_get_adapter_params(\r
+ IN NDIS_HANDLE* const wrapper_config_context,\r
+ IN OUT ipoib_adapter_t *p_adapter );\r
+\r
+\r
+/* Implementation */\r
+ib_api_status_t\r
+ipoib_create_adapter(\r
+ IN NDIS_HANDLE wrapper_config_context,\r
+ IN void* const h_adapter,\r
+ OUT ipoib_adapter_t** const pp_adapter )\r
+{\r
+ ipoib_adapter_t *p_adapter;\r
+ ib_api_status_t status;\r
+ cl_status_t cl_status;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ p_adapter = cl_zalloc( sizeof(ipoib_adapter_t) );\r
+ if( !p_adapter )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to allocate ipoib_adapter_t (%d bytes)",\r
+ sizeof(ipoib_adapter_t)) );\r
+ return IB_INSUFFICIENT_MEMORY;\r
+ }\r
+\r
+ adapter_construct( p_adapter );\r
+\r
+ p_adapter->h_adapter = h_adapter;\r
+\r
+ p_adapter->p_ifc = cl_zalloc( sizeof(ib_al_ifc_t) );\r
+ if( !p_adapter->p_ifc )\r
+ {\r
+ __adapter_free( &p_adapter->obj );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_create_adapter failed to alloc ipoib_ifc_t %d bytes\n",\r
+ sizeof(ib_al_ifc_t)) );\r
+ return IB_INSUFFICIENT_MEMORY;\r
+ }\r
+\r
+ /* Get the CA and port GUID from the bus driver. */\r
+ status = ipoib_get_adapter_guids( h_adapter, p_adapter );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ __adapter_free( &p_adapter->obj );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_get_adapter_guids returned 0x%.8X.\n", status) );\r
+ return status;\r
+ }\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Port %016I64x (CA %016I64x port %d) initializing\n",\r
+ p_adapter->guids.port_guid, p_adapter->guids.ca_guid,\r
+ p_adapter->guids.port_num) );\r
+\r
+ cl_status = cl_obj_init( &p_adapter->obj, CL_DESTROY_SYNC,\r
+ __adapter_destroying, NULL, __adapter_free );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ __adapter_free( &p_adapter->obj );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("cl_obj_init returned %#x\n", cl_status) );\r
+ return IB_ERROR;\r
+ }\r
+\r
+ status = adapter_init( p_adapter );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ cl_obj_destroy( &p_adapter->obj );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("adapter_init returned %s.\n", \r
+ p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* Read configuration parameters. */\r
+ status = ipoib_get_adapter_params( wrapper_config_context,\r
+ p_adapter );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ cl_obj_destroy( &p_adapter->obj );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_get_adapter_params returned 0x%.8x.\n", status) );\r
+ return status;\r
+ }\r
+\r
+ *pp_adapter = p_adapter;\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return status;\r
+}\r
+\r
+\r
+ib_api_status_t\r
+ipoib_start_adapter(\r
+ IN ipoib_adapter_t* const p_adapter )\r
+{\r
+ ib_api_status_t status;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ status = __ipoib_pnp_reg( p_adapter,\r
+ IB_PNP_FLAG_REG_SYNC | IB_PNP_FLAG_REG_COMPLETE );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return status;\r
+}\r
+\r
+\r
+void\r
+ipoib_destroy_adapter(\r
+ IN ipoib_adapter_t* const p_adapter )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ CL_ASSERT( p_adapter );\r
+\r
+ /*\r
+ * Flag the adapter as being removed. We use the IB_PNP_PORT_REMOVE state\r
+ * for this purpose. Note that we protect this state change with both the\r
+ * mutex and the lock. The mutex provides synchronization as a whole\r
+ * between destruction and AL callbacks (PnP, Query, Destruction).\r
+ * The lock provides protection\r
+ */\r
+ KeWaitForMutexObject(\r
+ &p_adapter->mutex, Executive, KernelMode, FALSE, NULL );\r
+ cl_obj_lock( &p_adapter->obj );\r
+ p_adapter->state = IB_PNP_PORT_REMOVE;\r
+\r
+ /*\r
+ * Clear the pointer to the port object since the object destruction\r
+ * will cascade to child objects. This prevents potential duplicate\r
+ * destruction (or worse, stale pointer usage).\r
+ */\r
+ p_adapter->p_port = NULL;\r
+\r
+ cl_obj_unlock( &p_adapter->obj );\r
+\r
+ KeReleaseMutex( &p_adapter->mutex, FALSE );\r
+\r
+ cl_obj_destroy( &p_adapter->obj );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static void\r
+adapter_construct(\r
+ IN ipoib_adapter_t* const p_adapter )\r
+{\r
+ cl_obj_construct( &p_adapter->obj, IPOIB_OBJ_INSTANCE );\r
+ cl_spinlock_construct( &p_adapter->send_stat_lock );\r
+ cl_spinlock_construct( &p_adapter->recv_stat_lock );\r
+ cl_qpool_construct( &p_adapter->item_pool );\r
+ KeInitializeMutex( &p_adapter->mutex, 0 );\r
+\r
+ cl_thread_construct(&p_adapter->destroy_thread);\r
+ \r
+ cl_vector_construct( &p_adapter->ip_vector );\r
+\r
+ cl_perf_construct( &p_adapter->perf );\r
+\r
+ p_adapter->state = IB_PNP_PORT_ADD;\r
+ p_adapter->rate = FOUR_X_IN_100BPS;\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+adapter_init(\r
+ IN ipoib_adapter_t* const p_adapter )\r
+{\r
+ cl_status_t cl_status;\r
+ ib_api_status_t status;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ cl_status = cl_perf_init( &p_adapter->perf, MaxPerf );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("cl_perf_init returned %#x\n", cl_status) );\r
+ return IB_ERROR;\r
+ }\r
+\r
+ cl_status = cl_spinlock_init( &p_adapter->send_stat_lock );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("cl_spinlock_init returned %#x\n", cl_status) );\r
+ return IB_ERROR;\r
+ }\r
+\r
+ cl_status = cl_spinlock_init( &p_adapter->recv_stat_lock );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("cl_spinlock_init returned %#x\n", cl_status) );\r
+ return IB_ERROR;\r
+ }\r
+\r
+ cl_status = cl_qpool_init( &p_adapter->item_pool, ITEM_POOL_START, 0,\r
+ ITEM_POOL_GROW, sizeof(cl_pool_obj_t), NULL, NULL, NULL );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("cl_qpool_init returned %#x\n", cl_status) );\r
+ return IB_ERROR;\r
+ }\r
+\r
+\r
+ /* We manually manage the size and capacity of the vector. */\r
+ cl_status = cl_vector_init( &p_adapter->ip_vector, 0,\r
+ 0, sizeof(net_address_item_t), NULL, NULL, p_adapter );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("cl_vector_init for ip_vector returned %#x\n",\r
+ cl_status) );\r
+ return IB_ERROR;\r
+ }\r
+\r
+\r
+ /* Validate the port GUID and generate the MAC address. */\r
+ status =\r
+ ipoib_mac_from_guid( p_adapter->guids.port_guid, &p_adapter->mac );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_mac_from_guid returned %s\n", \r
+ p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ \r
+ \r
+ /* Open AL. */\r
+ status = p_adapter->p_ifc->open_al( &p_adapter->h_al );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_open_al returned %s\n", \r
+ p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return status;\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__ipoib_pnp_reg(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN ib_pnp_class_t flags )\r
+{\r
+ ib_api_status_t status;\r
+ ib_pnp_req_t pnp_req;\r
+ \r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ CL_ASSERT( !p_adapter->h_pnp );\r
+ CL_ASSERT( !p_adapter->registering );\r
+\r
+ p_adapter->registering = TRUE;\r
+ \r
+ /* Register for PNP events. */\r
+ cl_memclr( &pnp_req, sizeof(pnp_req) );\r
+ pnp_req.pnp_class = IB_PNP_PORT | flags;\r
+ /*\r
+ * Context is the cl_obj of the adapter to allow passing cl_obj_deref\r
+ * to ib_dereg_pnp.\r
+ */\r
+ pnp_req.pnp_context = &p_adapter->obj;\r
+ pnp_req.pfn_pnp_cb = __ipoib_pnp_cb;\r
+ status = p_adapter->p_ifc->reg_pnp( p_adapter->h_al, &pnp_req, &p_adapter->h_pnp );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ p_adapter->registering = FALSE;\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_reg_pnp returned %s\n", \r
+ p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+ /*\r
+ * Reference the adapter on behalf of the PNP registration.\r
+ * This allows the destruction to block until the PNP deregistration\r
+ * completes.\r
+ */\r
+ cl_obj_ref( &p_adapter->obj );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return status;\r
+}\r
+\r
+\r
+static void\r
+__adapter_destroying(\r
+ IN cl_obj_t* const p_obj )\r
+{\r
+ ipoib_adapter_t *p_adapter;\r
+ KLOCK_QUEUE_HANDLE hdl;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ p_adapter = PARENT_STRUCT( p_obj, ipoib_adapter_t, obj );\r
+\r
+ /*\r
+ * The adapter's object will be dereferenced when the deregistration\r
+ * completes. No need to lock here since all PnP related API calls\r
+ * are driven by NDIS (via the Init/Reset/Destroy paths).\r
+ */\r
+ if( p_adapter->h_pnp )\r
+ {\r
+ p_adapter->p_ifc->dereg_pnp( p_adapter->h_pnp, cl_obj_deref );\r
+ p_adapter->h_pnp = NULL;\r
+ }\r
+\r
+ if( p_adapter->packet_filter )\r
+ {\r
+ KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl );\r
+ cl_obj_lock( &p_adapter->obj );\r
+\r
+ ASSERT( cl_qlist_count( &g_ipoib.adapter_list ) );\r
+ cl_qlist_remove_item( &g_ipoib.adapter_list, &p_adapter->entry );\r
+\r
+ p_adapter->packet_filter = 0;\r
+\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ KeReleaseInStackQueuedSpinLock( &hdl );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static void\r
+__adapter_free(\r
+ IN cl_obj_t* const p_obj )\r
+{\r
+ ipoib_adapter_t *p_adapter;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ p_adapter = PARENT_STRUCT( p_obj, ipoib_adapter_t, obj );\r
+\r
+ if( p_adapter->p_ifc )\r
+ {\r
+ if( p_adapter->h_al )\r
+ p_adapter->p_ifc->close_al( p_adapter->h_al );\r
+\r
+ cl_free( p_adapter->p_ifc );\r
+ }\r
+\r
+ cl_vector_destroy( &p_adapter->ip_vector );\r
+ cl_qpool_destroy( &p_adapter->item_pool );\r
+ cl_spinlock_destroy( &p_adapter->recv_stat_lock );\r
+ cl_spinlock_destroy( &p_adapter->send_stat_lock );\r
+ cl_obj_deinit( p_obj );\r
+\r
+ cl_perf_destroy( &p_adapter->perf, TRUE );\r
+\r
+ cl_free( p_adapter );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__ipoib_pnp_cb(\r
+ IN ib_pnp_rec_t *p_pnp_rec )\r
+{\r
+ ib_api_status_t status;\r
+ ipoib_adapter_t *p_adapter;\r
+ ipoib_port_t *p_port;\r
+ ib_pnp_event_t old_state;\r
+ ib_pnp_port_rec_t *p_port_rec;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_PNP );\r
+\r
+ CL_ASSERT( p_pnp_rec );\r
+\r
+ p_adapter =\r
+ PARENT_STRUCT( p_pnp_rec->pnp_context, ipoib_adapter_t, obj );\r
+\r
+ CL_ASSERT( p_adapter );\r
+\r
+ /* Synchronize with destruction */\r
+ KeWaitForMutexObject(\r
+ &p_adapter->mutex, Executive, KernelMode, FALSE, NULL );\r
+ cl_obj_lock( &p_adapter->obj );\r
+ old_state = p_adapter->state;\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ if( old_state == IB_PNP_PORT_REMOVE )\r
+ {\r
+ KeReleaseMutex( &p_adapter->mutex, FALSE );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_PNP,\r
+ ("Aborting - Adapter destroying.\n") );\r
+ return IB_NOT_DONE;\r
+ }\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_PNP,\r
+ ("p_pnp_rec->pnp_event = 0x%x (%s)\n",\r
+ p_pnp_rec->pnp_event, ib_get_pnp_event_str( p_pnp_rec->pnp_event )) );\r
+\r
+ p_port_rec = (ib_pnp_port_rec_t*)p_pnp_rec;\r
+\r
+ switch( p_pnp_rec->pnp_event )\r
+ {\r
+ case IB_PNP_PORT_ADD:\r
+ CL_ASSERT( !p_pnp_rec->context );\r
+ /* Only process our port GUID. */\r
+ if( p_pnp_rec->guid != p_adapter->guids.port_guid )\r
+ {\r
+ status = IB_NOT_DONE;\r
+ break;\r
+ }\r
+\r
+ /* Don't process if we're destroying. */\r
+ if( p_adapter->obj.state == CL_DESTROYING )\r
+ {\r
+ status = IB_NOT_DONE;\r
+ break;\r
+ }\r
+\r
+ CL_ASSERT( !p_adapter->p_port );\r
+ /* Allocate all IB resources. */\r
+ cl_obj_lock( &p_adapter->obj );\r
+ p_adapter->state = IB_PNP_PORT_ADD;\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ status = ipoib_create_port( p_adapter, p_port_rec, &p_port );\r
+ cl_obj_lock( &p_adapter->obj );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ p_adapter->state = old_state;\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ p_adapter->hung = TRUE;\r
+ break;\r
+ }\r
+\r
+ p_pnp_rec->context = p_port;\r
+\r
+ p_adapter->p_port = p_port;\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ break;\r
+\r
+ case IB_PNP_PORT_REMOVE:\r
+ /* Release all IB resources. */\r
+ CL_ASSERT( p_pnp_rec->context );\r
+\r
+ cl_obj_lock( &p_adapter->obj );\r
+ p_adapter->state = IB_PNP_PORT_REMOVE;\r
+ p_port = p_adapter->p_port;\r
+ p_adapter->p_port = NULL;\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ ipoib_port_destroy( p_port );\r
+ p_pnp_rec->context = NULL;\r
+ status = IB_SUCCESS;\r
+ break;\r
+\r
+ case IB_PNP_PORT_ACTIVE:\r
+ /* Join multicast groups and put QP in RTS. */\r
+ CL_ASSERT( p_pnp_rec->context );\r
+\r
+ cl_obj_lock( &p_adapter->obj );\r
+ p_adapter->state = IB_PNP_PORT_INIT;\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ ipoib_port_up( p_adapter->p_port, p_port_rec );\r
+\r
+ status = IB_SUCCESS;\r
+ break;\r
+\r
+ case IB_PNP_PORT_ARMED:\r
+ status = IB_SUCCESS;\r
+ break;\r
+\r
+ case IB_PNP_PORT_INIT:\r
+ /*\r
+ * Init could happen if the SM brings the port down\r
+ * without changing the physical link.\r
+ */\r
+ case IB_PNP_PORT_DOWN:\r
+ CL_ASSERT( p_pnp_rec->context );\r
+\r
+ cl_obj_lock( &p_adapter->obj );\r
+ old_state = p_adapter->state;\r
+ p_adapter->state = IB_PNP_PORT_DOWN;\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ status = IB_SUCCESS;\r
+\r
+ if( !p_adapter->registering && old_state != IB_PNP_PORT_DOWN )\r
+ {\r
+ NdisMIndicateStatus( p_adapter->h_adapter,\r
+ NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
+ NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Link DOWN!\n") );\r
+\r
+ ipoib_port_down( p_adapter->p_port );\r
+ }\r
+ break;\r
+\r
+ case IB_PNP_REG_COMPLETE:\r
+ if( p_adapter->registering )\r
+ {\r
+ p_adapter->registering = FALSE;\r
+ cl_obj_lock( &p_adapter->obj );\r
+ old_state = p_adapter->state;\r
+ cl_obj_unlock( &p_adapter->obj );\r
+\r
+ if( old_state == IB_PNP_PORT_DOWN )\r
+ {\r
+ /* If we were initializing, we might have pended some OIDs. */\r
+ ipoib_resume_oids( p_adapter );\r
+ NdisMIndicateStatus( p_adapter->h_adapter,\r
+ NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
+ NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
+ }\r
+ }\r
+\r
+ if( p_adapter->reset && p_adapter->state != IB_PNP_PORT_INIT )\r
+ {\r
+ p_adapter->reset = FALSE;\r
+ NdisMResetComplete(\r
+ p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
+ }\r
+ status = IB_SUCCESS;\r
+ break;\r
+\r
+ default:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("IPOIB: Received unhandled PnP event 0x%x (%s)\n",\r
+ p_pnp_rec->pnp_event, ib_get_pnp_event_str( p_pnp_rec->pnp_event )) );\r
+ /* Fall through. */\r
+ case IB_PNP_PKEY_CHANGE:\r
+ case IB_PNP_SM_CHANGE:\r
+ case IB_PNP_GID_CHANGE:\r
+ case IB_PNP_LID_CHANGE:\r
+ status = IB_SUCCESS;\r
+\r
+ /* We ignore this event if the link is not active. */\r
+ if( p_port_rec->p_port_attr->link_state != IB_LINK_ACTIVE )\r
+ break;\r
+\r
+ cl_obj_lock( &p_adapter->obj );\r
+ old_state = p_adapter->state;\r
+ switch( old_state )\r
+ {\r
+ case IB_PNP_PORT_DOWN:\r
+ p_adapter->state = IB_PNP_PORT_INIT;\r
+ break;\r
+\r
+ default:\r
+ p_adapter->state = IB_PNP_PORT_DOWN;\r
+ }\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ \r
+ if( p_adapter->registering )\r
+ break;\r
+\r
+ switch( old_state )\r
+ {\r
+ case IB_PNP_PORT_ACTIVE:\r
+ case IB_PNP_PORT_INIT:\r
+ NdisMIndicateStatus( p_adapter->h_adapter,\r
+ NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
+ NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Link DOWN!\n") );\r
+\r
+ ipoib_port_down( p_adapter->p_port );\r
+ /* Fall through. */\r
+\r
+ case IB_PNP_PORT_DOWN:\r
+ cl_obj_lock( &p_adapter->obj );\r
+ p_adapter->state = IB_PNP_PORT_INIT;\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ ipoib_port_up( p_adapter->p_port, (ib_pnp_port_rec_t*)p_pnp_rec );\r
+ }\r
+ break;\r
+ }\r
+\r
+ KeReleaseMutex( &p_adapter->mutex, FALSE );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+\r
+/* Joins/leaves mcast groups based on currently programmed mcast MACs. */\r
+void\r
+ipoib_refresh_mcast(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN mac_addr_t* const p_mac_array,\r
+ IN const uint8_t num_macs )\r
+{\r
+ uint8_t i, j;\r
+ ipoib_port_t *p_port = NULL;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_MCAST );\r
+ cl_obj_lock( &p_adapter->obj );\r
+ if( p_adapter->state == IB_PNP_PORT_ACTIVE )\r
+ {\r
+ p_port = p_adapter->p_port;\r
+ ipoib_port_ref( p_port, ref_refresh_mcast );\r
+ }\r
+ cl_obj_unlock( &p_adapter->obj );\r
+\r
+ if( p_port )\r
+ {\r
+ /* Purge old entries. */\r
+ for( i = 0; i < p_adapter->mcast_array_size; i++ )\r
+ {\r
+ for( j = 0; j < num_macs; j++ )\r
+ {\r
+ if( !cl_memcmp( &p_adapter->mcast_array[i], &p_mac_array[j],\r
+ sizeof(mac_addr_t) ) )\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ if( j != num_macs )\r
+ continue;\r
+\r
+ ipoib_port_remove_endpt( p_port, p_adapter->mcast_array[i] );\r
+ }\r
+\r
+ /* Add new entries */\r
+ for( i = 0; i < num_macs; i++ )\r
+ {\r
+ for( j = 0; j < p_adapter->mcast_array_size; j++ )\r
+ {\r
+ if( !cl_memcmp( &p_adapter->mcast_array[j], &p_mac_array[i],\r
+ sizeof(mac_addr_t) ) )\r
+ {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if( j != p_adapter->mcast_array_size )\r
+ continue;\r
+\r
+ ipoib_port_join_mcast( p_port, p_mac_array[i] ,IB_MC_REC_STATE_FULL_MEMBER);\r
+ }\r
+ }\r
+\r
+ /* Copy the MAC array. */\r
+ NdisMoveMemory( p_adapter->mcast_array, p_mac_array,\r
+ num_macs * sizeof(mac_addr_t) );\r
+ p_adapter->mcast_array_size = num_macs;\r
+\r
+ if( p_port )\r
+ ipoib_port_deref( p_port, ref_refresh_mcast );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_MCAST );\r
+}\r
+\r
+\r
+ib_api_status_t\r
+ipoib_reset_adapter(\r
+ IN ipoib_adapter_t* const p_adapter )\r
+{\r
+ ib_api_status_t status;\r
+ ib_pnp_handle_t h_pnp;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ if( p_adapter->reset )\r
+ return IB_INVALID_STATE;\r
+\r
+ p_adapter->hung = FALSE;\r
+ p_adapter->reset = TRUE;\r
+\r
+ if( p_adapter->h_pnp )\r
+ {\r
+ h_pnp = p_adapter->h_pnp;\r
+ p_adapter->h_pnp = NULL;\r
+ status = p_adapter->p_ifc->dereg_pnp( h_pnp, __ipoib_pnp_dereg );\r
+ if( status == IB_SUCCESS )\r
+ status = IB_NOT_DONE;\r
+ }\r
+ else\r
+ {\r
+ status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE );\r
+ if( status == IB_SUCCESS )\r
+ p_adapter->hung = FALSE;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return status;\r
+}\r
+\r
+\r
+static void\r
+__ipoib_pnp_dereg(\r
+ IN void* context )\r
+{\r
+ ipoib_adapter_t* p_adapter;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ p_adapter = PARENT_STRUCT( context, ipoib_adapter_t, obj );\r
+\r
+ cl_thread_init(&p_adapter->destroy_thread, __ipoib_adapter_reset, (void*)p_adapter, "destroy_thread");\r
+ \r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+}\r
+\r
+static void\r
+__ipoib_adapter_reset(\r
+ IN void* context)\r
+{\r
+\r
+ ipoib_adapter_t *p_adapter;\r
+ ipoib_port_t *p_port;\r
+ ib_api_status_t status;\r
+ ib_pnp_event_t state;\r
+ \r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ p_adapter = (ipoib_adapter_t*)context;\r
+ \r
+ /* Synchronize with destruction */\r
+ KeWaitForMutexObject(\r
+ &p_adapter->mutex, Executive, KernelMode, FALSE, NULL );\r
+\r
+ cl_obj_lock( &p_adapter->obj );\r
+\r
+ CL_ASSERT( !p_adapter->h_pnp );\r
+\r
+ if( p_adapter->state != IB_PNP_PORT_REMOVE )\r
+ p_adapter->state = IB_PNP_PORT_ADD;\r
+\r
+ state = p_adapter->state;\r
+\r
+ /* Destroy the current port instance if it still exists. */\r
+ p_port = p_adapter->p_port;\r
+ p_adapter->p_port = NULL;\r
+ cl_obj_unlock( &p_adapter->obj );\r
+\r
+ if( p_port )\r
+ ipoib_port_destroy( p_port );\r
+\r
+ if( state != IB_PNP_PORT_REMOVE )\r
+ {\r
+ status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ p_adapter->reset = FALSE;\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__ipoib_pnp_reg returned %s\n",\r
+ p_adapter->p_ifc->get_err_str( status )) );\r
+ NdisMResetComplete( \r
+ p_adapter->h_adapter, NDIS_STATUS_HARD_ERRORS, TRUE );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ p_adapter->reset = FALSE;\r
+ NdisMResetComplete(\r
+ p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
+ status = IB_SUCCESS;\r
+ }\r
+\r
+ /* Dereference the adapter since the previous registration is now gone. */\r
+ cl_obj_deref( &p_adapter->obj );\r
+\r
+ KeReleaseMutex( &p_adapter->mutex, FALSE );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+void\r
+ipoib_set_rate(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN const uint8_t link_width, \r
+ IN const uint8_t link_speed )\r
+{\r
+ uint32_t rate;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ /* Set the link speed based on the IB link speed (1x vs 4x, etc). */\r
+ switch( link_speed )\r
+ {\r
+ case IB_LINK_SPEED_ACTIVE_2_5:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Link speed is 2.5Gs\n") );\r
+ rate = IB_LINK_SPEED_ACTIVE_2_5;\r
+ break;\r
+\r
+ case IB_LINK_SPEED_ACTIVE_5:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Link speed is 5G\n") );\r
+ rate = IB_LINK_SPEED_ACTIVE_5;\r
+ break;\r
+\r
+ case IB_LINK_SPEED_ACTIVE_10:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Link speed is 10G\n") );\r
+ rate = IB_LINK_SPEED_ACTIVE_10;\r
+ break;\r
+\r
+ default:\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid link speed %d.\n", link_speed) );\r
+ rate = 0;\r
+ }\r
+\r
+ switch( link_width )\r
+ {\r
+ case IB_LINK_WIDTH_ACTIVE_1X:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Link width is 1X\n") );\r
+ rate *= ONE_X_IN_100BPS;\r
+ break;\r
+\r
+ case IB_LINK_WIDTH_ACTIVE_4X:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Link width is 4X\n") );\r
+ rate *= FOUR_X_IN_100BPS;\r
+ break;\r
+\r
+ case IB_LINK_WIDTH_ACTIVE_12X:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Link width is 12X\n") );\r
+ rate *= TWELVE_X_IN_100BPS;\r
+ break;\r
+\r
+ default:\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid link rate (%d).\n", link_width) );\r
+ rate = 0;\r
+ }\r
+\r
+ p_adapter->rate = rate;\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+void\r
+ipoib_set_active(\r
+ IN ipoib_adapter_t* const p_adapter )\r
+{\r
+ ib_pnp_event_t old_state;\r
+ uint8_t i;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ cl_obj_lock( &p_adapter->obj );\r
+ old_state = p_adapter->state;\r
+\r
+ /* Change the state to indicate that we are now connected and live. */\r
+ if( old_state == IB_PNP_PORT_INIT )\r
+ p_adapter->state = IB_PNP_PORT_ACTIVE;\r
+\r
+ cl_obj_unlock( &p_adapter->obj );\r
+\r
+ /*\r
+ * If we had a pending OID request for OID_GEN_LINK_SPEED,\r
+ * complete it now.\r
+ */\r
+ switch( old_state )\r
+ {\r
+ case IB_PNP_PORT_ADD:\r
+ ipoib_reg_addrs( p_adapter );\r
+ /* Fall through. */\r
+\r
+ case IB_PNP_PORT_REMOVE:\r
+ ipoib_resume_oids( p_adapter );\r
+ break;\r
+\r
+ default:\r
+ /* Join all programmed multicast groups. */\r
+ for( i = 0; i < p_adapter->mcast_array_size; i++ )\r
+ {\r
+ ipoib_port_join_mcast(\r
+ p_adapter->p_port, p_adapter->mcast_array[i] ,IB_MC_REC_STATE_FULL_MEMBER);\r
+ }\r
+\r
+ /* Register all existing addresses. */\r
+ ipoib_reg_addrs( p_adapter );\r
+\r
+ ipoib_resume_oids( p_adapter );\r
+\r
+ /*\r
+ * Now that we're in the broadcast group, notify that\r
+ * we have a link.\r
+ */\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, ("Link UP!\n") );\r
+ NdisWriteErrorLogEntry( p_adapter->h_adapter,\r
+ EVENT_IPOIB_PORT_UP + (p_adapter->rate/ONE_X_IN_100BPS),\r
+ 1, p_adapter->rate );\r
+\r
+ if( !p_adapter->reset )\r
+ {\r
+ NdisMIndicateStatus( p_adapter->h_adapter, NDIS_STATUS_MEDIA_CONNECT,\r
+ NULL, 0 );\r
+ NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
+ }\r
+ }\r
+\r
+ if( p_adapter->reset )\r
+ {\r
+ p_adapter->reset = FALSE;\r
+ NdisMResetComplete(\r
+ p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+/*\r
+ * If something goes wrong after the port goes active, e.g.\r
+ * - PortInfo query failure\r
+ * - MC Join timeout\r
+ * - etc\r
+ * Mark the port state as down, resume any pended OIDS, etc.\r
+ */\r
+void\r
+ipoib_set_inactive(\r
+ IN ipoib_adapter_t* const p_adapter )\r
+{\r
+ ib_pnp_event_t old_state;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ cl_obj_lock( &p_adapter->obj );\r
+ old_state = p_adapter->state;\r
+ if( old_state != IB_PNP_PORT_REMOVE )\r
+ p_adapter->state = IB_PNP_PORT_DOWN;\r
+ cl_obj_unlock( &p_adapter->obj );\r
+\r
+ /*\r
+ * If we had a pending OID request for OID_GEN_LINK_SPEED,\r
+ * complete it now.\r
+ */\r
+ if( old_state == IB_PNP_PORT_INIT )\r
+ {\r
+ NdisMIndicateStatus( p_adapter->h_adapter,\r
+ NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
+ NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
+\r
+ ipoib_resume_oids( p_adapter );\r
+ }\r
+\r
+ if( p_adapter->reset )\r
+ {\r
+ p_adapter->reset = FALSE;\r
+ NdisMResetComplete(\r
+ p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+NDIS_STATUS\r
+ipoib_get_recv_stat(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN const ip_stat_sel_t stat_sel,\r
+ IN pending_oid_t* const p_oid_info )\r
+{\r
+ uint64_t stat;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_STAT );\r
+\r
+ CL_ASSERT( p_adapter );\r
+\r
+ cl_spinlock_acquire( &p_adapter->recv_stat_lock );\r
+ switch( stat_sel )\r
+ {\r
+ case IP_STAT_SUCCESS:\r
+ stat = p_adapter->recv_stats.comp.success;\r
+ break;\r
+\r
+ case IP_STAT_ERROR:\r
+ stat = p_adapter->recv_stats.comp.error;\r
+ break;\r
+\r
+ case IP_STAT_DROPPED:\r
+ stat = p_adapter->recv_stats.comp.dropped;\r
+ break;\r
+\r
+ case IP_STAT_UCAST_BYTES:\r
+ stat = p_adapter->recv_stats.ucast.bytes;\r
+ break;\r
+\r
+ case IP_STAT_UCAST_FRAMES:\r
+ stat = p_adapter->recv_stats.ucast.frames;\r
+ break;\r
+\r
+ case IP_STAT_BCAST_BYTES:\r
+ stat = p_adapter->recv_stats.bcast.bytes;\r
+ break;\r
+\r
+ case IP_STAT_BCAST_FRAMES:\r
+ stat = p_adapter->recv_stats.bcast.frames;\r
+ break;\r
+\r
+ case IP_STAT_MCAST_BYTES:\r
+ stat = p_adapter->recv_stats.mcast.bytes;\r
+ break;\r
+\r
+ case IP_STAT_MCAST_FRAMES:\r
+ stat = p_adapter->recv_stats.mcast.frames;\r
+ break;\r
+\r
+ default:\r
+ stat = 0;\r
+ }\r
+ cl_spinlock_release( &p_adapter->recv_stat_lock );\r
+\r
+ *p_oid_info->p_bytes_needed = sizeof(uint64_t);\r
+\r
+ if( p_oid_info->buf_len >= sizeof(uint64_t) )\r
+ {\r
+ *((uint64_t*)p_oid_info->p_buf) = stat;\r
+ *p_oid_info->p_bytes_used = sizeof(uint64_t);\r
+ }\r
+ else if( p_oid_info->buf_len >= sizeof(uint32_t) )\r
+ {\r
+ *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat;\r
+ *p_oid_info->p_bytes_used = sizeof(uint32_t);\r
+ }\r
+ else\r
+ {\r
+ *p_oid_info->p_bytes_used = 0;\r
+ IPOIB_EXIT( IPOIB_DBG_STAT );\r
+ return NDIS_STATUS_INVALID_LENGTH;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_STAT );\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+void\r
+ipoib_inc_recv_stat(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN const ip_stat_sel_t stat_sel,\r
+ IN const size_t bytes OPTIONAL )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_STAT );\r
+\r
+ cl_spinlock_acquire( &p_adapter->recv_stat_lock );\r
+ switch( stat_sel )\r
+ {\r
+ case IP_STAT_ERROR:\r
+ p_adapter->recv_stats.comp.error++;\r
+ break;\r
+\r
+ case IP_STAT_DROPPED:\r
+ p_adapter->recv_stats.comp.dropped++;\r
+ break;\r
+\r
+ case IP_STAT_UCAST_BYTES:\r
+ case IP_STAT_UCAST_FRAMES:\r
+ p_adapter->recv_stats.comp.success++;\r
+ p_adapter->recv_stats.ucast.frames++;\r
+ p_adapter->recv_stats.ucast.bytes += bytes;\r
+ break;\r
+\r
+ case IP_STAT_BCAST_BYTES:\r
+ case IP_STAT_BCAST_FRAMES:\r
+ p_adapter->recv_stats.comp.success++;\r
+ p_adapter->recv_stats.bcast.frames++;\r
+ p_adapter->recv_stats.bcast.bytes += bytes;\r
+ break;\r
+\r
+ case IP_STAT_MCAST_BYTES:\r
+ case IP_STAT_MCAST_FRAMES:\r
+ p_adapter->recv_stats.comp.success++;\r
+ p_adapter->recv_stats.mcast.frames++;\r
+ p_adapter->recv_stats.mcast.bytes += bytes;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ cl_spinlock_release( &p_adapter->recv_stat_lock );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_STAT );\r
+}\r
+\r
+NDIS_STATUS\r
+ipoib_get_send_stat(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN const ip_stat_sel_t stat_sel,\r
+ IN pending_oid_t* const p_oid_info )\r
+{\r
+ uint64_t stat;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_STAT );\r
+\r
+ CL_ASSERT( p_adapter );\r
+\r
+ cl_spinlock_acquire( &p_adapter->send_stat_lock );\r
+ switch( stat_sel )\r
+ {\r
+ case IP_STAT_SUCCESS:\r
+ stat = p_adapter->send_stats.comp.success;\r
+ break;\r
+\r
+ case IP_STAT_ERROR:\r
+ stat = p_adapter->send_stats.comp.error;\r
+ break;\r
+\r
+ case IP_STAT_DROPPED:\r
+ stat = p_adapter->send_stats.comp.dropped;\r
+ break;\r
+\r
+ case IP_STAT_UCAST_BYTES:\r
+ stat = p_adapter->send_stats.ucast.bytes;\r
+ break;\r
+\r
+ case IP_STAT_UCAST_FRAMES:\r
+ stat = p_adapter->send_stats.ucast.frames;\r
+ break;\r
+\r
+ case IP_STAT_BCAST_BYTES:\r
+ stat = p_adapter->send_stats.bcast.bytes;\r
+ break;\r
+\r
+ case IP_STAT_BCAST_FRAMES:\r
+ stat = p_adapter->send_stats.bcast.frames;\r
+ break;\r
+\r
+ case IP_STAT_MCAST_BYTES:\r
+ stat = p_adapter->send_stats.mcast.bytes;\r
+ break;\r
+\r
+ case IP_STAT_MCAST_FRAMES:\r
+ stat = p_adapter->send_stats.mcast.frames;\r
+ break;\r
+\r
+ default:\r
+ stat = 0;\r
+ }\r
+ cl_spinlock_release( &p_adapter->send_stat_lock );\r
+\r
+ *p_oid_info->p_bytes_needed = sizeof(uint64_t);\r
+\r
+ if( p_oid_info->buf_len >= sizeof(uint64_t) )\r
+ {\r
+ *((uint64_t*)p_oid_info->p_buf) = stat;\r
+ *p_oid_info->p_bytes_used = sizeof(uint64_t);\r
+ }\r
+ else if( p_oid_info->buf_len >= sizeof(uint32_t) )\r
+ {\r
+ *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat;\r
+ *p_oid_info->p_bytes_used = sizeof(uint32_t);\r
+ }\r
+ else\r
+ {\r
+ *p_oid_info->p_bytes_used = 0;\r
+ IPOIB_EXIT( IPOIB_DBG_STAT );\r
+ return NDIS_STATUS_INVALID_LENGTH;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_STAT );\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+void\r
+ipoib_inc_send_stat(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN const ip_stat_sel_t stat_sel,\r
+ IN const size_t bytes OPTIONAL )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_STAT );\r
+\r
+ cl_spinlock_acquire( &p_adapter->send_stat_lock );\r
+ switch( stat_sel )\r
+ {\r
+ case IP_STAT_ERROR:\r
+ p_adapter->send_stats.comp.error++;\r
+ break;\r
+\r
+ case IP_STAT_DROPPED:\r
+ p_adapter->send_stats.comp.dropped++;\r
+ break;\r
+\r
+ case IP_STAT_UCAST_BYTES:\r
+ case IP_STAT_UCAST_FRAMES:\r
+ p_adapter->send_stats.comp.success++;\r
+ p_adapter->send_stats.ucast.frames++;\r
+ p_adapter->send_stats.ucast.bytes += bytes;\r
+ break;\r
+\r
+ case IP_STAT_BCAST_BYTES:\r
+ case IP_STAT_BCAST_FRAMES:\r
+ p_adapter->send_stats.comp.success++;\r
+ p_adapter->send_stats.bcast.frames++;\r
+ p_adapter->send_stats.bcast.bytes += bytes;\r
+ break;\r
+\r
+ case IP_STAT_MCAST_BYTES:\r
+ case IP_STAT_MCAST_FRAMES:\r
+ p_adapter->send_stats.comp.success++;\r
+ p_adapter->send_stats.mcast.frames++;\r
+ p_adapter->send_stats.mcast.bytes += bytes;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ cl_spinlock_release( &p_adapter->send_stat_lock );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_STAT );\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ * Copyright (c) 2006 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+#ifndef _IPOIB_ADAPTER_H_\r
+#define _IPOIB_ADAPTER_H_\r
+\r
+#include <iba/ipoib_ifc.h>\r
+#include <iba/ib_al.h>\r
+#include <complib/cl_obj.h>\r
+#include <complib/cl_spinlock.h>\r
+#include <complib/cl_mutex.h>\r
+#include <complib/cl_qpool.h>\r
+#include <complib/cl_atomic.h>\r
+#include <complib/cl_perf.h>\r
+#include <complib/cl_vector.h>\r
+#include <ip_packet.h>\r
+#include "ip_stats.h"\r
+\r
+\r
+/*\r
+ * Definitions\r
+ */\r
+#define MAX_MCAST 32\r
+\r
+#define IPV4_ADDR_SIZE 4\r
+\r
+#define PORT_NUM_INDEX_IN_GUID 3 /* 0 based index into big endian GUID to get port number */\r
+\r
+/*\r
+ * Macros\r
+ */\r
+\r
+\r
+typedef struct _ipoib_params\r
+{\r
+ int32_t rq_depth;\r
+ int32_t rq_low_watermark;\r
+ int32_t sq_depth;\r
+ boolean_t send_chksum_offload;\r
+ boolean_t recv_chksum_offload;\r
+ uint32_t sa_timeout;\r
+ uint32_t sa_retry_cnt;\r
+ uint32_t recv_pool_ratio;\r
+ uint32_t payload_mtu;\r
+ uint32_t xfer_block_size;\r
+ mac_addr_t conf_mac;\r
+\r
+} ipoib_params_t;\r
+/*\r
+* FIELDS\r
+* rq_depth\r
+* Number of receive WQEs to allocate.\r
+*\r
+* rq_low_watermark\r
+* Receives are indicated with NDIS_STATUS_RESOURCES when the number of\r
+* receives posted to the RQ falls bellow this value.\r
+*\r
+* sq_depth\r
+* Number of send WQEs to allocate.\r
+*\r
+* send_chksum_offload\r
+* Flag to indicate whether to offload send checksums. This will make it\r
+* so that IPoIB packets should never be forwarded out of the IB subnet\r
+* without recalculating the checksum.\r
+*\r
+* recv_chksum_offload\r
+* Flag to indicate whether to offload recv checksums.\r
+*\r
+* wsdp_enabled\r
+* Flag to indicate whether WSDP is enabled for an adapter adapter.\r
+*\r
+* static_lid\r
+* LID to assign to the port if that port is down (not init) and has none.\r
+* This feature allows a LID to be assigned, alowing locally targetted\r
+* traffic to occur even on ports that are not plugged in.\r
+*\r
+* sa_timeout\r
+* Time, in milliseconds, to wait for a response before retransmitting an\r
+* SA query request.\r
+*\r
+* sa_retry_cnt\r
+* Number of times to retry an SA query request.\r
+*\r
+* recv_pool_ratio\r
+* Initial ratio of receive pool size to receive queue depth.\r
+*\r
+* grow_thresh\r
+* Threshold at which to grow the receive pool. Valid values start are\r
+* powers of 2, excluding 1. When zero, grows only when the pool is\r
+* exhausted. Other values indicate fractional values\r
+* (i.e. 2 indicates 1/2, 4 indicates 1/4, etc.)\r
+*********/\r
+\r
+\r
+typedef struct _pending_oid\r
+{\r
+ NDIS_OID oid;\r
+ PVOID p_buf;\r
+ ULONG buf_len;\r
+ PULONG p_bytes_used;\r
+ PULONG p_bytes_needed;\r
+\r
+} pending_oid_t;\r
+\r
+\r
+typedef struct _ipoib_adapter\r
+{\r
+ cl_obj_t obj;\r
+ NDIS_HANDLE h_adapter;\r
+ ipoib_ifc_data_t guids;\r
+\r
+ cl_list_item_t entry;\r
+\r
+ ib_al_handle_t h_al;\r
+ ib_pnp_handle_t h_pnp;\r
+\r
+ ib_pnp_event_t state;\r
+ boolean_t hung;\r
+ boolean_t reset;\r
+ boolean_t registering;\r
+\r
+ boolean_t pending_query;\r
+ pending_oid_t query_oid;\r
+ boolean_t pending_set;\r
+ pending_oid_t set_oid;\r
+\r
+ struct _ipoib_port *p_port;\r
+\r
+ uint32_t rate;\r
+\r
+ ipoib_params_t params;\r
+ cl_spinlock_t recv_stat_lock;\r
+ ip_stats_t recv_stats;\r
+ cl_spinlock_t send_stat_lock;\r
+ ip_stats_t send_stats;\r
+\r
+ boolean_t is_primary;\r
+ struct _ipoib_adapter *p_primary;\r
+\r
+ uint32_t packet_filter;\r
+\r
+ mac_addr_t mac;\r
+ mac_addr_t mcast_array[MAX_MCAST];\r
+ uint8_t mcast_array_size;\r
+\r
+ cl_qpool_t item_pool;\r
+\r
+ KMUTEX mutex;\r
+\r
+ cl_thread_t destroy_thread;\r
+ cl_vector_t ip_vector;\r
+\r
+ cl_perf_t perf;\r
+ ib_al_ifc_t *p_ifc;\r
+\r
+} ipoib_adapter_t;\r
+/*\r
+* FIELDS\r
+* obj\r
+* Complib object for reference counting and destruction synchronization.\r
+*\r
+* h_adapter\r
+* NDIS adapter handle.\r
+*\r
+* guids\r
+* CA and port GUIDs returned by the bus driver.\r
+*\r
+* entry\r
+* List item for storing all adapters in a list for address translation.\r
+* We add adapters when their packet filter is set to a non-zero value,\r
+* and remove them when their packet filter is cleared. This is needed\r
+* since user-mode removal events are generated after the packet filter\r
+* is cleared, but before the adapter is destroyed.\r
+*\r
+* h_al\r
+* AL handle for all IB resources.\r
+*\r
+* h_pnp\r
+* PNP registration handle for port events.\r
+*\r
+* state\r
+* State of the adapter. IB_PNP_PORT_ADD indicates that the adapter\r
+* is ready to transfer data.\r
+*\r
+* hung\r
+* Boolean flag used to return whether we are hung or not.\r
+*\r
+* p_port\r
+* Pointer to an ipoib_port_t representing all resources for moving data\r
+* on the IB fabric.\r
+*\r
+* rate\r
+* Rate, in 100bps increments, of the link.\r
+*\r
+* params\r
+* Configuration parameters.\r
+*\r
+* pending_query\r
+* Indicates that an query OID request is being processed asynchronously.\r
+*\r
+* query_oid\r
+* Information about the pended query OID request.\r
+* Valid only if pending_query is TRUE.\r
+*\r
+* pending_set\r
+* Indicates that an set OID request is being processed asynchronously.\r
+*\r
+* set_oid\r
+* Information about the pended set OID request.\r
+* Valid only if pending_set is TRUE.\r
+*\r
+* recv_lock\r
+* Spinlock protecting receive processing.\r
+*\r
+* recv_stats\r
+* Receive statistics.\r
+*\r
+* send_lock\r
+* Spinlock protecting send processing.\r
+*\r
+* send_stats\r
+* Send statistics.\r
+*\r
+* is_primary\r
+* Boolean flag to indicate if an adapter is the primary adapter\r
+* of a bundle.\r
+*\r
+* p_primary\r
+* Pointer to the primary adapter for a bundle.\r
+*\r
+* packet_filter\r
+* Packet filter set by NDIS.\r
+*\r
+* mac_addr\r
+* Ethernet MAC address reported to NDIS.\r
+*\r
+* mcast_array\r
+* List of multicast MAC addresses programmed by NDIS.\r
+*\r
+* mcast_array_size\r
+* Number of entries in the multicat MAC address array;\r
+*\r
+* item_pool\r
+* Pool of cl_pool_obj_t structures to use for queueing pending\r
+* packets for transmission.\r
+*\r
+* mutex\r
+* Mutex to synchronized PnP callbacks with destruction.\r
+*\r
+* ip_vector\r
+* Vector of assigned IP addresses.\r
+*\r
+* p_ifc\r
+* Pointer to transport interface.\r
+*\r
+*********/\r
+\r
+\r
+typedef struct _ats_reg\r
+{\r
+ ipoib_adapter_t *p_adapter;\r
+ ib_reg_svc_handle_t h_reg_svc;\r
+\r
+} ats_reg_t;\r
+/*\r
+* FIELDS\r
+* p_adapter\r
+* Pointer to the adapter to which this address is assigned.\r
+*\r
+* h_reg_svc\r
+* Service registration handle.\r
+*********/\r
+\r
+\r
+typedef struct _net_address_item\r
+{\r
+ ats_reg_t *p_reg;\r
+ union _net_address_item_address\r
+ {\r
+ ULONG as_ulong;\r
+ UCHAR as_bytes[IPV4_ADDR_SIZE];\r
+ } address;\r
+\r
+} net_address_item_t;\r
+/*\r
+* FIELDS\r
+* p_reg\r
+* Pointer to the ATS registration assigned to this address.\r
+*\r
+* address\r
+* Union representing the IP address as an unsigned long or as\r
+* an array of bytes.\r
+*\r
+* as_ulong\r
+* The IP address represented as an unsigned long. Windows stores\r
+* IPs this way.\r
+*\r
+* as_bytes\r
+* The IP address represented as an array of bytes.\r
+*********/\r
+\r
+\r
+ib_api_status_t\r
+ipoib_create_adapter(\r
+ IN NDIS_HANDLE wrapper_config_context,\r
+ IN void* const h_adapter,\r
+ OUT ipoib_adapter_t** const pp_adapter );\r
+\r
+\r
+ib_api_status_t\r
+ipoib_start_adapter(\r
+ IN ipoib_adapter_t* const p_adapter );\r
+\r
+\r
+void\r
+ipoib_destroy_adapter(\r
+ IN ipoib_adapter_t* const p_adapter );\r
+\r
+\r
+/* Joins/leaves mcast groups based on currently programmed mcast MACs. */\r
+void\r
+ipoib_refresh_mcast(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN mac_addr_t* const p_mac_array,\r
+ IN const uint8_t num_macs );\r
+/*\r
+* PARAMETERS\r
+* p_adapter\r
+* Instance whose multicast MAC address list to modify.\r
+*\r
+* p_mac_array\r
+* Array of multicast MAC addresses assigned to the adapter.\r
+*\r
+* num_macs\r
+* Number of MAC addresses in the array.\r
+*********/\r
+\r
+\r
+NDIS_STATUS\r
+ipoib_get_recv_stat(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN const ip_stat_sel_t stat_sel,\r
+ IN pending_oid_t* const p_oid_info );\r
+\r
+\r
+void\r
+ipoib_inc_recv_stat(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN const ip_stat_sel_t stat_sel,\r
+ IN const size_t bytes OPTIONAL );\r
+\r
+\r
+NDIS_STATUS\r
+ipoib_get_send_stat(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN const ip_stat_sel_t stat_sel,\r
+ IN pending_oid_t* const p_oid_info );\r
+\r
+\r
+void\r
+ipoib_inc_send_stat(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN const ip_stat_sel_t stat_sel,\r
+ IN const size_t bytes OPTIONAL );\r
+\r
+\r
+void\r
+ipoib_set_rate(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN const uint8_t link_width,\r
+ IN const uint8_t link_speed );\r
+\r
+\r
+void\r
+ipoib_set_active(\r
+ IN ipoib_adapter_t* const p_adapter );\r
+\r
+void\r
+ipoib_set_inactive(\r
+ IN ipoib_adapter_t* const p_adapter );\r
+\r
+ib_api_status_t\r
+ipoib_reset_adapter(\r
+ IN ipoib_adapter_t* const p_adapter );\r
+\r
+void\r
+ipoib_reg_addrs(\r
+ IN ipoib_adapter_t* const p_adapter );\r
+\r
+void\r
+ipoib_dereg_addrs(\r
+ IN ipoib_adapter_t* const p_adapter );\r
+\r
+#endif /* _IPOIB_ADAPTER_H_ */\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ * Copyright (c) 2006 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+#ifndef _IPOIB_DEBUG_H_\r
+#define _IPOIB_DEBUG_H_\r
+\r
+\r
+#define __MODULE__ "[IPoIB]"\r
+\r
+#include <complib/cl_debug.h>\r
+\r
+\r
+/* Object types for passing into complib. */\r
+#define IPOIB_OBJ_INSTANCE 1\r
+#define IPOIB_OBJ_PORT 2\r
+#define IPOIB_OBJ_ENDPOINT 3\r
+\r
+\r
+extern uint32_t g_ipoib_dbg_level;\r
+extern uint32_t g_ipoib_dbg_flags;\r
+\r
+\r
+#if defined(EVENT_TRACING)\r
+//\r
+// Software Tracing Definitions\r
+//\r
+#define WPP_CONTROL_GUIDS \\r
+ WPP_DEFINE_CONTROL_GUID( \\r
+ IPOIBCtlGuid,(3F9BC73D, EB03, 453a, B27B, 20F9A664211A), \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_ERROR) \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_INIT) \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_PNP) \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_SEND) \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_RECV) \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_ENDPT) \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_IB) \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_BUF) \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_MCAST) \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_ALLOC) \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_OID) \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_IOCTL) \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_STAT) \\r
+ WPP_DEFINE_BIT(IPOIB_DBG_OBJ))\r
+\r
+\r
+\r
+#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \\r
+ (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)\r
+#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags)\r
+#define WPP_FLAG_ENABLED(flags) \\r
+ (WPP_LEVEL_ENABLED(flags) && \\r
+ WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE)\r
+#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags)\r
+\r
+// begin_wpp config\r
+// IPOIB_ENTER(FLAG);\r
+// IPOIB_EXIT(FLAG);\r
+// USEPREFIX(IPOIB_PRINT, "%!STDPREFIX! [IPoIB] :%!FUNC!() :");\r
+// USEPREFIX(IPOIB_PRINT_EXIT, "%!STDPREFIX! [IPoIB] :%!FUNC!() :");\r
+// USESUFFIX(IPOIB_PRINT_EXIT, "[IpoIB] :%!FUNC!():]");\r
+// USESUFFIX(IPOIB_ENTER, " [IPoIB] :%!FUNC!():[");\r
+// USESUFFIX(IPOIB_EXIT, " [IPoIB] :%!FUNC!():]");\r
+// end_wpp\r
+\r
+#else\r
+\r
+#include <evntrace.h>\r
+\r
+\r
+/*\r
+ * Debug macros\r
+ */\r
+#define IPOIB_DBG_ERR (1 << 0)\r
+#define IPOIB_DBG_INIT (1 << 1)\r
+#define IPOIB_DBG_PNP (1 << 2)\r
+#define IPOIB_DBG_SEND (1 << 3)\r
+#define IPOIB_DBG_RECV (1 << 4)\r
+#define IPOIB_DBG_ENDPT (1 << 5)\r
+#define IPOIB_DBG_IB (1 << 6)\r
+#define IPOIB_DBG_BUF (1 << 7)\r
+#define IPOIB_DBG_MCAST (1 << 8)\r
+#define IPOIB_DBG_ALLOC (1 << 9)\r
+#define IPOIB_DBG_OID (1 << 10)\r
+#define IPOIB_DBG_IOCTL (1 << 11)\r
+#define IPOIB_DBG_STAT (1 << 12)\r
+#define IPOIB_DBG_OBJ (1 << 13)\r
+\r
+#define IPOIB_DBG_ERROR (CL_DBG_ERROR | IPOIB_DBG_ERR)\r
+#define IPOIB_DBG_ALL CL_DBG_ALL\r
+\r
+\r
+#if DBG\r
+\r
+// assignment of _level_ is need to to overcome warning C4127\r
+#define IPOIB_PRINT(_level_,_flag_,_msg_) \\r
+ { \\r
+ if( g_ipoib_dbg_level >= (_level_) ) \\r
+ CL_TRACE( _flag_, g_ipoib_dbg_flags, _msg_ ); \\r
+ }\r
+\r
+#define IPOIB_PRINT_EXIT(_level_,_flag_,_msg_) \\r
+ { \\r
+ if( g_ipoib_dbg_level >= (_level_) ) \\r
+ CL_TRACE( _flag_, g_ipoib_dbg_flags, _msg_ );\\r
+ IPOIB_EXIT(_flag_);\\r
+ }\r
+\r
+#define IPOIB_ENTER(_flag_) \\r
+ { \\r
+ if( g_ipoib_dbg_level >= TRACE_LEVEL_VERBOSE ) \\r
+ CL_ENTER( _flag_, g_ipoib_dbg_flags ); \\r
+ }\r
+\r
+#define IPOIB_EXIT(_flag_)\\r
+ { \\r
+ if( g_ipoib_dbg_level >= TRACE_LEVEL_VERBOSE ) \\r
+ CL_EXIT( _flag_, g_ipoib_dbg_flags ); \\r
+ }\r
+\r
+#define IPOIB_TRACE_BYTES( lvl, ptr, len ) \\r
+ { \\r
+ if( g_ipoib_dbg_level >= (_level_) && \\r
+ (g_ipoib_dbg_flags & (_flag_)) ) \\r
+ { \\r
+ size_t _loop_; \\r
+ for( _loop_ = 0; _loop_ < (len); ++_loop_ ) \\r
+ { \\r
+ DbgPrint( "0x%.2X ", ((uint8_t*)(ptr))[_loop_] ); \\r
+ if( (_loop_ + 1)% 16 == 0 ) \\r
+ DbgPrint("\n"); \\r
+ else if( (_loop_ % 4 + 1) == 0 ) \\r
+ DbgPrint(" "); \\r
+ } \\r
+ DbgPrint("\n"); \\r
+ } \\r
+ }\r
+\r
+#else\r
+\r
+#define IPOIB_PRINT(lvl, flags, msg)\r
+\r
+#define IPOIB_PRINT_EXIT(_level_,_flag_,_msg_)\r
+\r
+#define IPOIB_ENTER(_flag_)\r
+\r
+#define IPOIB_EXIT(_flag_)\r
+\r
+#define IPOIB_TRACE_BYTES( lvl, ptr, len )\r
+\r
+#endif\r
+\r
+#endif //EVENT_TRACING\r
+\r
+\r
+enum ipoib_perf_counters\r
+{\r
+ SendBundle,\r
+ SendPackets,\r
+ PortSend,\r
+ GetEthHdr,\r
+ SendMgrQueue,\r
+ GetEndpt,\r
+ EndptQueue,\r
+ QueuePacket,\r
+ BuildSendDesc,\r
+ SendMgrFilter,\r
+ FilterIp,\r
+ QueryIp,\r
+ SendTcp,\r
+ FilterUdp,\r
+ QueryUdp,\r
+ SendUdp,\r
+ FilterDhcp,\r
+ FilterArp,\r
+ SendGen,\r
+ SendCopy,\r
+ PostSend,\r
+ ProcessFailedSends,\r
+ SendCompBundle,\r
+ SendCb,\r
+ PollSend,\r
+ SendComp,\r
+ FreeSendBuf,\r
+ RearmSend,\r
+ PortResume,\r
+ RecvCompBundle,\r
+ RecvCb,\r
+ PollRecv,\r
+ FilterRecv,\r
+ GetRecvEndpts,\r
+ GetEndptByGid,\r
+ GetEndptByLid,\r
+ EndptInsert,\r
+ RecvTcp,\r
+ RecvUdp,\r
+ RecvDhcp,\r
+ RecvArp,\r
+ RecvGen,\r
+ BuildPktArray,\r
+ PreparePkt,\r
+ GetNdisPkt,\r
+ RecvNdisIndicate,\r
+ PutRecvList,\r
+ RepostRecv,\r
+ GetRecv,\r
+ PostRecv,\r
+ RearmRecv,\r
+ ReturnPacket,\r
+ ReturnPutRecv,\r
+ ReturnRepostRecv,\r
+ ReturnPreparePkt,\r
+ ReturnNdisIndicate,\r
+\r
+ /* Must be last! */\r
+ MaxPerf\r
+\r
+};\r
+\r
+\r
+enum ref_cnt_buckets\r
+{\r
+ ref_init = 0,\r
+ ref_refresh_mcast, /* only used in refresh_mcast */\r
+ ref_send_packets, /* only in send_packets */\r
+ ref_get_recv,\r
+ ref_repost, /* only in __recv_mgr_repost */\r
+ ref_recv_cb, /* only in __recv_cb */\r
+ ref_send_cb, /* only in __send_cb */\r
+ ref_port_up,\r
+ ref_get_bcast,\r
+ ref_bcast, /* join and create, used as base only */\r
+ ref_join_mcast,\r
+ ref_leave_mcast,\r
+ ref_endpt_track, /* used when endpt is in port's child list. */\r
+\r
+ ref_array_size, /* Used to size the array of ref buckets. */\r
+ ref_mask = 100, /* Used to differentiate derefs. */\r
+\r
+ ref_failed_recv_wc = 100 | ref_get_recv,\r
+ ref_recv_inv_len = 200 | ref_get_recv,\r
+ ref_recv_loopback = 300 | ref_get_recv,\r
+ ref_recv_filter = 400 | ref_get_recv,\r
+\r
+ ref_bcast_get_cb = 100 | ref_get_bcast,\r
+\r
+ ref_join_bcast = 100 | ref_bcast,\r
+ ref_create_bcast = 200 | ref_bcast,\r
+ ref_bcast_inv_state = 300 | ref_bcast,\r
+ ref_bcast_req_failed = 400 | ref_bcast,\r
+ ref_bcast_error = 500 | ref_bcast,\r
+ ref_bcast_join_failed = 600 | ref_bcast,\r
+ ref_bcast_create_failed = 700 | ref_bcast,\r
+\r
+ ref_mcast_inv_state = 100 | ref_join_mcast,\r
+ ref_mcast_req_failed = 200 | ref_join_mcast,\r
+ ref_mcast_no_endpt = 300 | ref_join_mcast,\r
+ ref_mcast_av_failed = 400 | ref_join_mcast,\r
+ ref_mcast_join_failed = 500 | ref_join_mcast,\r
+\r
+ ref_port_info_cb = 100 | ref_port_up\r
+\r
+};\r
+\r
+\r
+#endif /* _IPOIB_DEBUG_H_ */\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ * Copyright (c) 2006 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+#include "ipoib_driver.h"\r
+#include "ipoib_debug.h"\r
+\r
+#if defined(EVENT_TRACING)\r
+#ifdef offsetof\r
+#undef offsetof\r
+#endif\r
+#include "ipoib_driver.tmh"\r
+#endif\r
+\r
+#include "ipoib_port.h"\r
+#include "ipoib_ibat.h"\r
+#include <complib/cl_bus_ifc.h>\r
+#include <complib/cl_init.h>\r
+#include <initguid.h>\r
+#include <iba/ipoib_ifc.h>\r
+\r
+\r
+#if defined(NDIS50_MINIPORT)\r
+#define MAJOR_NDIS_VERSION 5\r
+#define MINOR_NDIS_VERSION 0\r
+#elif defined (NDIS51_MINIPORT)\r
+#define MAJOR_NDIS_VERSION 5\r
+#define MINOR_NDIS_VERSION 1\r
+#else\r
+#error NDIS Version not defined, try defining NDIS50_MINIPORT or NDIS51_MINIPORT\r
+#endif\r
+\r
+static const NDIS_OID SUPPORTED_OIDS[] =\r
+{\r
+ OID_GEN_SUPPORTED_LIST,\r
+ OID_GEN_HARDWARE_STATUS,\r
+ OID_GEN_MEDIA_SUPPORTED,\r
+ OID_GEN_MEDIA_IN_USE,\r
+ OID_GEN_MAXIMUM_LOOKAHEAD,\r
+ OID_GEN_MAXIMUM_FRAME_SIZE,\r
+ OID_GEN_LINK_SPEED,\r
+ OID_GEN_TRANSMIT_BUFFER_SPACE,\r
+ OID_GEN_RECEIVE_BUFFER_SPACE,\r
+ OID_GEN_TRANSMIT_BLOCK_SIZE,\r
+ OID_GEN_RECEIVE_BLOCK_SIZE,\r
+ OID_GEN_VENDOR_ID,\r
+ OID_GEN_VENDOR_DESCRIPTION,\r
+ OID_GEN_CURRENT_PACKET_FILTER,\r
+ OID_GEN_CURRENT_LOOKAHEAD,\r
+ OID_GEN_DRIVER_VERSION,\r
+ OID_GEN_MAXIMUM_TOTAL_SIZE,\r
+ OID_GEN_PROTOCOL_OPTIONS,\r
+ OID_GEN_MAC_OPTIONS,\r
+ OID_GEN_MEDIA_CONNECT_STATUS,\r
+ OID_GEN_MAXIMUM_SEND_PACKETS,\r
+ OID_GEN_NETWORK_LAYER_ADDRESSES,\r
+ OID_GEN_VENDOR_DRIVER_VERSION,\r
+ OID_GEN_PHYSICAL_MEDIUM,\r
+ OID_GEN_XMIT_OK,\r
+ OID_GEN_RCV_OK,\r
+ OID_GEN_XMIT_ERROR,\r
+ OID_GEN_RCV_ERROR,\r
+ OID_GEN_RCV_NO_BUFFER,\r
+ OID_GEN_DIRECTED_BYTES_XMIT,\r
+ OID_GEN_DIRECTED_FRAMES_XMIT,\r
+ OID_GEN_MULTICAST_BYTES_XMIT,\r
+ OID_GEN_MULTICAST_FRAMES_XMIT,\r
+ OID_GEN_BROADCAST_BYTES_XMIT,\r
+ OID_GEN_BROADCAST_FRAMES_XMIT,\r
+ OID_GEN_DIRECTED_BYTES_RCV,\r
+ OID_GEN_DIRECTED_FRAMES_RCV,\r
+ OID_GEN_MULTICAST_BYTES_RCV,\r
+ OID_GEN_MULTICAST_FRAMES_RCV,\r
+ OID_GEN_BROADCAST_BYTES_RCV,\r
+ OID_GEN_BROADCAST_FRAMES_RCV,\r
+ OID_802_3_PERMANENT_ADDRESS,\r
+ OID_802_3_CURRENT_ADDRESS,\r
+ OID_802_3_MULTICAST_LIST,\r
+ OID_802_3_MAXIMUM_LIST_SIZE,\r
+ OID_802_3_MAC_OPTIONS,\r
+ OID_802_3_RCV_ERROR_ALIGNMENT,\r
+ OID_802_3_XMIT_ONE_COLLISION,\r
+ OID_802_3_XMIT_MORE_COLLISIONS,\r
+ OID_TCP_TASK_OFFLOAD\r
+};\r
+\r
+static const unsigned char VENDOR_ID[] = {0x00, 0x06, 0x6A, 0x00};\r
+\r
+#define VENDOR_DESCRIPTION "Internet Protocol over InfiniBand"\r
+\r
+#define IB_INFINITE_SERVICE_LEASE 0xFFFFFFFF\r
+\r
+\r
+/* Global driver debug level */\r
+uint32_t g_ipoib_dbg_level = TRACE_LEVEL_ERROR;\r
+uint32_t g_ipoib_dbg_flags = 0x00000fff;\r
+ipoib_globals_t g_ipoib = {0};\r
+\r
+\r
+NTSTATUS\r
+DriverEntry(\r
+ IN PDRIVER_OBJECT p_drv_obj,\r
+ IN PUNICODE_STRING p_reg_path );\r
+\r
+VOID\r
+ipoib_unload(\r
+ IN PDRIVER_OBJECT p_drv_obj );\r
+\r
+NDIS_STATUS\r
+ipoib_initialize(\r
+ OUT PNDIS_STATUS p_open_err_status,\r
+ OUT PUINT p_selected_medium_index,\r
+ IN PNDIS_MEDIUM medium_array,\r
+ IN UINT medium_array_size,\r
+ IN NDIS_HANDLE h_adapter,\r
+ IN NDIS_HANDLE wrapper_configuration_context );\r
+\r
+BOOLEAN\r
+ipoib_check_for_hang(\r
+ IN NDIS_HANDLE adapter_context );\r
+\r
+void\r
+ipoib_halt(\r
+ IN NDIS_HANDLE adapter_context );\r
+\r
+NDIS_STATUS\r
+ipoib_query_info(\r
+ IN NDIS_HANDLE adapter_context,\r
+ IN NDIS_OID oid,\r
+ IN PVOID info_buf,\r
+ IN ULONG info_buf_len,\r
+ OUT PULONG p_bytes_written,\r
+ OUT PULONG p_bytes_needed );\r
+\r
+NDIS_STATUS\r
+ipoib_reset(\r
+ OUT PBOOLEAN p_addressing_reset,\r
+ IN NDIS_HANDLE adapter_context );\r
+\r
+NDIS_STATUS\r
+ipoib_set_info(\r
+ IN NDIS_HANDLE adapter_context,\r
+ IN NDIS_OID oid,\r
+ IN PVOID info_buf,\r
+ IN ULONG info_buf_length,\r
+ OUT PULONG p_bytes_read,\r
+ OUT PULONG p_bytes_needed );\r
+\r
+void\r
+ipoib_send_packets(\r
+ IN NDIS_HANDLE adapter_context,\r
+ IN PPNDIS_PACKET packet_array,\r
+ IN UINT num_packets );\r
+\r
+void\r
+ipoib_pnp_notify(\r
+ IN NDIS_HANDLE adapter_context,\r
+ IN NDIS_DEVICE_PNP_EVENT pnp_event,\r
+ IN PVOID info_buf,\r
+ IN ULONG info_buf_len );\r
+\r
+void\r
+ipoib_shutdown(\r
+ IN PVOID adapter_context );\r
+\r
+static void\r
+ipoib_complete_query(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN pending_oid_t* const p_oid_info,\r
+ IN const NDIS_STATUS status,\r
+ IN const void* const p_buf,\r
+ IN const ULONG buf_len );\r
+\r
+static NDIS_STATUS\r
+__ipoib_set_net_addr(\r
+ IN ipoib_adapter_t * p_adapter,\r
+ IN PVOID info_buf,\r
+ IN ULONG info_buf_len,\r
+ OUT PULONG p_bytes_read,\r
+ OUT PULONG p_bytes_needed );\r
+\r
+static NDIS_STATUS\r
+__ipoib_get_tcp_task_offload(\r
+ IN ipoib_adapter_t* p_adapter,\r
+ IN pending_oid_t* const p_oid_info );\r
+\r
+static void\r
+__ipoib_ats_reg_cb(\r
+ IN ib_reg_svc_rec_t *p_reg_svc_rec );\r
+\r
+static void\r
+__ipoib_ats_dereg_cb(\r
+ IN void *context );\r
+\r
+static NTSTATUS\r
+__ipoib_read_registry(\r
+ IN UNICODE_STRING* const p_registry_path );\r
+\r
+\r
+//! Standard Windows Device Driver Entry Point\r
+/*! DriverEntry is the first routine called after a driver is loaded, and\r
+is responsible for initializing the driver. On W2k this occurs when the PnP\r
+Manager matched a PnP ID to one in an INF file that references this driver.\r
+Any not success return value will cause the driver to fail to load.\r
+IRQL = PASSIVE_LEVEL\r
+\r
+@param p_drv_obj Pointer to Driver Object for this device driver\r
+@param p_registry_path Pointer to unicode string containing path to this driver's registry area\r
+@return STATUS_SUCCESS, NDIS_STATUS_BAD_CHARACTERISTICS, NDIS_STATUS_BAD_VERSION,\r
+NDIS_STATUS_RESOURCES, or NDIS_STATUS_FAILURE\r
+*/\r
+NTSTATUS\r
+DriverEntry(\r
+ IN PDRIVER_OBJECT p_drv_obj,\r
+ IN PUNICODE_STRING p_registry_path )\r
+{\r
+ NDIS_STATUS status;\r
+ NDIS_HANDLE ndis_handle;\r
+ NDIS_MINIPORT_CHARACTERISTICS characteristics;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+#ifdef _DEBUG_\r
+ PAGED_CODE();\r
+#endif\r
+#if defined(EVENT_TRACING)\r
+ WPP_INIT_TRACING(p_drv_obj, p_registry_path);\r
+#endif\r
+ status = CL_INIT;\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("cl_init failed.\n") );\r
+ return status;\r
+ }\r
+\r
+ status = NDIS_STATUS_SUCCESS;\r
+ ndis_handle = NULL;\r
+\r
+ __ipoib_read_registry(p_registry_path);\r
+ \r
+ KeInitializeSpinLock( &g_ipoib.lock );\r
+ cl_qlist_init( &g_ipoib.adapter_list );\r
+\r
+ NdisMInitializeWrapper(\r
+ &g_ipoib.h_ndis_wrapper, p_drv_obj, p_registry_path, NULL );\r
+\r
+ memset(&characteristics, 0, sizeof(characteristics));\r
+ characteristics.MajorNdisVersion = MAJOR_NDIS_VERSION;\r
+ characteristics.MinorNdisVersion = MINOR_NDIS_VERSION;\r
+ characteristics.CheckForHangHandler = ipoib_check_for_hang;\r
+ characteristics.HaltHandler = ipoib_halt;\r
+ characteristics.InitializeHandler = ipoib_initialize;\r
+ characteristics.QueryInformationHandler = ipoib_query_info;\r
+ characteristics.ResetHandler = ipoib_reset;\r
+ characteristics.SetInformationHandler = ipoib_set_info;\r
+\r
+ characteristics.ReturnPacketHandler = ipoib_return_packet;\r
+ characteristics.SendPacketsHandler = ipoib_send_packets;\r
+\r
+#ifdef NDIS51_MINIPORT\r
+ characteristics.PnPEventNotifyHandler = ipoib_pnp_notify;\r
+ characteristics.AdapterShutdownHandler = ipoib_shutdown;\r
+#endif\r
+\r
+ status = NdisMRegisterMiniport(\r
+ g_ipoib.h_ndis_wrapper, &characteristics, sizeof(characteristics) );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, \r
+ ("NdisMRegisterMiniport failed with status of %d\n", status) );\r
+ NdisTerminateWrapper( g_ipoib.h_ndis_wrapper, NULL );\r
+ CL_DEINIT;\r
+ return status;\r
+ }\r
+\r
+ NdisMRegisterUnloadHandler( g_ipoib.h_ndis_wrapper, ipoib_unload );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return status;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+__ipoib_read_registry(\r
+ IN UNICODE_STRING* const p_registry_path )\r
+{\r
+ NTSTATUS status;\r
+ /* Remember the terminating entry in the table below. */\r
+ RTL_QUERY_REGISTRY_TABLE table[4];\r
+ UNICODE_STRING param_path;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+ RtlInitUnicodeString( ¶m_path, NULL );\r
+ param_path.MaximumLength = p_registry_path->Length + \r
+ sizeof(L"\\Parameters");\r
+ param_path.Buffer = cl_zalloc( param_path.MaximumLength );\r
+ if( !param_path.Buffer )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, \r
+ ("Failed to allocate parameters path buffer.\n") );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ RtlAppendUnicodeStringToString( ¶m_path, p_registry_path );\r
+ RtlAppendUnicodeToString( ¶m_path, L"\\Parameters" );\r
+\r
+ /*\r
+ * Clear the table. This clears all the query callback pointers,\r
+ * and sets up the terminating table entry.\r
+ */\r
+ cl_memclr( table, sizeof(table) );\r
+\r
+ /* Setup the table entries. */\r
+ table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
+ table[0].Name = L"DebugLevel";\r
+ table[0].EntryContext = &g_ipoib_dbg_level;\r
+ table[0].DefaultType = REG_DWORD;\r
+ table[0].DefaultData = &g_ipoib_dbg_level;\r
+ table[0].DefaultLength = sizeof(ULONG);\r
+\r
+ table[1].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
+ table[1].Name = L"DebugFlags";\r
+ table[1].EntryContext = &g_ipoib_dbg_flags;\r
+ table[1].DefaultType = REG_DWORD;\r
+ table[1].DefaultData = &g_ipoib_dbg_flags;\r
+ table[1].DefaultLength = sizeof(ULONG);\r
+\r
+ table[2].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
+ table[2].Name = L"bypass_check_bcast_rate";\r
+ table[2].EntryContext = &g_ipoib.bypass_check_bcast_rate;\r
+ table[2].DefaultType = REG_DWORD;\r
+ table[2].DefaultData = &g_ipoib.bypass_check_bcast_rate;\r
+ table[2].DefaultLength = sizeof(ULONG);\r
+\r
+ /* Have at it! */\r
+ status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
+ param_path.Buffer, table, NULL, NULL );\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("debug level %d debug flags 0x%.8x\n",\r
+ g_ipoib_dbg_level,\r
+ g_ipoib_dbg_flags));\r
+\r
+#if DBG\r
+ if( g_ipoib_dbg_flags & IPOIB_DBG_ERR )\r
+ g_ipoib_dbg_flags |= CL_DBG_ERROR;\r
+#endif\r
+\r
+ cl_free( param_path.Buffer );\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return status;\r
+}\r
+\r
+\r
+VOID\r
+ipoib_unload(\r
+ IN PDRIVER_OBJECT p_drv_obj )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+ #if defined(EVENT_TRACING)\r
+ WPP_CLEANUP(p_drv_obj);\r
+ #endif\r
+\r
+ UNREFERENCED_PARAMETER( p_drv_obj );\r
+ CL_DEINIT;\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+NDIS_STATUS\r
+ipoib_get_adapter_params(\r
+ IN NDIS_HANDLE* const wrapper_config_context,\r
+ IN OUT ipoib_adapter_t *p_adapter )\r
+{\r
+ NDIS_STATUS status;\r
+ NDIS_HANDLE h_config;\r
+ NDIS_CONFIGURATION_PARAMETER *p_param;\r
+ NDIS_STRING keyword;\r
+ PUCHAR mac;\r
+ UINT len;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ NdisOpenConfiguration( &status, &h_config, wrapper_config_context );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("NdisOpenConfiguration returned 0x%.8x\n", status) );\r
+ return status;\r
+ }\r
+\r
+ /* Required: Receive queue depth. */\r
+ RtlInitUnicodeString( &keyword, L"RqDepth" );\r
+ NdisReadConfiguration(\r
+ &status, &p_param, h_config, &keyword, NdisParameterInteger );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Receive Queue Depth parameter missing.\n") );\r
+ return status;\r
+ }\r
+ p_adapter->params.rq_depth = p_param->ParameterData.IntegerData;\r
+\r
+ /* Optional: Receive queue low watermark. */\r
+ RtlInitUnicodeString( &keyword, L"RqLowWatermark" );\r
+ NdisReadConfiguration(\r
+ &status, &p_param, h_config, &keyword, NdisParameterInteger );\r
+ if( status != NDIS_STATUS_SUCCESS || !p_param->ParameterData.IntegerData )\r
+ {\r
+ p_adapter->params.rq_low_watermark = p_adapter->params.rq_depth >> 2;\r
+ }\r
+ else\r
+ {\r
+ p_adapter->params.rq_low_watermark =\r
+ p_adapter->params.rq_depth / p_param->ParameterData.IntegerData;\r
+ }\r
+\r
+ /* Required: Send queue depth. */\r
+ RtlInitUnicodeString( &keyword, L"SqDepth" );\r
+ NdisReadConfiguration(\r
+ &status, &p_param, h_config, &keyword, NdisParameterInteger );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Send Queue Depth parameter missing.\n") );\r
+ return status;\r
+ }\r
+ p_adapter->params.sq_depth = p_param->ParameterData.IntegerData;\r
+ /* Send queue depth needs to be a power of two. */\r
+ if( p_adapter->params.sq_depth <= 128 )\r
+ p_adapter->params.sq_depth = 128;\r
+ else if( p_adapter->params.sq_depth <= 256 )\r
+ p_adapter->params.sq_depth = 256;\r
+ else if( p_adapter->params.sq_depth <= 512 )\r
+ p_adapter->params.sq_depth = 512;\r
+ else\r
+ p_adapter->params.sq_depth = 1024;\r
+\r
+ /* Required: Send Checksum Offload. */\r
+ RtlInitUnicodeString( &keyword, L"SendChksum" );\r
+ NdisReadConfiguration(\r
+ &status, &p_param, h_config, &keyword, NdisParameterInteger );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Send Checksum Offload parameter missing.\n") );\r
+ return status;\r
+ }\r
+ p_adapter->params.send_chksum_offload = (p_param->ParameterData.IntegerData != 0);\r
+\r
+ /* Required: Send Checksum Offload. */\r
+ RtlInitUnicodeString( &keyword, L"RecvChksum" );\r
+ NdisReadConfiguration(\r
+ &status, &p_param, h_config, &keyword, NdisParameterInteger );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Recv Checksum Offload parameter missing.\n") );\r
+ return status;\r
+ }\r
+ p_adapter->params.recv_chksum_offload = (p_param->ParameterData.IntegerData != 0);\r
+\r
+ /* Required: SA query timeout, in milliseconds. */\r
+ RtlInitUnicodeString( &keyword, L"SaTimeout" );\r
+ NdisReadConfiguration(\r
+ &status, &p_param, h_config, &keyword, NdisParameterInteger );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("SA query timeout parameter missing.\n") );\r
+ return status;\r
+ }\r
+ p_adapter->params.sa_timeout = p_param->ParameterData.IntegerData;\r
+\r
+ /* Required: SA query retry count. */\r
+ RtlInitUnicodeString( &keyword, L"SaRetries" );\r
+ NdisReadConfiguration(\r
+ &status, &p_param, h_config, &keyword, NdisParameterInteger );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("SA query retry count parameter missing.\n") );\r
+ return status;\r
+ }\r
+ p_adapter->params.sa_retry_cnt = p_param->ParameterData.IntegerData;\r
+\r
+ /* Required: Receive pool to queue depth ratio. */\r
+ RtlInitUnicodeString( &keyword, L"RecvRatio" );\r
+ NdisReadConfiguration(\r
+ &status, &p_param, h_config, &keyword, NdisParameterInteger );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Receive pool to queue depth ratio parameter missing.\n") );\r
+ return status;\r
+ }\r
+ p_adapter->params.recv_pool_ratio = p_param->ParameterData.IntegerData;\r
+\r
+ /* required: MTU size. */\r
+ RtlInitUnicodeString( &keyword, L"PayloadMtu" );\r
+ NdisReadConfiguration(\r
+ &status, &p_param, h_config, &keyword, NdisParameterInteger );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("PayloadMtu parameter missing. Use the default.\n") );\r
+ return status;\r
+ }\r
+ p_adapter->params.payload_mtu = p_param->ParameterData.IntegerData;\r
+ p_adapter->params.xfer_block_size = (sizeof(eth_hdr_t) + p_adapter->params.payload_mtu);\r
+ NdisReadNetworkAddress( &status, &mac, &len, h_config );\r
+\r
+ ETH_COPY_NETWORK_ADDRESS( p_adapter->params.conf_mac.addr, p_adapter->mac.addr );\r
+ /* If there is a NetworkAddress override in registry, use it */\r
+ if( (status == NDIS_STATUS_SUCCESS) && (len == HW_ADDR_LEN) )\r
+ {\r
+ if( ETH_IS_MULTICAST(mac) || ETH_IS_BROADCAST(mac) ||\r
+ !ETH_IS_LOCALLY_ADMINISTERED(mac) )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_INIT,\r
+ ("Overriding NetworkAddress is invalid - "\r
+ "%02x-%02x-%02x-%02x-%02x-%02x\n",\r
+ mac[0], mac[1], mac[2],\r
+ mac[3], mac[4], mac[5]) );\r
+ }\r
+ else\r
+ {\r
+ ETH_COPY_NETWORK_ADDRESS( p_adapter->params.conf_mac.addr, mac );\r
+ }\r
+ }\r
+\r
+ NdisCloseConfiguration( h_config );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+NDIS_STATUS\r
+ipoib_get_adapter_guids(\r
+ IN NDIS_HANDLE* const h_adapter,\r
+ IN OUT ipoib_adapter_t *p_adapter )\r
+{\r
+ NTSTATUS status;\r
+ ib_al_ifc_data_t data;\r
+ IO_STACK_LOCATION io_stack, *p_fwd_io_stack;\r
+ DEVICE_OBJECT *p_pdo;\r
+ IRP *p_irp;\r
+ KEVENT event;\r
+ IO_STATUS_BLOCK io_status;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ NdisMGetDeviceProperty( h_adapter, &p_pdo, NULL, NULL, NULL, NULL );\r
+\r
+ /* Query for our interface */\r
+ data.size = sizeof(ipoib_ifc_data_t);\r
+ data.version = IPOIB_INTERFACE_DATA_VERSION;\r
+ data.type = &GUID_IPOIB_INTERFACE_DATA;\r
+ data.p_data = &p_adapter->guids;\r
+\r
+ io_stack.MinorFunction = IRP_MN_QUERY_INTERFACE;\r
+ io_stack.Parameters.QueryInterface.Version = AL_INTERFACE_VERSION;\r
+ io_stack.Parameters.QueryInterface.Size = sizeof(ib_al_ifc_t);\r
+ io_stack.Parameters.QueryInterface.Interface =\r
+ (INTERFACE*)p_adapter->p_ifc;\r
+ io_stack.Parameters.QueryInterface.InterfaceSpecificData = &data;\r
+ io_stack.Parameters.QueryInterface.InterfaceType = \r
+ &GUID_IB_AL_INTERFACE;\r
+\r
+ KeInitializeEvent( &event, NotificationEvent, FALSE );\r
+\r
+ /* Build the IRP for the HCA. */\r
+ p_irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, p_pdo,\r
+ NULL, 0, NULL, &event, &io_status );\r
+ if( !p_irp )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to allocate query interface IRP.\n") );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ /* Copy the request query parameters. */\r
+ p_fwd_io_stack = IoGetNextIrpStackLocation( p_irp );\r
+ p_fwd_io_stack->MinorFunction = IRP_MN_QUERY_INTERFACE;\r
+ p_fwd_io_stack->Parameters.QueryInterface =\r
+ io_stack.Parameters.QueryInterface;\r
+ p_irp->IoStatus.Status = STATUS_NOT_SUPPORTED;\r
+\r
+ /* Send the IRP. */\r
+ status = IoCallDriver( p_pdo, p_irp );\r
+ if( status == STATUS_PENDING )\r
+ {\r
+ KeWaitForSingleObject( &event, Executive, KernelMode,\r
+ FALSE, NULL );\r
+ status = io_status.Status;\r
+ }\r
+\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Query interface for IPOIB interface returned %08x.\n", status) );\r
+ return status;\r
+ }\r
+\r
+ /*\r
+ * Dereference the interface now so that the bus driver doesn't fail a\r
+ * query remove IRP. We will always get unloaded before the bus driver\r
+ * since we're a child device.\r
+ */\r
+ p_adapter->p_ifc->wdm.InterfaceDereference(\r
+ p_adapter->p_ifc->wdm.Context );\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+//! Initialization function called for each IOC discovered\r
+/* The MiniportInitialize function is a required function that sets up a\r
+NIC (or virtual NIC) for network I/O operations, claims all hardware\r
+resources necessary to the NIC in the registry, and allocates resources\r
+the driver needs to carry out network I/O operations.\r
+IRQL = PASSIVE_LEVEL\r
+\r
+@param p_open_status Pointer to a status field set if this function returns NDIS_STATUS_OPEN_ERROR\r
+@param p_selected_medium_index Pointer to unsigned integer noting index into medium_array for this NIC\r
+@param medium_array Array of mediums for this NIC\r
+@param medium_array_size Number of elements in medium_array\r
+@param h_adapter Handle assigned by NDIS for this NIC\r
+@param wrapper_config_context Handle used for Ndis initialization functions\r
+@return NDIS_STATUS_SUCCESS, NDIS_STATUS_UNSUPPORTED_MEDIA, NDIS_STATUS_RESOURCES,\r
+NDIS_STATUS_NOT_SUPPORTED \r
+*/\r
+NDIS_STATUS\r
+ipoib_initialize(\r
+ OUT PNDIS_STATUS p_open_status,\r
+ OUT PUINT p_selected_medium_index,\r
+ IN PNDIS_MEDIUM medium_array,\r
+ IN UINT medium_array_size,\r
+ IN NDIS_HANDLE h_adapter,\r
+ IN NDIS_HANDLE wrapper_config_context )\r
+{\r
+ NDIS_STATUS status;\r
+ ib_api_status_t ib_status;\r
+ UINT medium_index;\r
+ ipoib_adapter_t *p_adapter;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+#ifdef _DEBUG_\r
+ PAGED_CODE();\r
+#endif\r
+\r
+ UNUSED_PARAM( p_open_status );\r
+ UNUSED_PARAM( wrapper_config_context );\r
+\r
+ /* Search for our medium */\r
+ for( medium_index = 0; medium_index < medium_array_size; ++medium_index )\r
+ {\r
+ /* Check to see if we found our medium */\r
+ if( medium_array[medium_index] == NdisMedium802_3 )\r
+ break;\r
+ }\r
+\r
+ if( medium_index == medium_array_size ) /* Never found it */\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("No supported media.\n") );\r
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;\r
+ }\r
+\r
+ *p_selected_medium_index = medium_index;\r
+\r
+ /* Create the adapter adapter */\r
+ ib_status = ipoib_create_adapter( wrapper_config_context, h_adapter, &p_adapter );\r
+ if( ib_status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_create_adapter returned status %d.\n", ib_status ) );\r
+ return NDIS_STATUS_FAILURE;\r
+ }\r
+\r
+ /* Allow ten seconds for all SA queries to finish up. */\r
+ NdisMSetAttributesEx( h_adapter, p_adapter, 5,\r
+ NDIS_ATTRIBUTE_BUS_MASTER | NDIS_ATTRIBUTE_DESERIALIZE |\r
+ NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS,\r
+ NdisInterfacePNPBus );\r
+\r
+#if IPOIB_USE_DMA\r
+ status =\r
+ NdisMInitializeScatterGatherDma( h_adapter, TRUE, p_adapter->params.xfer_block_size );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ ipoib_destroy_adapter( p_adapter );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("NdisMInitializeScatterGatherDma returned 0x%.8x.\n", status) );\r
+ return status;\r
+ }\r
+#endif\r
+\r
+ /* Create the adapter adapter */\r
+ ib_status = ipoib_start_adapter( p_adapter );\r
+ if( ib_status != IB_SUCCESS )\r
+ {\r
+ NdisWriteErrorLogEntry( h_adapter,\r
+ NDIS_ERROR_CODE_HARDWARE_FAILURE, 0 );\r
+ ipoib_destroy_adapter( p_adapter );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_start_adapter returned status %d.\n", ib_status ) );\r
+ return NDIS_STATUS_FAILURE;\r
+ }\r
+\r
+ ipoib_ref_ibat();\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return status;\r
+}\r
+\r
+\r
+//! Deallocates resources when the NIC is removed and halts the NIC..\r
+/* IRQL = DISPATCH_LEVEL\r
+\r
+@param adapter_context The adapter context allocated at start\r
+*/\r
+void\r
+ipoib_halt(\r
+ IN NDIS_HANDLE adapter_context )\r
+{\r
+ ipoib_adapter_t *p_adapter;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ ipoib_deref_ibat();\r
+\r
+ CL_ASSERT( adapter_context );\r
+ p_adapter = (ipoib_adapter_t*)adapter_context;\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Port %016I64x (CA %016I64x port %d) halting\n",\r
+ p_adapter->guids.port_guid, p_adapter->guids.ca_guid,\r
+ p_adapter->guids.port_num) );\r
+\r
+ ipoib_destroy_adapter( p_adapter );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+//! Reports the state of the NIC, or monitors the responsiveness of an underlying device driver.\r
+/* IRQL = DISPATCH_LEVEL\r
+\r
+@param adapter_context The adapter context allocated at start\r
+@return TRUE if the driver determines that its NIC is not operating\r
+*/\r
+BOOLEAN\r
+ipoib_check_for_hang(\r
+ IN NDIS_HANDLE adapter_context )\r
+{\r
+ ipoib_adapter_t *p_adapter;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+ CL_ASSERT( adapter_context );\r
+ p_adapter = (ipoib_adapter_t*)adapter_context;\r
+\r
+ if( p_adapter->reset )\r
+ {\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return FALSE;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return (p_adapter->hung? TRUE:FALSE);\r
+}\r
+\r
+\r
+//! Returns information about the capabilities and status of the driver and/or its NIC.\r
+/* IRQL = DISPATCH_LEVEL\r
+\r
+@param adapter_context The adapter context allocated at start\r
+@param oid Object ID representing the query operation to be carried out\r
+@param info_buf Buffer containing any input for this query and location for output\r
+@param info_buf_len Number of bytes available in info_buf\r
+@param p_bytes_written Pointer to number of bytes written into info_buf\r
+@param p_bytes_needed Pointer to number of bytes needed to satisfy this oid\r
+@return NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING, NDIS_STATUS_INVALID_OID,\r
+NDIS_STATUS_INVALID_LENGTH, NDIS_STATUS_NOT_ACCEPTED, NDIS_STATUS_NOT_SUPPORTED,\r
+NDIS_STATUS_RESOURCES\r
+*/\r
+NDIS_STATUS\r
+ipoib_query_info(\r
+ IN NDIS_HANDLE adapter_context,\r
+ IN NDIS_OID oid,\r
+ IN PVOID info_buf,\r
+ IN ULONG info_buf_len,\r
+ OUT PULONG p_bytes_written,\r
+ OUT PULONG p_bytes_needed )\r
+{\r
+ ipoib_adapter_t *p_adapter;\r
+ NDIS_STATUS status;\r
+ USHORT version;\r
+ ULONG info;\r
+ PVOID src_buf;\r
+ ULONG buf_len;\r
+ pending_oid_t oid_info;\r
+ uint8_t port_num;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_OID );\r
+\r
+ oid_info.oid = oid;\r
+ oid_info.p_buf = info_buf;\r
+ oid_info.buf_len = info_buf_len;\r
+ oid_info.p_bytes_used = p_bytes_written;\r
+ oid_info.p_bytes_needed = p_bytes_needed;\r
+\r
+ CL_ASSERT( adapter_context );\r
+ p_adapter = (ipoib_adapter_t*)adapter_context;\r
+\r
+ CL_ASSERT( p_bytes_written );\r
+ CL_ASSERT( p_bytes_needed );\r
+ CL_ASSERT( !p_adapter->pending_query );\r
+\r
+ status = NDIS_STATUS_SUCCESS;\r
+ src_buf = &info;\r
+ buf_len = sizeof(info);\r
+\r
+ port_num = p_adapter->guids.port_num;\r
+\r
+ switch( oid )\r
+ {\r
+ /* Required General */\r
+ case OID_GEN_SUPPORTED_LIST:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_SUPPORTED_LIST\n", port_num) );\r
+ src_buf = (PVOID)SUPPORTED_OIDS;\r
+ buf_len = sizeof(SUPPORTED_OIDS);\r
+ break;\r
+\r
+ case OID_GEN_HARDWARE_STATUS:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_HARDWARE_STATUS\n", port_num) );\r
+ cl_obj_lock( &p_adapter->obj );\r
+ switch( p_adapter->state )\r
+ {\r
+ case IB_PNP_PORT_ADD:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d returning NdisHardwareStatusInitializing\n", port_num) );\r
+ info = NdisHardwareStatusInitializing;\r
+ break;\r
+ \r
+ case IB_PNP_PORT_ACTIVE:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d returning NdisHardwareStatusReady\n", port_num) );\r
+ info = NdisHardwareStatusReady;\r
+ break;\r
+\r
+ default:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d returning NdisHardwareStatusNotReady\n", port_num) );\r
+ info = NdisHardwareStatusNotReady;\r
+ }\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ break;\r
+\r
+ case OID_GEN_MEDIA_SUPPORTED:\r
+ case OID_GEN_MEDIA_IN_USE:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_MEDIA_SUPPORTED "\r
+ "or OID_GEN_MEDIA_IN_USE\n", port_num) );\r
+ info = NdisMedium802_3;\r
+ break;\r
+\r
+ case OID_GEN_MAXIMUM_FRAME_SIZE:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_MAXIMUM_FRAME_SIZE\n", port_num) );\r
+ info = p_adapter->params.payload_mtu;\r
+ break;\r
+\r
+ case OID_GEN_LINK_SPEED:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_LINK_SPEED\n", port_num) );\r
+ cl_obj_lock( &p_adapter->obj );\r
+ switch( p_adapter->state )\r
+ {\r
+ case IB_PNP_PORT_ADD:\r
+ /* Mark the adapter as pending an OID */\r
+ p_adapter->pending_query = TRUE;\r
+\r
+ /* Save the request parameters. */\r
+ p_adapter->query_oid = oid_info;\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d returning NDIS_STATUS_PENDING\n", port_num) );\r
+ status = NDIS_STATUS_PENDING;\r
+ break;\r
+\r
+ case IB_PNP_PORT_REMOVE:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d returning NDIS_STATUS_NOT_ACCEPTED\n", port_num) );\r
+ status = NDIS_STATUS_NOT_ACCEPTED;\r
+ break;\r
+\r
+ default:\r
+ CL_ASSERT( p_adapter->p_port );\r
+ info = p_adapter->rate;\r
+ break;\r
+ }\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ break;\r
+\r
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_TRANSMIT_BUFFER_SPACE\n", port_num) );\r
+ info = p_adapter->params.sq_depth * p_adapter->params.xfer_block_size;\r
+ break;\r
+\r
+ case OID_GEN_RECEIVE_BUFFER_SPACE:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_TRANSMIT_BUFFER_SPACE "\r
+ "or OID_GEN_RECEIVE_BUFFER_SPACE\n", port_num) );\r
+ info = p_adapter->params.rq_depth * p_adapter->params.xfer_block_size;\r
+ break;\r
+\r
+ case OID_GEN_MAXIMUM_LOOKAHEAD:\r
+ case OID_GEN_CURRENT_LOOKAHEAD:\r
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:\r
+ case OID_GEN_RECEIVE_BLOCK_SIZE:\r
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_MAXIMUM_LOOKAHEAD "\r
+ "or OID_GEN_CURRENT_LOOKAHEAD or "\r
+ "OID_GEN_TRANSMIT_BLOCK_SIZE or "\r
+ "OID_GEN_RECEIVE_BLOCK_SIZE or "\r
+ "OID_GEN_MAXIMUM_TOTAL_SIZE\n", port_num) );\r
+ info = p_adapter->params.xfer_block_size;\r
+ break;\r
+\r
+ case OID_GEN_VENDOR_ID:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_VENDOR_ID\n", port_num) );\r
+ src_buf = (void*)VENDOR_ID;\r
+ buf_len = sizeof(VENDOR_ID);\r
+ break;\r
+\r
+ case OID_GEN_VENDOR_DESCRIPTION:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, \r
+ ("Port %d received query for OID_GEN_VENDOR_DESCRIPTION\n", port_num) );\r
+ src_buf = VENDOR_DESCRIPTION;\r
+ buf_len = sizeof(VENDOR_DESCRIPTION);\r
+ break;\r
+\r
+ case OID_GEN_VENDOR_DRIVER_VERSION:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_VENDOR_DRIVER_VERSION\n", port_num) );\r
+ src_buf = &version;\r
+ buf_len = sizeof(version);\r
+ //TODO: Figure out what the right version is.\r
+ version = 1 << 8 | 1;\r
+ break;\r
+\r
+ case OID_GEN_PHYSICAL_MEDIUM:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_PHYSICAL_MEDIUM\n", port_num) );\r
+ info = NdisPhysicalMediumUnspecified;\r
+ break;\r
+\r
+ case OID_GEN_CURRENT_PACKET_FILTER:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_CURRENT_PACKET_FILTER\n", port_num) );\r
+ info = p_adapter->packet_filter;\r
+ break;\r
+\r
+ case OID_GEN_DRIVER_VERSION:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_DRIVER_VERSION\n", port_num) );\r
+ src_buf = &version;\r
+ buf_len = sizeof(version);\r
+ version = MAJOR_NDIS_VERSION << 8 | MINOR_NDIS_VERSION;\r
+ break;\r
+\r
+ case OID_GEN_MAC_OPTIONS:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_MAC_OPTIONS\n", port_num) );\r
+ info = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |\r
+ NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |\r
+ NDIS_MAC_OPTION_NO_LOOPBACK |\r
+ NDIS_MAC_OPTION_FULL_DUPLEX;\r
+//TODO: Figure out if we will support priority and VLANs.\r
+// NDIS_MAC_OPTION_8021P_PRIORITY;\r
+//#ifdef NDIS51_MINIPORT\r
+// info |= NDIS_MAC_OPTION_8021Q_VLAN;\r
+//#endif\r
+ break;\r
+\r
+ case OID_GEN_MEDIA_CONNECT_STATUS:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_MEDIA_CONNECT_STATUS\n", port_num) );\r
+ cl_obj_lock( &p_adapter->obj );\r
+ switch( p_adapter->state )\r
+ {\r
+ case IB_PNP_PORT_ADD:\r
+ case IB_PNP_PORT_INIT:\r
+ /*\r
+ * Delay reporting media state until we know whether the port is\r
+ * either up or down.\r
+ */\r
+ p_adapter->pending_query = TRUE;\r
+ p_adapter->query_oid = oid_info;\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d returning NDIS_STATUS_PENDING\n", port_num) );\r
+ status = NDIS_STATUS_PENDING;\r
+ break;\r
+\r
+ case IB_PNP_PORT_ACTIVE:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d returning NdisMediaStateConnected\n", port_num) );\r
+ info = NdisMediaStateConnected;\r
+ break;\r
+\r
+ case IB_PNP_PORT_REMOVE:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d returning NDIS_STATUS_NOT_ACCEPTED\n", port_num) );\r
+ status = NDIS_STATUS_NOT_ACCEPTED;\r
+ break;\r
+\r
+ default:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d returning NdisMediaStateDisconnected\n", port_num) );\r
+ info = NdisMediaStateDisconnected;\r
+ }\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ break;\r
+\r
+ case OID_GEN_MAXIMUM_SEND_PACKETS:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_MAXIMUM_SEND_PACKETS\n", port_num) );\r
+ info = MAXULONG;\r
+ break;\r
+\r
+ /* Required General Statistics */\r
+ case OID_GEN_XMIT_OK:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_XMIT_OK\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_send_stat( p_adapter, IP_STAT_SUCCESS, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_RCV_OK:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_RCV_OK\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_recv_stat( p_adapter, IP_STAT_SUCCESS, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_XMIT_ERROR:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_XMIT_ERROR\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_send_stat( p_adapter, IP_STAT_ERROR, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_RCV_ERROR:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_RCV_ERROR\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_recv_stat( p_adapter, IP_STAT_ERROR, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_RCV_NO_BUFFER:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_RCV_NO_BUFFER\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_recv_stat( p_adapter, IP_STAT_DROPPED, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_DIRECTED_BYTES_XMIT:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_DIRECTED_BYTES_XMIT\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_send_stat( p_adapter, IP_STAT_UCAST_BYTES, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_DIRECTED_FRAMES_XMIT:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_DIRECTED_FRAMES_XMIT\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_send_stat( p_adapter, IP_STAT_UCAST_FRAMES, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_MULTICAST_BYTES_XMIT:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_MULTICAST_BYTES_XMIT\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_send_stat( p_adapter, IP_STAT_MCAST_BYTES, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_MULTICAST_FRAMES_XMIT:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_MULTICAST_FRAMES_XMIT\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_send_stat( p_adapter, IP_STAT_MCAST_FRAMES, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_BROADCAST_BYTES_XMIT:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_BROADCAST_BYTES_XMIT\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_send_stat( p_adapter, IP_STAT_BCAST_BYTES, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_BROADCAST_FRAMES_XMIT:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_BROADCAST_FRAMES_XMIT\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_send_stat( p_adapter, IP_STAT_BCAST_FRAMES, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_DIRECTED_BYTES_RCV:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_DIRECTED_BYTES_RCV\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_recv_stat( p_adapter, IP_STAT_UCAST_BYTES, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_DIRECTED_FRAMES_RCV:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_DIRECTED_FRAMES_RCV\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_recv_stat( p_adapter, IP_STAT_UCAST_FRAMES, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_MULTICAST_BYTES_RCV:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_MULTICAST_BYTES_RCV\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_recv_stat( p_adapter, IP_STAT_MCAST_BYTES, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_MULTICAST_FRAMES_RCV:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_MULTICAST_FRAMES_RCV\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_recv_stat( p_adapter, IP_STAT_MCAST_FRAMES, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_BROADCAST_BYTES_RCV:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_BROADCAST_BYTES_RCV\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_recv_stat( p_adapter, IP_STAT_BCAST_BYTES, &oid_info );\r
+ break;\r
+\r
+ case OID_GEN_BROADCAST_FRAMES_RCV:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_GEN_BROADCAST_FRAMES_RCV\n", port_num) );\r
+ src_buf = NULL;\r
+ status = ipoib_get_recv_stat( p_adapter, IP_STAT_BCAST_FRAMES, &oid_info );\r
+ break;\r
+\r
+ /* Required Ethernet operational characteristics */\r
+ case OID_802_3_PERMANENT_ADDRESS:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_802_3_PERMANENT_ADDRESS\n", port_num) );\r
+ src_buf = &p_adapter->mac;\r
+ buf_len = sizeof(p_adapter->mac);\r
+ break;\r
+\r
+ case OID_802_3_CURRENT_ADDRESS:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_802_3_CURRENT_ADDRESS\n", port_num) );\r
+ src_buf = &p_adapter->params.conf_mac;\r
+ buf_len = sizeof(p_adapter->params.conf_mac);\r
+ break;\r
+\r
+ case OID_802_3_MULTICAST_LIST:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_802_3_MULTICAST_LIST\n", port_num) );\r
+ src_buf = p_adapter->mcast_array;\r
+ buf_len = p_adapter->mcast_array_size * sizeof(mac_addr_t);\r
+ break;\r
+\r
+ case OID_802_3_MAXIMUM_LIST_SIZE:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_802_3_MAXIMUM_LIST_SIZE\n", port_num) );\r
+ info = MAX_MCAST;\r
+ break;\r
+\r
+ case OID_802_3_MAC_OPTIONS:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_802_3_MAC_OPTIONS\n", port_num) );\r
+ info = 0;\r
+ break;\r
+\r
+ /* Required Ethernet stats */\r
+ case OID_802_3_RCV_ERROR_ALIGNMENT:\r
+ case OID_802_3_XMIT_ONE_COLLISION:\r
+ case OID_802_3_XMIT_MORE_COLLISIONS:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_802_3_RCV_ERROR_ALIGNMENT or "\r
+ "OID_802_3_XMIT_ONE_COLLISION or "\r
+ "OID_802_3_XMIT_MORE_COLLISIONS\n", port_num) );\r
+ info = 0;\r
+ break;\r
+\r
+ case OID_TCP_TASK_OFFLOAD:\r
+ src_buf = NULL;\r
+ status = __ipoib_get_tcp_task_offload( p_adapter, &oid_info );\r
+ break;\r
+\r
+ /* Optional General */\r
+ case OID_GEN_SUPPORTED_GUIDS:\r
+#ifdef NDIS51_MINIPORT\r
+ case OID_GEN_VLAN_ID:\r
+#endif\r
+\r
+ /* Optional General Stats */\r
+ case OID_GEN_RCV_CRC_ERROR:\r
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:\r
+\r
+ /* Optional Ethernet Stats */\r
+ case OID_802_3_XMIT_DEFERRED:\r
+ case OID_802_3_XMIT_MAX_COLLISIONS:\r
+ case OID_802_3_RCV_OVERRUN:\r
+ case OID_802_3_XMIT_UNDERRUN:\r
+ case OID_802_3_XMIT_HEARTBEAT_FAILURE:\r
+ case OID_802_3_XMIT_TIMES_CRS_LOST:\r
+ case OID_802_3_XMIT_LATE_COLLISIONS:\r
+ case OID_PNP_CAPABILITIES:\r
+ status = NDIS_STATUS_NOT_SUPPORTED;\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received an unsupported oid of 0x%.8X!\n", port_num, oid) );\r
+ break;\r
+\r
+ case OID_GEN_PROTOCOL_OPTIONS:\r
+ case OID_GEN_NETWORK_LAYER_ADDRESSES:\r
+ case OID_GEN_TRANSPORT_HEADER_OFFSET:\r
+#ifdef NDIS51_MINIPORT\r
+ case OID_GEN_MACHINE_NAME:\r
+ case OID_GEN_RNDIS_CONFIG_PARAMETER:\r
+#endif\r
+ default:\r
+ status = NDIS_STATUS_INVALID_OID;\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received an invalid oid of 0x%.8X!\n", port_num, oid) );\r
+ break;\r
+ }\r
+\r
+ /*\r
+ * Complete the request as if it was handled asynchronously to maximize\r
+ * code reuse for when we really handle the requests asynchronously.\r
+ * Note that this requires the QueryInformation entry point to always\r
+ * return NDIS_STATUS_PENDING\r
+ */\r
+ if( status != NDIS_STATUS_PENDING )\r
+ {\r
+ ipoib_complete_query(\r
+ p_adapter, &oid_info, status, src_buf, buf_len );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_OID );\r
+ return NDIS_STATUS_PENDING;\r
+}\r
+\r
+\r
+static void\r
+ipoib_complete_query(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN pending_oid_t* const p_oid_info,\r
+ IN const NDIS_STATUS status,\r
+ IN const void* const p_buf,\r
+ IN const ULONG buf_len )\r
+{\r
+ NDIS_STATUS oid_status = status;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_OID );\r
+\r
+ CL_ASSERT( status != NDIS_STATUS_PENDING );\r
+\r
+ if( status == NDIS_STATUS_SUCCESS )\r
+ {\r
+ if( p_oid_info->buf_len < buf_len )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Insufficient buffer space. "\r
+ "Returning NDIS_STATUS_INVALID_LENGTH.\n") );\r
+ oid_status = NDIS_STATUS_INVALID_LENGTH;\r
+ *p_oid_info->p_bytes_needed = buf_len;\r
+ *p_oid_info->p_bytes_used = 0;\r
+ }\r
+ else if( p_oid_info->p_buf )\r
+ {\r
+ /* Only copy if we have a distinct source buffer. */\r
+ if( p_buf )\r
+ {\r
+ NdisMoveMemory( p_oid_info->p_buf, p_buf, buf_len );\r
+ *p_oid_info->p_bytes_used = buf_len;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Returning NDIS_NOT_ACCEPTED") );\r
+ oid_status = NDIS_STATUS_NOT_ACCEPTED;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ *p_oid_info->p_bytes_used = 0;\r
+ }\r
+\r
+ p_adapter->pending_query = FALSE;\r
+\r
+ NdisMQueryInformationComplete( p_adapter->h_adapter, oid_status );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_OID );\r
+}\r
+\r
+\r
+static NDIS_STATUS\r
+__ipoib_get_tcp_task_offload(\r
+ IN ipoib_adapter_t* p_adapter,\r
+ IN pending_oid_t* const p_oid_info )\r
+{\r
+ NDIS_TASK_OFFLOAD_HEADER *p_offload_hdr;\r
+ NDIS_TASK_OFFLOAD *p_offload_task;\r
+ NDIS_TASK_TCP_IP_CHECKSUM *p_offload_chksum;\r
+ ULONG buf_len;\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received query for OID_TCP_TASK_OFFLOAD\n",\r
+ p_adapter->guids.port_num) );\r
+\r
+ buf_len = sizeof(NDIS_TASK_OFFLOAD_HEADER) +\r
+ offsetof( NDIS_TASK_OFFLOAD, TaskBuffer ) +\r
+ sizeof(NDIS_TASK_TCP_IP_CHECKSUM);\r
+\r
+ *(p_oid_info->p_bytes_needed) = buf_len;\r
+\r
+ if( p_oid_info->buf_len < buf_len )\r
+ return NDIS_STATUS_INVALID_LENGTH;\r
+\r
+ p_offload_hdr = (NDIS_TASK_OFFLOAD_HEADER*)p_oid_info->p_buf;\r
+ if( p_offload_hdr->Version != NDIS_TASK_OFFLOAD_VERSION )\r
+ return NDIS_STATUS_INVALID_DATA;\r
+\r
+ if( p_offload_hdr->EncapsulationFormat.Encapsulation !=\r
+ IEEE_802_3_Encapsulation )\r
+ {\r
+ return NDIS_STATUS_INVALID_DATA;\r
+ }\r
+\r
+ p_offload_hdr->OffsetFirstTask = sizeof(NDIS_TASK_OFFLOAD_HEADER);\r
+ p_offload_task = (NDIS_TASK_OFFLOAD*)(p_offload_hdr + 1);\r
+ p_offload_task->Version = NDIS_TASK_OFFLOAD_VERSION;\r
+ p_offload_task->Size = sizeof(NDIS_TASK_OFFLOAD);\r
+ p_offload_task->Task = TcpIpChecksumNdisTask;\r
+ p_offload_task->OffsetNextTask = 0;\r
+ p_offload_task->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM);\r
+ p_offload_chksum =\r
+ (NDIS_TASK_TCP_IP_CHECKSUM*)p_offload_task->TaskBuffer;\r
+\r
+ p_offload_chksum->V4Transmit.IpOptionsSupported =\r
+ p_adapter->params.send_chksum_offload;\r
+ p_offload_chksum->V4Transmit.TcpOptionsSupported =\r
+ p_adapter->params.send_chksum_offload;\r
+ p_offload_chksum->V4Transmit.TcpChecksum =\r
+ p_adapter->params.send_chksum_offload;\r
+ p_offload_chksum->V4Transmit.UdpChecksum =\r
+ p_adapter->params.send_chksum_offload;\r
+ p_offload_chksum->V4Transmit.IpChecksum =\r
+ p_adapter->params.send_chksum_offload;\r
+\r
+ p_offload_chksum->V4Receive.IpOptionsSupported =\r
+ p_adapter->params.recv_chksum_offload;\r
+ p_offload_chksum->V4Receive.TcpOptionsSupported =\r
+ p_adapter->params.recv_chksum_offload;\r
+ p_offload_chksum->V4Receive.TcpChecksum =\r
+ p_adapter->params.recv_chksum_offload;\r
+ p_offload_chksum->V4Receive.UdpChecksum =\r
+ p_adapter->params.recv_chksum_offload;\r
+ p_offload_chksum->V4Receive.IpChecksum =\r
+ p_adapter->params.recv_chksum_offload;\r
+\r
+ p_offload_chksum->V6Transmit.IpOptionsSupported = FALSE;\r
+ p_offload_chksum->V6Transmit.TcpOptionsSupported = FALSE;\r
+ p_offload_chksum->V6Transmit.TcpChecksum = FALSE;\r
+ p_offload_chksum->V6Transmit.UdpChecksum = FALSE;\r
+\r
+ p_offload_chksum->V6Receive.IpOptionsSupported = FALSE;\r
+ p_offload_chksum->V6Receive.TcpOptionsSupported = FALSE;\r
+ p_offload_chksum->V6Receive.TcpChecksum = FALSE;\r
+ p_offload_chksum->V6Receive.UdpChecksum = FALSE;\r
+\r
+ *(p_oid_info->p_bytes_used) = buf_len;\r
+\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NDIS_STATUS\r
+__ipoib_set_tcp_task_offload(\r
+ IN ipoib_adapter_t* p_adapter,\r
+ IN void* const p_info_buf,\r
+ IN ULONG* const p_info_len )\r
+{\r
+ NDIS_TASK_OFFLOAD_HEADER *p_offload_hdr;\r
+ NDIS_TASK_OFFLOAD *p_offload_task;\r
+ NDIS_TASK_TCP_IP_CHECKSUM *p_offload_chksum;\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received set for OID_TCP_TASK_OFFLOAD\n",\r
+ p_adapter->guids.port_num) );\r
+\r
+ p_offload_hdr = (NDIS_TASK_OFFLOAD_HEADER*)p_info_buf;\r
+\r
+ if( *p_info_len < sizeof(NDIS_TASK_OFFLOAD_HEADER) )\r
+ return NDIS_STATUS_INVALID_LENGTH;\r
+\r
+ if( p_offload_hdr->Version != NDIS_TASK_OFFLOAD_VERSION )\r
+ return NDIS_STATUS_INVALID_DATA;\r
+\r
+ if( p_offload_hdr->Size != sizeof(NDIS_TASK_OFFLOAD_HEADER) )\r
+ return NDIS_STATUS_INVALID_LENGTH;\r
+\r
+ if( !p_offload_hdr->OffsetFirstTask )\r
+ return NDIS_STATUS_SUCCESS;\r
+\r
+ if( p_offload_hdr->EncapsulationFormat.Encapsulation !=\r
+ IEEE_802_3_Encapsulation )\r
+ {\r
+ return NDIS_STATUS_INVALID_DATA;\r
+ }\r
+\r
+ p_offload_task = (NDIS_TASK_OFFLOAD*)\r
+ (((UCHAR*)p_offload_hdr) + p_offload_hdr->OffsetFirstTask);\r
+\r
+ if( *p_info_len < sizeof(NDIS_TASK_OFFLOAD_HEADER) +\r
+ offsetof( NDIS_TASK_OFFLOAD, TaskBuffer ) +\r
+ sizeof(NDIS_TASK_TCP_IP_CHECKSUM) )\r
+ {\r
+ return NDIS_STATUS_INVALID_LENGTH;\r
+ }\r
+\r
+ if( p_offload_task->Version != NDIS_TASK_OFFLOAD_VERSION )\r
+ return NDIS_STATUS_INVALID_DATA;\r
+ p_offload_chksum =\r
+ (NDIS_TASK_TCP_IP_CHECKSUM*)p_offload_task->TaskBuffer;\r
+\r
+ if( !p_adapter->params.send_chksum_offload &&\r
+ (p_offload_chksum->V4Transmit.IpOptionsSupported ||\r
+ p_offload_chksum->V4Transmit.TcpOptionsSupported ||\r
+ p_offload_chksum->V4Transmit.TcpChecksum ||\r
+ p_offload_chksum->V4Transmit.UdpChecksum ||\r
+ p_offload_chksum->V4Transmit.IpChecksum) )\r
+ {\r
+ return NDIS_STATUS_NOT_SUPPORTED;\r
+ }\r
+\r
+ if( !p_adapter->params.recv_chksum_offload &&\r
+ (p_offload_chksum->V4Receive.IpOptionsSupported ||\r
+ p_offload_chksum->V4Receive.TcpOptionsSupported ||\r
+ p_offload_chksum->V4Receive.TcpChecksum ||\r
+ p_offload_chksum->V4Receive.UdpChecksum ||\r
+ p_offload_chksum->V4Receive.IpChecksum) )\r
+ {\r
+ return NDIS_STATUS_NOT_SUPPORTED;\r
+ }\r
+\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+//! Issues a hardware reset to the NIC and/or resets the driver's software state.\r
+/* Tear down the connection and start over again. This is only called when there is a problem.\r
+For example, if a send, query info, or set info had a time out. MiniportCheckForHang will\r
+be called first.\r
+IRQL = DISPATCH_LEVEL\r
+\r
+@param p_addr_resetPointer to BOOLLEAN that is set to TRUE if the NDIS\r
+library should call MiniportSetInformation to restore addressing information to the current values.\r
+@param adapter_context The adapter context allocated at start\r
+@return NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING, NDIS_STATUS_NOT_RESETTABLE,\r
+NDIS_STATUS_RESET_IN_PROGRESS, NDIS_STATUS_SOFT_ERRORS, NDIS_STATUS_HARD_ERRORS\r
+*/\r
+NDIS_STATUS\r
+ipoib_reset(\r
+ OUT PBOOLEAN p_addr_reset,\r
+ IN NDIS_HANDLE adapter_context)\r
+{\r
+ ipoib_adapter_t* p_adapter;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ CL_ASSERT( p_addr_reset );\r
+ CL_ASSERT( adapter_context );\r
+ p_adapter = (ipoib_adapter_t*)adapter_context;\r
+\r
+ switch( ipoib_reset_adapter( p_adapter ) )\r
+ {\r
+ case IB_NOT_DONE:\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return NDIS_STATUS_PENDING;\r
+\r
+ case IB_SUCCESS:\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ *p_addr_reset = TRUE;\r
+ return NDIS_STATUS_SUCCESS;\r
+\r
+ case IB_INVALID_STATE:\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return NDIS_STATUS_RESET_IN_PROGRESS;\r
+\r
+ default:\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return NDIS_STATUS_HARD_ERRORS;\r
+ }\r
+}\r
+\r
+\r
+//! Request changes in the state information that the miniport driver maintains\r
+/* For example, this is used to set multicast addresses and the packet filter.\r
+IRQL = DISPATCH_LEVEL\r
+\r
+@param adapter_context The adapter context allocated at start\r
+@param oid Object ID representing the set operation to be carried out\r
+@param info_buf Buffer containing input for this set and location for any output\r
+@param info_buf_len Number of bytes available in info_buf\r
+@param p_bytes_read Pointer to number of bytes read from info_buf\r
+@param p_bytes_needed Pointer to number of bytes needed to satisfy this oid\r
+@return NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING, NDIS_STATUS_INVALID_OID,\r
+NDIS_STATUS_INVALID_LENGTH, NDIS_STATUS_INVALID_DATA, NDIS_STATUS_NOT_ACCEPTED,\r
+NDIS_STATUS_NOT_SUPPORTED, NDIS_STATUS_RESOURCES\r
+*/\r
+NDIS_STATUS\r
+ipoib_set_info(\r
+ IN NDIS_HANDLE adapter_context,\r
+ IN NDIS_OID oid,\r
+ IN PVOID info_buf,\r
+ IN ULONG info_buf_len,\r
+ OUT PULONG p_bytes_read,\r
+ OUT PULONG p_bytes_needed )\r
+{\r
+ ipoib_adapter_t* p_adapter;\r
+ NDIS_STATUS status;\r
+\r
+ ULONG buf_len;\r
+ uint8_t port_num;\r
+\r
+ KLOCK_QUEUE_HANDLE hdl;\r
+ \r
+ IPOIB_ENTER( IPOIB_DBG_OID );\r
+\r
+ CL_ASSERT( adapter_context );\r
+ p_adapter = (ipoib_adapter_t*)adapter_context;\r
+\r
+ CL_ASSERT( p_bytes_read );\r
+ CL_ASSERT( p_bytes_needed );\r
+ CL_ASSERT( !p_adapter->pending_set );\r
+\r
+ status = NDIS_STATUS_SUCCESS;\r
+ *p_bytes_needed = 0;\r
+ buf_len = sizeof(ULONG);\r
+\r
+ port_num = p_adapter->guids.port_num;\r
+\r
+ switch( oid )\r
+ {\r
+ /* Required General */\r
+ case OID_GEN_CURRENT_PACKET_FILTER:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received set for OID_GEN_CURRENT_PACKET_FILTER\n", port_num));\r
+ if( info_buf_len < sizeof(p_adapter->packet_filter) )\r
+ {\r
+ status = NDIS_STATUS_INVALID_LENGTH;\r
+ }\r
+ else if( !info_buf )\r
+ {\r
+ status = NDIS_STATUS_INVALID_DATA;\r
+ }\r
+ else\r
+ {\r
+ KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl );\r
+ cl_obj_lock( &p_adapter->obj );\r
+ switch( p_adapter->state )\r
+ {\r
+ case IB_PNP_PORT_ADD:\r
+ p_adapter->set_oid.oid = oid;\r
+ p_adapter->set_oid.p_buf = info_buf;\r
+ p_adapter->set_oid.buf_len = info_buf_len;\r
+ p_adapter->set_oid.p_bytes_used = p_bytes_read;\r
+ p_adapter->set_oid.p_bytes_needed = p_bytes_needed;\r
+ p_adapter->pending_set = TRUE;\r
+ status = NDIS_STATUS_PENDING;\r
+ break;\r
+\r
+ case IB_PNP_PORT_REMOVE:\r
+ status = NDIS_STATUS_NOT_ACCEPTED;\r
+ break;\r
+\r
+ default:\r
+ if( !p_adapter->packet_filter && (*(uint32_t*)info_buf) )\r
+ {\r
+ cl_qlist_insert_tail(\r
+ &g_ipoib.adapter_list, &p_adapter->entry );\r
+\r
+ /*\r
+ * Filter was zero, now non-zero. Register IP addresses\r
+ * with SA.\r
+ */\r
+ ipoib_reg_addrs( p_adapter );\r
+ }\r
+ else if( p_adapter->packet_filter && !(*(uint32_t*)info_buf) )\r
+ {\r
+ /*\r
+ * Filter was non-zero, now zero. Deregister IP addresses.\r
+ */\r
+ ipoib_dereg_addrs( p_adapter );\r
+\r
+ ASSERT( cl_qlist_count( &g_ipoib.adapter_list ) );\r
+ cl_qlist_remove_item(\r
+ &g_ipoib.adapter_list, &p_adapter->entry );\r
+ }\r
+\r
+ p_adapter->packet_filter = *(uint32_t*)info_buf;\r
+ }\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ KeReleaseInStackQueuedSpinLock( &hdl );\r
+ }\r
+ break;\r
+\r
+ case OID_GEN_CURRENT_LOOKAHEAD:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received set for OID_GEN_CURRENT_LOOKAHEAD\n", port_num));\r
+ if( info_buf_len < buf_len )\r
+ status = NDIS_STATUS_INVALID_LENGTH;\r
+ break;\r
+\r
+ case OID_GEN_PROTOCOL_OPTIONS:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received set for OID_GEN_PROTOCOL_OPTIONS\n", port_num));\r
+ if( info_buf_len < buf_len )\r
+ status = NDIS_STATUS_INVALID_LENGTH;\r
+ break;\r
+\r
+ case OID_GEN_NETWORK_LAYER_ADDRESSES:\r
+ status = __ipoib_set_net_addr( p_adapter, info_buf, info_buf_len, p_bytes_read, p_bytes_needed);\r
+ break;\r
+\r
+#ifdef NDIS51_MINIPORT\r
+ case OID_GEN_MACHINE_NAME:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID,\r
+ ("Port %d received set for OID_GEN_MACHINE_NAME\n", port_num) );\r
+ break;\r
+#endif\r
+\r
+ /* Required Ethernet operational characteristics */\r
+ case OID_802_3_MULTICAST_LIST:\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID,\r
+ ("Port %d received set for OID_802_3_MULTICAST_LIST\n", port_num) );\r
+ if( info_buf_len > MAX_MCAST * sizeof(mac_addr_t) )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d OID_802_3_MULTICAST_LIST - Multicast list full.\n", port_num) );\r
+ status = NDIS_STATUS_MULTICAST_FULL;\r
+ *p_bytes_needed = MAX_MCAST * sizeof(mac_addr_t);\r
+ }\r
+ else if( info_buf_len % sizeof(mac_addr_t) )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d OID_802_3_MULTICAST_LIST - Invalid input buffer.\n", port_num) );\r
+ status = NDIS_STATUS_INVALID_DATA;\r
+ }\r
+ else if( !info_buf && info_buf_len )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d OID_802_3_MULTICAST_LIST - Invalid input buffer.\n", port_num) );\r
+ status = NDIS_STATUS_INVALID_DATA;\r
+ }\r
+ else\r
+ {\r
+ ipoib_refresh_mcast( p_adapter, (mac_addr_t*)info_buf,\r
+ (uint8_t)(info_buf_len / sizeof(mac_addr_t)) );\r
+\r
+ buf_len = info_buf_len;\r
+ /*\r
+ * Note that we don't return pending. It will likely take longer\r
+ * for our SA transactions to complete than NDIS will give us\r
+ * before reseting the adapter. If an SA failure is encountered,\r
+ * the adapter will be marked as hung and we will get reset.\r
+ */\r
+ status = NDIS_STATUS_SUCCESS;\r
+ }\r
+ break;\r
+\r
+ case OID_TCP_TASK_OFFLOAD:\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received set for OID_TCP_TASK_OFFLOAD\n", port_num) );\r
+\r
+ buf_len = info_buf_len;\r
+ status =\r
+ __ipoib_set_tcp_task_offload( p_adapter, info_buf, &buf_len );\r
+ break;\r
+\r
+ /* Optional General */\r
+ case OID_GEN_TRANSPORT_HEADER_OFFSET:\r
+#ifdef NDIS51_MINIPORT\r
+ case OID_GEN_RNDIS_CONFIG_PARAMETER:\r
+ case OID_GEN_VLAN_ID:\r
+#endif\r
+ status = NDIS_STATUS_NOT_SUPPORTED;\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received an unsupported oid of 0x%.8X!\n", port_num, oid));\r
+ break;\r
+\r
+ case OID_GEN_SUPPORTED_LIST:\r
+ case OID_GEN_HARDWARE_STATUS:\r
+ case OID_GEN_MEDIA_SUPPORTED:\r
+ case OID_GEN_MEDIA_IN_USE:\r
+ case OID_GEN_MAXIMUM_FRAME_SIZE:\r
+ case OID_GEN_LINK_SPEED:\r
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:\r
+ case OID_GEN_RECEIVE_BUFFER_SPACE:\r
+ case OID_GEN_MAXIMUM_LOOKAHEAD:\r
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:\r
+ case OID_GEN_RECEIVE_BLOCK_SIZE:\r
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:\r
+ case OID_GEN_VENDOR_ID:\r
+ case OID_GEN_VENDOR_DESCRIPTION:\r
+ case OID_GEN_VENDOR_DRIVER_VERSION:\r
+ case OID_GEN_DRIVER_VERSION:\r
+ case OID_GEN_MAC_OPTIONS:\r
+ case OID_GEN_MEDIA_CONNECT_STATUS:\r
+ case OID_GEN_MAXIMUM_SEND_PACKETS:\r
+ case OID_GEN_SUPPORTED_GUIDS:\r
+ case OID_GEN_PHYSICAL_MEDIUM:\r
+ default:\r
+ status = NDIS_STATUS_INVALID_OID;\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received an invalid oid of 0x%.8X!\n", port_num, oid));\r
+ break;\r
+ }\r
+\r
+ if( status == NDIS_STATUS_SUCCESS )\r
+ {\r
+ *p_bytes_read = buf_len;\r
+ }\r
+ else\r
+ {\r
+ if( status == NDIS_STATUS_INVALID_LENGTH )\r
+ {\r
+ if ( !*p_bytes_needed )\r
+ {\r
+ *p_bytes_needed = buf_len;\r
+ }\r
+ }\r
+\r
+ *p_bytes_read = 0;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_OID );\r
+ return status;\r
+}\r
+\r
+\r
+//! Transfers some number of packets, specified as an array of packet pointers, over the network. \r
+/* For a deserialized driver, these packets are completed asynchronously\r
+using NdisMSendComplete.\r
+IRQL <= DISPATCH_LEVEL\r
+\r
+@param adapter_context Pointer to ipoib_adapter_t structure with per NIC state\r
+@param packet_array Array of packets to send\r
+@param numPackets Number of packets in the array\r
+*/\r
+void\r
+ipoib_send_packets(\r
+ IN NDIS_HANDLE adapter_context,\r
+ IN PPNDIS_PACKET packet_array,\r
+ IN UINT num_packets )\r
+{\r
+ ipoib_adapter_t *p_adapter;\r
+ ipoib_port_t *p_port;\r
+ UINT packet_num;\r
+ PERF_DECLARE( SendPackets );\r
+ PERF_DECLARE( PortSend );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ cl_perf_start( SendPackets );\r
+\r
+ CL_ASSERT( adapter_context );\r
+ p_adapter = (ipoib_adapter_t*)adapter_context;\r
+\r
+ cl_obj_lock( &p_adapter->obj );\r
+ if( p_adapter->state != IB_PNP_PORT_ACTIVE || !p_adapter->p_port )\r
+ {\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ for( packet_num = 0; packet_num < num_packets; ++packet_num )\r
+ {\r
+ ipoib_inc_send_stat( p_adapter, IP_STAT_DROPPED, 0 );\r
+ NdisMSendComplete( p_adapter->h_adapter,\r
+ packet_array[packet_num], NDIS_STATUS_ADAPTER_NOT_READY );\r
+ }\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return;\r
+ }\r
+\r
+ p_port = p_adapter->p_port;\r
+ ipoib_port_ref( p_port, ref_send_packets );\r
+ cl_obj_unlock( &p_adapter->obj );\r
+\r
+ cl_perf_start( PortSend );\r
+ ipoib_port_send( p_port, packet_array, num_packets );\r
+ cl_perf_stop( &p_port->p_adapter->perf, PortSend );\r
+ ipoib_port_deref( p_port, ref_send_packets );\r
+\r
+ cl_perf_stop( &p_adapter->perf, SendPackets );\r
+\r
+ cl_perf_log( &p_adapter->perf, SendBundle, num_packets );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+}\r
+\r
+\r
+void\r
+ipoib_pnp_notify(\r
+ IN NDIS_HANDLE adapter_context,\r
+ IN NDIS_DEVICE_PNP_EVENT pnp_event,\r
+ IN PVOID info_buf,\r
+ IN ULONG info_buf_len )\r
+{\r
+ ipoib_adapter_t *p_adapter;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_PNP );\r
+\r
+ UNUSED_PARAM( info_buf );\r
+ UNUSED_PARAM( info_buf_len );\r
+\r
+ p_adapter = (ipoib_adapter_t*)adapter_context;\r
+\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_PNP, ("Event %d\n", pnp_event) );\r
+ if( pnp_event != NdisDevicePnPEventPowerProfileChanged )\r
+ {\r
+ cl_obj_lock( &p_adapter->obj );\r
+ p_adapter->state = IB_PNP_PORT_REMOVE;\r
+ cl_obj_unlock( &p_adapter->obj );\r
+\r
+ ipoib_resume_oids( p_adapter );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_PNP );\r
+}\r
+\r
+\r
+void\r
+ipoib_shutdown(\r
+ IN PVOID adapter_context )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+ UNUSED_PARAM( adapter_context );\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+void\r
+ipoib_resume_oids(\r
+ IN ipoib_adapter_t* const p_adapter )\r
+{\r
+ ULONG info;\r
+ NDIS_STATUS status;\r
+ boolean_t pending_query, pending_set;\r
+ pending_oid_t query_oid = {0};\r
+ pending_oid_t set_oid = {0};\r
+ KLOCK_QUEUE_HANDLE hdl;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ cl_obj_lock( &p_adapter->obj );\r
+ /*\r
+ * Set the status depending on our state. Fail OID requests that\r
+ * are pending while we reset the adapter.\r
+ */\r
+ switch( p_adapter->state )\r
+ {\r
+ case IB_PNP_PORT_ADD:\r
+ status = NDIS_STATUS_FAILURE;\r
+ break;\r
+\r
+ case IB_PNP_PORT_REMOVE:\r
+ status = NDIS_STATUS_NOT_ACCEPTED;\r
+ break;\r
+ \r
+ default:\r
+ status = NDIS_STATUS_SUCCESS;\r
+ }\r
+\r
+ pending_query = p_adapter->pending_query;\r
+ if( pending_query )\r
+ {\r
+ query_oid = p_adapter->query_oid;\r
+ p_adapter->pending_query = FALSE;\r
+ }\r
+ pending_set = p_adapter->pending_set;\r
+ if( pending_set )\r
+ {\r
+ set_oid = p_adapter->set_oid;\r
+ p_adapter->pending_set = FALSE;\r
+ }\r
+ cl_obj_unlock( &p_adapter->obj );\r
+\r
+ /*\r
+ * If we had a pending OID request for OID_GEN_LINK_SPEED,\r
+ * complete it now. Note that we hold the object lock since\r
+ * NdisMQueryInformationComplete is called at DISPATCH_LEVEL.\r
+ */\r
+ if( pending_query )\r
+ {\r
+ switch( query_oid.oid )\r
+ {\r
+ case OID_GEN_LINK_SPEED:\r
+ ipoib_complete_query( p_adapter, &query_oid,\r
+ status, &p_adapter->rate, sizeof(p_adapter->rate) );\r
+ break;\r
+\r
+ case OID_GEN_MEDIA_CONNECT_STATUS:\r
+ info = NdisMediaStateConnected;\r
+ ipoib_complete_query( p_adapter, &query_oid,\r
+ status, &info, sizeof(info) );\r
+ break;\r
+\r
+ default:\r
+ CL_ASSERT( query_oid.oid == OID_GEN_LINK_SPEED ||\r
+ query_oid.oid == OID_GEN_MEDIA_CONNECT_STATUS );\r
+ break;\r
+ }\r
+ }\r
+\r
+ if( pending_set )\r
+ {\r
+ switch( set_oid.oid )\r
+ {\r
+ case OID_GEN_CURRENT_PACKET_FILTER:\r
+ /* Validation already performed in the SetInformation path. */\r
+\r
+ KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl );\r
+ cl_obj_lock( &p_adapter->obj );\r
+ if( !p_adapter->packet_filter && (*(PULONG)set_oid.p_buf) )\r
+ {\r
+ cl_qlist_insert_tail(\r
+ &g_ipoib.adapter_list, &p_adapter->entry );\r
+ /*\r
+ * Filter was zero, now non-zero. Register IP addresses\r
+ * with SA.\r
+ */\r
+ ipoib_reg_addrs( p_adapter );\r
+ }\r
+ else if( p_adapter->packet_filter && !(*(PULONG)set_oid.p_buf) )\r
+ {\r
+ /* Filter was non-zero, now zero. Deregister IP addresses. */\r
+ ipoib_dereg_addrs( p_adapter );\r
+\r
+ ASSERT( cl_qlist_count( &g_ipoib.adapter_list ) );\r
+ cl_qlist_remove_item(\r
+ &g_ipoib.adapter_list, &p_adapter->entry );\r
+ }\r
+ p_adapter->packet_filter = *(PULONG)set_oid.p_buf;\r
+\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ KeReleaseInStackQueuedSpinLock( &hdl );\r
+\r
+ NdisMSetInformationComplete( p_adapter->h_adapter, status );\r
+ break;\r
+\r
+ case OID_GEN_NETWORK_LAYER_ADDRESSES:\r
+ status = __ipoib_set_net_addr( p_adapter,\r
+ p_adapter->set_oid.p_buf,\r
+ p_adapter->set_oid.buf_len,\r
+ p_adapter->set_oid.p_bytes_used,\r
+ p_adapter->set_oid.p_bytes_needed );\r
+ if( status != NDIS_STATUS_PENDING )\r
+ {\r
+ NdisMSetInformationComplete( p_adapter->h_adapter, status );\r
+ }\r
+ break;\r
+\r
+ default:\r
+ CL_ASSERT( set_oid.oid && 0 );\r
+ break;\r
+ }\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static NDIS_STATUS\r
+__ipoib_set_net_addr(\r
+ IN ipoib_adapter_t * p_adapter,\r
+ IN PVOID info_buf,\r
+ IN ULONG info_buf_len,\r
+ OUT PULONG p_bytes_read,\r
+ OUT PULONG p_bytes_needed )\r
+{\r
+ NDIS_STATUS status;\r
+ PNETWORK_ADDRESS_LIST p_net_addrs;\r
+ PNETWORK_ADDRESS p_net_addr_oid;\r
+ PNETWORK_ADDRESS_IP p_ip_addr;\r
+\r
+ net_address_item_t *p_addr_item;\r
+\r
+ cl_status_t cl_status;\r
+\r
+ size_t idx;\r
+ LONG i;\r
+ ULONG addr_size;\r
+ ULONG total_size;\r
+\r
+ uint8_t port_num;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_OID );\r
+\r
+ status = NDIS_STATUS_SUCCESS;\r
+ port_num = p_adapter->guids.port_num;\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d received set for OID_GEN_NETWORK_LAYER_ADDRESSES\n",\r
+ port_num) );\r
+\r
+ if( !info_buf )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Port %d - OID_GEN_NETWORK_LAYER_ADDRESSES - "\r
+ "NULL buffer\n", port_num) );\r
+ IPOIB_EXIT( IPOIB_DBG_OID );\r
+ return NDIS_STATUS_INVALID_DATA;\r
+ }\r
+\r
+ /*\r
+ * Must use field offset because the structures define array's of size one\r
+ * of a the incorrect type for what is really stored.\r
+ */\r
+ if( info_buf_len < FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address) )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, \r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - "\r
+ "bad length of %d, not enough "\r
+ "for NETWORK_ADDRESS_LIST (%d)\n", port_num, info_buf_len,\r
+ FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address)) );\r
+ *p_bytes_needed = FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address);\r
+ IPOIB_EXIT( IPOIB_DBG_OID );\r
+ return NDIS_STATUS_INVALID_LENGTH;\r
+ }\r
+\r
+ p_net_addrs = (PNETWORK_ADDRESS_LIST)info_buf;\r
+ if( p_net_addrs->AddressCount == 0)\r
+ {\r
+ if( p_net_addrs->AddressType == NDIS_PROTOCOL_ID_TCP_IP )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - "\r
+ "clear TCP/IP addresses\n", port_num) );\r
+ }\r
+ else\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - "\r
+ "Non TCP/IP address type of 0x%.4X on clear\n",\r
+ port_num, p_net_addrs->AddressType) );\r
+ IPOIB_EXIT( IPOIB_DBG_OID );\r
+ return NDIS_STATUS_SUCCESS;\r
+ }\r
+ }\r
+\r
+ addr_size = FIELD_OFFSET(NETWORK_ADDRESS, Address) +\r
+ NETWORK_ADDRESS_LENGTH_IP;\r
+ total_size = FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address) +\r
+ addr_size * p_net_addrs->AddressCount;\r
+\r
+ if( info_buf_len < total_size )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - "\r
+ "bad length of %d, %d required for %d addresses\n",\r
+ port_num, info_buf_len, total_size, p_net_addrs->AddressCount) );\r
+ *p_bytes_needed = total_size;\r
+ IPOIB_EXIT( IPOIB_DBG_OID );\r
+ return NDIS_STATUS_INVALID_LENGTH;\r
+ }\r
+\r
+ /* Lock lists for duration since SA callbacks can occur on other CPUs */\r
+ cl_obj_lock( &p_adapter->obj );\r
+\r
+ /* Set the capacity of the vector to accomodate all assinged addresses. */\r
+ cl_status = cl_vector_set_capacity(\r
+ &p_adapter->ip_vector, p_net_addrs->AddressCount );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ cl_obj_unlock( &p_adapter->obj );\r
+ IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Port %d - OID_GEN_NETWORK_LAYER_ADDRESSES - "\r
+ "Failed to set IP vector capacity: %#x\n", port_num,\r
+ cl_status) );\r
+ IPOIB_EXIT( IPOIB_DBG_OID );\r
+ return NDIS_STATUS_RESOURCES;\r
+ }\r
+\r
+ *p_bytes_read = total_size;\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - List contains %d addresses\n",\r
+ port_num, p_net_addrs->AddressCount));\r
+\r
+ /* First look for addresses we had that should be removed */\r
+ for( idx = 0; idx != cl_vector_get_size( &p_adapter->ip_vector ); idx++ )\r
+ {\r
+ p_addr_item = (net_address_item_t*)\r
+ cl_vector_get_ptr( &p_adapter->ip_vector, idx );\r
+ p_net_addr_oid = (PNETWORK_ADDRESS)p_net_addrs->Address;\r
+\r
+ for( i = 0; i < p_net_addrs->AddressCount; ++i, p_net_addr_oid =\r
+ (PNETWORK_ADDRESS)((uint8_t *)p_net_addr_oid +\r
+ FIELD_OFFSET(NETWORK_ADDRESS, Address) +\r
+ p_net_addr_oid->AddressLength) )\r
+ {\r
+\r
+ if( p_net_addr_oid->AddressType != NDIS_PROTOCOL_ID_TCP_IP )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_OID,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong type of 0x%.4X, "\r
+ "should be 0x%.4X\n", port_num, i, p_net_addr_oid->AddressType,\r
+ NDIS_PROTOCOL_ID_TCP_IP));\r
+ continue;\r
+ }\r
+\r
+ if( p_net_addr_oid->AddressLength != NETWORK_ADDRESS_LENGTH_IP)\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_OID,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong size of %d, "\r
+ "should be %d\n", port_num, i, p_net_addr_oid->AddressLength,\r
+ NETWORK_ADDRESS_LENGTH_IP));\r
+ continue;\r
+ }\r
+\r
+ p_ip_addr = (PNETWORK_ADDRESS_IP)p_net_addr_oid->Address;\r
+ if( !cl_memcmp( &p_ip_addr->in_addr,\r
+ &p_addr_item->address.as_ulong, sizeof(ULONG) ) )\r
+ {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if( i == p_net_addrs->AddressCount )\r
+ {\r
+ /* Didn't find a match, delete from SA */\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Deleting Address %d.%d.%d.%d\n",\r
+ port_num,\r
+ p_addr_item->address.as_bytes[0],\r
+ p_addr_item->address.as_bytes[1],\r
+ p_addr_item->address.as_bytes[2],\r
+ p_addr_item->address.as_bytes[3]));\r
+\r
+ if( p_addr_item->p_reg )\r
+ {\r
+ if( p_addr_item->p_reg->h_reg_svc )\r
+ {\r
+ p_adapter->p_ifc->dereg_svc(\r
+ p_addr_item->p_reg->h_reg_svc, __ipoib_ats_dereg_cb );\r
+ }\r
+ else\r
+ {\r
+ cl_free( p_addr_item->p_reg );\r
+ }\r
+ p_addr_item->p_reg = NULL;\r
+ }\r
+ p_addr_item->address.as_ulong = 0;\r
+ }\r
+ }\r
+\r
+ /* Now look for new addresses */\r
+ p_net_addr_oid = (NETWORK_ADDRESS *)p_net_addrs->Address;\r
+ idx = 0;\r
+ for( i = 0; i < p_net_addrs->AddressCount; i++, p_net_addr_oid =\r
+ (PNETWORK_ADDRESS)((uint8_t *)p_net_addr_oid +\r
+ FIELD_OFFSET(NETWORK_ADDRESS, Address) + p_net_addr_oid->AddressLength) )\r
+ {\r
+\r
+ if( p_net_addr_oid->AddressType != NDIS_PROTOCOL_ID_TCP_IP )\r
+ {\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong type of 0x%.4X, "\r
+ "should be 0x%.4X\n", port_num, i, p_net_addr_oid->AddressType,\r
+ NDIS_PROTOCOL_ID_TCP_IP));\r
+ continue;\r
+ }\r
+\r
+ if( p_net_addr_oid->AddressLength != NETWORK_ADDRESS_LENGTH_IP)\r
+ {\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong size of %d, "\r
+ "should be %d\n", port_num, i, p_net_addr_oid->AddressLength,\r
+ NETWORK_ADDRESS_LENGTH_IP));\r
+ continue;\r
+ }\r
+\r
+ p_ip_addr = (PNETWORK_ADDRESS_IP)p_net_addr_oid->Address;\r
+\r
+ /* Size the vector as needed. */\r
+ if( cl_vector_get_size( &p_adapter->ip_vector ) <= idx )\r
+ cl_vector_set_size( &p_adapter->ip_vector, idx + 1 );\r
+\r
+ p_addr_item = cl_vector_get_ptr( &p_adapter->ip_vector, idx );\r
+ if( !cl_memcmp( &p_ip_addr->in_addr, &p_addr_item->address.as_ulong,\r
+ sizeof(ULONG) ) )\r
+ {\r
+ idx++;\r
+ /* Already have this address - no change needed */\r
+ continue;\r
+ }\r
+\r
+ /*\r
+ * Copy the address information, but don't register yet - the port\r
+ * could be down.\r
+ */\r
+ if( p_addr_item->p_reg )\r
+ {\r
+ /* If in use by some other address, deregister. */\r
+ if( p_addr_item->p_reg->h_reg_svc )\r
+ {\r
+ p_adapter->p_ifc->dereg_svc(\r
+ p_addr_item->p_reg->h_reg_svc, __ipoib_ats_dereg_cb );\r
+ }\r
+ else\r
+ {\r
+ cl_free( p_addr_item->p_reg );\r
+ }\r
+ p_addr_item->p_reg = NULL;\r
+ }\r
+ memcpy ((void *)&p_addr_item->address.as_ulong, (const void *)&p_ip_addr->in_addr, sizeof(ULONG) );\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Adding Address %d.%d.%d.%d\n",\r
+ port_num,\r
+ p_addr_item->address.as_bytes[0],\r
+ p_addr_item->address.as_bytes[1],\r
+ p_addr_item->address.as_bytes[2],\r
+ p_addr_item->address.as_bytes[3]) );\r
+ idx++;\r
+ }\r
+\r
+ /* Now clear any extra entries that shouldn't be there. */\r
+ while( idx < cl_vector_get_size( &p_adapter->ip_vector ) )\r
+ {\r
+ p_addr_item = (net_address_item_t*)\r
+ cl_vector_get_ptr( &p_adapter->ip_vector,\r
+ cl_vector_get_size( &p_adapter->ip_vector ) - 1 );\r
+\r
+ if( p_addr_item->p_reg )\r
+ {\r
+ if( p_addr_item->p_reg->h_reg_svc )\r
+ {\r
+ p_adapter->p_ifc->dereg_svc(\r
+ p_addr_item->p_reg->h_reg_svc, __ipoib_ats_dereg_cb );\r
+ }\r
+ else\r
+ {\r
+ cl_free( p_addr_item->p_reg );\r
+ }\r
+ p_addr_item->p_reg = NULL;\r
+ p_addr_item->address.as_ulong = 0;\r
+ }\r
+\r
+ /* No need to check return value - shrinking always succeeds. */\r
+ cl_vector_set_size( &p_adapter->ip_vector,\r
+ cl_vector_get_size( &p_adapter->ip_vector ) - 1 );\r
+ }\r
+\r
+ if( p_adapter->state == IB_PNP_PORT_ACTIVE && p_adapter->packet_filter )\r
+ ipoib_reg_addrs( p_adapter );\r
+\r
+ cl_obj_unlock( &p_adapter->obj );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_OID );\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+/* Object lock is held when this function is called. */\r
+void\r
+ipoib_reg_addrs(\r
+ IN ipoib_adapter_t* const p_adapter )\r
+{\r
+ net_address_item_t *p_addr_item;\r
+\r
+ size_t idx;\r
+\r
+ uint8_t port_num;\r
+\r
+ ib_api_status_t ib_status;\r
+ ib_reg_svc_req_t ib_service;\r
+ ib_gid_t port_gid;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_OID );\r
+\r
+ port_num = p_adapter->guids.port_num;\r
+\r
+ /* Setup our service call with things common to all calls */\r
+ cl_memset( &ib_service, 0, sizeof(ib_service) );\r
+\r
+ /* BUGBUG Only register local subnet GID prefix for now */\r
+ ib_gid_set_default( &port_gid, p_adapter->guids.port_guid );\r
+ ib_service.svc_rec.service_gid = port_gid;\r
+\r
+ ib_service.svc_rec.service_pkey = IB_DEFAULT_PKEY;\r
+ ib_service.svc_rec.service_lease = IB_INFINITE_SERVICE_LEASE;\r
+\r
+ /* Must cast here because the service name is an array of unsigned chars but\r
+ * strcpy want a pointer to a signed char */\r
+ strcpy( (char *)ib_service.svc_rec.service_name, ATS_NAME );\r
+\r
+ /* IP Address in question will be put in below */\r
+ ib_service.port_guid = p_adapter->guids.port_guid;\r
+ ib_service.timeout_ms = p_adapter->params.sa_timeout;\r
+ ib_service.retry_cnt = p_adapter->params.sa_retry_cnt;\r
+\r
+ /* Can't set IB_FLAGS_SYNC here because I can't wait at dispatch */\r
+ ib_service.flags = 0;\r
+\r
+ /* Service context will be put in below */\r
+\r
+ ib_service.svc_data_mask = IB_SR_COMPMASK_SID |\r
+ IB_SR_COMPMASK_SGID |\r
+ IB_SR_COMPMASK_SPKEY |\r
+ IB_SR_COMPMASK_SLEASE |\r
+ IB_SR_COMPMASK_SNAME |\r
+ IB_SR_COMPMASK_SDATA8_12 |\r
+ IB_SR_COMPMASK_SDATA8_13 |\r
+ IB_SR_COMPMASK_SDATA8_14 |\r
+ IB_SR_COMPMASK_SDATA8_15;\r
+ ib_service.pfn_reg_svc_cb = __ipoib_ats_reg_cb;\r
+\r
+ for( idx = 0; idx < cl_vector_get_size( &p_adapter->ip_vector); idx++ )\r
+ {\r
+ p_addr_item = (net_address_item_t*)\r
+ cl_vector_get_ptr( &p_adapter->ip_vector, idx );\r
+\r
+ if( p_addr_item->p_reg )\r
+ continue;\r
+\r
+ p_addr_item->p_reg = cl_zalloc( sizeof(ats_reg_t) );\r
+ if( !p_addr_item->p_reg )\r
+ break;\r
+\r
+ p_addr_item->p_reg->p_adapter = p_adapter;\r
+\r
+ ib_service.svc_context = p_addr_item->p_reg;\r
+\r
+ ib_service.svc_rec.service_id =\r
+ ATS_SERVICE_ID & CL_HTON64(0xFFFFFFFFFFFFFF00);\r
+ /* ATS service IDs start at 0x10000CE100415453 */\r
+ ib_service.svc_rec.service_id |= ((uint64_t)(idx + 0x53)) << 56;\r
+\r
+ cl_memcpy( &ib_service.svc_rec.service_data8[ATS_IPV4_OFFSET],\r
+ p_addr_item->address.as_bytes, IPV4_ADDR_SIZE );\r
+\r
+ /* Take a reference for each service request. */\r
+ cl_obj_ref(&p_adapter->obj);\r
+ ib_status = p_adapter->p_ifc->reg_svc(\r
+ p_adapter->h_al, &ib_service, &p_addr_item->p_reg->h_reg_svc );\r
+ if( ib_status != IB_SUCCESS )\r
+ {\r
+ if( ib_status == IB_INVALID_GUID )\r
+ {\r
+ /* If this occurs, we log the error but do not fail the OID yet */\r
+ IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_OID,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - "\r
+ "Failed to register IP Address "\r
+ "of %d.%d.%d.%d with error IB_INVALID_GUID\n",\r
+ port_num,\r
+ p_addr_item->address.as_bytes[0],\r
+ p_addr_item->address.as_bytes[1],\r
+ p_addr_item->address.as_bytes[2],\r
+ p_addr_item->address.as_bytes[3]) );\r
+ }\r
+ else\r
+ {\r
+ /* Fatal error. */\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Failed to register IP Address "\r
+ "of %d.%d.%d.%d with error %s\n",\r
+ port_num,\r
+ p_addr_item->address.as_bytes[0],\r
+ p_addr_item->address.as_bytes[1],\r
+ p_addr_item->address.as_bytes[2],\r
+ p_addr_item->address.as_bytes[3],\r
+ p_adapter->p_ifc->get_err_str( ib_status )) );\r
+ p_adapter->hung = TRUE;\r
+ }\r
+ cl_obj_deref(&p_adapter->obj);\r
+ cl_free( p_addr_item->p_reg );\r
+ p_addr_item->p_reg = NULL;\r
+ }\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_OID );\r
+}\r
+\r
+\r
+/* Object lock is held when this function is called. */\r
+void\r
+ipoib_dereg_addrs(\r
+ IN ipoib_adapter_t* const p_adapter )\r
+{\r
+ net_address_item_t *p_addr_item;\r
+\r
+ size_t idx;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_OID );\r
+\r
+ for( idx = 0; idx < cl_vector_get_size( &p_adapter->ip_vector); idx++ )\r
+ {\r
+ p_addr_item = (net_address_item_t*)\r
+ cl_vector_get_ptr( &p_adapter->ip_vector, idx );\r
+\r
+ if( !p_addr_item->p_reg )\r
+ continue;\r
+\r
+ if( p_addr_item->p_reg->h_reg_svc )\r
+ {\r
+ p_adapter->p_ifc->dereg_svc(\r
+ p_addr_item->p_reg->h_reg_svc, __ipoib_ats_dereg_cb );\r
+ }\r
+ else\r
+ {\r
+ cl_free( p_addr_item->p_reg );\r
+ }\r
+ p_addr_item->p_reg = NULL;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_OID );\r
+}\r
+\r
+\r
+static void\r
+__ipoib_ats_reg_cb(\r
+ IN ib_reg_svc_rec_t *p_reg_svc_rec )\r
+{\r
+ ats_reg_t *p_reg;\r
+ uint8_t port_num;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_OID );\r
+\r
+ CL_ASSERT( p_reg_svc_rec );\r
+ CL_ASSERT( p_reg_svc_rec->svc_context );\r
+\r
+ p_reg = (ats_reg_t* __ptr64)p_reg_svc_rec->svc_context;\r
+ port_num = p_reg->p_adapter->guids.port_num;\r
+\r
+ cl_obj_lock( &p_reg->p_adapter->obj );\r
+\r
+ if( p_reg_svc_rec->req_status == IB_SUCCESS &&\r
+ !p_reg_svc_rec->resp_status )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Registered IP Address "\r
+ "of %d.%d.%d.%d\n",\r
+ port_num,\r
+ p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET],\r
+ p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+1],\r
+ p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+2],\r
+ p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+3]) );\r
+ }\r
+ else if( p_reg_svc_rec->req_status != IB_CANCELED )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_OID,\r
+ ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Failed to register IP Address "\r
+ "of %d.%d.%d.%d with error %s\n",\r
+ port_num,\r
+ p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET],\r
+ p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+1],\r
+ p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+2],\r
+ p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+3],\r
+ p_reg->p_adapter->p_ifc->get_err_str( p_reg_svc_rec->resp_status )) );\r
+ p_reg->p_adapter->hung = TRUE;\r
+ p_reg->h_reg_svc = NULL;\r
+ }\r
+\r
+ cl_obj_unlock( &p_reg->p_adapter->obj );\r
+ cl_obj_deref(&p_reg->p_adapter->obj);\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_OID );\r
+}\r
+\r
+\r
+static void\r
+__ipoib_ats_dereg_cb(\r
+ IN void *context )\r
+{\r
+ cl_free( context );\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ * Copyright (c) 2006 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+#ifndef _IPOIB_DRIVER_H_\r
+#define _IPOIB_DRIVER_H_\r
+\r
+\r
+#include "ipoib_log.h"\r
+#include "ipoib_adapter.h"\r
+#include <complib/cl_spinlock.h>\r
+#include <complib/cl_qlist.h>\r
+#include "ipoib_debug.h"\r
+\r
+\r
+/*\r
+ * Definitions\r
+ */\r
+#define MAX_BUNDLE_ID_LENGTH 32\r
+\r
+\r
+#define IB_MTU 2048\r
+/*\r
+ * Header length as defined by IPoIB spec:\r
+ * http://www.ietf.org/internet-drafts/draft-ietf-ipoib-ip-over-infiniband-04.txt\r
+ */\r
+ \r
+#define MAX_PAYLOAD_MTU (IB_MTU - sizeof(ipoib_hdr_t))\r
+\r
+/*\r
+ * Only the protocol type is sent as part of the UD payload\r
+ * since the rest of the Ethernet header is encapsulated in the\r
+ * various IB headers. We report out buffer space as if we\r
+ * transmit the ethernet headers.\r
+ */\r
+#define MAX_XFER_BLOCK_SIZE (sizeof(eth_hdr_t) + MAX_PAYLOAD_MTU)\r
+\r
+\r
+typedef struct _ipoib_globals\r
+{\r
+ KSPIN_LOCK lock;\r
+ cl_qlist_t adapter_list;\r
+ cl_qlist_t bundle_list;\r
+\r
+ atomic32_t laa_idx;\r
+\r
+ NDIS_HANDLE h_ndis_wrapper;\r
+ NDIS_HANDLE h_ibat_dev;\r
+ volatile LONG ibat_ref;\r
+ uint32_t bypass_check_bcast_rate;\r
+\r
+} ipoib_globals_t;\r
+/*\r
+* FIELDS\r
+* lock\r
+* Spinlock to protect list access.\r
+*\r
+* adapter_list\r
+* List of all adapter instances. Used for address translation support.\r
+*\r
+* bundle_list\r
+* List of all adapter bundles.\r
+*\r
+* laa_idx\r
+* Global counter for generating LAA MACs\r
+*\r
+* h_ibat_dev\r
+* Device handle returned by NdisMRegisterDevice.\r
+*********/\r
+\r
+extern ipoib_globals_t g_ipoib;\r
+\r
+\r
+typedef struct _ipoib_bundle\r
+{\r
+ cl_list_item_t list_item;\r
+ char bundle_id[MAX_BUNDLE_ID_LENGTH];\r
+ cl_qlist_t adapter_list;\r
+\r
+} ipoib_bundle_t;\r
+/*\r
+* FIELDS\r
+* list_item\r
+* List item for storing the bundle in a quick list.\r
+*\r
+* bundle_id\r
+* Bundle identifier.\r
+*\r
+* adapter_list\r
+* List of adapters in the bundle. The adapter at the head is the\r
+* primary adapter of the bundle.\r
+*********/\r
+\r
+\r
+\r
+void\r
+ipoib_resume_oids(\r
+ IN ipoib_adapter_t* const p_adapter );\r
+\r
+#endif /* _IPOIB_DRIVER_H_ */\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ * Copyright (c) 2006 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+\r
+#include "ipoib_endpoint.h"\r
+#include "ipoib_port.h"\r
+#include "ipoib_debug.h"\r
+#if defined(EVENT_TRACING)\r
+#ifdef offsetof\r
+#undef offsetof\r
+#endif\r
+#include "ipoib_endpoint.tmh"\r
+#endif\r
+#include <complib/cl_atomic.h>\r
+\r
+\r
+static void\r
+__endpt_destroying(\r
+ IN cl_obj_t* p_obj );\r
+\r
+static void\r
+__endpt_cleanup(\r
+ IN cl_obj_t* p_obj );\r
+\r
+static void\r
+__endpt_free(\r
+ IN cl_obj_t* p_obj );\r
+\r
+static ib_api_status_t\r
+__create_mcast_av(\r
+ IN ib_pd_handle_t h_pd,\r
+ IN uint8_t port_num,\r
+ IN ib_member_rec_t* const p_member_rec,\r
+ OUT ib_av_handle_t* const ph_av );\r
+\r
+static inline ipoib_port_t*\r
+__endpt_parent(\r
+ IN ipoib_endpt_t* const p_endpt );\r
+\r
+static void\r
+__path_query_cb(\r
+ IN ib_query_rec_t *p_query_rec );\r
+\r
+static void\r
+__endpt_resolve(\r
+ IN ipoib_endpt_t* const p_endpt );\r
+\r
+\r
+ipoib_endpt_t*\r
+ipoib_endpt_create(\r
+ IN const ib_gid_t* const p_dgid,\r
+ IN const net16_t dlid,\r
+ IN const net32_t qpn )\r
+{\r
+ ipoib_endpt_t *p_endpt;\r
+ cl_status_t status;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ p_endpt = cl_zalloc( sizeof(ipoib_endpt_t) );\r
+ if( !p_endpt )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to allocate endpoint (%d bytes)\n",\r
+ sizeof(ipoib_endpt_t)) );\r
+ return NULL;\r
+ }\r
+\r
+ cl_obj_construct( &p_endpt->obj, IPOIB_OBJ_ENDPOINT );\r
+\r
+ status = cl_obj_init( &p_endpt->obj, CL_DESTROY_ASYNC,\r
+ __endpt_destroying, __endpt_cleanup, __endpt_free );\r
+\r
+ p_endpt->dgid = *p_dgid;\r
+ p_endpt->dlid = dlid;\r
+ p_endpt->qpn = qpn;\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+ return p_endpt;\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__create_mcast_av(\r
+ IN ib_pd_handle_t h_pd,\r
+ IN uint8_t port_num,\r
+ IN ib_member_rec_t* const p_member_rec,\r
+ OUT ib_av_handle_t* const ph_av )\r
+{\r
+ ib_av_attr_t av_attr;\r
+ uint32_t flow_lbl;\r
+ uint8_t hop_lmt;\r
+ ib_api_status_t status;\r
+ ipoib_endpt_t *p_endpt;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_MCAST );\r
+\r
+ p_endpt = PARENT_STRUCT(ph_av, ipoib_endpt_t, h_av );\r
+\r
+ cl_memclr( &av_attr, sizeof(ib_av_attr_t) );\r
+ av_attr.port_num = port_num;\r
+ ib_member_get_sl_flow_hop( p_member_rec->sl_flow_hop,\r
+ &av_attr.sl, &flow_lbl, &hop_lmt );\r
+ av_attr.dlid = p_member_rec->mlid;\r
+ av_attr.grh_valid = TRUE;\r
+ av_attr.grh.hop_limit = hop_lmt;\r
+ av_attr.grh.dest_gid = p_member_rec->mgid;\r
+ av_attr.grh.src_gid = p_member_rec->port_gid;\r
+ av_attr.grh.ver_class_flow =\r
+ ib_grh_set_ver_class_flow( 6, p_member_rec->tclass, flow_lbl );\r
+ av_attr.static_rate = p_member_rec->rate & IB_PATH_REC_BASE_MASK;\r
+ av_attr.path_bits = 0;\r
+ /* port is not attached to endpoint at this point, so use endpt ifc reference */\r
+ status = p_endpt->p_ifc->create_av( h_pd, &av_attr, ph_av );\r
+\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_create_av returned %s\n",\r
+ p_endpt->p_ifc->get_err_str( status )) );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_MCAST );\r
+ return status;\r
+}\r
+\r
+\r
+ib_api_status_t\r
+ipoib_endpt_set_mcast(\r
+ IN ipoib_endpt_t* const p_endpt,\r
+ IN ib_pd_handle_t h_pd,\r
+ IN uint8_t port_num,\r
+ IN ib_mcast_rec_t* const p_mcast_rec )\r
+{\r
+ ib_api_status_t status;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,\r
+ ("Create av for MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",\r
+ p_endpt->mac.addr[0], p_endpt->mac.addr[1],\r
+ p_endpt->mac.addr[2], p_endpt->mac.addr[3],\r
+ p_endpt->mac.addr[4], p_endpt->mac.addr[5]) );\r
+ \r
+ status = __create_mcast_av( h_pd, port_num, p_mcast_rec->p_member_rec,\r
+ &p_endpt->h_av );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__create_mcast_av returned %s\n", \r
+ p_endpt->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+ p_endpt->h_mcast = p_mcast_rec->h_mcast;\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+static void\r
+__endpt_destroying(\r
+ IN cl_obj_t* p_obj )\r
+{\r
+ ipoib_endpt_t *p_endpt;\r
+ ipoib_port_t *p_port;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj );\r
+ p_port = __endpt_parent( p_endpt );\r
+\r
+ cl_obj_lock( p_obj );\r
+ if( p_endpt->h_query )\r
+ {\r
+ p_port->p_adapter->p_ifc->cancel_query(\r
+ p_port->p_adapter->h_al, p_endpt->h_query );\r
+ p_endpt->h_query = NULL;\r
+ }\r
+\r
+ /* Leave the multicast group if it exists. */\r
+ if( p_endpt->h_mcast )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,\r
+ ("Leaving MCast group\n") );\r
+ ipoib_port_ref(p_port, ref_leave_mcast);\r
+ p_port->p_adapter->p_ifc->leave_mcast( p_endpt->h_mcast, ipoib_leave_mcast_cb );\r
+ }\r
+ \r
+ cl_obj_unlock( p_obj );\r
+ \r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+}\r
+\r
+\r
+static void\r
+__endpt_cleanup(\r
+ IN cl_obj_t* p_obj )\r
+{\r
+ ipoib_endpt_t *p_endpt;\r
+ ipoib_port_t *p_port;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj );\r
+ p_port = __endpt_parent( p_endpt );\r
+\r
+ /* Destroy the AV if it exists. */\r
+ if( p_endpt->h_av )\r
+ p_port->p_adapter->p_ifc->destroy_av( p_endpt->h_av );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+}\r
+\r
+\r
+static void\r
+__endpt_free(\r
+ IN cl_obj_t* p_obj )\r
+{\r
+ ipoib_endpt_t *p_endpt;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj );\r
+\r
+ cl_obj_deinit( p_obj );\r
+ cl_free( p_endpt );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+}\r
+\r
+\r
+static inline ipoib_port_t*\r
+__endpt_parent(\r
+ IN ipoib_endpt_t* const p_endpt )\r
+{\r
+ return PARENT_STRUCT( p_endpt->rel.p_parent_obj, ipoib_port_t, obj );\r
+}\r
+\r
+\r
+/*\r
+ * This function is called with the port object's send lock held and\r
+ * a reference held on the endpoint. If we fail, we release the reference.\r
+ */\r
+NDIS_STATUS\r
+ipoib_endpt_queue(\r
+ IN ipoib_endpt_t* const p_endpt )\r
+{\r
+ ib_api_status_t status;\r
+ ipoib_port_t *p_port;\r
+ ib_query_req_t query;\r
+ ib_user_query_t info;\r
+ ib_path_rec_t path;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ if( p_endpt->h_av )\r
+ {\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+ return NDIS_STATUS_SUCCESS;\r
+ }\r
+\r
+ if( p_endpt->h_query ||\r
+ p_endpt->qpn == CL_HTON32(0x00FFFFFF) )\r
+ {\r
+ ipoib_endpt_deref( p_endpt );\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+ return NDIS_STATUS_PENDING;\r
+ }\r
+\r
+ /* This is the first packet for this endpoint. Query the SA. */\r
+ p_port = __endpt_parent( p_endpt );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ info.method = IB_MAD_METHOD_GETTABLE;\r
+ info.attr_id = IB_MAD_ATTR_PATH_RECORD;\r
+ info.attr_size = sizeof(ib_path_rec_t);\r
+ info.comp_mask = IB_PR_COMPMASK_DGID | IB_PR_COMPMASK_SGID |\r
+ IB_PR_COMPMASK_REVERSIBLE | IB_PR_COMPMASK_NUM_PATH;\r
+ info.p_attr = &path;\r
+\r
+ cl_memclr( &path, sizeof(ib_path_rec_t) );\r
+ path.dgid = p_endpt->dgid;\r
+ ib_gid_set_default( &path.sgid, p_port->p_adapter->guids.port_guid );\r
+ path.num_path = 0x1;\r
+\r
+ cl_memclr( &query, sizeof(ib_query_req_t) );\r
+ query.query_type = IB_QUERY_USER_DEFINED;\r
+ query.p_query_input = &info;\r
+ query.port_guid = p_port->p_adapter->guids.port_guid;\r
+ query.timeout_ms = p_port->p_adapter->params.sa_timeout;\r
+ query.retry_cnt = p_port->p_adapter->params.sa_retry_cnt;\r
+\r
+ query.query_context = p_endpt;\r
+ query.pfn_query_cb = __path_query_cb;\r
+\r
+ status = p_port->p_adapter->p_ifc->query(\r
+ p_port->p_adapter->h_al, &query, &p_endpt->h_query );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ENDPT,\r
+ ("ib_query for path returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ ipoib_endpt_deref( p_endpt );\r
+ /* Flag the adapter as hung. */\r
+ p_port->p_adapter->hung = TRUE;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+ return NDIS_STATUS_PENDING;\r
+}\r
+\r
+\r
+static void\r
+__path_query_cb(\r
+ IN ib_query_rec_t *p_query_rec )\r
+{\r
+ ib_api_status_t status;\r
+ ipoib_endpt_t *p_endpt;\r
+ ipoib_port_t *p_port;\r
+ ib_av_attr_t av_attr;\r
+ ib_path_rec_t *p_path;\r
+ net32_t flow_lbl;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ p_endpt = (ipoib_endpt_t*__ptr64)p_query_rec->query_context;\r
+ p_port = __endpt_parent( p_endpt );\r
+\r
+ cl_obj_lock( &p_endpt->obj );\r
+ p_endpt->h_query = NULL;\r
+ if( p_endpt->obj.state == CL_DESTROYING )\r
+ {\r
+ cl_obj_unlock( &p_endpt->obj );\r
+ ipoib_endpt_deref( p_endpt );\r
+ if( p_query_rec->p_result_mad )\r
+ p_port->p_adapter->p_ifc->put_mad( p_query_rec->p_result_mad );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Endpoint destroying, aborting.\n") );\r
+ return;\r
+ }\r
+ cl_obj_unlock( &p_endpt->obj );\r
+\r
+ if( p_query_rec->status != IB_SUCCESS || !p_query_rec->result_cnt )\r
+ {\r
+ p_port->p_adapter->hung = TRUE;\r
+ ipoib_endpt_deref( p_endpt );\r
+ if( p_query_rec->p_result_mad )\r
+ p_port->p_adapter->p_ifc->put_mad( p_query_rec->p_result_mad );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Path query failed with %s\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( p_query_rec->status )) );\r
+ return;\r
+ }\r
+\r
+ p_path = ib_get_query_path_rec( p_query_rec->p_result_mad, 0 );\r
+\r
+ cl_memclr( &av_attr, sizeof(ib_av_attr_t) );\r
+\r
+ av_attr.port_num = p_port->port_num;\r
+\r
+ av_attr.sl = ib_path_rec_sl( p_path );\r
+ av_attr.dlid = p_path->dlid;\r
+\r
+ /*\r
+ * We always send the GRH so that we preferably lookup endpoints\r
+ * by GID rather than by LID. This allows certain WHQL tests\r
+ * such as the 2c_MediaCheck test to succeed since they don't use\r
+ * IP. This allows endpoints to be created on the fly for requests\r
+ * for which there is no match, something that doesn't work when\r
+ * using LIDs only.\r
+ */\r
+ flow_lbl = ib_path_rec_flow_lbl( p_path );\r
+ av_attr.grh_valid = TRUE;\r
+ av_attr.grh.ver_class_flow = ib_grh_set_ver_class_flow(\r
+ 6, p_path->tclass, flow_lbl );\r
+ av_attr.grh.resv1 = 0;\r
+ av_attr.grh.resv2 = 0;\r
+ av_attr.grh.hop_limit = ib_path_rec_hop_limit( p_path );\r
+ av_attr.grh.src_gid = p_path->sgid;\r
+ av_attr.grh.dest_gid = p_path->dgid;\r
+ \r
+ cl_obj_lock( &p_port->obj );\r
+ if( !p_endpt->dlid )\r
+ {\r
+ cl_map_item_t *p_qitem;\r
+\r
+ /* This is a subnet local endpoint that does not have its LID set. */\r
+ p_endpt->dlid = p_path->dlid;\r
+ /*\r
+ * Insert the item in the LID map so that locally routed unicast\r
+ * traffic will resolve it properly.\r
+ */\r
+ p_qitem = cl_qmap_insert( &p_port->endpt_mgr.lid_endpts,\r
+ p_endpt->dlid, &p_endpt->lid_item );\r
+ CL_ASSERT( p_qitem == &p_endpt->lid_item );\r
+ }\r
+ cl_obj_unlock( &p_port->obj );\r
+ av_attr.static_rate = ib_path_rec_rate( p_path );\r
+ av_attr.path_bits = 0;\r
+\r
+ /* Done with the path record. Release the MAD. */\r
+ p_port->p_adapter->p_ifc->put_mad( p_query_rec->p_result_mad );\r
+\r
+ /* Create the AV. */\r
+ status = p_port->p_adapter->p_ifc->create_av(\r
+ p_port->ib_mgr.h_pd, &av_attr, &p_endpt->h_av );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ p_port->p_adapter->hung = TRUE;\r
+ ipoib_endpt_deref( p_endpt );\r
+ cl_obj_unlock( &p_endpt->obj );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_create_av failed with %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return;\r
+ }\r
+\r
+ /* Try to send all pending sends. */\r
+ ipoib_port_resume( p_port );\r
+\r
+ /* Release the reference taken for the SA query. */\r
+ ipoib_endpt_deref( p_endpt );\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ * Copyright (c) 2006 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+#ifndef _IPOIB_ENDPOINT_H_\r
+#define _IPOIB_ENDPOINT_H_\r
+\r
+\r
+#include <iba/ib_al.h>\r
+#include <complib/cl_qlist.h>\r
+#include <complib/cl_qmap.h>\r
+#include <complib/cl_fleximap.h>\r
+#include <complib/cl_obj.h>\r
+#include "iba/ipoib_ifc.h"\r
+#include <ip_packet.h>\r
+#include "ipoib_debug.h"\r
+\r
+\r
+typedef struct _ipoib_endpt\r
+{\r
+ cl_obj_t obj;\r
+ cl_obj_rel_t rel;\r
+ cl_map_item_t mac_item;\r
+ cl_fmap_item_t gid_item;\r
+ cl_map_item_t lid_item;\r
+ ib_query_handle_t h_query;\r
+ ib_mcast_handle_t h_mcast;\r
+ mac_addr_t mac;\r
+ ib_gid_t dgid;\r
+ net16_t dlid;\r
+ net32_t qpn;\r
+ ib_av_handle_t h_av;\r
+ boolean_t expired;\r
+ ib_al_ifc_t *p_ifc;\r
+\r
+} ipoib_endpt_t;\r
+/*\r
+* FIELDS\r
+* mac_item\r
+* Map item for storing the endpoint in a map. The key is the\r
+* destination MAC address.\r
+*\r
+* lid_item\r
+* Map item for storing the endpoint in a map. The key is the\r
+* destination LID.\r
+*\r
+* gid_item\r
+* Map item for storing the endpoint in a map. The key is the\r
+* destination GID.\r
+*\r
+* h_query\r
+* Query handle for cancelling SA queries.\r
+*\r
+* h_mcast\r
+* For multicast endpoints, the multicast handle.\r
+*\r
+* mac\r
+* MAC address.\r
+*\r
+* dgid\r
+* Destination GID.\r
+*\r
+* dlid\r
+* Destination LID. The destination LID is only set for endpoints\r
+* that are on the same subnet. It is used as key in the LID map.\r
+*\r
+* qpn\r
+* Destination queue pair number.\r
+*\r
+* h_av\r
+* Address vector for sending data.\r
+*\r
+* expired\r
+* Flag to indicate that the endpoint should be flushed.\r
+*\r
+* p_ifc\r
+* Reference to transport functions, can be used\r
+* while endpoint is not attached to port yet.\r
+*\r
+* NOTES\r
+* If the h_mcast member is set, the endpoint is never expired.\r
+*********/\r
+\r
+\r
+ipoib_endpt_t*\r
+ipoib_endpt_create(\r
+ IN const ib_gid_t* const p_dgid,\r
+ IN const net16_t dlid,\r
+ IN const net32_t qpn );\r
+\r
+\r
+ib_api_status_t\r
+ipoib_endpt_set_mcast(\r
+ IN ipoib_endpt_t* const p_endpt,\r
+ IN ib_pd_handle_t h_pd,\r
+ IN uint8_t port_num,\r
+ IN ib_mcast_rec_t* const p_mcast_rec );\r
+\r
+\r
+static inline void\r
+ipoib_endpt_ref(\r
+ IN ipoib_endpt_t* const p_endpt )\r
+{\r
+ CL_ASSERT( p_endpt );\r
+\r
+ cl_obj_ref( &p_endpt->obj );\r
+ /*\r
+ * Anytime we reference the endpoint, we're either receiving data\r
+ * or trying to send data to that endpoint. Clear the expired flag\r
+ * to prevent the AV from being flushed.\r
+ */\r
+ p_endpt->expired = FALSE;\r
+}\r
+\r
+\r
+static inline void\r
+ipoib_endpt_deref(\r
+ IN ipoib_endpt_t* const p_endpt )\r
+{\r
+ cl_obj_deref( &p_endpt->obj );\r
+}\r
+\r
+\r
+NDIS_STATUS\r
+ipoib_endpt_queue(\r
+ IN ipoib_endpt_t* const p_endpt );\r
+\r
+\r
+#endif /* _IPOIB_ENDPOINT_H_ */\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+#include "ipoib_driver.h"\r
+#include "ipoib_adapter.h"\r
+#include "ipoib_port.h"\r
+#include "ipoib_debug.h"\r
+#if defined(EVENT_TRACING)\r
+#ifdef offsetof\r
+#undef offsetof\r
+#endif\r
+#include "ipoib_ibat.tmh"\r
+#endif\r
+#include <iba/ib_at_ioctl.h>\r
+\r
+\r
+static NTSTATUS\r
+__ipoib_create(\r
+ IN DEVICE_OBJECT* const pDevObj,\r
+ IN IRP* const pIrp );\r
+\r
+static NTSTATUS\r
+__ipoib_cleanup(\r
+ IN DEVICE_OBJECT* const pDevObj,\r
+ IN IRP* const pIrp );\r
+\r
+static NTSTATUS\r
+__ipoib_close(\r
+ IN DEVICE_OBJECT* const pDevObj,\r
+ IN IRP* const pIrp );\r
+\r
+static NTSTATUS\r
+__ipoib_dispatch(\r
+ IN DEVICE_OBJECT* const pDevObj,\r
+ IN IRP* const pIrp );\r
+\r
+\r
+static NTSTATUS\r
+__ibat_get_ports(\r
+ IN IRP *pIrp,\r
+ IN IO_STACK_LOCATION *pIoStack )\r
+{\r
+ IOCTL_IBAT_PORTS_IN *pIn;\r
+ IOCTL_IBAT_PORTS_OUT *pOut;\r
+ KLOCK_QUEUE_HANDLE hdl;\r
+ cl_list_item_t *pItem;\r
+ ipoib_adapter_t *pAdapter;\r
+ LONG nPorts;\r
+\r
+ IPOIB_ENTER(IPOIB_DBG_IOCTL);\r
+\r
+ if( pIoStack->Parameters.DeviceIoControl.InputBufferLength !=\r
+ sizeof(IOCTL_IBAT_PORTS_IN) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid input buffer size.\n") );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+ \r
+ if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength <\r
+ sizeof(IOCTL_IBAT_PORTS_OUT) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid output buffer size.\n") );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ pIn = pIrp->AssociatedIrp.SystemBuffer;\r
+ pOut = pIrp->AssociatedIrp.SystemBuffer;\r
+\r
+ if( pIn->Version != IBAT_IOCTL_VERSION )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid version.\n") );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl );\r
+ nPorts = (LONG)cl_qlist_count( &g_ipoib.adapter_list );\r
+ switch( nPorts )\r
+ {\r
+ case 0:\r
+ cl_memclr( pOut->Ports, sizeof(pOut->Ports) );\r
+ /* Fall through */\r
+ case 1:\r
+ pOut->Size = sizeof(IOCTL_IBAT_PORTS_OUT);\r
+ break;\r
+\r
+ default:\r
+ pOut->Size = sizeof(IOCTL_IBAT_PORTS_OUT) + \r
+ (sizeof(IBAT_PORT_RECORD) * (nPorts - 1));\r
+ break;\r
+ }\r
+\r
+ pIrp->IoStatus.Information = pOut->Size;\r
+\r
+ if( pOut->Size > pIoStack->Parameters.DeviceIoControl.OutputBufferLength )\r
+ {\r
+ nPorts = 1 +\r
+ (pIoStack->Parameters.DeviceIoControl.OutputBufferLength -\r
+ sizeof(IOCTL_IBAT_PORTS_OUT)) / sizeof(IBAT_PORT_RECORD);\r
+\r
+ pIrp->IoStatus.Information = sizeof(IOCTL_IBAT_PORTS_OUT) +\r
+ ((nPorts - 1) * sizeof(IBAT_PORT_RECORD));\r
+ }\r
+\r
+ pOut->NumPorts = 0;\r
+ pItem = cl_qlist_head( &g_ipoib.adapter_list );\r
+ while( pOut->NumPorts != nPorts )\r
+ {\r
+ pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry );\r
+ pOut->Ports[pOut->NumPorts].CaGuid = pAdapter->guids.ca_guid;\r
+ pOut->Ports[pOut->NumPorts].PortGuid = pAdapter->guids.port_guid;\r
+ pOut->Ports[pOut->NumPorts].PortNum = pAdapter->guids.port_num;\r
+ pOut->NumPorts++;\r
+\r
+ pItem = cl_qlist_next( pItem );\r
+ }\r
+\r
+ KeReleaseInStackQueuedSpinLock( &hdl );\r
+ IPOIB_EXIT( IPOIB_DBG_IOCTL );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+__ibat_get_ips(\r
+ IN IRP *pIrp,\r
+ IN IO_STACK_LOCATION *pIoStack )\r
+{\r
+ IOCTL_IBAT_IP_ADDRESSES_IN *pIn;\r
+ IOCTL_IBAT_IP_ADDRESSES_OUT *pOut;\r
+ KLOCK_QUEUE_HANDLE hdl;\r
+ cl_list_item_t *pItem;\r
+ ipoib_adapter_t *pAdapter;\r
+ LONG nIps, maxIps;\r
+ size_t idx;\r
+ net_address_item_t *pAddr;\r
+ UINT64 PortGuid;\r
+\r
+ IPOIB_ENTER(IPOIB_DBG_IOCTL);\r
+\r
+ if( pIoStack->Parameters.DeviceIoControl.InputBufferLength !=\r
+ sizeof(IOCTL_IBAT_IP_ADDRESSES_IN) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid input buffer size.\n") );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+ \r
+ if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength <\r
+ sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid output buffer size.\n") );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ pIn = pIrp->AssociatedIrp.SystemBuffer;\r
+ pOut = pIrp->AssociatedIrp.SystemBuffer;\r
+\r
+ if( pIn->Version != IBAT_IOCTL_VERSION )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid version.\n") );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ PortGuid = pIn->PortGuid;\r
+\r
+ nIps = 0;\r
+ pOut->AddressCount = 0;\r
+ maxIps = 1 +\r
+ ((pIoStack->Parameters.DeviceIoControl.OutputBufferLength -\r
+ sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT)) / sizeof(IP_ADDRESS));\r
+\r
+ KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl );\r
+ for( pItem = cl_qlist_head( &g_ipoib.adapter_list );\r
+ pItem != cl_qlist_end( &g_ipoib.adapter_list );\r
+ pItem = cl_qlist_next( pItem ) )\r
+ {\r
+ pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry );\r
+ if( PortGuid && pAdapter->guids.port_guid != PortGuid )\r
+ continue;\r
+\r
+ cl_obj_lock( &pAdapter->obj );\r
+ nIps += (LONG)cl_vector_get_size( &pAdapter->ip_vector );\r
+\r
+ for( idx = 0;\r
+ idx < cl_vector_get_size( &pAdapter->ip_vector );\r
+ idx++ )\r
+ {\r
+ if( pOut->AddressCount == maxIps )\r
+ break;\r
+\r
+ pAddr = (net_address_item_t*)\r
+ cl_vector_get_ptr( &pAdapter->ip_vector, idx );\r
+\r
+ pOut->Address[pOut->AddressCount].IpVersion = 4;\r
+ cl_memclr( &pOut->Address[pOut->AddressCount].Address,\r
+ sizeof(IP_ADDRESS) );\r
+ cl_memcpy( &pOut->Address[pOut->AddressCount].Address[12],\r
+ pAddr->address.as_bytes, IPV4_ADDR_SIZE );\r
+\r
+ pOut->AddressCount++;\r
+ }\r
+ cl_obj_unlock( &pAdapter->obj );\r
+ }\r
+\r
+ pOut->Size = sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT);\r
+ if( --nIps )\r
+ pOut->Size += sizeof(IP_ADDRESS) * nIps;\r
+\r
+ pIrp->IoStatus.Information = sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT);\r
+ if( --maxIps < nIps )\r
+ pIrp->IoStatus.Information += (sizeof(IP_ADDRESS) * maxIps);\r
+ else\r
+ pIrp->IoStatus.Information += (sizeof(IP_ADDRESS) * nIps);\r
+\r
+ KeReleaseInStackQueuedSpinLock( &hdl );\r
+ IPOIB_EXIT( IPOIB_DBG_IOCTL );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+__ibat_mac_to_gid(\r
+ IN IRP *pIrp,\r
+ IN IO_STACK_LOCATION *pIoStack )\r
+{\r
+ NTSTATUS status = STATUS_INVALID_PARAMETER;\r
+ IOCTL_IBAT_MAC_TO_GID_IN *pIn;\r
+ IOCTL_IBAT_MAC_TO_GID_OUT *pOut;\r
+ KLOCK_QUEUE_HANDLE hdl;\r
+ cl_list_item_t *pItem;\r
+ ipoib_adapter_t *pAdapter;\r
+\r
+ IPOIB_ENTER(IPOIB_DBG_IOCTL);\r
+\r
+ if( pIoStack->Parameters.DeviceIoControl.InputBufferLength !=\r
+ sizeof(IOCTL_IBAT_MAC_TO_GID_IN) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid input buffer size.\n") );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+ \r
+ if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength !=\r
+ sizeof(IOCTL_IBAT_MAC_TO_GID_OUT) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid output buffer size.\n") );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ pIn = pIrp->AssociatedIrp.SystemBuffer;\r
+ pOut = pIrp->AssociatedIrp.SystemBuffer;\r
+\r
+ if( pIn->Version != IBAT_IOCTL_VERSION )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid version.\n") );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl );\r
+\r
+ for( pItem = cl_qlist_head( &g_ipoib.adapter_list );\r
+ pItem != cl_qlist_end( &g_ipoib.adapter_list );\r
+ pItem = cl_qlist_next( pItem ) )\r
+ {\r
+ pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry );\r
+ if( pIn->PortGuid != pAdapter->guids.port_guid )\r
+ continue;\r
+\r
+ /* Found the port - lookup the MAC. */\r
+ cl_obj_lock( &pAdapter->obj );\r
+ if( pAdapter->p_port )\r
+ {\r
+ status = ipoib_mac_to_gid(\r
+ pAdapter->p_port, *(mac_addr_t*)pIn->DestMac, &pOut->DestGid );\r
+ if( NT_SUCCESS( status ) )\r
+ {\r
+ pIrp->IoStatus.Information =\r
+ sizeof(IOCTL_IBAT_MAC_TO_GID_OUT);\r
+ }\r
+ }\r
+ cl_obj_unlock( &pAdapter->obj );\r
+ break;\r
+ }\r
+\r
+ KeReleaseInStackQueuedSpinLock( &hdl );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_IOCTL );\r
+ return status;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+__ibat_ip_to_port(\r
+ IN IRP *pIrp,\r
+ IN IO_STACK_LOCATION *pIoStack )\r
+{\r
+ IOCTL_IBAT_IP_TO_PORT_IN *pIn;\r
+ IOCTL_IBAT_IP_TO_PORT_OUT *pOut;\r
+ KLOCK_QUEUE_HANDLE hdl;\r
+ cl_list_item_t *pItem;\r
+ ipoib_adapter_t *pAdapter;\r
+ size_t idx;\r
+ net_address_item_t *pAddr;\r
+ NTSTATUS status = STATUS_NOT_FOUND;\r
+\r
+ IPOIB_ENTER(IPOIB_DBG_IOCTL);\r
+\r
+ if( pIoStack->Parameters.DeviceIoControl.InputBufferLength !=\r
+ sizeof(IOCTL_IBAT_IP_TO_PORT_IN) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid input buffer size.\n") );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+ \r
+ if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength !=\r
+ sizeof(IOCTL_IBAT_IP_TO_PORT_OUT) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid output buffer size.\n") );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ pIn = pIrp->AssociatedIrp.SystemBuffer;\r
+ pOut = pIrp->AssociatedIrp.SystemBuffer;\r
+\r
+ if( pIn->Version != IBAT_IOCTL_VERSION )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid version.\n") );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (pIn->Address.IpVersion != 4)\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid IP version (%d). Supported only 4\n", pIn->Address.IpVersion) );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl );\r
+ for( pItem = cl_qlist_head( &g_ipoib.adapter_list );\r
+ pItem != cl_qlist_end( &g_ipoib.adapter_list );\r
+ pItem = cl_qlist_next( pItem ) )\r
+ {\r
+ pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry );\r
+\r
+ cl_obj_lock( &pAdapter->obj );\r
+\r
+ for( idx = 0;\r
+ idx < cl_vector_get_size( &pAdapter->ip_vector );\r
+ idx++ )\r
+ {\r
+ pAddr = (net_address_item_t*)\r
+ cl_vector_get_ptr( &pAdapter->ip_vector, idx );\r
+\r
+ if (!memcmp( &pIn->Address.Address[12], pAddr->address.as_bytes, IPV4_ADDR_SIZE))\r
+ {\r
+ pOut->Port.CaGuid = pAdapter->guids.ca_guid;\r
+ pOut->Port.PortGuid = pAdapter->guids.port_guid;\r
+ pOut->Port.PortNum = pAdapter->guids.port_num;\r
+ pIrp->IoStatus.Information = sizeof(IOCTL_IBAT_IP_TO_PORT_OUT);\r
+ status = STATUS_SUCCESS;\r
+ break;\r
+ }\r
+ }\r
+ cl_obj_unlock( &pAdapter->obj );\r
+ if (status == STATUS_SUCCESS)\r
+ break;\r
+ }\r
+\r
+ KeReleaseInStackQueuedSpinLock( &hdl );\r
+ IPOIB_EXIT( IPOIB_DBG_IOCTL );\r
+ return status;\r
+}\r
+\r
+void\r
+ipoib_ref_ibat()\r
+{\r
+ NDIS_STATUS status;\r
+ NDIS_STRING DeviceName;\r
+ NDIS_STRING DeviceLinkUnicodeString;\r
+ PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];\r
+ DEVICE_OBJECT *p_dev_obj;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_IOCTL );\r
+\r
+ if( InterlockedIncrement( &g_ipoib.ibat_ref ) == 1 )\r
+ {\r
+ NdisInitUnicodeString( &DeviceName, IBAT_DEV_NAME );\r
+ NdisInitUnicodeString( &DeviceLinkUnicodeString, IBAT_DOS_DEV_NAME );\r
+\r
+ NdisZeroMemory( DispatchTable, sizeof(DispatchTable) );\r
+\r
+ DispatchTable[IRP_MJ_CREATE] = __ipoib_create;\r
+ DispatchTable[IRP_MJ_CLEANUP] = __ipoib_cleanup;\r
+ DispatchTable[IRP_MJ_CLOSE] = __ipoib_close;\r
+ DispatchTable[IRP_MJ_DEVICE_CONTROL] = __ipoib_dispatch;\r
+ DispatchTable[IRP_MJ_INTERNAL_DEVICE_CONTROL] = __ipoib_dispatch;\r
+\r
+ status = NdisMRegisterDevice( g_ipoib.h_ndis_wrapper,\r
+ &DeviceName, &DeviceLinkUnicodeString, &DispatchTable[0],\r
+ &p_dev_obj, &g_ipoib.h_ibat_dev );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, \r
+ ("NdisMRegisterDevice failed with status of %d\n", status) );\r
+ }\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_IOCTL );\r
+}\r
+\r
+\r
+void\r
+ipoib_deref_ibat()\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_IOCTL );\r
+\r
+ if( InterlockedDecrement( &g_ipoib.ibat_ref ) )\r
+ {\r
+ IPOIB_EXIT( IPOIB_DBG_IOCTL );\r
+ return;\r
+ }\r
+\r
+ if( g_ipoib.h_ibat_dev )\r
+ {\r
+ NdisMDeregisterDevice( g_ipoib.h_ibat_dev );\r
+ g_ipoib.h_ibat_dev = NULL;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_IOCTL );\r
+}\r
+\r
+\r
+static NTSTATUS\r
+__ipoib_create(\r
+ IN DEVICE_OBJECT* const pDevObj,\r
+ IN IRP* const pIrp )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_IOCTL );\r
+\r
+ UNREFERENCED_PARAMETER( pDevObj );\r
+\r
+ ipoib_ref_ibat();\r
+\r
+ pIrp->IoStatus.Status = STATUS_SUCCESS;\r
+ pIrp->IoStatus.Information = 0;\r
+ IoCompleteRequest( pIrp, IO_NO_INCREMENT );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_IOCTL );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+__ipoib_cleanup(\r
+ IN DEVICE_OBJECT* const pDevObj,\r
+ IN IRP* const pIrp )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_IOCTL );\r
+\r
+ UNREFERENCED_PARAMETER( pDevObj );\r
+\r
+ ipoib_deref_ibat();\r
+\r
+ pIrp->IoStatus.Status = STATUS_SUCCESS;\r
+ pIrp->IoStatus.Information = 0;\r
+ IoCompleteRequest( pIrp, IO_NO_INCREMENT );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_IOCTL );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+__ipoib_close(\r
+ IN DEVICE_OBJECT* const pDevObj,\r
+ IN IRP* const pIrp )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_IOCTL );\r
+\r
+ UNREFERENCED_PARAMETER( pDevObj );\r
+\r
+ pIrp->IoStatus.Status = STATUS_SUCCESS;\r
+ pIrp->IoStatus.Information = 0;\r
+ IoCompleteRequest( pIrp, IO_NO_INCREMENT );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_IOCTL );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+__ipoib_dispatch(\r
+ IN DEVICE_OBJECT* const pDevObj,\r
+ IN IRP* const pIrp )\r
+{\r
+ IO_STACK_LOCATION *pIoStack;\r
+ NTSTATUS status = STATUS_SUCCESS;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_IOCTL );\r
+\r
+ UNREFERENCED_PARAMETER( pDevObj );\r
+\r
+ pIoStack = IoGetCurrentIrpStackLocation( pIrp );\r
+\r
+ pIrp->IoStatus.Information = 0;\r
+\r
+ switch( pIoStack->Parameters.DeviceIoControl.IoControlCode )\r
+ {\r
+ case IOCTL_IBAT_PORTS:\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL,\r
+ ("IOCTL_IBAT_PORTS received\n") );\r
+ status = __ibat_get_ports( pIrp, pIoStack );\r
+ break;\r
+\r
+ case IOCTL_IBAT_IP_ADDRESSES:\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL,\r
+ ("IOCTL_IBAT_IP_ADDRESSES received\n" ));\r
+ status = __ibat_get_ips( pIrp, pIoStack );\r
+ break;\r
+\r
+ case IOCTL_IBAT_MAC_TO_GID:\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL,\r
+ ("IOCTL_IBAT_MAC_TO_GID received\n" ));\r
+ status = __ibat_mac_to_gid( pIrp, pIoStack );\r
+ break;\r
+\r
+ case IOCTL_IBAT_IP_TO_PORT:\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL,\r
+ ("IOCTL_IBAT_IP_TO_PORT received\n" ));\r
+ status = __ibat_ip_to_port( pIrp, pIoStack );\r
+ break;\r
+\r
+ default:\r
+ IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_IOCTL,\r
+ ("unknow IOCTL code = 0x%x\n",\r
+ pIoStack->Parameters.DeviceIoControl.IoControlCode) );\r
+ status = STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ pIrp->IoStatus.Status = status;\r
+ IoCompleteRequest( pIrp, IO_NO_INCREMENT );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_IOCTL );\r
+ return status;\r
+}\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+#ifndef _IPOIB_IBAT_H_\r
+#define _IPOIB_IBAT_H_\r
+\r
+\r
+void\r
+ipoib_ref_ibat();\r
+\r
+void\r
+ipoib_deref_ibat();\r
+\r
+\r
+#endif /* _IPOIB_IBAT_H_ */\r
--- /dev/null
+;/*++\r
+;=============================================================================\r
+;Copyright (c) 2001 Mellanox Technologies\r
+;\r
+;Module Name:\r
+;\r
+; ipoiblog.mc\r
+;\r
+;Abstract:\r
+;\r
+; IPoIB Driver event log messages\r
+;\r
+;Authors:\r
+;\r
+; Yossi Leybovich\r
+;\r
+;Environment:\r
+;\r
+; Kernel Mode .\r
+;\r
+;=============================================================================\r
+;--*/\r
+;\r
+MessageIdTypedef = NDIS_ERROR_CODE\r
+\r
+SeverityNames = (\r
+ Success = 0x0:STATUS_SEVERITY_SUCCESS\r
+ Informational = 0x1:STATUS_SEVERITY_INFORMATIONAL\r
+ Warning = 0x2:STATUS_SEVERITY_WARNING\r
+ Error = 0x3:STATUS_SEVERITY_ERROR\r
+ )\r
+\r
+FacilityNames = (\r
+ System = 0x0\r
+ RpcRuntime = 0x2:FACILITY_RPC_RUNTIME\r
+ RpcStubs = 0x3:FACILITY_RPC_STUBS\r
+ Io = 0x4:FACILITY_IO_ERROR_CODE\r
+ IPoIB = 0x7:FACILITY_IPOIB_ERROR_CODE\r
+ )\r
+\r
+\r
+MessageId=0x0001\r
+Facility=IPoIB\r
+Severity=Warning\r
+SymbolicName=EVENT_IPOIB_PORT_DOWN\r
+Language=English\r
+%2: Network controller link is down.\r
+.\r
+\r
+MessageId=0x0002\r
+Facility=IPoIB\r
+Severity=Informational\r
+SymbolicName=EVENT_IPOIB_PORT_UP\r
+Language=English\r
+%2: Network controller link is up.\r
+.\r
+\r
+\r
+MessageId=0x0003\r
+Facility=IPoIB\r
+Severity=Informational\r
+SymbolicName=EVENT_IPOIB_PORT_UP1\r
+Language=English\r
+%2: Network controller link is up at 2.5Gbps.\r
+.\r
+\r
+MessageId=0x0004\r
+Facility=IPoIB\r
+Severity=Informational\r
+SymbolicName=EVENT_IPOIB_PORT_UP2\r
+Language=English\r
+%2: Network controller link is up at 5Gbps.\r
+.\r
+\r
+MessageId=0x0006\r
+Facility=IPoIB\r
+Severity=Informational\r
+SymbolicName=EVENT_IPOIB_PORT_UP3\r
+Language=English\r
+%2: Network controller link is up at 10Gbps.\r
+.\r
+\r
+MessageId=0x000a\r
+Facility=IPoIB\r
+Severity=Informational\r
+SymbolicName=EVENT_IPOIB_PORT_UP4\r
+Language=English\r
+%2: Network controller link is up at 20Gps.\r
+.\r
+\r
+MessageId=0x000e\r
+Facility=IPoIB\r
+Severity=Informational\r
+SymbolicName=EVENT_IPOIB_PORT_UP5\r
+Language=English\r
+%2: Network controller link is up at 30Gps.\r
+.\r
+\r
+MessageId=0x0012\r
+Facility=IPoIB\r
+Severity=Informational\r
+SymbolicName=EVENT_IPOIB_PORT_UP6\r
+Language=English\r
+%2: Network controller link is up at 40Gps.\r
+.\r
+\r
+MessageId=0x001a\r
+Facility=IPoIB\r
+Severity=Informational\r
+SymbolicName=EVENT_IPOIB_PORT_UP7\r
+Language=English\r
+%2: Network controller link is up at 60Gps.\r
+.\r
+\r
+MessageId=0x0032\r
+Facility=IPoIB\r
+Severity=Informational\r
+SymbolicName=EVENT_IPOIB_PORT_UP8\r
+Language=English\r
+%2: Network controller link is up at 120Gps.\r
+.\r
+\r
+MessageId=0x0040\r
+Facility=IPoIB\r
+Severity=Informational\r
+SymbolicName=EVENT_IPOIB_INIT_SUCCESS\r
+Language=English\r
+%2: Driver Initialized succesfully.\r
+.\r
+\r
+MessageId=0x0041\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_OPEN_CA\r
+Language=English\r
+%2: Failed to open Channel Adapter.\r
+.\r
+\r
+MessageId=0x0042\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_ALLOC_PD\r
+Language=English\r
+%2: Failed to allocate Protection Domain.\r
+.\r
+\r
+MessageId=0x0043\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_CREATE_RECV_CQ\r
+Language=English\r
+%2: Failed to create receive Completion Queue.\r
+.\r
+\r
+MessageId=0x0044\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_CREATE_SEND_CQ\r
+Language=English\r
+%2: Failed to create send Completion Queue.\r
+.\r
+\r
+MessageId=0x0045\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_CREATE_QP\r
+Language=English\r
+%2: Failed to create Queue Pair.\r
+.\r
+\r
+MessageId=0x0046\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_QUERY_QP\r
+Language=English\r
+%2: Failed to get Queue Pair number.\r
+.\r
+\r
+MessageId=0x0047\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_REG_PHYS\r
+Language=English\r
+%2: Failed to create DMA Memory Region.\r
+.\r
+\r
+MessageId=0x0048\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_RECV_POOL\r
+Language=English\r
+%2: Failed to create receive descriptor pool.\r
+.\r
+\r
+MessageId=0x0049\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_RECV_PKT_POOL\r
+Language=English\r
+%2: Failed to create NDIS_PACKET pool for receive indications.\r
+.\r
+\r
+MessageId=0x004A\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_RECV_BUF_POOL\r
+Language=English\r
+%2: Failed to create NDIS_BUFFER pool for receive indications.\r
+.\r
+\r
+MessageId=0x004B\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_SEND_PKT_POOL\r
+Language=English\r
+%2: Failed to create NDIS_PACKET pool for send processing.\r
+.\r
+\r
+MessageId=0x004C\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_SEND_BUF_POOL\r
+Language=English\r
+%2: Failed to create NDIS_BUFFER pool for send processing.\r
+.\r
+\r
+MessageId=0x004D\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_RECV_PKT_ARRAY\r
+Language=English\r
+%2: Failed to allocate receive indication array.\r
+.\r
+\r
+MessageId=0x004E\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_PORT_INFO_TIMEOUT\r
+Language=English\r
+%2: Subnet Administrator query for port information timed out. \r
+Make sure the SA is functioning properly. Increasing the number\r
+of retries and retry timeout adapter parameters may solve the\r
+issue.\r
+.\r
+\r
+MessageId=0x004F\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_PORT_INFO_REJECT\r
+Language=English\r
+%2: Subnet Administrator failed the query for port information.\r
+Make sure the SA is functioning properly and compatible.\r
+.\r
+\r
+MessageId=0x0050\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_QUERY_PORT_INFO\r
+Language=English\r
+%2: Subnet Administrator query for port information failed.\r
+.\r
+\r
+MessageId=0x0055\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_BCAST_GET\r
+Language=English\r
+%2: Subnet Administrator failed query for broadcast group information.\r
+.\r
+\r
+MessageId=0x0056\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_BCAST_JOIN\r
+Language=English\r
+%2: Subnet Administrator failed request to joing broadcast group.\r
+.\r
+\r
+MessageId=0x0057\r
+Facility=IPoIB\r
+Severity=Error\r
+SymbolicName=EVENT_IPOIB_BCAST_RATE\r
+Language=English\r
+%2: The local port rate is too slow for the existing broadcast MC group.\r
+.\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ * Copyright (c) 2006 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+\r
+#include "ipoib_port.h"\r
+#include "ipoib_adapter.h"\r
+#include "ipoib_debug.h"\r
+#if defined(EVENT_TRACING)\r
+#ifdef offsetof\r
+#undef offsetof\r
+#endif\r
+#include "ipoib_port.tmh"\r
+#endif\r
+\r
+\r
+/* Amount of physical memory to register. */\r
+#define MEM_REG_SIZE 0xFFFFFFFFFFFFFFFF\r
+\r
+/* Number of work completions to chain for send and receive polling. */\r
+#define MAX_SEND_WC 8\r
+#define MAX_RECV_WC 16\r
+\r
+\r
+ib_gid_t bcast_mgid_template = {\r
+ 0xff, /* multicast field */\r
+ 0x12, /* scope (to be filled in) */\r
+ 0x40, 0x1b, /* IPv4 signature */\r
+ 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */\r
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */\r
+ 0xff, 0xff, 0xff, 0xff, /* 32 bit IPv4 broadcast address */\r
+};\r
+\r
+\r
+#ifdef _DEBUG_\r
+/* Handy pointer for debug use. */\r
+ipoib_port_t *gp_ipoib_port;\r
+#endif\r
+\r
+\r
+/******************************************************************************\r
+*\r
+* Declarations\r
+*\r
+******************************************************************************/\r
+static void\r
+__port_construct(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static ib_api_status_t\r
+__port_init(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN ib_pnp_port_rec_t* const p_pnp_rec );\r
+\r
+static void\r
+__port_destroying(\r
+ IN cl_obj_t* const p_obj );\r
+\r
+static void\r
+__port_cleanup(\r
+ IN cl_obj_t* const p_obj );\r
+\r
+static void\r
+__port_free(\r
+ IN cl_obj_t* const p_obj );\r
+\r
+\r
+/******************************************************************************\r
+*\r
+* IB resource manager operations\r
+*\r
+******************************************************************************/\r
+static void\r
+__ib_mgr_construct(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static ib_api_status_t\r
+__ib_mgr_init(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static void\r
+__ib_mgr_destroy(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static void\r
+__qp_event(\r
+ IN ib_async_event_rec_t *p_event_rec );\r
+\r
+static void\r
+__cq_event(\r
+ IN ib_async_event_rec_t *p_event_rec );\r
+\r
+static ib_api_status_t\r
+__ib_mgr_activate(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+/******************************************************************************\r
+*\r
+* Buffer manager operations.\r
+*\r
+******************************************************************************/\r
+static void\r
+__buf_mgr_construct(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static ib_api_status_t\r
+__buf_mgr_init(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static void\r
+__buf_mgr_destroy(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static cl_status_t\r
+__recv_ctor(\r
+ IN void* const p_object,\r
+ IN void* context,\r
+ OUT cl_pool_item_t** const pp_pool_item );\r
+\r
+#if !IPOIB_INLINE_RECV\r
+static void\r
+__recv_dtor(\r
+ IN const cl_pool_item_t* const p_pool_item,\r
+ IN void *context );\r
+#endif /* IPOIB_INLINE_RECV */\r
+\r
+static inline ipoib_send_desc_t*\r
+__buf_mgr_get_send(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static inline void\r
+__buf_mgr_put_send(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_send_desc_t* const p_desc );\r
+\r
+static inline ipoib_recv_desc_t*\r
+__buf_mgr_get_recv(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static inline void\r
+__buf_mgr_put_recv(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_recv_desc_t* const p_desc,\r
+ IN NDIS_PACKET* const p_packet OPTIONAL );\r
+\r
+static inline void\r
+__buf_mgr_put_recv_list(\r
+ IN ipoib_port_t* const p_port,\r
+ IN cl_qlist_t* const p_list );\r
+\r
+static inline NDIS_PACKET*\r
+__buf_mgr_get_ndis_pkt(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_recv_desc_t* const p_desc );\r
+\r
+\r
+/******************************************************************************\r
+*\r
+* Receive manager operations.\r
+*\r
+******************************************************************************/\r
+static void\r
+__recv_mgr_construct(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static ib_api_status_t\r
+__recv_mgr_init(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static void\r
+__recv_mgr_destroy(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+/* Posts receive buffers to the receive queue. */\r
+static ib_api_status_t\r
+__recv_mgr_repost(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static void\r
+__recv_cb(\r
+ IN const ib_cq_handle_t h_cq,\r
+ IN void *cq_context );\r
+\r
+static void\r
+__recv_get_endpts(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_recv_desc_t* const p_desc,\r
+ IN ib_wc_t* const p_wc,\r
+ OUT ipoib_endpt_t** const pp_src,\r
+ OUT ipoib_endpt_t** const pp_dst );\r
+\r
+static int32_t\r
+__recv_mgr_filter(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ib_wc_t* const p_done_wc_list,\r
+ OUT cl_qlist_t* const p_done_list,\r
+ OUT cl_qlist_t* const p_bad_list );\r
+\r
+static ib_api_status_t\r
+__recv_gen(\r
+ IN const ipoib_pkt_t* const p_ipoib,\r
+ OUT eth_pkt_t* const p_eth,\r
+ IN ipoib_endpt_t* const p_src,\r
+ IN ipoib_endpt_t* const p_dst );\r
+\r
+static ib_api_status_t\r
+__recv_dhcp(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const ipoib_pkt_t* const p_ipoib,\r
+ OUT eth_pkt_t* const p_eth,\r
+ IN ipoib_endpt_t* const p_src,\r
+ IN ipoib_endpt_t* const p_dst );\r
+\r
+static ib_api_status_t\r
+__recv_arp(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ib_wc_t* const p_wc,\r
+ IN const ipoib_pkt_t* const p_ipoib,\r
+ OUT eth_pkt_t* const p_eth,\r
+ IN ipoib_endpt_t** const p_src,\r
+ IN ipoib_endpt_t* const p_dst );\r
+\r
+static ib_api_status_t\r
+__recv_mgr_prepare_pkt(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_recv_desc_t* const p_desc,\r
+ OUT NDIS_PACKET** const pp_packet );\r
+\r
+static uint32_t\r
+__recv_mgr_build_pkt_array(\r
+ IN ipoib_port_t* const p_port,\r
+ IN int32_t shortage,\r
+ OUT cl_qlist_t* const p_done_list,\r
+ OUT int32_t* const p_discarded );\r
+\r
+/******************************************************************************\r
+*\r
+* Send manager operations.\r
+*\r
+******************************************************************************/\r
+static void\r
+__send_mgr_construct(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static void\r
+__send_mgr_destroy(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static NDIS_STATUS\r
+__send_gen(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_send_desc_t* const p_desc );\r
+\r
+static NDIS_STATUS\r
+__send_mgr_filter_ip(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const eth_hdr_t* const p_eth_hdr,\r
+ IN NDIS_BUFFER* p_buf,\r
+ IN size_t buf_len,\r
+ IN OUT ipoib_send_desc_t* const p_desc );\r
+\r
+static NDIS_STATUS\r
+__send_mgr_filter_udp(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const ip_hdr_t* const p_ip_hdr,\r
+ IN NDIS_BUFFER* p_buf,\r
+ IN size_t buf_len,\r
+ IN OUT ipoib_send_desc_t* const p_desc );\r
+\r
+static NDIS_STATUS\r
+__send_mgr_filter_dhcp(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const udp_hdr_t* const p_udp_hdr,\r
+ IN NDIS_BUFFER* p_buf,\r
+ IN size_t buf_len,\r
+ IN OUT ipoib_send_desc_t* const p_desc );\r
+\r
+static NDIS_STATUS\r
+__send_mgr_filter_arp(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const eth_hdr_t* const p_eth_hdr,\r
+ IN NDIS_BUFFER* p_buf,\r
+ IN size_t buf_len,\r
+ IN OUT ipoib_send_desc_t* const p_desc );\r
+\r
+static void\r
+__process_failed_send(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_send_desc_t* const p_desc,\r
+ IN const NDIS_STATUS status );\r
+\r
+static void\r
+__send_cb(\r
+ IN const ib_cq_handle_t h_cq,\r
+ IN void *cq_context );\r
+\r
+\r
+/******************************************************************************\r
+*\r
+* Endpoint manager operations\r
+*\r
+******************************************************************************/\r
+static void\r
+__endpt_mgr_construct(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static ib_api_status_t\r
+__endpt_mgr_init(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static void\r
+__endpt_mgr_destroy(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+/****f* IPoIB/__endpt_mgr_remove_all\r
+* NAME\r
+* __endpt_mgr_remove_all\r
+*\r
+* DESCRIPTION\r
+* Removes all enpoints from the port, dereferencing them to initiate\r
+* destruction.\r
+*\r
+* SYNOPSIS\r
+*/\r
+static void\r
+__endpt_mgr_remove_all(\r
+ IN ipoib_port_t* const p_port );\r
+/*\r
+********/\r
+\r
+static void\r
+__endpt_mgr_remove(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_endpt_t* const p_endpt );\r
+\r
+static void\r
+__endpt_mgr_reset_all(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static inline NDIS_STATUS\r
+__endpt_mgr_ref(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac,\r
+ OUT ipoib_endpt_t** const pp_endpt );\r
+\r
+static inline NDIS_STATUS\r
+__endpt_mgr_get_gid_qpn(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac,\r
+ OUT ib_gid_t* const p_gid,\r
+ OUT UNALIGNED net32_t* const p_qpn );\r
+\r
+static inline ipoib_endpt_t*\r
+__endpt_mgr_get_by_gid(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const ib_gid_t* const p_gid );\r
+\r
+static inline ipoib_endpt_t*\r
+__endpt_mgr_get_by_lid(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const net16_t lid );\r
+\r
+static inline ib_api_status_t\r
+__endpt_mgr_insert_locked(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac,\r
+ IN ipoib_endpt_t* const p_endpt );\r
+\r
+static inline ib_api_status_t\r
+__endpt_mgr_insert(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac,\r
+ IN ipoib_endpt_t* const p_endpt );\r
+\r
+static ib_api_status_t\r
+__endpt_mgr_add_local(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ib_port_info_t* const p_port_info );\r
+\r
+static ib_api_status_t\r
+__endpt_mgr_add_bcast(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ib_mcast_rec_t *p_mcast_rec );\r
+\r
+/******************************************************************************\r
+*\r
+* MCast operations.\r
+*\r
+******************************************************************************/\r
+static ib_api_status_t\r
+__port_get_bcast(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static ib_api_status_t\r
+__port_join_bcast(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ib_member_rec_t* const p_member_rec );\r
+\r
+static ib_api_status_t\r
+__port_create_bcast(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+static void\r
+__port_info_cb(\r
+ IN ib_query_rec_t *p_query_rec );\r
+\r
+\r
+static void\r
+__bcast_get_cb(\r
+ IN ib_query_rec_t *p_query_rec );\r
+\r
+\r
+static void\r
+__bcast_cb(\r
+ IN ib_mcast_rec_t *p_mcast_rec );\r
+\r
+\r
+static void\r
+__mcast_cb(\r
+ IN ib_mcast_rec_t *p_mcast_rec );\r
+\r
+void\r
+__leave_error_mcast_cb(\r
+ IN void *context );\r
+\r
+\r
+static intn_t\r
+__gid_cmp(\r
+ IN const void* const p_key1,\r
+ IN const void* const p_key2 )\r
+{\r
+ return cl_memcmp( p_key1, p_key2, sizeof(ib_gid_t) );\r
+}\r
+\r
+\r
+inline void ipoib_port_ref( ipoib_port_t * p_port, int type )\r
+{\r
+ cl_obj_ref( &p_port->obj );\r
+#if DBG\r
+ cl_atomic_inc( &p_port->ref[type % ref_mask] );\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,\r
+ ("ref type %d ref_cnt %d\n", type, p_port->obj.ref_cnt) );\r
+#else\r
+ UNREFERENCED_PARAMETER(type);\r
+#endif\r
+}\r
+\r
+\r
+inline void ipoib_port_deref(ipoib_port_t * p_port, int type)\r
+{\r
+ cl_obj_deref( &p_port->obj );\r
+\r
+#if DBG\r
+ cl_atomic_dec( &p_port->ref[type % ref_mask] );\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,\r
+ ("deref type %d ref_cnt %d\n", type, p_port->obj.ref_cnt) );\r
+#else\r
+ UNREFERENCED_PARAMETER(type);\r
+#endif\r
+}\r
+\r
+\r
+/******************************************************************************\r
+*\r
+* Implementation\r
+*\r
+******************************************************************************/\r
+ib_api_status_t\r
+ipoib_create_port(\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN ib_pnp_port_rec_t* const p_pnp_rec,\r
+ OUT ipoib_port_t** const pp_port )\r
+{\r
+ ib_api_status_t status;\r
+ ipoib_port_t *p_port;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ CL_ASSERT( !p_adapter->p_port );\r
+\r
+ p_port = cl_zalloc( sizeof(ipoib_port_t) +\r
+ (sizeof(ipoib_hdr_t) * (p_adapter->params.sq_depth - 1)) );\r
+ if( !p_port )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to allocate ipoib_port_t (%d bytes)\n",\r
+ sizeof(ipoib_port_t)) );\r
+ return IB_INSUFFICIENT_MEMORY;\r
+ }\r
+\r
+#ifdef _DEBUG_\r
+ gp_ipoib_port = p_port;\r
+#endif\r
+\r
+ __port_construct( p_port );\r
+\r
+ status = __port_init( p_port, p_adapter, p_pnp_rec );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_port_init returned %s.\n", \r
+ p_adapter->p_ifc->get_err_str( status )) );\r
+ __port_cleanup( &p_port->obj );\r
+ __port_free( &p_port->obj );\r
+ return status;\r
+ }\r
+\r
+ *pp_port = p_port;\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+void\r
+ipoib_port_destroy(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ CL_ASSERT( p_port );\r
+ CL_ASSERT( p_port->p_adapter );\r
+ CL_ASSERT( !p_port->p_adapter->p_port );\r
+\r
+ cl_obj_destroy( &p_port->obj );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static void\r
+__port_construct(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ p_port->state = IB_QPS_RESET;\r
+\r
+ cl_obj_construct( &p_port->obj, IPOIB_OBJ_PORT );\r
+ cl_spinlock_construct( &p_port->send_lock );\r
+ cl_spinlock_construct( &p_port->recv_lock );\r
+ __ib_mgr_construct( p_port );\r
+ __buf_mgr_construct( p_port );\r
+\r
+ __recv_mgr_construct( p_port );\r
+ __send_mgr_construct( p_port );\r
+\r
+ __endpt_mgr_construct( p_port );\r
+\r
+ KeInitializeEvent( &p_port->sa_event, NotificationEvent, TRUE );\r
+ KeInitializeEvent( &p_port->leave_mcast_event, NotificationEvent, TRUE );\r
+ \r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__port_init(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_adapter_t* const p_adapter,\r
+ IN ib_pnp_port_rec_t* const p_pnp_rec )\r
+{\r
+ cl_status_t cl_status;\r
+ ib_api_status_t status;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ p_port->port_num = p_pnp_rec->p_port_attr->port_num;\r
+ p_port->p_adapter = p_adapter;\r
+\r
+ cl_status = cl_spinlock_init( &p_port->send_lock );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("cl_spinlock_init returned %#x\n", cl_status) );\r
+ return IB_ERROR;\r
+ }\r
+\r
+ cl_status = cl_spinlock_init( &p_port->recv_lock );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("cl_spinlock_init returned %#x\n", cl_status) );\r
+ return IB_ERROR;\r
+ }\r
+\r
+ /* Initialize the IB resource manager. */\r
+ status = __ib_mgr_init( p_port );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__ib_mgr_init returned %s\n", \r
+ p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* Initialize the buffer manager. */\r
+ status = __buf_mgr_init( p_port );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__buf_mgr_init returned %s\n", \r
+ p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* Initialize the receive manager. */\r
+ status = __recv_mgr_init( p_port );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__recv_mgr_init returned %s\n", \r
+ p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* Initialize the endpoint manager. */\r
+ status = __endpt_mgr_init( p_port );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__endpt_mgr_init returned %s\n", \r
+ p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* We only ever destroy from the PnP callback thread. */\r
+ cl_status = cl_obj_init( &p_port->obj, CL_DESTROY_SYNC,\r
+ __port_destroying, __port_cleanup, __port_free );\r
+\r
+#if DBG\r
+ cl_atomic_inc( &p_port->ref[ref_init] );\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,\r
+ ("ref type %d ref_cnt %d\n", ref_init, p_port->obj.ref_cnt) );\r
+#endif\r
+\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("cl_obj_init returned %#x\n", cl_status) );\r
+ return IB_ERROR;\r
+ }\r
+\r
+ cl_status = cl_obj_insert_rel( &p_port->rel, &p_adapter->obj, &p_port->obj );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("cl_obj_insert_rel returned %#x\n", cl_status) );\r
+ cl_obj_destroy( &p_port->obj );\r
+ return IB_ERROR;\r
+ }\r
+\r
+#if DBG\r
+ cl_atomic_inc( &p_port->ref[ref_init] );\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_OBJ,\r
+ ("ref type %d ref_cnt %d\n", ref_init, p_port->obj.ref_cnt) );\r
+#endif\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+static void\r
+__port_destroying(\r
+ IN cl_obj_t* const p_obj )\r
+{\r
+ ipoib_port_t *p_port;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ CL_ASSERT( p_obj );\r
+\r
+ p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj );\r
+\r
+ ipoib_port_down( p_port );\r
+\r
+ __endpt_mgr_remove_all( p_port );\r
+\r
+ ipoib_port_resume( p_port );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static void\r
+__port_cleanup(\r
+ IN cl_obj_t* const p_obj )\r
+{\r
+ ipoib_port_t *p_port;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ CL_ASSERT( p_obj );\r
+\r
+ p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj );\r
+\r
+ /* Wait for all sends and receives to get flushed. */\r
+ while( p_port->send_mgr.depth || p_port->recv_mgr.depth )\r
+ cl_thread_suspend( 0 );\r
+\r
+ /* Destroy the send and receive managers before closing the CA. */\r
+ __ib_mgr_destroy( p_port );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static void\r
+__port_free(\r
+ IN cl_obj_t* const p_obj )\r
+{\r
+ ipoib_port_t *p_port;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ CL_ASSERT( p_obj );\r
+\r
+ p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj );\r
+\r
+ __endpt_mgr_destroy( p_port );\r
+ __recv_mgr_destroy( p_port );\r
+ __send_mgr_destroy( p_port );\r
+ __buf_mgr_destroy( p_port );\r
+\r
+ cl_spinlock_destroy( &p_port->send_lock );\r
+ cl_spinlock_destroy( &p_port->recv_lock );\r
+\r
+ cl_obj_deinit( p_obj );\r
+\r
+ cl_free( p_port );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+\r
+/******************************************************************************\r
+*\r
+* IB resource manager implementation.\r
+*\r
+******************************************************************************/\r
+static void\r
+__ib_mgr_construct(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ cl_memclr( &p_port->ib_mgr, sizeof(ipoib_ib_mgr_t) );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__ib_mgr_init(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ ib_api_status_t status;\r
+ ib_cq_create_t cq_create;\r
+ ib_qp_create_t qp_create;\r
+ ib_phys_create_t phys_create;\r
+ ib_phys_range_t phys_range;\r
+ uint64_t vaddr;\r
+ net32_t rkey;\r
+ ib_qp_attr_t qp_attr;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ /* Open the CA. */\r
+ status = p_port->p_adapter->p_ifc->open_ca(\r
+ p_port->p_adapter->h_al, p_port->p_adapter->guids.ca_guid,\r
+ NULL, p_port, &p_port->ib_mgr.h_ca );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_OPEN_CA, 1, status );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_open_ca returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* Allocate the PD. */\r
+ status = p_port->p_adapter->p_ifc->alloc_pd(\r
+ p_port->ib_mgr.h_ca, IB_PDT_UD, p_port, &p_port->ib_mgr.h_pd );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_ALLOC_PD, 1, status );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_alloc_pd returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* Allocate receive CQ. */\r
+ cq_create.size = p_port->p_adapter->params.rq_depth;\r
+ cq_create.pfn_comp_cb = __recv_cb;\r
+ cq_create.h_wait_obj = NULL;\r
+\r
+ status = p_port->p_adapter->p_ifc->create_cq(\r
+ p_port->ib_mgr.h_ca, &cq_create, p_port,\r
+ __cq_event, &p_port->ib_mgr.h_recv_cq );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_CREATE_RECV_CQ, 1, status );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_create_cq returned %s.\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* Allocate send CQ. */\r
+ cq_create.size = p_port->p_adapter->params.sq_depth;\r
+ cq_create.pfn_comp_cb = __send_cb;\r
+\r
+ status = p_port->p_adapter->p_ifc->create_cq(\r
+ p_port->ib_mgr.h_ca, &cq_create, p_port,\r
+ __cq_event, &p_port->ib_mgr.h_send_cq );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_CREATE_SEND_CQ, 1, status );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_create_cq returned %s.\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* Allocate the QP. */\r
+ cl_memclr( &qp_create, sizeof(qp_create) );\r
+ qp_create.qp_type = IB_QPT_UNRELIABLE_DGRM;\r
+ qp_create.rq_depth = p_port->p_adapter->params.rq_depth;\r
+ qp_create.rq_sge = 2; /* To support buffers spanning pages. */\r
+ qp_create.h_rq_cq = p_port->ib_mgr.h_recv_cq;\r
+ qp_create.sq_depth = p_port->p_adapter->params.sq_depth;\r
+ //TODO: Figure out the right number of SGE entries for sends.\r
+ qp_create.sq_sge = MAX_SEND_SGE;\r
+ qp_create.h_sq_cq = p_port->ib_mgr.h_send_cq;\r
+ qp_create.sq_signaled = TRUE;\r
+ status = p_port->p_adapter->p_ifc->create_qp(\r
+ p_port->ib_mgr.h_pd, &qp_create, p_port,\r
+ __qp_event, &p_port->ib_mgr.h_qp );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_CREATE_QP, 1, status );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_create_qp returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+ /* Query the QP so we can get our QPN. */\r
+ status = p_port->p_adapter->p_ifc->query_qp(\r
+ p_port->ib_mgr.h_qp, &qp_attr );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_QUERY_QP, 1, status );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_query_qp returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+ p_port->ib_mgr.qpn = qp_attr.num;\r
+\r
+ /* Register all of physical memory */\r
+ phys_create.length = MEM_REG_SIZE;\r
+ phys_create.num_ranges = 1;\r
+ phys_create.range_array = &phys_range;\r
+ phys_create.buf_offset = 0;\r
+ phys_create.hca_page_size = PAGE_SIZE;\r
+ phys_create.access_ctrl = IB_AC_LOCAL_WRITE;\r
+ phys_range.base_addr = 0;\r
+ phys_range.size = MEM_REG_SIZE;\r
+ vaddr = 0;\r
+ status = p_port->p_adapter->p_ifc->reg_phys(\r
+ p_port->ib_mgr.h_pd, &phys_create, &vaddr,\r
+ &p_port->ib_mgr.lkey, &rkey, &p_port->ib_mgr.h_mr );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_REG_PHYS, 1, status );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_reg_phys returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+static void\r
+__ib_mgr_destroy(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ ib_api_status_t status;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ if( p_port->ib_mgr.h_ca )\r
+ {\r
+ status =\r
+ p_port->p_adapter->p_ifc->close_ca( p_port->ib_mgr.h_ca, NULL );\r
+ CL_ASSERT( status == IB_SUCCESS );\r
+ p_port->ib_mgr.h_ca = NULL;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+\r
+/******************************************************************************\r
+*\r
+* Buffer manager implementation.\r
+*\r
+******************************************************************************/\r
+static void\r
+__buf_mgr_construct(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ cl_qpool_construct( &p_port->buf_mgr.recv_pool );\r
+\r
+ p_port->buf_mgr.h_packet_pool = NULL;\r
+ p_port->buf_mgr.h_buffer_pool = NULL;\r
+\r
+ ExInitializeNPagedLookasideList( &p_port->buf_mgr.send_buf_list,\r
+ NULL, NULL, 0, MAX_XFER_BLOCK_SIZE, 'bipi', 0 );\r
+\r
+ p_port->buf_mgr.h_send_pkt_pool = NULL;\r
+ p_port->buf_mgr.h_send_buf_pool = NULL;\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__buf_mgr_init(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ cl_status_t cl_status;\r
+ NDIS_STATUS ndis_status;\r
+ ipoib_params_t *p_params;\r
+\r
+ IPOIB_ENTER(IPOIB_DBG_INIT );\r
+\r
+ CL_ASSERT( p_port );\r
+ CL_ASSERT( p_port->p_adapter );\r
+\r
+ p_params = &p_port->p_adapter->params;\r
+\r
+ /* Allocate the receive descriptor pool */\r
+ cl_status = cl_qpool_init( &p_port->buf_mgr.recv_pool,\r
+ p_params->rq_depth * p_params->recv_pool_ratio,\r
+#if IPOIB_INLINE_RECV\r
+ 0, 0, sizeof(ipoib_recv_desc_t), __recv_ctor, NULL, p_port );\r
+#else /* IPOIB_INLINE_RECV */\r
+ 0, 0, sizeof(ipoib_recv_desc_t), __recv_ctor, __recv_dtor, p_port );\r
+#endif /* IPOIB_INLINE_RECV */\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_RECV_POOL, 1, cl_status );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("cl_qpool_init for recvs returned %#x\n",\r
+ cl_status) );\r
+ return IB_INSUFFICIENT_MEMORY;\r
+ }\r
+\r
+ /* Allocate the NDIS buffer and packet pools for receive indication. */\r
+ NdisAllocatePacketPool( &ndis_status, &p_port->buf_mgr.h_packet_pool,\r
+ p_params->rq_depth, PROTOCOL_RESERVED_SIZE_IN_PACKET );\r
+ if( ndis_status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_RECV_PKT_POOL, 1, ndis_status );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("NdisAllocatePacketPool returned %08X\n", ndis_status) );\r
+ return IB_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ NdisAllocateBufferPool( &ndis_status, &p_port->buf_mgr.h_buffer_pool,\r
+ p_params->rq_depth );\r
+ if( ndis_status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_RECV_BUF_POOL, 1, ndis_status );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("NdisAllocateBufferPool returned %08X\n", ndis_status) );\r
+ return IB_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ /* Allocate the NDIS buffer and packet pools for send formatting. */\r
+ NdisAllocatePacketPool( &ndis_status, &p_port->buf_mgr.h_send_pkt_pool,\r
+ 1, PROTOCOL_RESERVED_SIZE_IN_PACKET );\r
+ if( ndis_status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_SEND_PKT_POOL, 1, ndis_status );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("NdisAllocatePacketPool returned %08X\n", ndis_status) );\r
+ return IB_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ NdisAllocateBufferPool( &ndis_status,\r
+ &p_port->buf_mgr.h_send_buf_pool, 1 );\r
+ if( ndis_status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_SEND_BUF_POOL, 1, ndis_status );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("NdisAllocateBufferPool returned %08X\n", ndis_status) );\r
+ return IB_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+static void\r
+__buf_mgr_destroy(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER(IPOIB_DBG_INIT );\r
+\r
+ CL_ASSERT( p_port );\r
+\r
+ /* Destroy the send packet and buffer pools. */\r
+ if( p_port->buf_mgr.h_send_buf_pool )\r
+ NdisFreeBufferPool( p_port->buf_mgr.h_send_buf_pool );\r
+ if( p_port->buf_mgr.h_send_pkt_pool )\r
+ NdisFreePacketPool( p_port->buf_mgr.h_send_pkt_pool );\r
+\r
+ /* Destroy the receive packet and buffer pools. */\r
+ if( p_port->buf_mgr.h_buffer_pool )\r
+ NdisFreeBufferPool( p_port->buf_mgr.h_buffer_pool );\r
+ if( p_port->buf_mgr.h_packet_pool )\r
+ NdisFreePacketPool( p_port->buf_mgr.h_packet_pool );\r
+\r
+ /* Free the receive and send descriptors. */\r
+ cl_qpool_destroy( &p_port->buf_mgr.recv_pool );\r
+\r
+ /* Free the lookaside list of scratch buffers. */\r
+ ExDeleteNPagedLookasideList( &p_port->buf_mgr.send_buf_list );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static cl_status_t\r
+__recv_ctor(\r
+ IN void* const p_object,\r
+ IN void* context,\r
+ OUT cl_pool_item_t** const pp_pool_item )\r
+{\r
+ ipoib_recv_desc_t *p_desc;\r
+ ipoib_port_t *p_port;\r
+ uint32_t ds0_len;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ALLOC );\r
+\r
+ CL_ASSERT( p_object );\r
+ CL_ASSERT( context );\r
+\r
+ p_desc = (ipoib_recv_desc_t*)p_object;\r
+ p_port = (ipoib_port_t*)context;\r
+\r
+ /* Setup the work request. */\r
+ p_desc->wr.ds_array = p_desc->local_ds;\r
+ p_desc->wr.wr_id = (uintn_t)p_desc;\r
+\r
+#if IPOIB_INLINE_RECV\r
+ /* Sanity check on the receive buffer layout */\r
+ CL_ASSERT( (void*)&p_desc->buf.eth.pkt.type ==\r
+ (void*)&p_desc->buf.ib.pkt.type );\r
+ CL_ASSERT( sizeof(recv_buf_t) == sizeof(ipoib_pkt_t) + sizeof(ib_grh_t) );\r
+\r
+ /* Setup the local data segment. */\r
+ p_desc->local_ds[0].vaddr = cl_get_physaddr( &p_desc->buf );\r
+ p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey;\r
+ ds0_len =\r
+ PAGE_SIZE - ((uint32_t)p_desc->local_ds[0].vaddr & (PAGE_SIZE - 1));\r
+ if( ds0_len >= sizeof(recv_buf_t) )\r
+ {\r
+ /* The whole buffer is within a page. */\r
+ p_desc->local_ds[0].length = ds0_len;\r
+ p_desc->wr.num_ds = 1;\r
+ }\r
+ else\r
+ {\r
+ /* The buffer crosses page boundaries. */\r
+ p_desc->local_ds[0].length = ds0_len;\r
+ p_desc->local_ds[1].vaddr = cl_get_physaddr( \r
+ ((uint8_t*)&p_desc->buf) + ds0_len );\r
+ p_desc->local_ds[1].lkey = p_port->ib_mgr.lkey;\r
+ p_desc->local_ds[1].length = sizeof(recv_buf_t) - ds0_len;\r
+ p_desc->wr.num_ds = 2;\r
+ }\r
+#else /* IPOIB_INLINE_RECV */\r
+ /* Allocate the receive buffer. */\r
+ p_desc->p_buf = (recv_buf_t*)cl_zalloc( sizeof(recv_buf_t) );\r
+ if( !p_desc->p_buf )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to allocate receive buffer.\n") );\r
+ return CL_INSUFFICIENT_MEMORY;\r
+ }\r
+\r
+ /* Sanity check on the receive buffer layout */\r
+ CL_ASSERT( (void*)&p_desc->p_buf->eth.pkt.type ==\r
+ (void*)&p_desc->p_buf->ib.pkt.type );\r
+\r
+ /* Setup the local data segment. */\r
+ p_desc->local_ds[0].vaddr = cl_get_physaddr( p_desc->p_buf );\r
+ p_desc->local_ds[0].length = sizeof(ipoib_pkt_t) + sizeof(ib_grh_t);\r
+ p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey;\r
+#endif /* IPOIB_INLINE_RECV */\r
+\r
+ *pp_pool_item = &p_desc->item;\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ALLOC );\r
+ return CL_SUCCESS;\r
+}\r
+\r
+\r
+#if !IPOIB_INLINE_RECV\r
+static void\r
+__recv_dtor(\r
+ IN const cl_pool_item_t* const p_pool_item,\r
+ IN void *context )\r
+{\r
+ ipoib_recv_desc_t *p_desc;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ALLOC );\r
+\r
+ UNUSED_PARAM( context );\r
+\r
+ p_desc = PARENT_STRUCT( p_pool_item, ipoib_recv_desc_t, item );\r
+\r
+ if( p_desc->p_buf )\r
+ cl_free( p_desc->p_buf );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ALLOC );\r
+}\r
+#endif\r
+\r
+\r
+static inline ipoib_recv_desc_t*\r
+__buf_mgr_get_recv(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ ipoib_recv_desc_t *p_desc;\r
+ IPOIB_ENTER( IPOIB_DBG_RECV );\r
+ p_desc = (ipoib_recv_desc_t*)cl_qpool_get( &p_port->buf_mgr.recv_pool );\r
+ /* Reference the port object for the send. */\r
+ if( p_desc )\r
+ {\r
+ ipoib_port_ref( p_port, ref_get_recv );\r
+ CL_ASSERT( p_desc->wr.wr_id == (uintn_t)p_desc );\r
+#if IPOIB_INLINE_RECV\r
+ CL_ASSERT( p_desc->local_ds[0].vaddr ==\r
+ cl_get_physaddr( &p_desc->buf ) );\r
+#else /* IPOIB_INLINE_RECV */\r
+ CL_ASSERT( p_desc->local_ds[0].vaddr ==\r
+ cl_get_physaddr( p_desc->p_buf ) );\r
+ CL_ASSERT( p_desc->local_ds[0].length ==\r
+ (sizeof(ipoib_pkt_t) + sizeof(ib_grh_t)) );\r
+#endif /* IPOIB_INLINE_RECV */\r
+ CL_ASSERT( p_desc->local_ds[0].lkey == p_port->ib_mgr.lkey );\r
+ }\r
+ IPOIB_EXIT( IPOIB_DBG_RECV );\r
+ return p_desc;\r
+}\r
+\r
+\r
+static inline void\r
+__buf_mgr_put_recv(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_recv_desc_t* const p_desc,\r
+ IN NDIS_PACKET* const p_packet OPTIONAL )\r
+{\r
+ NDIS_BUFFER *p_buf;\r
+\r
+ IPOIB_ENTER(IPOIB_DBG_RECV );\r
+\r
+ if( p_packet )\r
+ {\r
+ /* Unchain the NDIS buffer. */\r
+ NdisUnchainBufferAtFront( p_packet, &p_buf );\r
+ CL_ASSERT( p_buf );\r
+ /* Return the NDIS packet and NDIS buffer to their pools. */\r
+ NdisDprFreePacketNonInterlocked( p_packet );\r
+ NdisFreeBuffer( p_buf );\r
+ }\r
+\r
+ /* Return the descriptor to its pools. */\r
+ cl_qpool_put( &p_port->buf_mgr.recv_pool, &p_desc->item );\r
+\r
+ /*\r
+ * Dereference the port object since the receive is no longer outstanding.\r
+ */\r
+ ipoib_port_deref( p_port, ref_get_recv );\r
+ IPOIB_EXIT( IPOIB_DBG_RECV );\r
+}\r
+\r
+\r
+static inline void\r
+__buf_mgr_put_recv_list(\r
+ IN ipoib_port_t* const p_port,\r
+ IN cl_qlist_t* const p_list )\r
+{\r
+ //IPOIB_ENTER( IPOIB_DBG_RECV );\r
+ cl_qpool_put_list( &p_port->buf_mgr.recv_pool, p_list );\r
+ //IPOIB_EXIT( IPOIB_DBG_RECV );\r
+}\r
+\r
+\r
+static inline NDIS_PACKET*\r
+__buf_mgr_get_ndis_pkt(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_recv_desc_t* const p_desc )\r
+{\r
+ NDIS_STATUS status;\r
+ NDIS_PACKET *p_packet;\r
+ NDIS_BUFFER *p_buffer;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_RECV );\r
+\r
+ NdisDprAllocatePacketNonInterlocked( &status, &p_packet,\r
+ p_port->buf_mgr.h_packet_pool );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to allocate NDIS_PACKET: %08x\n", status) );\r
+ return NULL;\r
+ }\r
+\r
+ IPOIB_PORT_FROM_PACKET( p_packet ) = p_port;\r
+ IPOIB_RECV_FROM_PACKET( p_packet ) = p_desc;\r
+\r
+ NdisAllocateBuffer( &status, &p_buffer,\r
+#if IPOIB_INLINE_RECV\r
+ p_port->buf_mgr.h_buffer_pool, &p_desc->buf.eth.pkt, p_desc->len );\r
+#else /* IPOIB_INLINE_RECV */\r
+ p_port->buf_mgr.h_buffer_pool, &p_desc->p_buf->eth.pkt, p_desc->len );\r
+#endif /* IPOIB_INLINE_RECV */\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to allocate NDIS_BUFFER: %08x\n", status) );\r
+ NdisDprFreePacketNonInterlocked( p_packet );\r
+ return NULL;\r
+ }\r
+\r
+ NdisChainBufferAtFront( p_packet, p_buffer );\r
+ NDIS_SET_PACKET_HEADER_SIZE( p_packet, sizeof(eth_hdr_t) );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_RECV );\r
+ return p_packet;\r
+}\r
+\r
+/******************************************************************************\r
+*\r
+* Receive manager implementation.\r
+*\r
+******************************************************************************/\r
+static void\r
+__recv_mgr_construct(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ cl_qlist_init( &p_port->recv_mgr.done_list );\r
+\r
+ p_port->recv_mgr.recv_pkt_array = NULL;\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__recv_mgr_init(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ /* Allocate the NDIS_PACKET pointer array for indicating receives. */\r
+ p_port->recv_mgr.recv_pkt_array = cl_malloc(\r
+ sizeof(NDIS_PACKET*) * p_port->p_adapter->params.rq_depth );\r
+ if( !p_port->recv_mgr.recv_pkt_array )\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_RECV_PKT_ARRAY, 0 );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("cl_malloc for PNDIS_PACKET array failed.\n") );\r
+ return IB_INSUFFICIENT_MEMORY;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+static void\r
+__recv_mgr_destroy(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ CL_ASSERT( cl_is_qlist_empty( &p_port->recv_mgr.done_list ) );\r
+ CL_ASSERT( !p_port->recv_mgr.depth );\r
+\r
+ if( p_port->recv_mgr.recv_pkt_array )\r
+ cl_free( p_port->recv_mgr.recv_pkt_array );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+/*\r
+ * Posts receive buffers to the receive queue and returns the number\r
+ * of receives needed to bring the RQ to its low water mark. Note\r
+ * that the value is signed, and can go negative. All tests must\r
+ * be for > 0.\r
+ */\r
+static int32_t\r
+__recv_mgr_repost(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ ipoib_recv_desc_t *p_head = NULL, *p_tail = NULL, *p_next;\r
+ ib_api_status_t status;\r
+ ib_recv_wr_t *p_failed;\r
+ PERF_DECLARE( GetRecv );\r
+ PERF_DECLARE( PostRecv );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_RECV );\r
+\r
+ CL_ASSERT( p_port );\r
+ cl_obj_lock( &p_port->obj );\r
+ if( p_port->state != IB_QPS_RTS )\r
+ {\r
+ cl_obj_unlock( &p_port->obj );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
+ ("Port in invalid state. Not reposting.\n") );\r
+ return 0;\r
+ }\r
+ ipoib_port_ref( p_port, ref_repost );\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ while( p_port->recv_mgr.depth < p_port->p_adapter->params.rq_depth )\r
+ {\r
+ /* Pull receives out of the pool and chain them up. */\r
+ cl_perf_start( GetRecv );\r
+ p_next = __buf_mgr_get_recv( p_port );\r
+ cl_perf_stop( &p_port->p_adapter->perf, GetRecv );\r
+ if( !p_next )\r
+ {\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
+ ("Out of receive descriptors! recv queue depath 0x%x\n",p_port->recv_mgr.depth) );\r
+ break;\r
+ }\r
+\r
+ if( !p_tail )\r
+ {\r
+ p_tail = p_next;\r
+ p_next->wr.p_next = NULL;\r
+ }\r
+ else\r
+ {\r
+ p_next->wr.p_next = &p_head->wr;\r
+ }\r
+\r
+ p_head = p_next;\r
+\r
+ p_port->recv_mgr.depth++;\r
+ }\r
+\r
+ if( p_head )\r
+ {\r
+ cl_perf_start( PostRecv );\r
+ status = p_port->p_adapter->p_ifc->post_recv(\r
+ p_port->ib_mgr.h_qp, &p_head->wr, &p_failed );\r
+ cl_perf_stop( &p_port->p_adapter->perf, PostRecv );\r
+\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ip_post_recv returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ /* return the descriptors to the pool */\r
+ while( p_failed )\r
+ {\r
+ p_head = PARENT_STRUCT( p_failed, ipoib_recv_desc_t, wr );\r
+ p_failed = p_failed->p_next;\r
+\r
+ __buf_mgr_put_recv( p_port, p_head, NULL );\r
+ p_port->recv_mgr.depth--;\r
+ }\r
+ }\r
+ }\r
+\r
+ ipoib_port_deref( p_port, ref_repost );\r
+ IPOIB_EXIT( IPOIB_DBG_RECV );\r
+ return p_port->p_adapter->params.rq_low_watermark - p_port->recv_mgr.depth;\r
+}\r
+\r
+\r
+void\r
+ipoib_return_packet(\r
+ IN NDIS_HANDLE adapter_context,\r
+ IN NDIS_PACKET *p_packet )\r
+{\r
+ cl_list_item_t *p_item;\r
+ ipoib_port_t *p_port;\r
+ ipoib_recv_desc_t *p_desc;\r
+ ib_api_status_t status = IB_NOT_DONE;\r
+ int32_t shortage;\r
+ PERF_DECLARE( ReturnPacket );\r
+ PERF_DECLARE( ReturnPutRecv );\r
+ PERF_DECLARE( ReturnRepostRecv );\r
+ PERF_DECLARE( ReturnPreparePkt );\r
+ PERF_DECLARE( ReturnNdisIndicate );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_RECV );\r
+\r
+ UNUSED_PARAM( adapter_context );\r
+ CL_ASSERT( p_packet );\r
+\r
+ cl_perf_start( ReturnPacket );\r
+\r
+ /* Get the port and descriptor from the packet. */\r
+ p_port = IPOIB_PORT_FROM_PACKET( p_packet );\r
+ p_desc = IPOIB_RECV_FROM_PACKET( p_packet );\r
+\r
+ cl_spinlock_acquire( &p_port->recv_lock );\r
+\r
+ cl_perf_start( ReturnPutRecv );\r
+ __buf_mgr_put_recv( p_port, p_desc, p_packet );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ReturnPutRecv );\r
+\r
+ /* Repost buffers. */\r
+ cl_perf_start( ReturnRepostRecv );\r
+ shortage = __recv_mgr_repost( p_port );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ReturnRepostRecv );\r
+\r
+ for( p_item = cl_qlist_remove_head( &p_port->recv_mgr.done_list );\r
+ p_item != cl_qlist_end( &p_port->recv_mgr.done_list );\r
+ p_item = cl_qlist_remove_head( &p_port->recv_mgr.done_list ) )\r
+ {\r
+ p_desc = (ipoib_recv_desc_t*)p_item;\r
+\r
+ cl_perf_start( ReturnPreparePkt );\r
+ status = __recv_mgr_prepare_pkt( p_port, p_desc, &p_packet );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ReturnPreparePkt );\r
+ if( status == IB_SUCCESS )\r
+ {\r
+ if( shortage > 0 )\r
+ NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_RESOURCES );\r
+ else\r
+ NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_SUCCESS );\r
+\r
+ cl_spinlock_release( &p_port->recv_lock );\r
+ cl_perf_start( ReturnNdisIndicate );\r
+ NdisMIndicateReceivePacket( p_port->p_adapter->h_adapter,\r
+ &p_packet, 1 );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ReturnNdisIndicate );\r
+ cl_spinlock_acquire( &p_port->recv_lock );\r
+\r
+ if( shortage > 0 )\r
+ {\r
+ cl_perf_start( ReturnPutRecv );\r
+ __buf_mgr_put_recv( p_port, p_desc, p_packet );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ReturnPutRecv );\r
+\r
+ /* Repost buffers. */\r
+ cl_perf_start( ReturnRepostRecv );\r
+ shortage = __recv_mgr_repost( p_port );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ReturnRepostRecv );\r
+ }\r
+ }\r
+ else if( status != IB_NOT_DONE )\r
+ {\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
+ ("__recv_mgr_prepare_pkt returned %s\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ /* Return the item to the head of the list. */\r
+ cl_qlist_insert_head( &p_port->recv_mgr.done_list, p_item );\r
+ break;\r
+ }\r
+ }\r
+ cl_spinlock_release( &p_port->recv_lock );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ReturnPacket );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_RECV );\r
+}\r
+\r
+\r
+static void\r
+__recv_cb(\r
+ IN const ib_cq_handle_t h_cq,\r
+ IN void *cq_context )\r
+{\r
+ ipoib_port_t *p_port;\r
+ ib_api_status_t status;\r
+ ib_wc_t wc[MAX_RECV_WC], *p_free, *p_wc;\r
+ int32_t pkt_cnt, recv_cnt = 0, shortage, discarded;\r
+ cl_qlist_t done_list, bad_list;\r
+ size_t i;\r
+ PERF_DECLARE( RecvCompBundle );\r
+ PERF_DECLARE( RecvCb );\r
+ PERF_DECLARE( PollRecv );\r
+ PERF_DECLARE( RepostRecv );\r
+ PERF_DECLARE( FilterRecv );\r
+ PERF_DECLARE( BuildPktArray );\r
+ PERF_DECLARE( RecvNdisIndicate );\r
+ PERF_DECLARE( RearmRecv );\r
+ PERF_DECLARE( PutRecvList );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_RECV );\r
+\r
+ cl_perf_clr( RecvCompBundle );\r
+\r
+ cl_perf_start( RecvCb );\r
+\r
+ UNUSED_PARAM( h_cq );\r
+\r
+ p_port = (ipoib_port_t*)cq_context;\r
+\r
+ cl_qlist_init( &done_list );\r
+ cl_qlist_init( &bad_list );\r
+\r
+ ipoib_port_ref( p_port, ref_recv_cb );\r
+ for( i = 0; i < MAX_RECV_WC; i++ )\r
+ wc[i].p_next = &wc[i + 1];\r
+ wc[MAX_RECV_WC - 1].p_next = NULL;\r
+\r
+ /*\r
+ * We'll be accessing the endpoint map so take a reference\r
+ * on it to prevent modifications.\r
+ */\r
+ cl_obj_lock( &p_port->obj );\r
+ cl_atomic_inc( &p_port->endpt_rdr );\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ do\r
+ {\r
+ /* If we get here, then the list of WCs is intact. */\r
+ p_free = wc;\r
+\r
+ cl_perf_start( PollRecv );\r
+ status = p_port->p_adapter->p_ifc->poll_cq(\r
+ p_port->ib_mgr.h_recv_cq, &p_free, &p_wc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, PollRecv );\r
+ CL_ASSERT( status == IB_SUCCESS || status == IB_NOT_FOUND );\r
+\r
+ /* Look at the payload now and filter ARP and DHCP packets. */\r
+ cl_perf_start( FilterRecv );\r
+ recv_cnt += __recv_mgr_filter( p_port, p_wc, &done_list, &bad_list );\r
+ cl_perf_stop( &p_port->p_adapter->perf, FilterRecv );\r
+\r
+ } while( !p_free );\r
+\r
+ /* We're done looking at the endpoint map, release the reference. */\r
+ cl_atomic_dec( &p_port->endpt_rdr );\r
+\r
+ cl_perf_log( &p_port->p_adapter->perf, RecvCompBundle, recv_cnt );\r
+\r
+ cl_spinlock_acquire( &p_port->recv_lock );\r
+\r
+ /* Update our posted depth. */\r
+ p_port->recv_mgr.depth -= recv_cnt;\r
+\r
+ /* Return any discarded receives to the pool */\r
+ cl_perf_start( PutRecvList );\r
+ __buf_mgr_put_recv_list( p_port, &bad_list );\r
+ cl_perf_stop( &p_port->p_adapter->perf, PutRecvList );\r
+\r
+ do\r
+ {\r
+ /* Repost ASAP so we don't starve the RQ. */\r
+ cl_perf_start( RepostRecv );\r
+ shortage = __recv_mgr_repost( p_port );\r
+ cl_perf_stop( &p_port->p_adapter->perf, RepostRecv );\r
+\r
+ cl_perf_start( BuildPktArray );\r
+ /* Notify NDIS of any and all possible receive buffers. */\r
+ pkt_cnt = __recv_mgr_build_pkt_array(\r
+ p_port, shortage, &done_list, &discarded );\r
+ cl_perf_stop( &p_port->p_adapter->perf, BuildPktArray );\r
+\r
+ /* Only indicate receives if we actually had any. */\r
+ if( discarded && shortage > 0 )\r
+ {\r
+ /* We may have thrown away packets, and have a shortage */\r
+ cl_perf_start( RepostRecv );\r
+ __recv_mgr_repost( p_port );\r
+ cl_perf_stop( &p_port->p_adapter->perf, RepostRecv );\r
+ }\r
+\r
+ if( !pkt_cnt )\r
+ break;\r
+\r
+ cl_spinlock_release( &p_port->recv_lock );\r
+\r
+ cl_perf_start( RecvNdisIndicate );\r
+ NdisMIndicateReceivePacket( p_port->p_adapter->h_adapter,\r
+ p_port->recv_mgr.recv_pkt_array, pkt_cnt );\r
+ cl_perf_stop( &p_port->p_adapter->perf, RecvNdisIndicate );\r
+\r
+ /*\r
+ * Cap the number of receives to put back to what we just indicated\r
+ * with NDIS_STATUS_RESOURCES.\r
+ */\r
+ if( shortage > 0 )\r
+ {\r
+ if( pkt_cnt < shortage )\r
+ shortage = pkt_cnt;\r
+\r
+ /* Return all but the last packet to the pool. */\r
+ cl_spinlock_acquire( &p_port->recv_lock );\r
+ while( shortage-- > 1 )\r
+ {\r
+ __buf_mgr_put_recv( p_port,\r
+ IPOIB_RECV_FROM_PACKET( p_port->recv_mgr.recv_pkt_array[shortage] ),\r
+ p_port->recv_mgr.recv_pkt_array[shortage] );\r
+ }\r
+ cl_spinlock_release( &p_port->recv_lock );\r
+\r
+ /*\r
+ * Return the last packet as if NDIS returned it, so that we repost\r
+ * and report any other pending receives.\r
+ */\r
+ ipoib_return_packet( NULL, p_port->recv_mgr.recv_pkt_array[0] );\r
+ }\r
+ cl_spinlock_acquire( &p_port->recv_lock );\r
+\r
+ } while( pkt_cnt );\r
+ cl_spinlock_release( &p_port->recv_lock );\r
+\r
+ /*\r
+ * Rearm after filtering to prevent contention on the enpoint maps\r
+ * and eliminate the possibility of having a call to\r
+ * __endpt_mgr_insert find a duplicate.\r
+ */\r
+ cl_perf_start( RearmRecv );\r
+ status = p_port->p_adapter->p_ifc->rearm_cq(\r
+ p_port->ib_mgr.h_recv_cq, FALSE );\r
+ cl_perf_stop( &p_port->p_adapter->perf, RearmRecv );\r
+ CL_ASSERT( status == IB_SUCCESS );\r
+\r
+ ipoib_port_deref( p_port, ref_recv_cb );\r
+\r
+ cl_perf_stop( &p_port->p_adapter->perf, RecvCb );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_RECV );\r
+}\r
+\r
+\r
+static void\r
+__recv_get_endpts(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_recv_desc_t* const p_desc,\r
+ IN ib_wc_t* const p_wc,\r
+ OUT ipoib_endpt_t** const pp_src,\r
+ OUT ipoib_endpt_t** const pp_dst )\r
+{\r
+ ib_api_status_t status;\r
+ mac_addr_t mac;\r
+ PERF_DECLARE( GetEndptByGid );\r
+ PERF_DECLARE( GetEndptByLid );\r
+ PERF_DECLARE( EndptInsert );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_RECV );\r
+\r
+ /* Setup our shortcut pointers based on whether GRH is valid. */\r
+ if( p_wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID )\r
+ {\r
+ /* Lookup the source endpoints based on GID. */\r
+ cl_perf_start( GetEndptByGid );\r
+ *pp_src =\r
+#if IPOIB_INLINE_RECV\r
+ __endpt_mgr_get_by_gid( p_port, &p_desc->buf.ib.grh.src_gid );\r
+#else /* IPOIB_INLINE_RECV */\r
+ __endpt_mgr_get_by_gid( p_port, &p_desc->p_buf->ib.grh.src_gid );\r
+#endif /* IPOIB_INLINE_RECV */\r
+ cl_perf_stop( &p_port->p_adapter->perf, GetEndptByGid );\r
+\r
+ /*\r
+ * Lookup the destination endpoint based on GID.\r
+ * This is used along with the packet filter to determine\r
+ * whether to report this to NDIS.\r
+ */\r
+ cl_perf_start( GetEndptByGid );\r
+ *pp_dst =\r
+#if IPOIB_INLINE_RECV\r
+ __endpt_mgr_get_by_gid( p_port, &p_desc->buf.ib.grh.dest_gid );\r
+#else /* IPOIB_INLINE_RECV */\r
+ __endpt_mgr_get_by_gid( p_port, &p_desc->p_buf->ib.grh.dest_gid );\r
+#endif /* IPOIB_INLINE_RECV */\r
+ cl_perf_stop( &p_port->p_adapter->perf, GetEndptByGid );\r
+\r
+ /*\r
+ * Create the source endpoint if it does not exist. Note that we\r
+ * can only do this for globally routed traffic since we need the\r
+ * information from the GRH to generate the MAC.\r
+ */\r
+ if( !*pp_src )\r
+ {\r
+ status = ipoib_mac_from_guid(\r
+#if IPOIB_INLINE_RECV\r
+ p_desc->buf.ib.grh.src_gid.unicast.interface_id, &mac );\r
+#else /* IPOIB_INLINE_RECV */\r
+ p_desc->p_buf->ib.grh.src_gid.unicast.interface_id, &mac );\r
+#endif /* IPOIB_INLINE_RECV */\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_mac_from_guid returned %s\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return;\r
+ }\r
+\r
+ /* Create the endpoint. */\r
+#if IPOIB_INLINE_RECV\r
+ *pp_src = ipoib_endpt_create( &p_desc->buf.ib.grh.src_gid,\r
+#else /* IPOIB_INLINE_RECV */\r
+ *pp_src = ipoib_endpt_create( &p_desc->p_buf->ib.grh.src_gid,\r
+#endif /* IPOIB_INLINE_RECV */\r
+ 0, p_wc->recv.ud.remote_qp );\r
+ if( !*pp_src )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_endpt_create failed\n") );\r
+ return;\r
+ }\r
+ cl_perf_start( EndptInsert );\r
+ cl_obj_lock( &p_port->obj );\r
+ status = __endpt_mgr_insert( p_port, mac, *pp_src );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ cl_obj_unlock( &p_port->obj );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__endpt_mgr_insert returned %s\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return;\r
+ }\r
+ cl_obj_unlock( &p_port->obj );\r
+ cl_perf_stop( &p_port->p_adapter->perf, EndptInsert );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /*\r
+ * Lookup the remote endpoint based on LID. Note that only\r
+ * unicast traffic can be LID routed.\r
+ */\r
+ cl_perf_start( GetEndptByLid );\r
+ *pp_src = __endpt_mgr_get_by_lid( p_port, p_wc->recv.ud.remote_lid );\r
+ cl_perf_stop( &p_port->p_adapter->perf, GetEndptByLid );\r
+ *pp_dst = p_port->p_local_endpt;\r
+ CL_ASSERT( *pp_dst );\r
+ }\r
+\r
+ if( *pp_src && !ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) &&\r
+ (*pp_src)->qpn != p_wc->recv.ud.remote_qp )\r
+ {\r
+ /* Update the QPN for the endpoint. */\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
+ ("Updating QPN for MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",\r
+ (*pp_src )->mac.addr[0], (*pp_src )->mac.addr[1],\r
+ (*pp_src )->mac.addr[2], (*pp_src )->mac.addr[3],\r
+ (*pp_src )->mac.addr[4], (*pp_src )->mac.addr[5]) );\r
+ (*pp_src)->qpn = p_wc->recv.ud.remote_qp;\r
+ }\r
+\r
+ if( *pp_src && *pp_dst )\r
+ {\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
+ ("Recv:\n"\r
+ "\tsrc MAC: %02X-%02X-%02X-%02X-%02X-%02X\n"\r
+ "\tdst MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",\r
+ (*pp_src )->mac.addr[0], (*pp_src )->mac.addr[1],\r
+ (*pp_src )->mac.addr[2], (*pp_src )->mac.addr[3],\r
+ (*pp_src )->mac.addr[4], (*pp_src )->mac.addr[5],\r
+ (*pp_dst )->mac.addr[0], (*pp_dst )->mac.addr[1],\r
+ (*pp_dst )->mac.addr[2], (*pp_dst )->mac.addr[3],\r
+ (*pp_dst )->mac.addr[4], (*pp_dst )->mac.addr[5]) );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_RECV );\r
+}\r
+\r
+\r
+static int32_t\r
+__recv_mgr_filter(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ib_wc_t* const p_done_wc_list,\r
+ OUT cl_qlist_t* const p_done_list,\r
+ OUT cl_qlist_t* const p_bad_list )\r
+{\r
+ ipoib_recv_desc_t *p_desc;\r
+ ib_wc_t *p_wc;\r
+ ipoib_pkt_t *p_ipoib;\r
+ eth_pkt_t *p_eth;\r
+ ipoib_endpt_t *p_src, *p_dst;\r
+ ib_api_status_t status;\r
+ uint32_t len;\r
+ int32_t recv_cnt = 0;\r
+ PERF_DECLARE( GetRecvEndpts );\r
+ PERF_DECLARE( RecvGen );\r
+ PERF_DECLARE( RecvTcp );\r
+ PERF_DECLARE( RecvUdp );\r
+ PERF_DECLARE( RecvDhcp );\r
+ PERF_DECLARE( RecvArp );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_RECV );\r
+\r
+ for( p_wc = p_done_wc_list; p_wc; p_wc = p_wc->p_next )\r
+ {\r
+ CL_ASSERT( p_wc->status != IB_WCS_SUCCESS || p_wc->wc_type == IB_WC_RECV );\r
+ p_desc = (ipoib_recv_desc_t*)(uintn_t)p_wc->wr_id;\r
+ recv_cnt++;\r
+\r
+ if( p_wc->status != IB_WCS_SUCCESS )\r
+ {\r
+ if( p_wc->status != IB_WCS_WR_FLUSHED_ERR )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed completion %s (vendor specific %#x)\n",\r
+ p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status ),\r
+ (int)p_wc->vendor_specific) );\r
+ ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0 );\r
+ }\r
+ else\r
+ {\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
+ ("Flushed completion %s\n",\r
+ p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status )) );\r
+ ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_DROPPED, 0 );\r
+ }\r
+ cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );\r
+ /* Dereference the port object on behalf of the failed receive. */\r
+ ipoib_port_deref( p_port, ref_failed_recv_wc );\r
+ continue;\r
+ }\r
+\r
+ len = p_wc->length - sizeof(ib_grh_t);\r
+\r
+ if( len < sizeof(ipoib_hdr_t) )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Received ETH packet < min size\n") );\r
+ ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0 );\r
+ cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );\r
+ ipoib_port_deref( p_port, ref_recv_inv_len );\r
+ continue;\r
+ }\r
+\r
+ if((len - sizeof(ipoib_hdr_t)) > p_port->p_adapter->params.payload_mtu)\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Received ETH packet > payload MTU (%d)\n",\r
+ p_port->p_adapter->params.payload_mtu) );\r
+ ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0 );\r
+ cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );\r
+ ipoib_port_deref( p_port, ref_recv_inv_len );\r
+ continue;\r
+ \r
+ }\r
+ /* Successful completion. Get the receive information. */\r
+ cl_perf_start( GetRecvEndpts );\r
+ __recv_get_endpts( p_port, p_desc, p_wc, &p_src, &p_dst );\r
+ cl_perf_stop( &p_port->p_adapter->perf, GetRecvEndpts );\r
+\r
+#if IPOIB_INLINE_RECV\r
+ p_ipoib = &p_desc->buf.ib.pkt;\r
+ p_eth = &p_desc->buf.eth.pkt;\r
+#else /* IPOIB_INLINE_RECV */\r
+ p_ipoib = &p_desc->p_buf->ib.pkt;\r
+ p_eth = &p_desc->p_buf->eth.pkt;\r
+#endif /*IPOIB_INLINE_RECV */\r
+\r
+ if( p_src )\r
+ {\r
+ /* Don't report loopback traffic - we requested SW loopback. */\r
+ if( !cl_memcmp( &p_port->p_adapter->params.conf_mac,\r
+ &p_src->mac, sizeof(p_port->p_adapter->params.conf_mac) ) )\r
+ {\r
+ /*\r
+ * "This is not the packet you're looking for" - don't update\r
+ * receive statistics, the packet never happened.\r
+ */\r
+ cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );\r
+ /* Dereference the port object on behalf of the failed recv. */\r
+ ipoib_port_deref( p_port, ref_recv_loopback );\r
+ continue;\r
+ }\r
+ }\r
+\r
+ switch( p_ipoib->hdr.type )\r
+ {\r
+ case ETH_PROT_TYPE_IP:\r
+ if( len < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t)) )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Received IP packet < min size\n") );\r
+ status = IB_INVALID_SETTING;\r
+ break;\r
+ }\r
+\r
+ if( p_ipoib->type.ip.hdr.offset ||\r
+ p_ipoib->type.ip.hdr.prot != IP_PROT_UDP )\r
+ {\r
+ /* Unfiltered. Setup the ethernet header and report. */\r
+ cl_perf_start( RecvTcp );\r
+ status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );\r
+ cl_perf_stop( &p_port->p_adapter->perf, RecvTcp );\r
+ break;\r
+ }\r
+\r
+ /* First packet of a UDP transfer. */\r
+ if( len <\r
+ (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) + sizeof(udp_hdr_t)) )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Received UDP packet < min size\n") );\r
+ status = IB_INVALID_SETTING;\r
+ break;\r
+ }\r
+\r
+ /* Check if DHCP conversion is required. */\r
+ if( (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_SERVER &&\r
+ p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_CLIENT) ||\r
+ (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_CLIENT &&\r
+ p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_SERVER) )\r
+ {\r
+ if( len < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) +\r
+ sizeof(udp_hdr_t) + DHCP_MIN_SIZE) )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Received DHCP < min size\n") );\r
+ status = IB_INVALID_SETTING;\r
+ break;\r
+ }\r
+ if ((p_ipoib->type.ip.hdr.ver_hl & 0x0f) != 5 ) {\r
+ // If there are IP options in this message, we are in trouble in any case\r
+ status = IB_INVALID_SETTING;\r
+ break; \r
+ }\r
+ /* UDP packet with BOOTP ports in src/dst port numbers. */\r
+ cl_perf_start( RecvDhcp );\r
+ status = __recv_dhcp( p_port, p_ipoib, p_eth, p_src, p_dst );\r
+ cl_perf_stop( &p_port->p_adapter->perf, RecvDhcp );\r
+ }\r
+ else\r
+ {\r
+ /* Unfiltered. Setup the ethernet header and report. */\r
+ cl_perf_start( RecvUdp );\r
+ status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );\r
+ cl_perf_stop( &p_port->p_adapter->perf, RecvUdp );\r
+ }\r
+ break;\r
+\r
+ case ETH_PROT_TYPE_ARP:\r
+ if( len < (sizeof(ipoib_hdr_t) + sizeof(ipoib_arp_pkt_t)) )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Received ARP < min size\n") );\r
+ status = IB_INVALID_SETTING;\r
+ break;\r
+ }\r
+ cl_perf_start( RecvArp );\r
+ status = __recv_arp( p_port, p_wc, p_ipoib, p_eth, &p_src, p_dst );\r
+ cl_perf_stop( &p_port->p_adapter->perf, RecvArp );\r
+ len = sizeof(ipoib_hdr_t) + sizeof(arp_pkt_t);\r
+ break;\r
+\r
+ default:\r
+ /* Unfiltered. Setup the ethernet header and report. */\r
+ cl_perf_start( RecvGen );\r
+ status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );\r
+ cl_perf_stop( &p_port->p_adapter->perf, RecvGen );\r
+ }\r
+\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ /* Update stats. */\r
+ ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0 );\r
+ cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );\r
+ /* Dereference the port object on behalf of the failed receive. */\r
+ ipoib_port_deref( p_port, ref_recv_filter );\r
+ }\r
+ else\r
+ {\r
+ p_desc->len =\r
+ len + sizeof(eth_hdr_t) - sizeof(ipoib_hdr_t);\r
+ if( p_dst->h_mcast)\r
+ {\r
+ if( p_dst->dgid.multicast.raw_group_id[10] == 0xFF &&\r
+ p_dst->dgid.multicast.raw_group_id[11] == 0xFF &&\r
+ p_dst->dgid.multicast.raw_group_id[12] == 0xFF &&\r
+ p_dst->dgid.multicast.raw_group_id[13] == 0xFF )\r
+ {\r
+ p_desc->type = PKT_TYPE_BCAST;\r
+ }\r
+ else\r
+ {\r
+ p_desc->type = PKT_TYPE_MCAST;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ p_desc->type = PKT_TYPE_UCAST;\r
+ }\r
+ cl_qlist_insert_tail( p_done_list, &p_desc->item.list_item );\r
+ }\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_RECV );\r
+ return recv_cnt;\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__recv_gen(\r
+ IN const ipoib_pkt_t* const p_ipoib,\r
+ OUT eth_pkt_t* const p_eth,\r
+ IN ipoib_endpt_t* const p_src,\r
+ IN ipoib_endpt_t* const p_dst )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_RECV );\r
+\r
+ if( !p_src || !p_dst )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Received packet with no matching endpoints.\n") );\r
+ return IB_NOT_DONE;\r
+ }\r
+\r
+ /*\r
+ * Fill in the ethernet header. Note that doing so will overwrite\r
+ * the IPoIB header, so start by moving the information from the IPoIB\r
+ * header.\r
+ */\r
+ p_eth->hdr.type = p_ipoib->hdr.type;\r
+ p_eth->hdr.src = p_src->mac;\r
+ p_eth->hdr.dst = p_dst->mac;\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_RECV );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__recv_dhcp(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const ipoib_pkt_t* const p_ipoib,\r
+ OUT eth_pkt_t* const p_eth,\r
+ IN ipoib_endpt_t* const p_src,\r
+ IN ipoib_endpt_t* const p_dst )\r
+{\r
+ ib_api_status_t status;\r
+ dhcp_pkt_t *p_dhcp;\r
+ uint8_t *p_option;\r
+ uint8_t *p_cid = NULL;\r
+ ib_gid_t gid;\r
+ uint8_t msg = 0;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_RECV );\r
+\r
+ UNUSED_PARAM( p_port );\r
+\r
+ /* Create the ethernet header. */\r
+ status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__recv_gen returned %s.\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* Fixup the payload. */\r
+ p_dhcp = &p_eth->type.ip.prot.udp.dhcp;\r
+ if( p_dhcp->op != DHCP_REQUEST && p_dhcp->op != DHCP_REPLY )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid DHCP op code.\n") );\r
+ return IB_INVALID_SETTING;\r
+ }\r
+\r
+ /*\r
+ * Find the client identifier option, making sure to skip\r
+ * the "magic cookie".\r
+ */\r
+ p_option = &p_dhcp->options[0];\r
+ if ( *(uint32_t *)p_option != DHCP_COOKIE )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("DHCP cookie corrupted.\n") );\r
+ return IB_INVALID_PARAMETER;\r
+ }\r
+\r
+ p_option = &p_dhcp->options[4];\r
+ while( *p_option != DHCP_OPT_END && p_option < &p_dhcp->options[312] )\r
+ {\r
+ switch( *p_option )\r
+ {\r
+ case DHCP_OPT_PAD:\r
+ p_option++;\r
+ break;\r
+\r
+ case DHCP_OPT_MSG:\r
+ msg = p_option[2];\r
+ p_option += 3;\r
+ break;\r
+\r
+ case DHCP_OPT_CLIENT_ID:\r
+ p_cid = p_option;\r
+ /* Fall through. */\r
+\r
+ default:\r
+ /*\r
+ * All other options have a length byte following the option code.\r
+ * Offset by the length to get to the next option.\r
+ */\r
+ p_option += (p_option[1] + 2);\r
+ }\r
+ }\r
+\r
+ switch( msg )\r
+ {\r
+ /* message from client */\r
+ case DHCPDISCOVER:\r
+ case DHCPREQUEST:\r
+ case DHCPDECLINE:\r
+ case DHCPRELEASE:\r
+ case DHCPINFORM:\r
+ if( !p_cid )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to find required Client-identifier option.\n") );\r
+ return IB_INVALID_SETTING;\r
+ }\r
+ if( p_dhcp->htype != DHCP_HW_TYPE_IB )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalid hardware address type.\n") );\r
+ return IB_INVALID_SETTING;\r
+ }\r
+ break;\r
+ /* message from DHCP server */\r
+ case DHCPOFFER:\r
+ case DHCPACK:\r
+ case DHCPNAK:\r
+ break;\r
+\r
+ default:\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalide message type.\n") );\r
+ return IB_INVALID_PARAMETER;\r
+ }\r
+ p_eth->type.ip.prot.udp.hdr.chksum = 0;\r
+ p_dhcp->htype = DHCP_HW_TYPE_ETH;\r
+ p_dhcp->hlen = HW_ADDR_LEN;\r
+\r
+ if( p_cid ) /* from client */\r
+ {\r
+ /* Validate that the length and type of the option is as required. */\r
+ if( p_cid[1] != 21 )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Client-identifier length not 21 as required.\n") );\r
+ return IB_INVALID_SETTING;\r
+ }\r
+ if( p_cid[2] != DHCP_HW_TYPE_IB )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Client-identifier type is wrong.\n") );\r
+ return IB_INVALID_SETTING;\r
+ }\r
+ /*\r
+ * Copy the GID value from the option so that we can make aligned\r
+ * accesses to the contents.\r
+ * Recover CID to standard type.\r
+ */\r
+ cl_memcpy( &gid, &p_cid[7], sizeof(ib_gid_t) );\r
+ p_cid[1] = HW_ADDR_LEN +1;// CID length \r
+ p_cid[2] = DHCP_HW_TYPE_ETH;// CID type \r
+ status = ipoib_mac_from_guid( gid.unicast.interface_id, (mac_addr_t*)&p_cid[3] );\r
+ p_cid[HW_ADDR_LEN + 3] = DHCP_OPT_END; //terminate tag\r
+ }\r
+ IPOIB_EXIT( IPOIB_DBG_RECV );\r
+ return status;\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__recv_arp(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ib_wc_t* const p_wc,\r
+ IN const ipoib_pkt_t* const p_ipoib,\r
+ OUT eth_pkt_t* const p_eth,\r
+ IN ipoib_endpt_t** const pp_src,\r
+ IN ipoib_endpt_t* const p_dst )\r
+{\r
+ ib_api_status_t status;\r
+ arp_pkt_t *p_arp;\r
+ const ipoib_arp_pkt_t *p_ib_arp;\r
+ ib_gid_t gid;\r
+ mac_addr_t mac;\r
+ ipoib_hw_addr_t null_hw = {0};\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_RECV );\r
+\r
+ if( !p_dst )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Unknown destination endpoint\n") );\r
+ return IB_INVALID_SETTING;\r
+ }\r
+\r
+ p_ib_arp = &p_ipoib->type.arp;\r
+ p_arp = &p_eth->type.arp;\r
+\r
+ if( p_ib_arp->hw_type != ARP_HW_TYPE_IB )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ARP hardware type is not IB\n") );\r
+ return IB_INVALID_SETTING;\r
+ }\r
+\r
+ if( p_ib_arp->hw_size != sizeof(ipoib_hw_addr_t) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ARP hardware address size is not sizeof(ipoib_hw_addr_t)\n") );\r
+ return IB_INVALID_SETTING;\r
+ }\r
+\r
+ if( p_ib_arp->prot_type != ETH_PROT_TYPE_IP )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ARP protocal type not IP\n") );\r
+ return IB_INVALID_SETTING;\r
+ }\r
+\r
+ /*\r
+ * If we don't have a source, lookup the endpoint specified in the payload.\r
+ */\r
+ if( !*pp_src )\r
+ *pp_src = __endpt_mgr_get_by_gid( p_port, &p_ib_arp->src_hw.gid );\r
+\r
+ /*\r
+ * If the endpoint exists for the GID, make sure\r
+ * the dlid and qpn match the arp.\r
+ */\r
+ if( *pp_src )\r
+ {\r
+ if( cl_memcmp( &(*pp_src)->dgid, &p_ib_arp->src_hw.gid,\r
+ sizeof(ib_gid_t) ) )\r
+ {\r
+ /*\r
+ * GIDs for the endpoint are different. The ARP must\r
+ * have been proxied. Dereference it.\r
+ */\r
+ *pp_src = NULL;\r
+ }\r
+ else if( (*pp_src)->dlid &&\r
+ (*pp_src)->dlid != p_wc->recv.ud.remote_lid )\r
+ {\r
+ /* Out of date! Destroy the endpoint and replace it. */\r
+ __endpt_mgr_remove( p_port, *pp_src );\r
+ *pp_src = NULL;\r
+ }\r
+ else if( ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) )\r
+ {\r
+ if( (*pp_src)->qpn !=\r
+ (p_ib_arp->src_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) &&\r
+ p_wc->recv.ud.remote_qp !=\r
+ (p_ib_arp->src_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) )\r
+ {\r
+ /* Out of date! Destroy the endpoint and replace it. */\r
+ __endpt_mgr_remove( p_port, *pp_src );\r
+ *pp_src = NULL;\r
+ }\r
+ }\r
+ else if( (*pp_src)->qpn != p_wc->recv.ud.remote_qp )\r
+ {\r
+ /* Out of date! Destroy the endpoint and replace it. */\r
+ __endpt_mgr_remove( p_port, *pp_src );\r
+ *pp_src = NULL;\r
+ }\r
+ }\r
+\r
+ /* Do we need to create an endpoint for this GID? */\r
+ if( !*pp_src )\r
+ {\r
+ /* Copy the src GID to allow aligned access */\r
+ cl_memcpy( &gid, &p_ib_arp->src_hw.gid, sizeof(ib_gid_t) );\r
+ status = ipoib_mac_from_guid( gid.unicast.interface_id, &mac );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_mac_from_guid returned %s\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+ /*\r
+ * Create the endpoint. Note that the LID is left blank and will be\r
+ * resolved by a path query as needed. This is done because the\r
+ * remote LID/GID from the work completion may not be the original\r
+ * initiator.\r
+ */\r
+ *pp_src = ipoib_endpt_create( &p_ib_arp->src_hw.gid,\r
+ 0, (p_ib_arp->src_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) );\r
+\r
+ if( !*pp_src )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_endpt_create failed\n") );\r
+ return status;\r
+ }\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+ status = __endpt_mgr_insert( p_port, mac, *pp_src );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ cl_obj_unlock( &p_port->obj );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__endpt_mgr_insert return %s \n",\r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ cl_obj_unlock( &p_port->obj );\r
+ }\r
+\r
+ CL_ASSERT( !cl_memcmp(\r
+ &(*pp_src)->dgid, &p_ib_arp->src_hw.gid, sizeof(ib_gid_t) ) );\r
+ CL_ASSERT( ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) ||\r
+ (*pp_src)->qpn ==\r
+ (p_ib_arp->src_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) );\r
+ /* Now swizzle the data. */\r
+ p_arp->hw_type = ARP_HW_TYPE_ETH;\r
+ p_arp->hw_size = sizeof(mac_addr_t);\r
+ p_arp->src_hw = (*pp_src)->mac;\r
+ p_arp->src_ip = p_ib_arp->src_ip;\r
+\r
+ if( cl_memcmp( &p_ib_arp->dst_hw, &null_hw, sizeof(ipoib_hw_addr_t) ) )\r
+ {\r
+ if( cl_memcmp( &p_dst->dgid, &p_ib_arp->dst_hw.gid, sizeof(ib_gid_t) ) )\r
+ {\r
+ /*\r
+ * We received bcast ARP packet that means\r
+ * remote port lets everyone know it was changed IP/MAC\r
+ * or just activated\r
+ */\r
+\r
+ /* Guy: TODO: Check why this check fails in case of Voltaire IPR */\r
+\r
+ if ( !ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) &&\r
+ !ib_gid_is_multicast( (const ib_gid_t*)&p_dst->dgid ) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ARP: is not ARP MCAST\n") );\r
+ return IB_INVALID_SETTING;\r
+ }\r
+\r
+ p_arp->dst_hw = p_port->p_local_endpt->mac;\r
+ p_dst->mac = p_port->p_local_endpt->mac;\r
+ /*\r
+ * we don't care what receiver ip addr is,\r
+ * as long as OS' ARP table is global ???\r
+ */\r
+ p_arp->dst_ip = (net32_t)0;\r
+ }\r
+ else /* we've got reply to our ARP request */\r
+ {\r
+ p_arp->dst_hw = p_dst->mac;\r
+ p_arp->dst_ip = p_ib_arp->dst_ip;\r
+ CL_ASSERT( p_dst->qpn == \r
+ (p_ib_arp->dst_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) );\r
+ }\r
+ }\r
+ else /* we got ARP reqeust */\r
+ {\r
+ cl_memclr( &p_arp->dst_hw, sizeof(mac_addr_t) );\r
+ p_arp->dst_ip = p_ib_arp->dst_ip;\r
+ }\r
+\r
+ /*\r
+ * Create the ethernet header. Note that this is done last so that\r
+ * we have a chance to create a new endpoint.\r
+ */\r
+ status = __recv_gen( p_ipoib, p_eth, *pp_src, p_dst );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__recv_gen returned %s.\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_RECV );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__recv_mgr_prepare_pkt(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_recv_desc_t* const p_desc,\r
+ OUT NDIS_PACKET** const pp_packet )\r
+{\r
+ NDIS_STATUS status;\r
+ uint32_t pkt_filter;\r
+ ip_stat_sel_t type;\r
+ NDIS_TCP_IP_CHECKSUM_PACKET_INFO chksum;\r
+ PERF_DECLARE( GetNdisPkt );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_RECV );\r
+\r
+ pkt_filter = p_port->p_adapter->packet_filter;\r
+ /* Check the packet filter. */\r
+ switch( p_desc->type )\r
+ {\r
+ default:\r
+ case PKT_TYPE_UCAST:\r
+ if( pkt_filter & NDIS_PACKET_TYPE_PROMISCUOUS ||\r
+ pkt_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL ||\r
+ pkt_filter & NDIS_PACKET_TYPE_SOURCE_ROUTING ||\r
+ pkt_filter & NDIS_PACKET_TYPE_DIRECTED )\r
+ {\r
+ /* OK to report. */\r
+ type = IP_STAT_UCAST_BYTES;\r
+ status = NDIS_STATUS_SUCCESS;\r
+ }\r
+ else\r
+ {\r
+ type = IP_STAT_DROPPED;\r
+ status = NDIS_STATUS_FAILURE;\r
+ }\r
+ break;\r
+ case PKT_TYPE_BCAST:\r
+ if( pkt_filter & NDIS_PACKET_TYPE_PROMISCUOUS ||\r
+ pkt_filter & NDIS_PACKET_TYPE_BROADCAST )\r
+ {\r
+ /* OK to report. */\r
+ type = IP_STAT_BCAST_BYTES;\r
+ status = NDIS_STATUS_SUCCESS;\r
+ }\r
+ else\r
+ {\r
+ type = IP_STAT_DROPPED;\r
+ status = NDIS_STATUS_FAILURE;\r
+ }\r
+ break;\r
+ case PKT_TYPE_MCAST:\r
+ if( pkt_filter & NDIS_PACKET_TYPE_PROMISCUOUS ||\r
+ pkt_filter & NDIS_PACKET_TYPE_ALL_MULTICAST ||\r
+ pkt_filter & NDIS_PACKET_TYPE_MULTICAST )\r
+ {\r
+ /* OK to report. */\r
+ type = IP_STAT_MCAST_BYTES;\r
+ status = NDIS_STATUS_SUCCESS;\r
+ }\r
+ else\r
+ {\r
+ type = IP_STAT_DROPPED;\r
+ status = NDIS_STATUS_FAILURE;\r
+ }\r
+ break;\r
+ }\r
+\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ ipoib_inc_recv_stat( p_port->p_adapter, type, 0 );\r
+ /* Return the receive descriptor to the pool. */\r
+ __buf_mgr_put_recv( p_port, p_desc, NULL );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
+ ("Packet filter doesn't match receive. Dropping.\n") );\r
+ /*\r
+ * Return IB_NOT_DONE since the packet has been completed,\r
+ * but has not consumed an array entry.\r
+ */\r
+ return IB_NOT_DONE;\r
+ }\r
+\r
+ cl_perf_start( GetNdisPkt );\r
+ *pp_packet = __buf_mgr_get_ndis_pkt( p_port, p_desc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, GetNdisPkt );\r
+ if( !*pp_packet )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__buf_mgr_get_ndis_pkt failed\n") );\r
+ return IB_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ /* Flag the checksums as having been calculated. */\r
+ chksum.Value = 0;\r
+ chksum.Receive.NdisPacketTcpChecksumSucceeded = TRUE;\r
+ chksum.Receive.NdisPacketUdpChecksumSucceeded = TRUE;\r
+ chksum.Receive.NdisPacketIpChecksumSucceeded = TRUE;\r
+ NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) =\r
+ (void*)(uintn_t)chksum.Value;\r
+\r
+ ipoib_inc_recv_stat( p_port->p_adapter, type, p_desc->len );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_RECV );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+static uint32_t\r
+__recv_mgr_build_pkt_array(\r
+ IN ipoib_port_t* const p_port,\r
+ IN int32_t shortage,\r
+ OUT cl_qlist_t* const p_done_list,\r
+ OUT int32_t* const p_discarded )\r
+{\r
+ cl_list_item_t *p_item;\r
+ ipoib_recv_desc_t *p_desc;\r
+ uint32_t i = 0;\r
+ ib_api_status_t status;\r
+ PERF_DECLARE( PreparePkt );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_RECV );\r
+\r
+ *p_discarded = 0;\r
+\r
+ /* Move any existing receives to the head to preserve ordering. */\r
+ cl_qlist_insert_list_head( p_done_list, &p_port->recv_mgr.done_list );\r
+ p_item = cl_qlist_remove_head( p_done_list );\r
+ while( p_item != cl_qlist_end( p_done_list ) )\r
+ {\r
+ p_desc = (ipoib_recv_desc_t*)p_item;\r
+\r
+ cl_perf_start( PreparePkt );\r
+ status = __recv_mgr_prepare_pkt( p_port, p_desc,\r
+ &p_port->recv_mgr.recv_pkt_array[i] );\r
+ cl_perf_stop( &p_port->p_adapter->perf, PreparePkt );\r
+ if( status == IB_SUCCESS )\r
+ {\r
+ CL_ASSERT( p_port->recv_mgr.recv_pkt_array[i] );\r
+ if( shortage-- > 0 )\r
+ {\r
+ NDIS_SET_PACKET_STATUS(\r
+ p_port->recv_mgr.recv_pkt_array[i], NDIS_STATUS_RESOURCES );\r
+ }\r
+ else\r
+ {\r
+ NDIS_SET_PACKET_STATUS(\r
+ p_port->recv_mgr.recv_pkt_array[i], NDIS_STATUS_SUCCESS );\r
+ }\r
+ i++;\r
+ }\r
+ else if( status == IB_NOT_DONE )\r
+ {\r
+ (*p_discarded)++;\r
+ }\r
+ else\r
+ {\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
+ ("__recv_mgr_prepare_pkt returned %s\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ /* Put all completed receives on the port's done list. */\r
+ cl_qlist_insert_tail( &p_port->recv_mgr.done_list, p_item );\r
+ cl_qlist_insert_list_tail( &p_port->recv_mgr.done_list, p_done_list );\r
+ break;\r
+ }\r
+\r
+ p_item = cl_qlist_remove_head( p_done_list );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_RECV );\r
+ return i;\r
+}\r
+\r
+\r
+\r
+\r
+/******************************************************************************\r
+*\r
+* Send manager implementation.\r
+*\r
+******************************************************************************/\r
+static void\r
+__send_mgr_construct(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+ p_port->send_mgr.depth = 0;\r
+ cl_qlist_init( &p_port->send_mgr.pending_list );\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+}\r
+\r
+\r
+static void \r
+__pending_list_destroy(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ cl_list_item_t *p_item;\r
+ NDIS_PACKET *p_packet;\r
+ \r
+ cl_spinlock_acquire( &p_port->send_lock );\r
+ /* Complete any pending packets. */\r
+ for( p_item = cl_qlist_remove_head( &p_port->send_mgr.pending_list );\r
+ p_item != cl_qlist_end( &p_port->send_mgr.pending_list );\r
+ p_item = cl_qlist_remove_head( &p_port->send_mgr.pending_list ) )\r
+ {\r
+ p_packet = IPOIB_PACKET_FROM_LIST_ITEM( p_item );\r
+ NdisMSendComplete( p_port->p_adapter->h_adapter, p_packet,\r
+ NDIS_STATUS_RESET_IN_PROGRESS );\r
+ }\r
+ cl_spinlock_release( &p_port->send_lock );\r
+}\r
+\r
+static void\r
+__send_mgr_destroy(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+ __pending_list_destroy(p_port);\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+}\r
+\r
+\r
+static NDIS_STATUS\r
+__send_mgr_filter(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const eth_hdr_t* const p_eth_hdr,\r
+ IN NDIS_BUFFER* const p_buf,\r
+ IN size_t buf_len,\r
+ IN OUT ipoib_send_desc_t* const p_desc )\r
+{\r
+ NDIS_STATUS status;\r
+\r
+ PERF_DECLARE( FilterIp );\r
+ PERF_DECLARE( FilterArp );\r
+ PERF_DECLARE( SendGen );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ /*\r
+ * We already checked the ethernet header length, so we know it's safe\r
+ * to decrement the buf_len without underflowing.\r
+ */\r
+ buf_len -= sizeof(eth_hdr_t);\r
+\r
+ switch( p_eth_hdr->type )\r
+ {\r
+ case ETH_PROT_TYPE_IP:\r
+ cl_perf_start( FilterIp );\r
+ status = __send_mgr_filter_ip(\r
+ p_port, p_eth_hdr, p_buf, buf_len, p_desc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, FilterIp );\r
+ break;\r
+\r
+ case ETH_PROT_TYPE_ARP:\r
+ cl_perf_start( FilterArp );\r
+ status = __send_mgr_filter_arp(\r
+ p_port, p_eth_hdr, p_buf, buf_len, p_desc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, FilterArp );\r
+ break;\r
+\r
+ default:\r
+ /*\r
+ * The IPoIB spec doesn't define how to send non IP or ARP packets.\r
+ * Just send the payload and hope for the best.\r
+ */\r
+ cl_perf_start( SendGen );\r
+ status = __send_gen( p_port, p_desc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, SendGen );\r
+ break;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return status;\r
+}\r
+\r
+\r
+static NDIS_STATUS\r
+__send_copy(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_send_desc_t* const p_desc )\r
+{\r
+ NDIS_PACKET *p_packet;\r
+ NDIS_BUFFER *p_buf;\r
+ NDIS_STATUS status;\r
+ UINT tot_len, bytes_copied = 0;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ p_desc->p_buf = \r
+ ExAllocateFromNPagedLookasideList( &p_port->buf_mgr.send_buf_list );\r
+ if( !p_desc->p_buf )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to allocate buffer for packet copy.\n") );\r
+ return NDIS_STATUS_RESOURCES;\r
+ }\r
+\r
+ NdisAllocatePacket( &status, &p_packet, p_port->buf_mgr.h_send_pkt_pool );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND,\r
+ ("Failed to allocate NDIS_PACKET for copy.\n") );\r
+ return status;\r
+ }\r
+\r
+ NdisAllocateBuffer( &status, &p_buf, p_port->buf_mgr.h_send_buf_pool,\r
+ p_desc->p_buf, p_port->p_adapter->params.xfer_block_size );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ NdisFreePacket( p_packet );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND,\r
+ ("Failed to allocate NDIS_BUFFER for copy.\n") );\r
+ return status;\r
+ }\r
+\r
+ NdisChainBufferAtFront( p_packet, p_buf );\r
+\r
+ NdisQueryPacketLength( p_desc->p_pkt, &tot_len );\r
+\r
+ /* Setup the work request. */\r
+ p_desc->local_ds[1].vaddr = cl_get_physaddr(\r
+ ((uint8_t*)p_desc->p_buf) + sizeof(eth_hdr_t) );\r
+ p_desc->local_ds[1].length = tot_len - sizeof(eth_hdr_t);\r
+ p_desc->local_ds[1].lkey = p_port->ib_mgr.lkey;\r
+ p_desc->wr.num_ds = 2;\r
+\r
+ /* Copy the packet. */\r
+ NdisCopyFromPacketToPacketSafe( p_packet, bytes_copied, tot_len,\r
+ p_desc->p_pkt, bytes_copied, &bytes_copied,\r
+ NormalPagePriority );\r
+\r
+ /* Free our temp packet now that the data is copied. */\r
+ NdisUnchainBufferAtFront( p_packet, &p_buf );\r
+ NdisFreeBuffer( p_buf );\r
+ NdisFreePacket( p_packet );\r
+\r
+ if( bytes_copied != tot_len )\r
+ {\r
+ /* Something went wrong. Drop the packet. */\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to copy full packet: %d of %d bytes copied.\n",\r
+ bytes_copied, tot_len) );\r
+ return NDIS_STATUS_RESOURCES;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+#if !IPOIB_USE_DMA\r
+/* Send using the MDL's page information rather than the SGL. */\r
+static ib_api_status_t\r
+__send_gen(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_send_desc_t* const p_desc )\r
+{\r
+ uint32_t i, j = 1;\r
+ ULONG offset;\r
+ MDL *p_mdl;\r
+ UINT num_pages, tot_len;\r
+ ULONG buf_len;\r
+ PPFN_NUMBER page_array;\r
+ boolean_t hdr_done = FALSE;\r
+ ib_api_status_t status;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ NdisQueryPacket( p_desc->p_pkt, &num_pages, NULL, &p_mdl,\r
+ &tot_len );\r
+\r
+ if( !p_mdl )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("No buffers associated with packet.\n") );\r
+ return IB_ERROR;\r
+ }\r
+\r
+ /* Remember that one of the DS entries is reserved for the IPoIB header. */\r
+ if( num_pages >= MAX_SEND_SGE )\r
+ {\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND,\r
+ ("Too many buffers to fit in WR ds_array. Copying data.\n") );\r
+ status = __send_copy( p_port, p_desc );\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return status;\r
+ }\r
+\r
+ CL_ASSERT( tot_len > sizeof(eth_hdr_t) );\r
+ CL_ASSERT( tot_len <= p_port->p_adapter->params.xfer_block_size );\r
+ /*\r
+ * Assume that the ethernet header is always fully contained\r
+ * in the first page of the first MDL. This makes for much\r
+ * simpler code.\r
+ */\r
+ offset = MmGetMdlByteOffset( p_mdl ) + sizeof(eth_hdr_t);\r
+ CL_ASSERT( offset <= PAGE_SIZE );\r
+\r
+ while( tot_len )\r
+ {\r
+ buf_len = MmGetMdlByteCount( p_mdl );\r
+ page_array = MmGetMdlPfnArray( p_mdl );\r
+ CL_ASSERT( page_array );\r
+ i = 0;\r
+ if( !hdr_done )\r
+ {\r
+ CL_ASSERT( buf_len >= sizeof(eth_hdr_t) );\r
+ /* Skip the ethernet header. */\r
+ buf_len -= sizeof(eth_hdr_t);\r
+ CL_ASSERT( buf_len <= p_port->p_adapter->params.payload_mtu );\r
+ if( buf_len )\r
+ {\r
+ /* The ethernet header is a subset of this MDL. */\r
+ CL_ASSERT( i == 0 );\r
+ if( offset < PAGE_SIZE )\r
+ {\r
+ p_desc->local_ds[j].lkey = p_port->ib_mgr.lkey;\r
+ p_desc->local_ds[j].vaddr = (page_array[i] << PAGE_SHIFT);\r
+ /* Add the byte offset since we're on the 1st page. */\r
+ p_desc->local_ds[j].vaddr += offset;\r
+ if( offset + buf_len > PAGE_SIZE )\r
+ {\r
+ p_desc->local_ds[j].length = PAGE_SIZE - offset;\r
+ buf_len -= p_desc->local_ds[j].length;\r
+ }\r
+ else\r
+ {\r
+ p_desc->local_ds[j].length = buf_len;\r
+ buf_len = 0;\r
+ }\r
+ /* This data segment is done. Move to the next. */\r
+ j++;\r
+ }\r
+ /* This page is done. Move to the next. */\r
+ i++;\r
+ }\r
+ /* Done handling the ethernet header. */\r
+ hdr_done = TRUE;\r
+ }\r
+\r
+ /* Finish this MDL */\r
+ while( buf_len )\r
+ {\r
+ p_desc->local_ds[j].lkey = p_port->ib_mgr.lkey;\r
+ p_desc->local_ds[j].vaddr = (page_array[i] << PAGE_SHIFT);\r
+ /* Add the first page's offset if we're on the first page. */\r
+ if( i == 0 )\r
+ p_desc->local_ds[j].vaddr += MmGetMdlByteOffset( p_mdl );\r
+\r
+ if( i == 0 && (MmGetMdlByteOffset( p_mdl ) + buf_len) > PAGE_SIZE )\r
+ {\r
+ /* Buffers spans pages. */\r
+ p_desc->local_ds[j].length =\r
+ PAGE_SIZE - MmGetMdlByteOffset( p_mdl );\r
+ buf_len -= p_desc->local_ds[j].length;\r
+ /* This page is done. Move to the next. */\r
+ i++;\r
+ }\r
+ else\r
+ {\r
+ /* Last page of the buffer. */\r
+ p_desc->local_ds[j].length = buf_len;\r
+ buf_len = 0;\r
+ }\r
+ /* This data segment is done. Move to the next. */\r
+ j++;\r
+ }\r
+\r
+ tot_len -= MmGetMdlByteCount( p_mdl );\r
+ if( !tot_len )\r
+ break;\r
+\r
+ NdisGetNextBuffer( p_mdl, &p_mdl );\r
+ if( !p_mdl )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to get next buffer.\n") );\r
+ return IB_ERROR;\r
+ }\r
+ }\r
+\r
+ /* Set the number of data segments. */\r
+ p_desc->wr.num_ds = j;\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+#else\r
+\r
+static NDIS_STATUS\r
+__send_gen(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_send_desc_t* const p_desc )\r
+{\r
+ ib_api_status_t status;\r
+ SCATTER_GATHER_LIST *p_sgl;\r
+ uint32_t i, j = 1;\r
+ uint32_t offset = sizeof(eth_hdr_t);\r
+ PERF_DECLARE( SendCopy );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ p_sgl = NDIS_PER_PACKET_INFO_FROM_PACKET( p_desc->p_pkt,\r
+ ScatterGatherListPacketInfo );\r
+ if( !p_sgl )\r
+ {\r
+ ASSERT( p_sgl );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to get SGL from packet.\n") );\r
+ return NDIS_STATUS_FAILURE;\r
+ }\r
+\r
+ /* Remember that one of the DS entries is reserved for the IPoIB header. */\r
+ if( ( p_sgl->NumberOfElements >= MAX_SEND_SGE &&\r
+ p_sgl->Elements[0].Length > sizeof(eth_hdr_t)) ||\r
+ ( p_sgl->NumberOfElements > MAX_SEND_SGE &&\r
+ p_sgl->Elements[0].Length <= sizeof(eth_hdr_t)) )\r
+ {\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND,\r
+ ("Too many buffers to fit in WR ds_array. Copying data.\n") );\r
+ cl_perf_start( SendCopy );\r
+ status = __send_copy( p_port, p_desc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, SendCopy );\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return status;\r
+ }\r
+\r
+ /*\r
+ * Skip the ethernet header. It is either the first element,\r
+ * or part of it.\r
+ */\r
+ i = 0;\r
+ while( offset )\r
+ {\r
+ if( p_sgl->Elements[i].Length <= sizeof(eth_hdr_t) )\r
+ {\r
+ offset -= p_sgl->Elements[i++].Length;\r
+ }\r
+ else\r
+ {\r
+ p_desc->local_ds[j].vaddr =\r
+ p_sgl->Elements[i].Address.QuadPart + offset;\r
+ p_desc->local_ds[j].length =\r
+ p_sgl->Elements[i].Length - offset;\r
+ p_desc->local_ds[j].lkey = p_port->ib_mgr.lkey;\r
+ i++;\r
+ j++;\r
+ break;\r
+ }\r
+ }\r
+ /* Now fill in the rest of the local data segments. */\r
+ while( i < p_sgl->NumberOfElements )\r
+ {\r
+ p_desc->local_ds[j].vaddr = p_sgl->Elements[i].Address.QuadPart;\r
+ p_desc->local_ds[j].length = p_sgl->Elements[i].Length;\r
+ p_desc->local_ds[j].lkey = p_port->ib_mgr.lkey;\r
+ i++;\r
+ j++;\r
+ }\r
+\r
+ /* Set the number of data segments. */\r
+ p_desc->wr.num_ds = j;\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+#endif\r
+\r
+\r
+static NDIS_STATUS\r
+__send_mgr_filter_ip(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const eth_hdr_t* const p_eth_hdr,\r
+ IN NDIS_BUFFER* p_buf,\r
+ IN size_t buf_len,\r
+ IN OUT ipoib_send_desc_t* const p_desc )\r
+{\r
+ NDIS_STATUS status;\r
+ ip_hdr_t *p_ip_hdr;\r
+\r
+ PERF_DECLARE( QueryIp );\r
+ PERF_DECLARE( SendTcp );\r
+ PERF_DECLARE( FilterUdp );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ if( !buf_len )\r
+ {\r
+ cl_perf_start( QueryIp );\r
+ NdisGetNextBuffer( p_buf, &p_buf );\r
+ if( !p_buf )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to get IP header buffer.\n") );\r
+ return NDIS_STATUS_FAILURE;\r
+ }\r
+ NdisQueryBufferSafe( p_buf, &p_ip_hdr, &buf_len, NormalPagePriority );\r
+ if( !p_ip_hdr )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to query IP header buffer.\n") );\r
+ return NDIS_STATUS_FAILURE;\r
+ }\r
+ cl_perf_stop( &p_port->p_adapter->perf, QueryIp );\r
+ }\r
+ else\r
+ {\r
+ p_ip_hdr = (ip_hdr_t*)(p_eth_hdr + 1);\r
+ }\r
+ if( buf_len < sizeof(ip_hdr_t) )\r
+ {\r
+ /* This buffer is done for. Get the next buffer. */\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Buffer too small for IP packet.\n") );\r
+ return NDIS_STATUS_BUFFER_TOO_SHORT;\r
+ }\r
+\r
+ if( p_ip_hdr->offset ||\r
+ p_ip_hdr->prot != IP_PROT_UDP )\r
+ {\r
+ /* Not a UDP packet. */\r
+ cl_perf_start( SendTcp );\r
+ status = __send_gen( p_port, p_desc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, SendTcp );\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return status;\r
+ }\r
+\r
+ buf_len -= sizeof(ip_hdr_t);\r
+\r
+ cl_perf_start( FilterUdp );\r
+ status = __send_mgr_filter_udp(\r
+ p_port, p_ip_hdr, p_buf, buf_len, p_desc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, FilterUdp );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return status;\r
+}\r
+\r
+\r
+static NDIS_STATUS\r
+__send_mgr_filter_udp(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const ip_hdr_t* const p_ip_hdr,\r
+ IN NDIS_BUFFER* p_buf,\r
+ IN size_t buf_len,\r
+ IN OUT ipoib_send_desc_t* const p_desc )\r
+{\r
+ ib_api_status_t status;\r
+ udp_hdr_t *p_udp_hdr;\r
+ PERF_DECLARE( QueryUdp );\r
+ PERF_DECLARE( SendUdp );\r
+ PERF_DECLARE( FilterDhcp );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ if( !buf_len )\r
+ {\r
+ cl_perf_start( QueryUdp );\r
+ NdisGetNextBuffer( p_buf, &p_buf );\r
+ if( !p_buf )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to get UDP header buffer.\n") );\r
+ return NDIS_STATUS_FAILURE;\r
+ }\r
+ NdisQueryBufferSafe( p_buf, &p_udp_hdr, &buf_len, NormalPagePriority );\r
+ if( !p_udp_hdr )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to query UDP header buffer.\n") );\r
+ return NDIS_STATUS_FAILURE;\r
+ }\r
+ cl_perf_stop( &p_port->p_adapter->perf, QueryUdp );\r
+ }\r
+ else\r
+ {\r
+ p_udp_hdr = (udp_hdr_t*)(p_ip_hdr + 1);\r
+ }\r
+ /* Get the UDP header and check the destination port numbers. */\r
+ if( buf_len < sizeof(udp_hdr_t) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Buffer not large enough for UDP packet.\n") );\r
+ return NDIS_STATUS_BUFFER_TOO_SHORT;\r
+ }\r
+\r
+ if( (p_udp_hdr->src_port != DHCP_PORT_CLIENT ||\r
+ p_udp_hdr->dst_port != DHCP_PORT_SERVER) &&\r
+ (p_udp_hdr->src_port != DHCP_PORT_SERVER ||\r
+ p_udp_hdr->dst_port != DHCP_PORT_CLIENT) )\r
+ {\r
+ /* Not a DHCP packet. */\r
+ cl_perf_start( SendUdp );\r
+ status = __send_gen( p_port, p_desc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, SendUdp );\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return status;\r
+ }\r
+\r
+ buf_len -= sizeof(udp_hdr_t);\r
+\r
+ /* Allocate our scratch buffer. */\r
+ p_desc->p_buf = (send_buf_t*)\r
+ ExAllocateFromNPagedLookasideList( &p_port->buf_mgr.send_buf_list );\r
+ if( !p_desc->p_buf )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to query DHCP packet buffer.\n") );\r
+ return NDIS_STATUS_RESOURCES;\r
+ }\r
+ /* Copy the IP and UDP headers. */\r
+ cl_memcpy( &p_desc->p_buf->ip.hdr, p_ip_hdr , sizeof(ip_hdr_t) );\r
+ cl_memcpy(\r
+ &p_desc->p_buf->ip.prot.udp.hdr, p_udp_hdr, sizeof(udp_hdr_t) );\r
+\r
+ cl_perf_start( FilterDhcp );\r
+ status = __send_mgr_filter_dhcp(\r
+ p_port, p_udp_hdr, p_buf, buf_len, p_desc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, FilterDhcp );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return status;\r
+}\r
+\r
+\r
+static NDIS_STATUS\r
+__send_mgr_filter_dhcp(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const udp_hdr_t* const p_udp_hdr,\r
+ IN NDIS_BUFFER* p_buf,\r
+ IN size_t buf_len,\r
+ IN OUT ipoib_send_desc_t* const p_desc )\r
+{\r
+ dhcp_pkt_t *p_dhcp;\r
+ dhcp_pkt_t *p_ib_dhcp;\r
+ uint8_t *p_option, *p_cid = NULL;\r
+ uint8_t msg = 0;\r
+ size_t len;\r
+ ib_gid_t gid;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ if( !buf_len )\r
+ {\r
+ NdisGetNextBuffer( p_buf, &p_buf );\r
+ if( !p_buf )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to get DHCP buffer.\n") );\r
+ return NDIS_STATUS_FAILURE;\r
+ }\r
+ NdisQueryBufferSafe( p_buf, &p_dhcp, &buf_len, NormalPagePriority );\r
+ if( !p_dhcp )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to query DHCP buffer.\n") );\r
+ return NDIS_STATUS_FAILURE;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ p_dhcp = (dhcp_pkt_t*)(p_udp_hdr + 1);\r
+ }\r
+\r
+ if( buf_len < DHCP_MIN_SIZE )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Buffer not large enough for DHCP packet.\n") );\r
+ return NDIS_STATUS_BUFFER_TOO_SHORT;\r
+ }\r
+\r
+ p_ib_dhcp = &p_desc->p_buf->ip.prot.udp.dhcp;\r
+ cl_memcpy( p_ib_dhcp, p_dhcp, buf_len );\r
+\r
+ /* Now scan through the options looking for the client identifier. */\r
+ p_option = &p_ib_dhcp->options[4];\r
+ while( *p_option != DHCP_OPT_END && p_option < &p_ib_dhcp->options[312] )\r
+ {\r
+ switch( *p_option )\r
+ {\r
+ case DHCP_OPT_PAD:\r
+ p_option++;\r
+ break;\r
+\r
+ case DHCP_OPT_MSG:\r
+ msg = p_option[2];\r
+ p_option += 3;\r
+ break;\r
+\r
+ case DHCP_OPT_CLIENT_ID:\r
+ p_cid = p_option;\r
+ /* Fall through. */\r
+\r
+ default:\r
+ /*\r
+ * All other options have a length byte following the option code.\r
+ * Offset by the length to get to the next option.\r
+ */\r
+ p_option += (p_option[1] + 2);\r
+ }\r
+ }\r
+\r
+ switch( msg )\r
+ {\r
+ /* Client messages */\r
+ case DHCPDISCOVER:\r
+ case DHCPREQUEST:\r
+ p_ib_dhcp->flags |= DHCP_FLAGS_BROADCAST;\r
+ /* Fall through */\r
+ case DHCPDECLINE:\r
+ case DHCPRELEASE:\r
+ case DHCPINFORM:\r
+ /* Fix up the client identifier option */\r
+ if( p_cid )\r
+ {\r
+ /* do we need to replace it ? len eq ETH MAC sz 'and' MAC is mine */\r
+ if( p_cid[1] == HW_ADDR_LEN+1 && !cl_memcmp( &p_cid[3],\r
+ &p_port->p_adapter->params.conf_mac.addr, HW_ADDR_LEN ) )\r
+ {\r
+ /* Make sure there's room to extend it. 23 is the size of\r
+ * the CID option for IPoIB.\r
+ */\r
+ if( buf_len + 23 - p_cid[1] > sizeof(dhcp_pkt_t) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Can't convert CID to IPoIB format.\n") );\r
+ return IB_INSUFFICIENT_MEMORY;\r
+ }\r
+ /* Move the existing options down, and add a new CID option */\r
+ len = p_option - ( p_cid + p_cid[1] + 2 );\r
+ p_option = p_cid + p_cid[1] + 2;\r
+ RtlMoveMemory( p_cid, p_option, len );\r
+ \r
+ p_cid += len;\r
+ p_cid[0] = DHCP_OPT_CLIENT_ID;\r
+ p_cid[1] = 21;\r
+ p_cid[2] = DHCP_HW_TYPE_IB;\r
+ }\r
+ else\r
+ {\r
+ p_cid[2] = DHCP_HW_TYPE_IB;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /*\r
+ * Make sure there's room to extend it. 23 is the size of\r
+ * the CID option for IPoIB.\r
+ */\r
+ if( buf_len + 23 > sizeof(dhcp_pkt_t) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Can't convert CID to IPoIB format.\n") );\r
+ return NDIS_STATUS_RESOURCES;\r
+ }\r
+\r
+ p_cid = p_option;\r
+ p_option = p_cid + 23;\r
+ p_option[0] = DHCP_OPT_END;\r
+ p_cid[0] = DHCP_OPT_CLIENT_ID;\r
+ p_cid[1] = 21;\r
+ p_cid[2] = DHCP_HW_TYPE_IB;\r
+ }\r
+\r
+ CL_ASSERT( p_cid[1] == 21 );\r
+ p_cid[23]= DHCP_OPT_END;\r
+ ib_gid_set_default( &gid, p_port->p_adapter->guids.port_guid );\r
+ cl_memcpy( &p_cid[7], &gid, sizeof(ib_gid_t) );\r
+ cl_memcpy( &p_cid[3], &p_port->ib_mgr.qpn, sizeof(p_port->ib_mgr.qpn) ); \r
+ p_ib_dhcp->htype = DHCP_HW_TYPE_IB;\r
+ break;\r
+\r
+ /* Server messages. */\r
+ case DHCPOFFER:\r
+ case DHCPACK:\r
+ case DHCPNAK:\r
+ /* don't touch server messages */\r
+ break;\r
+\r
+ default:\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Invalide message type.\n") );\r
+ return NDIS_STATUS_INVALID_DATA;\r
+ }\r
+ /* no chksum for udp */\r
+ p_desc->p_buf->ip.prot.udp.hdr.chksum = 0;\r
+ p_desc->local_ds[1].vaddr = cl_get_physaddr( p_desc->p_buf );\r
+ p_desc->local_ds[1].length = sizeof(ip_hdr_t) + sizeof(udp_hdr_t) + sizeof(dhcp_pkt_t);\r
+ p_desc->local_ds[1].lkey = p_port->ib_mgr.lkey;\r
+ p_desc->wr.num_ds = 2;\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NDIS_STATUS\r
+__send_mgr_filter_arp(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const eth_hdr_t* const p_eth_hdr,\r
+ IN NDIS_BUFFER* p_buf,\r
+ IN size_t buf_len,\r
+ IN OUT ipoib_send_desc_t* const p_desc )\r
+{\r
+ arp_pkt_t *p_arp;\r
+ ipoib_arp_pkt_t *p_ib_arp;\r
+ NDIS_STATUS status;\r
+ mac_addr_t null_hw = {0};\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ if( !buf_len )\r
+ {\r
+ NdisGetNextBuffer( p_buf, &p_buf );\r
+ if( !p_buf )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to get ARP buffer.\n") );\r
+ return NDIS_STATUS_FAILURE;\r
+ }\r
+ NdisQueryBufferSafe( p_buf, &p_arp, &buf_len, NormalPagePriority );\r
+ if( !p_arp )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to get query ARP buffer.\n") );\r
+ return NDIS_STATUS_FAILURE;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ p_arp = (arp_pkt_t*)(p_eth_hdr + 1);\r
+ }\r
+\r
+ /* Single buffer ARP packet. */\r
+ if( buf_len < sizeof(arp_pkt_t) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Buffer too short for ARP.\n") );\r
+ return NDIS_STATUS_BUFFER_TOO_SHORT;\r
+ }\r
+\r
+ if( p_arp->prot_type != ETH_PROT_TYPE_IP )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Unsupported protocol type.\n") );\r
+ return NDIS_STATUS_INVALID_DATA;\r
+ }\r
+\r
+ /* Allocate our scratch buffer. */\r
+ p_desc->p_buf = (send_buf_t*)\r
+ ExAllocateFromNPagedLookasideList( &p_port->buf_mgr.send_buf_list );\r
+ if( !p_desc->p_buf )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to query ARP packet buffer.\n") );\r
+ return NDIS_STATUS_RESOURCES;\r
+ }\r
+ p_ib_arp = (ipoib_arp_pkt_t*)p_desc->p_buf;\r
+\r
+ /* Convert the ARP payload. */\r
+ p_ib_arp->hw_type = ARP_HW_TYPE_IB;\r
+ p_ib_arp->prot_type = p_arp->prot_type;\r
+ p_ib_arp->hw_size = sizeof(ipoib_hw_addr_t);\r
+ p_ib_arp->prot_size = p_arp->prot_size;\r
+ p_ib_arp->op = p_arp->op;\r
+ p_ib_arp->src_hw.flags_qpn = p_port->ib_mgr.qpn;\r
+ ib_gid_set_default( &p_ib_arp->src_hw.gid,\r
+ p_port->p_adapter->guids.port_guid );\r
+ p_ib_arp->src_ip = p_arp->src_ip;\r
+ if( cl_memcmp( &p_arp->dst_hw, &null_hw, sizeof(mac_addr_t) ) )\r
+ {\r
+ /* Get the endpoint referenced by the dst_hw address. */\r
+ status = __endpt_mgr_get_gid_qpn( p_port, p_arp->dst_hw,\r
+ &p_ib_arp->dst_hw.gid, &p_ib_arp->dst_hw.flags_qpn );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed lookup of destination HW address\n") );\r
+ return status;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ cl_memclr( &p_ib_arp->dst_hw, sizeof(ipoib_hw_addr_t) );\r
+ }\r
+ p_ib_arp->dst_ip = p_arp->dst_ip;\r
+\r
+ p_desc->local_ds[1].vaddr = cl_get_physaddr( p_ib_arp );\r
+ p_desc->local_ds[1].length = sizeof(ipoib_arp_pkt_t);\r
+ p_desc->local_ds[1].lkey = p_port->ib_mgr.lkey;\r
+ p_desc->wr.num_ds = 2;\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static inline NDIS_STATUS\r
+__send_mgr_get_eth_hdr(\r
+ IN NDIS_PACKET* const p_packet,\r
+ OUT NDIS_BUFFER** const pp_buf,\r
+ OUT eth_hdr_t** const pp_eth_hdr,\r
+ OUT UINT* p_buf_len )\r
+{\r
+ UINT tot_len;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ NdisGetFirstBufferFromPacketSafe(\r
+ p_packet, pp_buf, pp_eth_hdr, p_buf_len, &tot_len, NormalPagePriority );\r
+\r
+ if( !*pp_eth_hdr )\r
+ {\r
+ /* Failed to get first buffer. */\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("NdisMGetFirstBufferSafe failed.\n") );\r
+ return NDIS_STATUS_FAILURE;\r
+ }\r
+\r
+ if( *p_buf_len < sizeof(eth_hdr_t) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("First buffer in packet smaller than eth_hdr_t: %d.\n",\r
+ *p_buf_len) );\r
+ return NDIS_STATUS_BUFFER_TOO_SHORT;\r
+ }\r
+\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND,\r
+ ("Ethernet header:\n"\r
+ "\tsrc MAC: %02X-%02X-%02X-%02X-%02X-%02X\n"\r
+ "\tdst MAC: %02X-%02X-%02X-%02X-%02X-%02X\n"\r
+ "\tprotocol type: %04X\n",\r
+ (*pp_eth_hdr)->src.addr[0], (*pp_eth_hdr)->src.addr[1],\r
+ (*pp_eth_hdr)->src.addr[2], (*pp_eth_hdr)->src.addr[3],\r
+ (*pp_eth_hdr)->src.addr[4], (*pp_eth_hdr)->src.addr[5],\r
+ (*pp_eth_hdr)->dst.addr[0], (*pp_eth_hdr)->dst.addr[1],\r
+ (*pp_eth_hdr)->dst.addr[2], (*pp_eth_hdr)->dst.addr[3],\r
+ (*pp_eth_hdr)->dst.addr[4], (*pp_eth_hdr)->dst.addr[5],\r
+ cl_ntoh16( (*pp_eth_hdr)->type )) );\r
+\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static inline NDIS_STATUS\r
+__send_mgr_queue(\r
+ IN ipoib_port_t* const p_port,\r
+ IN eth_hdr_t* const p_eth_hdr,\r
+ OUT ipoib_endpt_t** const pp_endpt )\r
+{\r
+ NDIS_STATUS status;\r
+\r
+ PERF_DECLARE( GetEndpt );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ /* Check the send queue and pend the request if not empty. */\r
+ if( cl_qlist_count( &p_port->send_mgr.pending_list ) )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND,\r
+ ("Pending list not empty.\n") );\r
+ return NDIS_STATUS_PENDING;\r
+ }\r
+\r
+ /* Check the send queue and pend the request if not empty. */\r
+ if( p_port->send_mgr.depth == p_port->p_adapter->params.sq_depth )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND,\r
+ ("No available WQEs.\n") );\r
+ return NDIS_STATUS_PENDING;\r
+ }\r
+\r
+ cl_perf_start( GetEndpt );\r
+ status = __endpt_mgr_ref( p_port, p_eth_hdr->dst, pp_endpt );\r
+ cl_perf_stop( &p_port->p_adapter->perf, GetEndpt );\r
+\r
+ if( status == NDIS_STATUS_NO_ROUTE_TO_DESTINATION &&\r
+ ETH_IS_MULTICAST( p_eth_hdr->dst.addr ) )\r
+ {\r
+ if( ipoib_port_join_mcast( p_port, p_eth_hdr->dst, \r
+ IB_MC_REC_STATE_SEND_ONLY_MEMBER) == IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND,\r
+ ("Multicast Mac - trying to join.\n") );\r
+ return NDIS_STATUS_PENDING;\r
+ }\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return status;\r
+}\r
+\r
+\r
+static NDIS_STATUS\r
+__build_send_desc(\r
+ IN ipoib_port_t* const p_port,\r
+ IN eth_hdr_t* const p_eth_hdr,\r
+ IN NDIS_BUFFER* const p_buf,\r
+ IN const size_t buf_len,\r
+ IN OUT ipoib_send_desc_t* const p_desc )\r
+{\r
+ NDIS_STATUS status;\r
+ int32_t hdr_idx;\r
+\r
+ PERF_DECLARE( SendMgrFilter );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ /* Format the send descriptor. */\r
+ cl_perf_start( SendMgrFilter );\r
+ status = __send_mgr_filter(\r
+ p_port, p_eth_hdr, p_buf, buf_len, p_desc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, SendMgrFilter );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__send_mgr_filter returned 0x%08X.\n", status) );\r
+ return status;\r
+ }\r
+\r
+ /* Format the send descriptor. */\r
+ hdr_idx = cl_atomic_inc( &p_port->hdr_idx );\r
+ hdr_idx &= (p_port->p_adapter->params.sq_depth - 1);\r
+ ASSERT( hdr_idx < p_port->p_adapter->params.sq_depth );\r
+ p_port->hdr[hdr_idx].type = p_eth_hdr->type;\r
+ p_port->hdr[hdr_idx].resv = 0;\r
+\r
+ /* Setup the first local data segment (used for the IPoIB header). */\r
+ p_desc->local_ds[0].vaddr = cl_get_physaddr( &p_port->hdr[hdr_idx] );\r
+ p_desc->local_ds[0].length = sizeof(ipoib_hdr_t);\r
+ p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey;\r
+\r
+ /* Setup the work request. */\r
+ p_desc->wr.p_next = NULL;\r
+ p_desc->wr.wr_id = (uintn_t)p_desc->p_pkt;\r
+ p_desc->wr.wr_type = WR_SEND;\r
+ p_desc->wr.send_opt = IB_SEND_OPT_SIGNALED;\r
+ p_desc->wr.ds_array = p_desc->local_ds;\r
+\r
+ p_desc->wr.dgrm.ud.remote_qp = p_desc->p_endpt->qpn;\r
+ p_desc->wr.dgrm.ud.remote_qkey = p_port->ib_mgr.bcast_rec.qkey;\r
+ p_desc->wr.dgrm.ud.h_av = p_desc->p_endpt->h_av;\r
+ p_desc->wr.dgrm.ud.pkey_index = 0;\r
+ p_desc->wr.dgrm.ud.rsvd = NULL;\r
+\r
+ /* Store context in our reserved area of the packet. */\r
+ IPOIB_PORT_FROM_PACKET( p_desc->p_pkt ) = p_port;\r
+ IPOIB_ENDPT_FROM_PACKET( p_desc->p_pkt ) = p_desc->p_endpt;\r
+ IPOIB_SEND_FROM_PACKET( p_desc->p_pkt ) = p_desc->p_buf;\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static inline void\r
+__process_failed_send(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_send_desc_t* const p_desc,\r
+ IN const NDIS_STATUS status )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ /* Complete the packet. */\r
+ NdisMSendComplete( p_port->p_adapter->h_adapter,\r
+ p_desc->p_pkt, status );\r
+ ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_ERROR, 0 );\r
+ /* Deref the endpoint. */\r
+ if( p_desc->p_endpt )\r
+ ipoib_endpt_deref( p_desc->p_endpt );\r
+\r
+ if( p_desc->p_buf )\r
+ {\r
+ ExFreeToNPagedLookasideList(\r
+ &p_port->buf_mgr.send_buf_list, p_desc->p_buf );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+}\r
+\r
+\r
+void\r
+ipoib_port_send(\r
+ IN ipoib_port_t* const p_port,\r
+ IN NDIS_PACKET **p_packet_array,\r
+ IN uint32_t num_packets )\r
+{\r
+ NDIS_STATUS status;\r
+ ib_api_status_t ib_status;\r
+ ipoib_send_desc_t desc;\r
+ uint32_t i;\r
+ eth_hdr_t *p_eth_hdr;\r
+ NDIS_BUFFER *p_buf;\r
+ UINT buf_len;\r
+\r
+ PERF_DECLARE( GetEthHdr );\r
+ PERF_DECLARE( BuildSendDesc );\r
+ PERF_DECLARE( QueuePacket );\r
+ PERF_DECLARE( SendMgrQueue );\r
+ PERF_DECLARE( PostSend );\r
+ PERF_DECLARE( ProcessFailedSends );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+ if( p_port->state != IB_QPS_RTS )\r
+ {\r
+ cl_obj_unlock( &p_port->obj );\r
+ for( i = 0; i < num_packets; ++i )\r
+ {\r
+ ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_DROPPED, 0 );\r
+ /* Complete the packet. */\r
+ NdisMSendComplete( p_port->p_adapter->h_adapter,\r
+ p_packet_array[i], NDIS_STATUS_ADAPTER_NOT_READY );\r
+ \r
+ }\r
+\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND,\r
+ ("Invalid state - Aborting.\n") );\r
+ return;\r
+ }\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ \r
+ cl_spinlock_acquire( &p_port->send_lock );\r
+ for( i = 0; i < num_packets; i++ )\r
+ {\r
+ desc.p_pkt = p_packet_array[i];\r
+ desc.p_endpt = NULL;\r
+ desc.p_buf = NULL;\r
+\r
+ /* Get the ethernet header so we can find the endpoint. */\r
+ cl_perf_start( GetEthHdr );\r
+ status = __send_mgr_get_eth_hdr(\r
+ p_packet_array[i], &p_buf, &p_eth_hdr, &buf_len );\r
+ cl_perf_stop( &p_port->p_adapter->perf, GetEthHdr );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ cl_perf_start( ProcessFailedSends );\r
+ __process_failed_send( p_port, &desc, status );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends );\r
+ continue;\r
+ }\r
+\r
+ cl_perf_start( SendMgrQueue );\r
+ status = __send_mgr_queue( p_port, p_eth_hdr, &desc.p_endpt );\r
+ cl_perf_stop( &p_port->p_adapter->perf, SendMgrQueue );\r
+ if( status == NDIS_STATUS_PENDING )\r
+ {\r
+ /* Queue all remaining packets. */\r
+ cl_perf_start( QueuePacket );\r
+ while( i < num_packets )\r
+ {\r
+ cl_qlist_insert_tail( &p_port->send_mgr.pending_list,\r
+ IPOIB_LIST_ITEM_FROM_PACKET( p_packet_array[i++] ) );\r
+ }\r
+ cl_perf_stop( &p_port->p_adapter->perf, QueuePacket );\r
+ break;\r
+ }\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ ASSERT( status == NDIS_STATUS_NO_ROUTE_TO_DESTINATION );\r
+ /*\r
+ * Complete the send as if we sent it - WHQL tests don't like the\r
+ * sends to fail.\r
+ */\r
+ cl_perf_start( ProcessFailedSends );\r
+ __process_failed_send( p_port, &desc, NDIS_STATUS_SUCCESS );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends );\r
+ continue;\r
+ }\r
+\r
+ cl_perf_start( BuildSendDesc );\r
+ status = __build_send_desc( p_port, p_eth_hdr, p_buf, buf_len, &desc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, BuildSendDesc );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ cl_perf_start( ProcessFailedSends );\r
+ __process_failed_send( p_port, &desc, status );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends );\r
+ continue;\r
+ }\r
+\r
+ /* Post the WR. */\r
+ cl_perf_start( PostSend );\r
+ ib_status = p_port->p_adapter->p_ifc->post_send( p_port->ib_mgr.h_qp, &desc.wr, NULL );\r
+ cl_perf_stop( &p_port->p_adapter->perf, PostSend );\r
+ if( ib_status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_post_send returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( ib_status )) );\r
+ cl_perf_start( ProcessFailedSends );\r
+ __process_failed_send( p_port, &desc, NDIS_STATUS_FAILURE );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends );\r
+ /* Flag the adapter as hung since posting is busted. */\r
+ p_port->p_adapter->hung = TRUE;\r
+ continue;\r
+ }\r
+\r
+ cl_atomic_inc( &p_port->send_mgr.depth );\r
+ }\r
+ cl_spinlock_release( &p_port->send_lock );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+}\r
+\r
+\r
+void\r
+ipoib_port_resume(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ NDIS_STATUS status;\r
+ ib_api_status_t ib_status;\r
+ cl_list_item_t *p_item;\r
+ ipoib_send_desc_t desc;\r
+ eth_hdr_t *p_eth_hdr;\r
+ NDIS_BUFFER *p_buf;\r
+ UINT buf_len;\r
+\r
+ PERF_DECLARE( GetEndpt );\r
+ PERF_DECLARE( BuildSendDesc );\r
+ PERF_DECLARE( ProcessFailedSends );\r
+ PERF_DECLARE( PostSend );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+ if( p_port->state != IB_QPS_RTS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND,\r
+ ("Invalid state - Aborting.\n") );\r
+ cl_obj_unlock( &p_port->obj );\r
+ return;\r
+ }\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ cl_spinlock_acquire( &p_port->send_lock );\r
+\r
+ for( p_item = cl_qlist_head( &p_port->send_mgr.pending_list );\r
+ p_item != cl_qlist_end( &p_port->send_mgr.pending_list );\r
+ p_item = cl_qlist_head( &p_port->send_mgr.pending_list ) )\r
+ {\r
+ /* Check the send queue and pend the request if not empty. */\r
+ if( p_port->send_mgr.depth == p_port->p_adapter->params.sq_depth )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND,\r
+ ("No available WQEs.\n") );\r
+ break;\r
+ }\r
+\r
+ desc.p_pkt = IPOIB_PACKET_FROM_LIST_ITEM(\r
+ cl_qlist_remove_head( &p_port->send_mgr.pending_list ) );\r
+ desc.p_endpt = NULL;\r
+ desc.p_buf = NULL;\r
+\r
+ /* Get the ethernet header so we can find the endpoint. */\r
+ status = __send_mgr_get_eth_hdr(\r
+ desc.p_pkt, &p_buf, &p_eth_hdr, &buf_len );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ cl_perf_start( ProcessFailedSends );\r
+ __process_failed_send( p_port, &desc, status );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends );\r
+ continue;\r
+ }\r
+\r
+ cl_perf_start( GetEndpt );\r
+ status = __endpt_mgr_ref( p_port, p_eth_hdr->dst, &desc.p_endpt );\r
+ cl_perf_stop( &p_port->p_adapter->perf, GetEndpt );\r
+ if( status == NDIS_STATUS_PENDING )\r
+ {\r
+ cl_qlist_insert_head( &p_port->send_mgr.pending_list,\r
+ IPOIB_LIST_ITEM_FROM_PACKET( desc.p_pkt ) );\r
+ break;\r
+ }\r
+ else if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ ASSERT( status == NDIS_STATUS_NO_ROUTE_TO_DESTINATION );\r
+\r
+ if( ETH_IS_MULTICAST( p_eth_hdr->dst.addr ) )\r
+ {\r
+ if( ipoib_port_join_mcast( p_port, p_eth_hdr->dst,\r
+ IB_MC_REC_STATE_SEND_ONLY_MEMBER) == IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND,\r
+ ("Multicast Mac - trying to join.\n") );\r
+ cl_qlist_insert_head( &p_port->send_mgr.pending_list,\r
+ IPOIB_LIST_ITEM_FROM_PACKET( desc.p_pkt ) );\r
+ break;\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Complete the send as if we sent it - WHQL tests don't like the\r
+ * sends to fail.\r
+ */\r
+ cl_perf_start( ProcessFailedSends );\r
+ __process_failed_send( p_port, &desc, NDIS_STATUS_SUCCESS );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends );\r
+ continue;\r
+ }\r
+\r
+ cl_perf_start( BuildSendDesc );\r
+ status = __build_send_desc( p_port, p_eth_hdr, p_buf, buf_len, &desc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, BuildSendDesc );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ {\r
+ cl_perf_start( ProcessFailedSends );\r
+ __process_failed_send( p_port, &desc, status );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends );\r
+ continue;\r
+ }\r
+\r
+ /* Post the WR. */\r
+ cl_perf_start( PostSend );\r
+ ib_status = p_port->p_adapter->p_ifc->post_send( p_port->ib_mgr.h_qp, &desc.wr, NULL );\r
+ cl_perf_stop( &p_port->p_adapter->perf, PostSend );\r
+ if( ib_status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_post_send returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( ib_status )) );\r
+ cl_perf_start( ProcessFailedSends );\r
+ __process_failed_send( p_port, &desc, NDIS_STATUS_FAILURE );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends );\r
+ /* Flag the adapter as hung since posting is busted. */\r
+ p_port->p_adapter->hung = TRUE;\r
+ continue;\r
+ }\r
+\r
+ cl_atomic_inc( &p_port->send_mgr.depth );\r
+ }\r
+ cl_spinlock_release( &p_port->send_lock );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+}\r
+\r
+\r
+static void\r
+__send_cb(\r
+ IN const ib_cq_handle_t h_cq,\r
+ IN void *cq_context )\r
+{\r
+ ipoib_port_t *p_port;\r
+ ib_api_status_t status;\r
+ ib_wc_t wc[MAX_SEND_WC], *p_wc, *p_free;\r
+ cl_qlist_t done_list;\r
+ NDIS_PACKET *p_packet;\r
+ uint32_t length;\r
+ ipoib_endpt_t *p_endpt;\r
+ send_buf_t *p_send_buf;\r
+ ip_stat_sel_t type;\r
+ size_t i;\r
+ PERF_DECLARE( SendCompBundle );\r
+ PERF_DECLARE( SendCb );\r
+ PERF_DECLARE( PollSend );\r
+ PERF_DECLARE( SendComp );\r
+ PERF_DECLARE( FreeSendBuf );\r
+ PERF_DECLARE( RearmSend );\r
+ PERF_DECLARE( PortResume );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_SEND );\r
+\r
+ cl_perf_clr( SendCompBundle );\r
+\r
+ cl_perf_start( SendCb );\r
+\r
+ UNUSED_PARAM( h_cq );\r
+\r
+ cl_qlist_init( &done_list );\r
+\r
+ p_port = (ipoib_port_t*)cq_context;\r
+\r
+ ipoib_port_ref( p_port, ref_send_cb );\r
+\r
+ for( i = 0; i < MAX_SEND_WC; i++ )\r
+ wc[i].p_next = &wc[i + 1];\r
+ wc[MAX_SEND_WC - 1].p_next = NULL;\r
+\r
+ do\r
+ {\r
+ p_free = wc;\r
+ cl_perf_start( PollSend );\r
+ status = p_port->p_adapter->p_ifc->poll_cq( p_port->ib_mgr.h_send_cq, &p_free, &p_wc );\r
+ cl_perf_stop( &p_port->p_adapter->perf, PollSend );\r
+ CL_ASSERT( status == IB_SUCCESS || status == IB_NOT_FOUND );\r
+\r
+ while( p_wc )\r
+ {\r
+ cl_perf_start( SendComp );\r
+ CL_ASSERT( p_wc->status != IB_WCS_SUCCESS || p_wc->wc_type == IB_WC_SEND );\r
+ p_packet = (NDIS_PACKET*)(uintn_t)p_wc->wr_id;\r
+ CL_ASSERT( p_packet );\r
+ CL_ASSERT( IPOIB_PORT_FROM_PACKET( p_packet ) == p_port );\r
+\r
+ p_endpt = IPOIB_ENDPT_FROM_PACKET( p_packet );\r
+ p_send_buf = IPOIB_SEND_FROM_PACKET( p_packet );\r
+ switch( p_wc->status )\r
+ {\r
+ case IB_WCS_SUCCESS:\r
+ if( p_endpt->h_mcast )\r
+ {\r
+ if( p_endpt->dgid.multicast.raw_group_id[11] == 0xFF &&\r
+ p_endpt->dgid.multicast.raw_group_id[10] == 0xFF &&\r
+ p_endpt->dgid.multicast.raw_group_id[12] == 0xFF &&\r
+ p_endpt->dgid.multicast.raw_group_id[13] == 0xFF )\r
+ {\r
+ type = IP_STAT_BCAST_BYTES;\r
+ }\r
+ else\r
+ {\r
+ type = IP_STAT_MCAST_BYTES;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ type = IP_STAT_UCAST_BYTES;\r
+ }\r
+ NdisQueryPacketLength( p_packet, &length );\r
+ ipoib_inc_send_stat( p_port->p_adapter, type, length );\r
+ NdisMSendComplete( p_port->p_adapter->h_adapter,\r
+ p_packet, NDIS_STATUS_SUCCESS );\r
+ break;\r
+\r
+ case IB_WCS_WR_FLUSHED_ERR:\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND,\r
+ ("Flushed send completion.\n") );\r
+ ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_DROPPED, 0 );\r
+ NdisMSendComplete( p_port->p_adapter->h_adapter,\r
+ p_packet, NDIS_STATUS_RESET_IN_PROGRESS );\r
+ break;\r
+\r
+ default:\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Send failed with %s (vendor specific %#x)\n",\r
+ p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status ),\r
+ (int)p_wc->vendor_specific) );\r
+ ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_ERROR, 0 );\r
+ NdisMSendComplete( p_port->p_adapter->h_adapter,\r
+ p_packet, NDIS_STATUS_FAILURE );\r
+ break;\r
+ }\r
+ cl_perf_stop( &p_port->p_adapter->perf, SendComp );\r
+ /* Dereference the enpoint used for the transfer. */\r
+ ipoib_endpt_deref( p_endpt );\r
+\r
+ if( p_send_buf )\r
+ {\r
+ cl_perf_start( FreeSendBuf );\r
+ ExFreeToNPagedLookasideList( &p_port->buf_mgr.send_buf_list,\r
+ p_send_buf );\r
+ cl_perf_stop( &p_port->p_adapter->perf, FreeSendBuf );\r
+ }\r
+\r
+ cl_atomic_dec( &p_port->send_mgr.depth );\r
+\r
+ p_wc = p_wc->p_next;\r
+ cl_perf_inc( SendCompBundle );\r
+ }\r
+ /* If we didn't use up every WC, break out. */\r
+ } while( !p_free );\r
+\r
+ /* Rearm the CQ. */\r
+ cl_perf_start( RearmSend );\r
+ status = p_port->p_adapter->p_ifc->rearm_cq( p_port->ib_mgr.h_send_cq, FALSE );\r
+ cl_perf_stop( &p_port->p_adapter->perf, RearmSend );\r
+ CL_ASSERT( status == IB_SUCCESS );\r
+\r
+ /* Resume any sends awaiting resources. */\r
+ cl_perf_start( PortResume );\r
+ ipoib_port_resume( p_port );\r
+ cl_perf_stop( &p_port->p_adapter->perf, PortResume );\r
+ \r
+ ipoib_port_deref( p_port, ref_send_cb );\r
+\r
+ cl_perf_stop( &p_port->p_adapter->perf, SendCb );\r
+ cl_perf_update_ctr( &p_port->p_adapter->perf, SendCompBundle );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_SEND );\r
+}\r
+\r
+\r
+/******************************************************************************\r
+*\r
+* Endpoint manager implementation\r
+*\r
+******************************************************************************/\r
+static void\r
+__endpt_mgr_construct(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+ cl_qmap_init( &p_port->endpt_mgr.mac_endpts );\r
+ cl_qmap_init( &p_port->endpt_mgr.lid_endpts );\r
+ cl_fmap_init( &p_port->endpt_mgr.gid_endpts, __gid_cmp );\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__endpt_mgr_init(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+ UNUSED_PARAM( p_port );\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+static void\r
+__endpt_mgr_destroy(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+ CL_ASSERT( cl_is_qmap_empty( &p_port->endpt_mgr.mac_endpts ) );\r
+ CL_ASSERT( cl_is_qmap_empty( &p_port->endpt_mgr.lid_endpts ) );\r
+ CL_ASSERT( cl_is_fmap_empty( &p_port->endpt_mgr.gid_endpts ) );\r
+ UNUSED_PARAM( p_port );\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static void\r
+__endpt_mgr_remove_all(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+ \r
+ cl_obj_lock( &p_port->obj );\r
+ /* Wait for all readers to complete. */\r
+ while( p_port->endpt_rdr )\r
+ ;\r
+ /*\r
+ * We don't need to initiate destruction - this is called only\r
+ * from the __port_destroying function, and destruction cascades\r
+ * to all child objects. Just clear all the maps.\r
+ */\r
+ cl_qmap_remove_all( &p_port->endpt_mgr.mac_endpts );\r
+ cl_qmap_remove_all( &p_port->endpt_mgr.lid_endpts );\r
+ cl_fmap_remove_all( &p_port->endpt_mgr.gid_endpts );\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+}\r
+\r
+\r
+static void\r
+__endpt_mgr_reset_all(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ cl_map_item_t *p_item;\r
+ ipoib_endpt_t *p_endpt;\r
+ cl_qlist_t mc_list;\r
+ uint32_t local_exist = 0;\r
+\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ cl_qlist_init( &mc_list );\r
+ \r
+ cl_obj_lock( &p_port->obj );\r
+ /* Wait for all readers to complete. */\r
+ while( p_port->endpt_rdr )\r
+ ;\r
+\r
+ if( p_port->p_local_endpt )\r
+ {\r
+ cl_qmap_remove_item( &p_port->endpt_mgr.mac_endpts,\r
+ &p_port->p_local_endpt->mac_item );\r
+ cl_fmap_remove_item( &p_port->endpt_mgr.gid_endpts,\r
+ &p_port->p_local_endpt->gid_item );\r
+ cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts,\r
+ &p_port->p_local_endpt->lid_item );\r
+ \r
+ cl_qlist_insert_head(\r
+ &mc_list, &p_port->p_local_endpt->mac_item.pool_item.list_item );\r
+ local_exist = 1;\r
+\r
+ p_port->p_local_endpt = NULL;\r
+ }\r
+\r
+ p_item = cl_qmap_head( &p_port->endpt_mgr.mac_endpts );\r
+ while( p_item != cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) )\r
+ {\r
+ p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item );\r
+ p_item = cl_qmap_next( p_item );\r
+ if( p_endpt->h_mcast )\r
+ {\r
+ /*\r
+ * We destroy MC endpoints since they will get recreated\r
+ * when the port comes back up and we rejoin the MC groups.\r
+ */\r
+ cl_qmap_remove_item( &p_port->endpt_mgr.mac_endpts,\r
+ &p_endpt->mac_item );\r
+ cl_fmap_remove_item( &p_port->endpt_mgr.gid_endpts,\r
+ &p_endpt->gid_item );\r
+\r
+ cl_qlist_insert_tail(\r
+ &mc_list, &p_endpt->mac_item.pool_item.list_item );\r
+ }\r
+ else if( p_endpt->h_av )\r
+ {\r
+ /* Destroy the AV for all other endpoints. */\r
+ p_port->p_adapter->p_ifc->destroy_av( p_endpt->h_av );\r
+ p_endpt->h_av = NULL;\r
+ }\r
+ \r
+ if( p_endpt->dlid )\r
+ {\r
+ cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts,\r
+ &p_endpt->lid_item );\r
+ p_endpt->dlid = 0;\r
+ }\r
+ \r
+ }\r
+\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+\r
+ if(cl_qlist_count( &mc_list ) - local_exist)\r
+ {\r
+ p_port->mcast_cnt = (uint32_t)cl_qlist_count( &mc_list ) - local_exist;\r
+ }\r
+ else\r
+ {\r
+ p_port->mcast_cnt = 0;\r
+ KeSetEvent( &p_port->leave_mcast_event, EVENT_INCREMENT, FALSE );\r
+ } \r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,("p_port->mcast_cnt = %d\n", p_port->mcast_cnt - local_exist));\r
+\r
+ /* Destroy all multicast endpoints now that we have released the lock. */\r
+ while( cl_qlist_count( &mc_list ) )\r
+ {\r
+ cl_obj_destroy( &PARENT_STRUCT( cl_qlist_remove_head( &mc_list ),\r
+ ipoib_endpt_t, mac_item.pool_item.list_item )->obj );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+}\r
+\r
+\r
+/*\r
+ * Called when updating an endpoint entry in response to an ARP.\r
+ * Because receive processing is serialized, and holds a reference\r
+ * on the endpoint reader, we wait for all *other* readers to exit before\r
+ * removing the item.\r
+ */\r
+static void\r
+__endpt_mgr_remove(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ipoib_endpt_t* const p_endpt )\r
+{\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+ /* Wait for all readers to complete. */\r
+ while( p_port->endpt_rdr > 1 )\r
+ ;\r
+\r
+ /* Remove the endpoint from the maps so further requests don't find it. */\r
+ cl_qmap_remove_item( &p_port->endpt_mgr.mac_endpts, &p_endpt->mac_item );\r
+ /*\r
+ * The enpoints are *ALWAYS* in both the MAC and GID maps. They are only\r
+ * in the LID map if the GID has the same subnet prefix as us.\r
+ */\r
+ cl_fmap_remove_item( &p_port->endpt_mgr.gid_endpts, &p_endpt->gid_item );\r
+\r
+ if( p_endpt->dlid )\r
+ {\r
+ cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts,\r
+ &p_endpt->lid_item );\r
+ }\r
+\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ cl_obj_destroy( &p_endpt->obj );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+}\r
+\r
+\r
+NTSTATUS\r
+ipoib_mac_to_gid(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac,\r
+ OUT ib_gid_t* p_gid )\r
+{\r
+ ipoib_endpt_t* p_endpt;\r
+ cl_map_item_t *p_item;\r
+ uint64_t key = 0;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ cl_memcpy( &key, &mac, sizeof(mac_addr_t) );\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+\r
+ p_item = cl_qmap_get( &p_port->endpt_mgr.mac_endpts, key );\r
+ if( p_item == cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) )\r
+ {\r
+ cl_obj_unlock( &p_port->obj );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed endpoint lookup.\n") );\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item );\r
+ *p_gid = p_endpt->dgid;\r
+\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static inline NDIS_STATUS\r
+__endpt_mgr_ref(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac,\r
+ OUT ipoib_endpt_t** const pp_endpt )\r
+{\r
+ NDIS_STATUS status;\r
+ cl_map_item_t *p_item;\r
+ uint64_t key;\r
+\r
+ PERF_DECLARE( EndptQueue );\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ if( !cl_memcmp( &mac, &p_port->p_adapter->params.conf_mac, sizeof(mac) ) )\r
+ {\r
+ /* Discard loopback traffic. */\r
+ IPOIB_PRINT(TRACE_LEVEL_WARNING, IPOIB_DBG_ENDPT,\r
+ ("Discarding loopback traffic\n") );\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+ return NDIS_STATUS_NO_ROUTE_TO_DESTINATION;\r
+ }\r
+\r
+ key = 0;\r
+ cl_memcpy( &key, &mac, sizeof(mac_addr_t) );\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,\r
+ ("Look for :\t MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",\r
+ mac.addr[0], mac.addr[1], mac.addr[2],\r
+ mac.addr[3], mac.addr[4], mac.addr[5]) );\r
+\r
+ p_item = cl_qmap_get( &p_port->endpt_mgr.mac_endpts, key );\r
+ if( p_item == cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) )\r
+ {\r
+ cl_obj_unlock( &p_port->obj );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,\r
+ ("Failed endpoint lookup.\n") );\r
+ return NDIS_STATUS_NO_ROUTE_TO_DESTINATION;\r
+ }\r
+\r
+ *pp_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item );\r
+ ipoib_endpt_ref( *pp_endpt );\r
+\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ cl_perf_start( EndptQueue );\r
+ status = ipoib_endpt_queue( *pp_endpt );\r
+ cl_perf_stop( &p_port->p_adapter->perf, EndptQueue );\r
+ if( status != NDIS_STATUS_SUCCESS )\r
+ *pp_endpt = NULL;\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+ return status;\r
+}\r
+\r
+\r
+static inline NDIS_STATUS\r
+__endpt_mgr_get_gid_qpn(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac,\r
+ OUT ib_gid_t* const p_gid,\r
+ OUT UNALIGNED net32_t* const p_qpn )\r
+{\r
+ UNALIGNED\r
+ cl_map_item_t *p_item;\r
+ ipoib_endpt_t *p_endpt;\r
+ uint64_t key;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+\r
+ key = 0;\r
+ cl_memcpy( &key, &mac, sizeof(mac_addr_t) );\r
+ p_item = cl_qmap_get( &p_port->endpt_mgr.mac_endpts, key );\r
+ if( p_item == cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) )\r
+ {\r
+ cl_obj_unlock( &p_port->obj );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,\r
+ ("Failed endpoint lookup.\n") );\r
+ return NDIS_STATUS_FAILURE;\r
+ }\r
+\r
+ p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item );\r
+\r
+ *p_gid = p_endpt->dgid;\r
+ *p_qpn = p_endpt->qpn;\r
+\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+ return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static inline ipoib_endpt_t*\r
+__endpt_mgr_get_by_gid(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const ib_gid_t* const p_gid )\r
+{\r
+ cl_fmap_item_t *p_item;\r
+ ipoib_endpt_t *p_endpt;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ p_item = cl_fmap_get( &p_port->endpt_mgr.gid_endpts, p_gid );\r
+ if( p_item == cl_fmap_end( &p_port->endpt_mgr.gid_endpts ) )\r
+ p_endpt = NULL;\r
+ else\r
+ p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, gid_item );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+ return p_endpt;\r
+}\r
+\r
+\r
+static ipoib_endpt_t*\r
+__endpt_mgr_get_by_lid(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const net16_t lid )\r
+{\r
+ cl_map_item_t *p_item;\r
+ ipoib_endpt_t *p_endpt;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ p_item = cl_qmap_get( &p_port->endpt_mgr.lid_endpts, lid );\r
+ if( p_item == cl_qmap_end( &p_port->endpt_mgr.lid_endpts ) )\r
+ p_endpt = NULL;\r
+ else\r
+ p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, lid_item );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+ return p_endpt;\r
+}\r
+\r
+\r
+inline ib_api_status_t\r
+__endpt_mgr_insert_locked(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac,\r
+ IN ipoib_endpt_t* const p_endpt )\r
+{\r
+ ib_api_status_t status;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,\r
+ ("insert :\t MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",\r
+ mac.addr[0], mac.addr[1], mac.addr[2],\r
+ mac.addr[3], mac.addr[4], mac.addr[5]) );\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+ while( p_port->endpt_rdr )\r
+ {\r
+ cl_obj_unlock( &p_port->obj );\r
+ cl_obj_lock( &p_port->obj );\r
+ }\r
+ /* __endpt_mgr_insert expects *one* reference to be held when being called. */\r
+ cl_atomic_inc( &p_port->endpt_rdr );\r
+ status= __endpt_mgr_insert( p_port, mac, p_endpt );\r
+ cl_atomic_dec( &p_port->endpt_rdr );\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ return status;\r
+}\r
+\r
+\r
+inline ib_api_status_t\r
+__endpt_mgr_insert(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac,\r
+ IN ipoib_endpt_t* const p_endpt )\r
+{\r
+ uint64_t key;\r
+ cl_status_t cl_status;\r
+ cl_map_item_t *p_qitem;\r
+ cl_fmap_item_t *p_fitem;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ /* Wait for all accesses to the map to complete. */\r
+ while( p_port->endpt_rdr > 1 )\r
+ ;\r
+\r
+ /* Link the endpoint to the port. */\r
+ cl_status = cl_obj_insert_rel_parent_locked(\r
+ &p_endpt->rel, &p_port->obj, &p_endpt->obj );\r
+\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ cl_obj_destroy( &p_endpt->obj );\r
+ return IB_INVALID_STATE;\r
+ }\r
+\r
+#if DBG\r
+ cl_atomic_inc( &p_port->ref[ref_endpt_track] );\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,\r
+ ("ref type %d ref_cnt %d\n", ref_endpt_track, p_port->obj.ref_cnt) );\r
+#endif\r
+\r
+ p_endpt->mac = mac;\r
+ key = 0;\r
+ cl_memcpy( &key, &mac, sizeof(mac_addr_t) );\r
+ p_qitem = cl_qmap_insert(\r
+ &p_port->endpt_mgr.mac_endpts, key, &p_endpt->mac_item );\r
+ CL_ASSERT( p_qitem == &p_endpt->mac_item );\r
+ p_fitem = cl_fmap_insert(\r
+ &p_port->endpt_mgr.gid_endpts, &p_endpt->dgid, &p_endpt->gid_item );\r
+ CL_ASSERT( p_fitem == &p_endpt->gid_item );\r
+ if( p_endpt->dlid )\r
+ {\r
+ p_qitem = cl_qmap_insert(\r
+ &p_port->endpt_mgr.lid_endpts, p_endpt->dlid, &p_endpt->lid_item );\r
+ CL_ASSERT( p_qitem == &p_endpt->lid_item );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__endpt_mgr_add_bcast(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ib_mcast_rec_t *p_mcast_rec )\r
+{\r
+ ib_api_status_t status;\r
+ ipoib_endpt_t *p_endpt;\r
+ mac_addr_t bcast_mac;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ /*\r
+ * Cache the broadcast group properties for creating future mcast groups.\r
+ */\r
+ p_port->ib_mgr.bcast_rec = *p_mcast_rec->p_member_rec;\r
+\r
+ /* Allocate the broadcast endpoint. */\r
+ p_endpt = ipoib_endpt_create( &p_mcast_rec->p_member_rec->mgid,\r
+ p_mcast_rec->p_member_rec->mlid, CL_HTON32(0x00FFFFFF) );\r
+ if( !p_endpt )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_endpt_create failed.\n") );\r
+ return IB_INSUFFICIENT_RESOURCES;\r
+ }\r
+ /* set reference to transport to be used while is not attached to the port */\r
+ p_endpt->p_ifc = p_port->p_adapter->p_ifc;\r
+ status = ipoib_endpt_set_mcast( p_endpt, p_port->ib_mgr.h_pd,\r
+ p_port->port_num, p_mcast_rec );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_create_mcast_endpt returned %s\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* Add the broadcast endpoint to the endpoint map. */\r
+ cl_memset( &bcast_mac, 0xFF, sizeof(bcast_mac) );\r
+ status = __endpt_mgr_insert_locked( p_port, bcast_mac, p_endpt );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return status;\r
+}\r
+\r
+\r
+void\r
+ipoib_port_remove_endpt(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac )\r
+{\r
+ cl_map_item_t *p_item;\r
+ ipoib_endpt_t *p_endpt;\r
+ uint64_t key;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ key = 0;\r
+ cl_memcpy( &key, &mac, sizeof(mac_addr_t) );\r
+\r
+ /* Remove the endpoint from the maps so further requests don't find it. */\r
+ cl_obj_lock( &p_port->obj );\r
+ /* Wait for all readers to finish */\r
+ while( p_port->endpt_rdr )\r
+ ;\r
+ p_item = cl_qmap_remove( &p_port->endpt_mgr.mac_endpts, key );\r
+ /*\r
+ * Dereference the endpoint. If the ref count goes to zero, it\r
+ * will get freed.\r
+ */\r
+ if( p_item != cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) )\r
+ {\r
+ p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item );\r
+ /*\r
+ * The enpoints are *ALWAYS* in both the MAC and GID maps. They are only\r
+ * in the LID map if the GID has the same subnet prefix as us.\r
+ */\r
+ cl_fmap_remove_item(\r
+ &p_port->endpt_mgr.gid_endpts, &p_endpt->gid_item );\r
+\r
+ if( p_endpt->dlid )\r
+ {\r
+ cl_qmap_remove_item(\r
+ &p_port->endpt_mgr.lid_endpts, &p_endpt->lid_item );\r
+ }\r
+\r
+ cl_obj_unlock( &p_port->obj );\r
+ cl_obj_destroy( &p_endpt->obj );\r
+#if DBG\r
+ cl_atomic_dec( &p_port->ref[ref_endpt_track] );\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,\r
+ ("ref type %d ref_cnt %d\n", ref_endpt_track, p_port->obj.ref_cnt) );\r
+#endif\r
+\r
+ }\r
+ else\r
+ {\r
+ cl_obj_unlock( &p_port->obj );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+}\r
+\r
+\r
+void\r
+ipoib_port_flush_endpts(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ cl_map_item_t *p_item;\r
+ ipoib_endpt_t *p_endpt;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+ p_item = cl_qmap_head( &p_port->endpt_mgr.mac_endpts );\r
+ while( p_item != cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) )\r
+ {\r
+ p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item );\r
+ p_item = cl_qmap_next( p_item );\r
+\r
+ /*\r
+ * If the endpoint has been marked as expired before, and we have\r
+ * an AV handle, free the AV.\r
+ */\r
+ if( p_endpt->expired && p_endpt->h_av )\r
+ {\r
+ CL_ASSERT( p_endpt->obj.ref_cnt == 1 );\r
+ p_port->p_adapter->p_ifc->destroy_av( p_endpt->h_av );\r
+ p_endpt->h_av = NULL;\r
+ p_endpt->expired = FALSE;\r
+ }\r
+\r
+ /*\r
+ * If the endpoint is not in use, mark it as expired.\r
+ * Note that the ref count is only zero when the endpoint gets\r
+ * destroyed, so an endpoint that is not in use has a ref count of 1.\r
+ * Also note that we never expire any multicast endpoints.\r
+ */\r
+ CL_ASSERT( p_endpt->obj.ref_cnt != 0 );\r
+ if( p_endpt->obj.ref_cnt == 1 && p_endpt->h_av && !p_endpt->h_mcast )\r
+ p_endpt->expired = TRUE;\r
+ }\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
+}\r
+\r
+\r
+/*\r
+ * The sequence for port up is as follows:\r
+ * 1. The port goes active. This allows the adapter to send SA queries\r
+ * and join the broadcast group (and other groups).\r
+ *\r
+ * 2. The adapter sends an SA query for the broadcast group.\r
+ *\r
+ * 3. Upon completion of the query, the adapter joins the broadcast group.\r
+ */\r
+\r
+\r
+/*\r
+ * Query the SA for the broadcast group.\r
+ */\r
+void\r
+ipoib_port_up(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const ib_pnp_port_rec_t* const p_pnp_rec )\r
+{\r
+ ib_api_status_t status;\r
+ ib_query_req_t query;\r
+ ib_user_query_t info;\r
+ ib_portinfo_record_t port_rec;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ /* Wait for all work requests to get flushed. */\r
+ while( p_port->recv_mgr.depth || p_port->send_mgr.depth )\r
+ cl_thread_suspend( 0 );\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+ p_port->state = IB_QPS_INIT;\r
+ KeResetEvent( &p_port->sa_event );\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ info.method = IB_MAD_METHOD_GET;\r
+ info.attr_id = IB_MAD_ATTR_PORTINFO_RECORD;\r
+ info.attr_size = sizeof(ib_portinfo_record_t);\r
+ info.comp_mask = IB_PIR_COMPMASK_BASELID;\r
+ info.p_attr = &port_rec;\r
+\r
+ /* Query requires only the base LID. */\r
+ cl_memclr( &port_rec, sizeof(ib_portinfo_record_t) );\r
+ port_rec.port_info.base_lid = p_pnp_rec->p_port_attr->lid;\r
+\r
+ cl_memclr( &query, sizeof(ib_query_req_t) );\r
+ query.query_type = IB_QUERY_USER_DEFINED;\r
+ query.p_query_input = &info;\r
+ query.port_guid = p_port->p_adapter->guids.port_guid;\r
+ query.timeout_ms = p_port->p_adapter->params.sa_timeout;\r
+ query.retry_cnt = p_port->p_adapter->params.sa_retry_cnt;\r
+ query.query_context = p_port;\r
+ query.pfn_query_cb = __port_info_cb;\r
+\r
+ /* reference the object for the multicast query. */\r
+ ipoib_port_ref( p_port, ref_port_up );\r
+\r
+ status = p_port->p_adapter->p_ifc->query(\r
+ p_port->p_adapter->h_al, &query, &p_port->ib_mgr.h_query );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE );\r
+ ipoib_set_inactive( p_port->p_adapter );\r
+ ipoib_port_deref( p_port, ref_port_up );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_query returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__endpt_mgr_add_local(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ib_port_info_t* const p_port_info )\r
+{\r
+ ib_api_status_t status;\r
+ ib_gid_t gid;\r
+ ipoib_endpt_t *p_endpt;\r
+ ib_av_attr_t av_attr;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ ib_gid_set_default( &gid, p_port->p_adapter->guids.port_guid );\r
+ p_endpt = ipoib_endpt_create(\r
+ &gid, p_port_info->base_lid, p_port->ib_mgr.qpn );\r
+ if( !p_endpt )\r
+ {\r
+ p_port->p_adapter->hung = TRUE;\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Failed to create local endpt\n") );\r
+ return IB_INSUFFICIENT_MEMORY;\r
+ }\r
+\r
+ cl_memclr( &av_attr, sizeof(ib_av_attr_t) );\r
+ av_attr.port_num = p_port->port_num;\r
+ av_attr.sl = 0;\r
+ av_attr.dlid = p_port_info->base_lid;\r
+ av_attr.static_rate = ib_port_info_compute_rate( p_port_info );\r
+ av_attr.path_bits = 0;\r
+ status = p_port->p_adapter->p_ifc->create_av(\r
+ p_port->ib_mgr.h_pd, &av_attr, &p_endpt->h_av );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ cl_obj_destroy( &p_endpt->obj );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_create_av for local endpoint returned %s\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* __endpt_mgr_insert expects *one* reference to be held. */\r
+ cl_atomic_inc( &p_port->endpt_rdr );\r
+ status = __endpt_mgr_insert( p_port, p_port->p_adapter->params.conf_mac, p_endpt );\r
+ cl_atomic_dec( &p_port->endpt_rdr );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__endpt_mgr_insert for local endpoint returned %s\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ p_port->p_local_endpt = p_endpt;\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return status;\r
+}\r
+\r
+\r
+static void\r
+__port_info_cb(\r
+ IN ib_query_rec_t *p_query_rec )\r
+{\r
+ ib_api_status_t status;\r
+ ipoib_port_t *p_port;\r
+ ib_portinfo_record_t *p_port_rec;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ p_port = (ipoib_port_t* __ptr64)p_query_rec->query_context;\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+ p_port->ib_mgr.h_query = NULL;\r
+\r
+ if( p_port->state != IB_QPS_INIT )\r
+ {\r
+ status = IB_CANCELED;\r
+ goto done;\r
+ }\r
+\r
+ status = p_query_rec->status;\r
+\r
+ switch( status )\r
+ {\r
+ case IB_SUCCESS:\r
+ /* Note that the we report the rate from the port info. */\r
+ p_port_rec = (ib_portinfo_record_t*)\r
+ ib_get_query_result( p_query_rec->p_result_mad, 0 );\r
+\r
+ status = __endpt_mgr_add_local( p_port, &p_port_rec->port_info );\r
+ if( status == IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Received port info: link width = %d.\n",\r
+ p_port_rec->port_info.link_width_active) );\r
+\r
+ p_port->ib_mgr.rate =\r
+ ib_port_info_compute_rate( &p_port_rec->port_info );\r
+\r
+ ipoib_set_rate( p_port->p_adapter,\r
+ p_port_rec->port_info.link_width_active,\r
+ ib_port_info_get_link_speed_active( &p_port_rec->port_info ) );\r
+\r
+ status = __port_get_bcast( p_port );\r
+ }\r
+ else\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__endpt_mgr_add_local returned %s\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ }\r
+ break;\r
+\r
+ case IB_CANCELED:\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Instance destroying - Aborting.\n") );\r
+ break;\r
+\r
+ case IB_TIMEOUT:\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_PORT_INFO_TIMEOUT, 0 );\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Port info query timed out.\n") );\r
+ break;\r
+\r
+ case IB_REMOTE_ERROR:\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_PORT_INFO_REJECT, 0 );\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Port info query rejected by SA.\n") );\r
+ break;\r
+\r
+ default:\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_QUERY_PORT_INFO, 1, p_query_rec->status );\r
+ /* Hopefully we'll get an SM change event that will restart things. */\r
+ IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Port info query failed.\n") );\r
+ }\r
+\r
+done:\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ if( status != IB_CANCELED )\r
+ {\r
+ ipoib_set_inactive( p_port->p_adapter );\r
+ __endpt_mgr_reset_all( p_port );\r
+ }\r
+ KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE );\r
+ }\r
+\r
+ /* Return the response MAD to AL. */\r
+ if( p_query_rec->p_result_mad )\r
+ p_port->p_adapter->p_ifc->put_mad( p_query_rec->p_result_mad );\r
+\r
+ /* Release the reference taken when issuing the port info query. */\r
+ ipoib_port_deref( p_port, ref_port_info_cb );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__port_get_bcast(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ ib_api_status_t status;\r
+ ib_query_req_t query;\r
+ ib_user_query_t info;\r
+ ib_member_rec_t member_rec;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ info.method = IB_MAD_METHOD_GETTABLE;\r
+ info.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD;\r
+ info.attr_size = sizeof(ib_member_rec_t);\r
+ info.comp_mask = IB_MCR_COMPMASK_MGID;\r
+ info.p_attr = &member_rec;\r
+\r
+ /* Query requires only the MGID. */\r
+ cl_memclr( &member_rec, sizeof(ib_member_rec_t) );\r
+ member_rec.mgid = bcast_mgid_template;\r
+\r
+ cl_memclr( &query, sizeof(ib_query_req_t) );\r
+ query.query_type = IB_QUERY_USER_DEFINED;\r
+ query.p_query_input = &info;\r
+ query.port_guid = p_port->p_adapter->guids.port_guid;\r
+ query.timeout_ms = p_port->p_adapter->params.sa_timeout;\r
+ query.retry_cnt = p_port->p_adapter->params.sa_retry_cnt;\r
+ query.query_context = p_port;\r
+ query.pfn_query_cb = __bcast_get_cb;\r
+\r
+ /* reference the object for the multicast query. */\r
+ ipoib_port_ref( p_port, ref_get_bcast );\r
+\r
+ status = p_port->p_adapter->p_ifc->query(\r
+ p_port->p_adapter->h_al, &query, &p_port->ib_mgr.h_query );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ ipoib_port_deref( p_port, ref_get_bcast );\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_query returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return status;\r
+}\r
+\r
+\r
+/* Callback for the MCMemberRecord Get query for the IPv4 broadcast group. */\r
+static void\r
+__bcast_get_cb(\r
+ IN ib_query_rec_t *p_query_rec )\r
+{\r
+ ipoib_port_t *p_port;\r
+ ib_member_rec_t *p_mc_req;\r
+ ib_api_status_t status;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ p_port = (ipoib_port_t* __ptr64)p_query_rec->query_context;\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+ p_port->ib_mgr.h_query = NULL;\r
+ if( p_port->state != IB_QPS_INIT )\r
+ {\r
+ status = IB_CANCELED;\r
+ goto done;\r
+ }\r
+\r
+ status = p_query_rec->status;\r
+\r
+ switch( status )\r
+ {\r
+ case IB_SUCCESS:\r
+ if( p_query_rec->result_cnt )\r
+ {\r
+ p_mc_req = (ib_member_rec_t*)\r
+ ib_get_query_result( p_query_rec->p_result_mad, 0 );\r
+\r
+ /* Join the broadcast group. */\r
+ status = __port_join_bcast( p_port, p_mc_req );\r
+ break;\r
+ }\r
+ /* Fall through. */\r
+\r
+ case IB_REMOTE_ERROR:\r
+ /* SA failed the query. Broadcast group doesn't exist, create it. */\r
+ status = __port_create_bcast( p_port );\r
+ break;\r
+\r
+ case IB_CANCELED:\r
+ IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Instance destroying - Aborting.\n") );\r
+ break;\r
+\r
+ default:\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_BCAST_GET, 1, p_query_rec->status );\r
+ }\r
+\r
+done:\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ if( status != IB_CANCELED )\r
+ {\r
+ ipoib_set_inactive( p_port->p_adapter );\r
+ __endpt_mgr_reset_all( p_port );\r
+ }\r
+ KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE );\r
+ }\r
+\r
+ /* Return the response MAD to AL. */\r
+ if( p_query_rec->p_result_mad )\r
+ p_port->p_adapter->p_ifc->put_mad( p_query_rec->p_result_mad );\r
+\r
+ /* Release the reference taken when issuing the member record query. */\r
+ ipoib_port_deref( p_port, ref_bcast_get_cb );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__port_join_bcast(\r
+ IN ipoib_port_t* const p_port,\r
+ IN ib_member_rec_t* const p_member_rec )\r
+{\r
+ ib_api_status_t status;\r
+ ib_mcast_req_t mcast_req;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ /* Check that the rate is realizable for our port. */\r
+ if( p_port->ib_mgr.rate < (p_member_rec->rate & 0x3F) &&\r
+ (g_ipoib.bypass_check_bcast_rate == 0))\r
+ {\r
+ /*\r
+ * The MC group rate is higher than our port's rate. Log an error\r
+ * and stop. A port transition will drive the retry.\r
+ */\r
+ IPOIB_PRINT(TRACE_LEVEL_WARNING, IPOIB_DBG_INIT,\r
+ ("Unrealizable join due to rate mismatch.\n") );\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_BCAST_RATE, 2,\r
+ (uint32_t)(p_member_rec->rate & 0x3F),\r
+ (uint32_t)p_port->ib_mgr.rate );\r
+ return IB_ERROR;\r
+ }\r
+\r
+ /* Join the broadcast group. */\r
+ cl_memclr( &mcast_req, sizeof(mcast_req) );\r
+ /* Copy the results of the Get to use as parameters. */\r
+ mcast_req.member_rec = *p_member_rec;\r
+ /* We specify our port GID for the join operation. */\r
+ mcast_req.member_rec.port_gid.unicast.prefix = IB_DEFAULT_SUBNET_PREFIX;\r
+ mcast_req.member_rec.port_gid.unicast.interface_id =\r
+ p_port->p_adapter->guids.port_guid;\r
+\r
+ mcast_req.mcast_context = p_port;\r
+ mcast_req.pfn_mcast_cb = __bcast_cb;\r
+ mcast_req.timeout_ms = p_port->p_adapter->params.sa_timeout;\r
+ mcast_req.retry_cnt = p_port->p_adapter->params.sa_retry_cnt;\r
+ mcast_req.port_guid = p_port->p_adapter->guids.port_guid;\r
+ mcast_req.pkey_index = 0;\r
+\r
+ if( ib_member_get_state( mcast_req.member_rec.scope_state ) !=\r
+ IB_MC_REC_STATE_FULL_MEMBER )\r
+ {\r
+ IPOIB_PRINT(TRACE_LEVEL_WARNING, IPOIB_DBG_INIT,\r
+ ("Incorrect MC member rec join state in query response.\n") );\r
+ ib_member_set_state( &mcast_req.member_rec.scope_state,\r
+ IB_MC_REC_STATE_FULL_MEMBER );\r
+ }\r
+\r
+ /* reference the object for the multicast join request. */\r
+ ipoib_port_ref( p_port, ref_join_bcast );\r
+\r
+ status = p_port->p_adapter->p_ifc->join_mcast(\r
+ p_port->ib_mgr.h_qp, &mcast_req );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ ipoib_port_deref( p_port, ref_bcast_join_failed );\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_join_mcast returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ }\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return status;\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__port_create_bcast(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ ib_api_status_t status;\r
+ ib_mcast_req_t mcast_req;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ /* Join the broadcast group. */\r
+ cl_memclr( &mcast_req, sizeof(mcast_req) );\r
+ mcast_req.create = TRUE;\r
+ /*\r
+ * Create requires pkey, qkey, SL, flow label, traffic class, joing state\r
+ * and port GID.\r
+ *\r
+ * We specify the MGID since we don't want the SA to generate it for us.\r
+ */\r
+ mcast_req.member_rec.mgid = bcast_mgid_template;\r
+ ib_gid_set_default( &mcast_req.member_rec.port_gid,\r
+ p_port->p_adapter->guids.port_guid );\r
+ /*\r
+ * IPOIB spec requires that the QKEY have the MSb set so that the QKEY\r
+ * from the QP is used rather than the QKEY in the send WR.\r
+ */\r
+ mcast_req.member_rec.qkey =\r
+ (uint32_t)(uintn_t)p_port | IB_QP_PRIVILEGED_Q_KEY;\r
+ mcast_req.member_rec.mtu =\r
+ (IB_PATH_SELECTOR_EXACTLY << 6) | IB_MTU_LEN_2048;\r
+\r
+ mcast_req.member_rec.pkey = IB_DEFAULT_PKEY;\r
+\r
+ mcast_req.member_rec.sl_flow_hop = ib_member_set_sl_flow_hop( 0, 0, 0 );\r
+ mcast_req.member_rec.scope_state =\r
+ ib_member_set_scope_state( 2, IB_MC_REC_STATE_FULL_MEMBER );\r
+\r
+ mcast_req.mcast_context = p_port;\r
+ mcast_req.pfn_mcast_cb = __bcast_cb;\r
+ mcast_req.timeout_ms = p_port->p_adapter->params.sa_timeout;\r
+ mcast_req.retry_cnt = p_port->p_adapter->params.sa_retry_cnt;\r
+ mcast_req.port_guid = p_port->p_adapter->guids.port_guid;\r
+ mcast_req.pkey_index = 0;\r
+\r
+ /* reference the object for the multicast join request. */\r
+ ipoib_port_ref( p_port, ref_join_bcast );\r
+\r
+ status = p_port->p_adapter->p_ifc->join_mcast( p_port->ib_mgr.h_qp, &mcast_req );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ ipoib_port_deref( p_port, ref_bcast_create_failed );\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_join_mcast returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ }\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return status;\r
+}\r
+\r
+\r
+void\r
+ipoib_port_down(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ ib_api_status_t status;\r
+ ib_qp_mod_t qp_mod;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ /*\r
+ * Mark our state. This causes all callbacks to abort.\r
+ * Note that we hold the receive lock so that we synchronize\r
+ * with reposting. We must take the receive lock before the\r
+ * object lock since that is the order taken when reposting.\r
+ */\r
+ cl_spinlock_acquire( &p_port->recv_lock );\r
+ cl_obj_lock( &p_port->obj );\r
+ p_port->state = IB_QPS_ERROR;\r
+\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_PORT_DOWN, 0 );\r
+\r
+ if( p_port->ib_mgr.h_query )\r
+ {\r
+ p_port->p_adapter->p_ifc->cancel_query(\r
+ p_port->p_adapter->h_al, p_port->ib_mgr.h_query );\r
+ p_port->ib_mgr.h_query = NULL;\r
+ }\r
+ cl_obj_unlock( &p_port->obj );\r
+ cl_spinlock_release( &p_port->recv_lock );\r
+\r
+ KeWaitForSingleObject(\r
+ &p_port->sa_event, Executive, KernelMode, FALSE, NULL );\r
+\r
+ /*\r
+ * Put the QP in the error state. This removes the need to\r
+ * synchronize with send/receive callbacks.\r
+ */\r
+ CL_ASSERT( p_port->ib_mgr.h_qp );\r
+ cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) );\r
+ qp_mod.req_state = IB_QPS_ERROR;\r
+ status = p_port->p_adapter->p_ifc->modify_qp( p_port->ib_mgr.h_qp, &qp_mod );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_modify_qp to error state returned %s.\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ p_port->p_adapter->hung = TRUE;\r
+ return;\r
+ }\r
+\r
+ KeResetEvent(&p_port->leave_mcast_event);\r
+\r
+ /* Reset all endpoints so we don't flush our ARP cache. */\r
+ __endpt_mgr_reset_all( p_port );\r
+\r
+ KeWaitForSingleObject(\r
+ &p_port->leave_mcast_event, Executive, KernelMode, FALSE, NULL );\r
+\r
+ __pending_list_destroy(p_port);\r
+ \r
+ cl_obj_lock( &p_port->p_adapter->obj );\r
+ ipoib_dereg_addrs( p_port->p_adapter );\r
+ cl_obj_unlock( &p_port->p_adapter->obj );\r
+ \r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static void\r
+__bcast_cb(\r
+ IN ib_mcast_rec_t *p_mcast_rec )\r
+{\r
+ ipoib_port_t *p_port;\r
+ ib_api_status_t status;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+\r
+ p_port = (ipoib_port_t* __ptr64)p_mcast_rec->mcast_context;\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+ if( p_port->state != IB_QPS_INIT )\r
+ {\r
+ cl_obj_unlock( &p_port->obj );\r
+ if( p_mcast_rec->status == IB_SUCCESS )\r
+\r
+ {\r
+ ipoib_port_ref(p_port, ref_leave_mcast);\r
+ p_port->p_adapter->p_ifc->leave_mcast( p_mcast_rec->h_mcast, __leave_error_mcast_cb );\r
+ }\r
+ KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE );\r
+ ipoib_port_deref( p_port, ref_bcast_inv_state );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Invalid state - Aborting.\n") );\r
+ return;\r
+ }\r
+\r
+ status = p_mcast_rec->status;\r
+\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Multicast join for broadcast group returned %s.\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( p_mcast_rec->status )) );\r
+ if( status == IB_REMOTE_ERROR )\r
+ {\r
+ /*\r
+ * Either:\r
+ * - the join failed because the group no longer exists\r
+ * - the create failed because the group already exists\r
+ *\r
+ * Kick off a new Get query to the SA to restart the join process\r
+ * from the top. Note that as an optimization, it would be\r
+ * possible to distinguish between the join and the create.\r
+ * If the join fails, try the create. If the create fails, start\r
+ * over with the Get.\r
+ */\r
+ /* TODO: Assert is a place holder. Can we ever get here if the\r
+ state isn't IB_PNP_PORT_ADD or PORT_DOWN or PORT_INIT? */\r
+ CL_ASSERT( p_port->p_adapter->state == IB_PNP_PORT_ADD ||\r
+ p_port->p_adapter->state == IB_PNP_PORT_DOWN ||\r
+ p_port->p_adapter->state == IB_PNP_PORT_INIT );\r
+ status = __port_get_bcast( p_port );\r
+ }\r
+ else\r
+ {\r
+ NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
+ EVENT_IPOIB_BCAST_JOIN, 1, p_mcast_rec->status );\r
+ }\r
+\r
+ cl_obj_unlock( &p_port->obj );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ ipoib_set_inactive( p_port->p_adapter );\r
+ __endpt_mgr_reset_all( p_port );\r
+ KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE );\r
+ }\r
+ ipoib_port_deref( p_port, ref_bcast_req_failed );\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return;\r
+ }\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ status = __endpt_mgr_add_bcast( p_port, p_mcast_rec );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__endpt_mgr_add_bcast returned %s\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ ipoib_port_ref(p_port, ref_leave_mcast);\r
+ status = p_port->p_adapter->p_ifc->leave_mcast( p_mcast_rec->h_mcast, __leave_error_mcast_cb );\r
+ CL_ASSERT( status == IB_SUCCESS );\r
+ goto err;\r
+ }\r
+\r
+ /* Get the QP ready for action. */\r
+ status = __ib_mgr_activate( p_port );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__ib_mgr_activate returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+\r
+err:\r
+ /* Flag the adapter as hung. */\r
+ p_port->p_adapter->hung = TRUE;\r
+ KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE );\r
+ ipoib_port_deref( p_port, ref_bcast_error );\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return;\r
+ }\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+ /* Only change the state if we're still in INIT. */\r
+ if( p_port->state == IB_QPS_INIT )\r
+ p_port->state = IB_QPS_RTS;\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ /* Prepost receives. */\r
+ cl_spinlock_acquire( &p_port->recv_lock );\r
+ __recv_mgr_repost( p_port );\r
+ cl_spinlock_release( &p_port->recv_lock );\r
+\r
+ /* Notify the adapter that we now have an active connection. */\r
+ ipoib_set_active( p_port->p_adapter );\r
+\r
+ KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE );\r
+ ipoib_port_deref( p_port, ref_join_bcast );\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+}\r
+\r
+\r
+static void\r
+__qp_event(\r
+ IN ib_async_event_rec_t *p_event_rec )\r
+{\r
+ UNUSED_PARAM( p_event_rec );\r
+ CL_ASSERT( p_event_rec->context );\r
+ ((ipoib_port_t* __ptr64)p_event_rec->context)->p_adapter->hung = TRUE;\r
+}\r
+\r
+\r
+static void\r
+__cq_event(\r
+ IN ib_async_event_rec_t *p_event_rec )\r
+{\r
+ UNUSED_PARAM( p_event_rec );\r
+ CL_ASSERT( p_event_rec->context );\r
+ ((ipoib_port_t* __ptr64)p_event_rec->context)->p_adapter->hung = TRUE;\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__ib_mgr_activate(\r
+ IN ipoib_port_t* const p_port )\r
+{\r
+ ib_api_status_t status;\r
+ ib_dgrm_info_t dgrm_info;\r
+ ib_qp_mod_t qp_mod;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_INIT );\r
+ /*\r
+ * Move the QP to RESET. This allows us to reclaim any\r
+ * unflushed receives.\r
+ */\r
+ cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) );\r
+ qp_mod.req_state = IB_QPS_RESET;\r
+ status = p_port->p_adapter->p_ifc->modify_qp( p_port->ib_mgr.h_qp, &qp_mod );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_modify_qp returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* Move the QP to RTS. */\r
+ dgrm_info.port_guid = p_port->p_adapter->guids.port_guid;\r
+ dgrm_info.qkey = p_port->ib_mgr.bcast_rec.qkey;\r
+ dgrm_info.pkey_index = 0;\r
+ status = p_port->p_adapter->p_ifc->init_dgrm_svc( p_port->ib_mgr.h_qp, &dgrm_info );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_init_dgrm_svc returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* Rearm the CQs. */\r
+ status = p_port->p_adapter->p_ifc->rearm_cq( p_port->ib_mgr.h_recv_cq, FALSE );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_rearm_cq for recv returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+ status = p_port->p_adapter->p_ifc->rearm_cq( p_port->ib_mgr.h_send_cq, FALSE );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_rearm_cq for send returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_INIT );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+/* Transition to a passive level thread. */\r
+ib_api_status_t\r
+ipoib_port_join_mcast(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac,\r
+ IN const uint8_t state)\r
+{\r
+ ib_api_status_t status;\r
+ ib_mcast_req_t mcast_req;\r
+ ipoib_endpt_t *p_endpt;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_MCAST );\r
+\r
+ switch( __endpt_mgr_ref( p_port, mac, &p_endpt ) )\r
+ {\r
+ case NDIS_STATUS_NO_ROUTE_TO_DESTINATION:\r
+ break;\r
+\r
+ case NDIS_STATUS_SUCCESS:\r
+ ipoib_endpt_deref( p_endpt );\r
+ /* Fall through */\r
+\r
+ case NDIS_STATUS_PENDING:\r
+ return IB_SUCCESS;\r
+ }\r
+\r
+ /*\r
+ * Issue the mcast request, using the parameters of the broadcast group.\r
+ * This allows us to do a create request that should always succeed since\r
+ * the required parameters are known.\r
+ */\r
+ cl_memclr( &mcast_req, sizeof(mcast_req) );\r
+ mcast_req.create = TRUE;\r
+\r
+ /* Copy the settings from the broadcast group. */\r
+ mcast_req.member_rec = p_port->ib_mgr.bcast_rec;\r
+ /* Clear fields that aren't specified in the join */\r
+ mcast_req.member_rec.mlid = 0;\r
+ ib_member_set_state( &mcast_req.member_rec.scope_state,state);\r
+\r
+ if( mac.addr[0] == 1 && mac.addr[1] == 0 && mac.addr[2] == 0x5E )\r
+ {\r
+ /*\r
+ * Update the address portion of the MGID with the 28 lower bits of the\r
+ * IP address. Since we're given a MAC address, we end up using only\r
+ * the 24 lower bits of that network-byte-ordered value (assuming MSb\r
+ * is zero).\r
+ */\r
+ mcast_req.member_rec.mgid.raw[12] = 0;\r
+ mcast_req.member_rec.mgid.raw[13] = mac.addr[3];\r
+ mcast_req.member_rec.mgid.raw[14] = mac.addr[4];\r
+ mcast_req.member_rec.mgid.raw[15] = mac.addr[5];\r
+ }\r
+ else\r
+ {\r
+ /* Handle non IP mutlicast MAC addresses. */\r
+ /* Update the signature to use the lower 2 bytes of the OpenIB OUI. */\r
+ mcast_req.member_rec.mgid.raw[2] = 0x14;\r
+ mcast_req.member_rec.mgid.raw[3] = 0x05;\r
+ /* Now copy the MAC address into the last 6 bytes of the GID. */\r
+ cl_memcpy( &mcast_req.member_rec.mgid.raw[10], mac.addr, 6 );\r
+ }\r
+\r
+ mcast_req.mcast_context = p_port;\r
+ mcast_req.pfn_mcast_cb = __mcast_cb;\r
+ mcast_req.timeout_ms = p_port->p_adapter->params.sa_timeout;\r
+ mcast_req.retry_cnt = p_port->p_adapter->params.sa_retry_cnt;\r
+ mcast_req.port_guid = p_port->p_adapter->guids.port_guid;\r
+ mcast_req.pkey_index = 0;\r
+\r
+ /*\r
+ * Create the endpoint and insert it in the port. Since we don't wait for\r
+ * the mcast SA operations to complete before returning from the multicast\r
+ * list set OID asynchronously, it is possible for the mcast entry to be\r
+ * cleared before the SA interaction completes. In this case, when the\r
+ * mcast callback is invoked, it would not find the corresponding endpoint\r
+ * and would be undone.\r
+ */\r
+ p_endpt = ipoib_endpt_create(\r
+ &mcast_req.member_rec.mgid, 0, CL_HTON32(0x00FFFFFF) );\r
+ if( !p_endpt )\r
+ {\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ipoib_endpt_create failed.\n") );\r
+ return IB_INSUFFICIENT_MEMORY;\r
+ }\r
+\r
+ status = __endpt_mgr_insert_locked( p_port, mac, p_endpt );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("__endpt_mgr_insert_locked returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ return status;\r
+ }\r
+\r
+ /* reference the object for the multicast join request. */\r
+ ipoib_port_ref( p_port, ref_join_mcast );\r
+\r
+ status = p_port->p_adapter->p_ifc->join_mcast( p_port->ib_mgr.h_qp, &mcast_req );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ ipoib_port_deref( p_port, ref_mcast_join_failed );\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ib_join_mcast returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ }\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_MCAST );\r
+ return status;\r
+}\r
+\r
+\r
+static void\r
+__mcast_cb(\r
+ IN ib_mcast_rec_t *p_mcast_rec )\r
+{\r
+ ib_api_status_t status;\r
+ ipoib_port_t *p_port;\r
+ cl_fmap_item_t *p_item;\r
+ cl_map_item_t *p_qitem;\r
+ ipoib_endpt_t *p_endpt;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_MCAST );\r
+\r
+ p_port = (ipoib_port_t* __ptr64)p_mcast_rec->mcast_context;\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+ if( p_port->state != IB_QPS_RTS )\r
+ {\r
+ cl_obj_unlock( &p_port->obj );\r
+ if( p_mcast_rec->status == IB_SUCCESS )\r
+\r
+ {\r
+ ipoib_port_ref(p_port, ref_leave_mcast);\r
+ p_port->p_adapter->p_ifc->leave_mcast( p_mcast_rec->h_mcast, __leave_error_mcast_cb );\r
+ }\r
+ ipoib_port_deref( p_port, ref_mcast_inv_state );\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
+ ("Invalid state - Aborting.\n") );\r
+ return;\r
+ }\r
+ cl_obj_unlock( &p_port->obj );\r
+\r
+ if( p_mcast_rec->status != IB_SUCCESS )\r
+ {\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("Multicast join request failed with status %s.\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( p_mcast_rec->status )) );\r
+ /* Flag the adapter as hung. */\r
+ p_port->p_adapter->hung =TRUE;\r
+ ipoib_port_deref( p_port, ref_mcast_req_failed );\r
+ IPOIB_EXIT( IPOIB_DBG_MCAST );\r
+ return;\r
+ }\r
+\r
+ cl_obj_lock( &p_port->obj );\r
+ p_item = cl_fmap_get(\r
+ &p_port->endpt_mgr.gid_endpts, &p_mcast_rec->p_member_rec->mgid );\r
+ if( p_item == cl_fmap_end( &p_port->endpt_mgr.gid_endpts ) )\r
+ {\r
+ /*\r
+ * The endpoint must have been flushed while the join request\r
+ * was outstanding. Just leave the group and return. This\r
+ * is not an error.\r
+ */\r
+ cl_obj_unlock( &p_port->obj );\r
+ IPOIB_PRINT(TRACE_LEVEL_WARNING, IPOIB_DBG_ERROR,\r
+ ("Failed to find endpoint for update.\n") );\r
+\r
+ ipoib_port_ref(p_port, ref_leave_mcast);\r
+ p_port->p_adapter->p_ifc->leave_mcast( p_mcast_rec->h_mcast, __leave_error_mcast_cb );\r
+ ipoib_port_deref( p_port, ref_mcast_no_endpt );\r
+ IPOIB_EXIT( IPOIB_DBG_MCAST );\r
+ return;\r
+ }\r
+\r
+ p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, gid_item );\r
+ p_endpt->p_ifc = p_port->p_adapter->p_ifc;\r
+\r
+ /* Setup the endpoint for use. */\r
+ status = ipoib_endpt_set_mcast(\r
+ p_endpt, p_port->ib_mgr.h_pd, p_port->port_num, p_mcast_rec );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ cl_obj_unlock( &p_port->obj );\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_MCAST,\r
+ ("ipoib_endpt_set_mcast returned %s.\n",\r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ /* Flag the adapter as hung. */\r
+ p_port->p_adapter->hung = TRUE;\r
+ ipoib_port_deref( p_port, ref_mcast_av_failed );\r
+ IPOIB_EXIT( IPOIB_DBG_MCAST );\r
+ return;\r
+ }\r
+\r
+ /*\r
+ * The endpoint is already in the GID and MAC maps.\r
+ * Add it to the LID map if it has local scope.\r
+ */\r
+ if( p_endpt->dlid )\r
+ {\r
+ p_qitem = cl_qmap_insert(\r
+ &p_port->endpt_mgr.lid_endpts, p_endpt->dlid, &p_endpt->lid_item );\r
+ CL_ASSERT( p_qitem == &p_endpt->lid_item );\r
+ }\r
+ cl_obj_unlock( &p_port->obj );\r
+ \r
+ /* Try to send all pending sends. */\r
+ ipoib_port_resume( p_port );\r
+\r
+ ipoib_port_deref( p_port, ref_join_mcast );\r
+\r
+ IPOIB_EXIT( IPOIB_DBG_MCAST );\r
+}\r
+\r
+\r
+void\r
+ipoib_leave_mcast_cb(\r
+ IN void *context )\r
+{\r
+ ipoib_port_t *p_port;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_MCAST );\r
+\r
+ p_port = (ipoib_port_t* __ptr64)context;\r
+\r
+ IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_MCAST,("p_port->mcast_cnt = %d\n", p_port->mcast_cnt));\r
+ \r
+ ipoib_port_deref( p_port, ref_leave_mcast);\r
+ cl_atomic_dec( &p_port->mcast_cnt);\r
+ \r
+ if(0 == p_port->mcast_cnt)\r
+ {\r
+ KeSetEvent( &p_port->leave_mcast_event, EVENT_INCREMENT, FALSE );\r
+ }\r
+ \r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST,\r
+ ("Leave mcast callback deref ipoib_port \n") );\r
+ \r
+ IPOIB_EXIT( IPOIB_DBG_MCAST );\r
+}\r
+\r
+\r
+\r
+void\r
+__leave_error_mcast_cb(\r
+ IN void *context )\r
+{\r
+ ipoib_port_t *p_port;\r
+\r
+ IPOIB_ENTER( IPOIB_DBG_MCAST );\r
+\r
+ p_port = (ipoib_port_t* __ptr64)context;\r
+\r
+ ipoib_port_deref( p_port, ref_leave_mcast);\r
+ IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST,\r
+ ("Leave mcast callback deref ipoib_port \n") );\r
+ \r
+ IPOIB_EXIT( IPOIB_DBG_MCAST );\r
+}\r
+\r
+\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ * Copyright (c) 2006 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+\r
+#ifndef _IPOIB_PORT_H_\r
+#define _IPOIB_PORT_H_\r
+\r
+\r
+#include <iba/ib_al.h>\r
+#include <complib/cl_obj.h>\r
+#include <complib/cl_qmap.h>\r
+#include <complib/cl_fleximap.h>\r
+#include <ip_packet.h>\r
+#include "ipoib_endpoint.h"\r
+#include "ipoib_xfr_mgr.h"\r
+\r
+\r
+/*\r
+ * Define to place receive buffer inline in receive descriptor.\r
+ */\r
+#define IPOIB_INLINE_RECV 1\r
+\r
+\r
+/* Max send data segment list size. */\r
+#define MAX_SEND_SGE 8\r
+\r
+\r
+/*\r
+ * Define to control how transfers are done. When defined as 1, causes\r
+ * packets to be sent using NDIS DMA facilities (getting the SGL from the\r
+ * packet). When defined as 0, uses the NDIS_BUFFER structures as MDLs\r
+ * to get the physical page mappings of the buffers.\r
+ */\r
+#define IPOIB_USE_DMA 1\r
+\r
+\r
+#define IPOIB_PORT_FROM_PACKET( P ) \\r
+ (((ipoib_port_t**)P->MiniportReservedEx)[0])\r
+#define IPOIB_ENDPT_FROM_PACKET( P ) \\r
+ (((ipoib_endpt_t**)P->MiniportReservedEx)[1])\r
+#define IPOIB_RECV_FROM_PACKET( P ) \\r
+ (((ipoib_recv_desc_t**)P->MiniportReservedEx)[1])\r
+#define IPOIB_SEND_FROM_PACKET( P ) \\r
+ (((send_buf_t**)P->MiniportReservedEx)[2])\r
+#define IPOIB_PACKET_FROM_LIST_ITEM( I ) \\r
+ (PARENT_STRUCT( I, NDIS_PACKET, MiniportReservedEx ))\r
+#define IPOIB_LIST_ITEM_FROM_PACKET( P ) \\r
+ ((cl_list_item_t*)P->MiniportReservedEx)\r
+\r
+\r
+typedef struct _ipoib_ib_mgr\r
+{\r
+ ib_ca_handle_t h_ca;\r
+ ib_pd_handle_t h_pd;\r
+ ib_cq_handle_t h_recv_cq;\r
+ ib_cq_handle_t h_send_cq;\r
+ ib_qp_handle_t h_qp;\r
+ ib_query_handle_t h_query;\r
+ net32_t qpn;\r
+\r
+ ib_mr_handle_t h_mr;\r
+ net32_t lkey;\r
+\r
+ uint8_t rate;\r
+ ib_member_rec_t bcast_rec;\r
+\r
+} ipoib_ib_mgr_t;\r
+/*\r
+* FIELDS\r
+* h_ca\r
+* CA handle for all IB resources.\r
+*\r
+* h_pd\r
+* PD handle for all IB resources.\r
+*\r
+* h_recv_cq\r
+* Recv CQ handle.\r
+*\r
+* h_send_cq\r
+* Send CQ handle.\r
+*\r
+* h_qp\r
+* QP handle for data transfers.\r
+*\r
+* h_query\r
+* Query handle for cancelling SA queries.\r
+*\r
+* h_mr\r
+* Registration handle for all of physical memory. Used for\r
+* send/receive buffers to simplify growing the receive pool.\r
+*\r
+* lkey\r
+* LKey for the memory region.\r
+*\r
+* bcast_rec\r
+* Cached information about the broadcast group, used to specify\r
+* parameters used to join other multicast groups.\r
+*********/\r
+\r
+\r
+#include <complib/cl_packon.h>\r
+/****s* IPoIB Driver/ipoib_hdr_t\r
+* NAME\r
+* ipoib_hdr_t\r
+*\r
+* DESCRIPTION\r
+* IPoIB packet header.\r
+*\r
+* SYNOPSIS\r
+*/\r
+typedef struct _ipoib_hdr\r
+{\r
+ net16_t type;\r
+ net16_t resv;\r
+\r
+} PACK_SUFFIX ipoib_hdr_t;\r
+/*\r
+* FIELDS\r
+* type\r
+* Protocol type.\r
+*\r
+* resv\r
+* Reserved portion of IPoIB header.\r
+*********/\r
+\r
+typedef struct _ipoib_arp_pkt\r
+{\r
+ net16_t hw_type;\r
+ net16_t prot_type;\r
+ uint8_t hw_size;\r
+ uint8_t prot_size;\r
+ net16_t op;\r
+ ipoib_hw_addr_t src_hw;\r
+ net32_t src_ip;\r
+ ipoib_hw_addr_t dst_hw;\r
+ net32_t dst_ip;\r
+\r
+} PACK_SUFFIX ipoib_arp_pkt_t;\r
+\r
+\r
+/****s* IPoIB Driver/ipoib_pkt_t\r
+* NAME\r
+* ipoib_pkt_t\r
+*\r
+* DESCRIPTION\r
+* Represents an IPoIB packet with no GRH.\r
+*\r
+* SYNOPSIS\r
+*/\r
+typedef struct _ipoib_pkt\r
+{\r
+ ipoib_hdr_t hdr;\r
+ union _payload\r
+ {\r
+ uint8_t data[MAX_PAYLOAD_MTU];\r
+ ipoib_arp_pkt_t arp;\r
+ ip_pkt_t ip;\r
+\r
+ } PACK_SUFFIX type;\r
+\r
+} PACK_SUFFIX ipoib_pkt_t;\r
+/*\r
+* FIELDS\r
+* hdr\r
+* IPoIB header.\r
+*\r
+* type\r
+* Union for different types of payloads.\r
+*\r
+* type.data\r
+* raw packet.\r
+*\r
+* type.ib_arp\r
+* IPoIB ARP packet.\r
+*\r
+* type.arp\r
+* Ethernet ARP packet.\r
+*\r
+* type.ip\r
+* IP packet.\r
+*********/\r
+\r
+\r
+/****s* IPoIB Driver/recv_buf_t\r
+* NAME\r
+* recv_buf_t\r
+*\r
+* DESCRIPTION\r
+* Represents a receive buffer, including the ethernet header\r
+* used to indicate the receive to the OS.\r
+*\r
+* SYNOPSIS\r
+*/\r
+typedef union _recv_buf\r
+{\r
+ struct _recv_buf_type_eth\r
+ {\r
+ uint8_t pad[sizeof(ib_grh_t) +\r
+ sizeof(ipoib_hdr_t) -\r
+ sizeof(eth_hdr_t)];\r
+ eth_pkt_t pkt; /* data starts at sizeof(grh)+sizeof(eth_hdr) */\r
+\r
+ } PACK_SUFFIX eth;\r
+\r
+ struct _recv_buf_type_ib\r
+ {\r
+ ib_grh_t grh; /* Must be same offset as lcl_rt.ib.pkt */\r
+ ipoib_pkt_t pkt; /* data starts at 10+grh+4 */\r
+\r
+ } PACK_SUFFIX ib;\r
+\r
+} PACK_SUFFIX recv_buf_t;\r
+/*\r
+* FIELDS\r
+* eth.pkt\r
+* Ethernet packet, used to indicate the receive to the OS.\r
+*\r
+* ib.grh\r
+* GRH for a globally routed received packet.\r
+*\r
+* ib.pkt\r
+* IPOIB packet representing a globally routed received packet.\r
+*\r
+* NOTES\r
+* When posting the work request, the address of ib.grh is used.\r
+*\r
+* TODO: Do we need a pad to offset the header so that the data ends up\r
+* aligned on a pointer boundary?\r
+*********/\r
+\r
+/****s* IPoIB Driver/send_buf_t\r
+* NAME\r
+* send_buf_t\r
+*\r
+* DESCRIPTION\r
+* Represents a send buffer, used to convert packets to IPoIB format.\r
+*\r
+* SYNOPSIS\r
+*/\r
+typedef union _send_buf\r
+{\r
+ uint8_t data[MAX_PAYLOAD_MTU];\r
+ ipoib_arp_pkt_t arp;\r
+ ip_pkt_t ip;\r
+\r
+} PACK_SUFFIX send_buf_t;\r
+/*\r
+* FIELDS\r
+* data\r
+* IP/ARP packet.\r
+*\r
+* NOTES\r
+* TODO: Do we need a pad to offset the header so that the data ends up\r
+* aligned on a pointer boundary?\r
+*********/\r
+#include <complib/cl_packoff.h>\r
+\r
+\r
+typedef struct _ipoib_buf_mgr\r
+{\r
+ cl_qpool_t recv_pool;\r
+\r
+ NDIS_HANDLE h_packet_pool;\r
+ NDIS_HANDLE h_buffer_pool;\r
+\r
+ NPAGED_LOOKASIDE_LIST send_buf_list;\r
+ NDIS_HANDLE h_send_pkt_pool;\r
+ NDIS_HANDLE h_send_buf_pool;\r
+\r
+} ipoib_buf_mgr_t;\r
+/*\r
+* FIELDS\r
+* recv_pool\r
+* Pool of ipoib_recv_desc_t structures.\r
+*\r
+* h_packet_pool\r
+* NDIS packet pool, used to indicate receives to NDIS.\r
+*\r
+* h_buffer_pool\r
+* NDIS buffer pool, used to indicate receives to NDIS.\r
+*\r
+* send_buf_list\r
+* Lookaside list for dynamically allocating send buffers for send\r
+* that require copies (ARP, DHCP, and any with more physical pages\r
+* than can fit in the local data segments).\r
+*********/\r
+\r
+\r
+typedef enum _ipoib_pkt_type\r
+{\r
+ PKT_TYPE_UCAST,\r
+ PKT_TYPE_BCAST,\r
+ PKT_TYPE_MCAST\r
+\r
+} ipoib_pkt_type_t;\r
+\r
+\r
+typedef struct _ipoib_recv_desc\r
+{\r
+ cl_pool_item_t item; /* Must be first. */\r
+ uint32_t len;\r
+ ipoib_pkt_type_t type;\r
+ ib_recv_wr_t wr;\r
+ ib_local_ds_t local_ds[2];\r
+#if IPOIB_INLINE_RECV\r
+ recv_buf_t buf;\r
+#else\r
+ recv_buf_t *p_buf;\r
+#endif\r
+\r
+} ipoib_recv_desc_t;\r
+/*\r
+* FIELDS\r
+* item\r
+* Pool item for storing descriptors in a pool.\r
+*\r
+* len\r
+* Length to indicate to NDIS. This is different than the length of the\r
+* received data as some data is IPoIB specific and filtered out.\r
+*\r
+* type\r
+* Type of packet, used in filtering received packets against the packet\r
+* filter. Also used to update stats.\r
+*\r
+* wr\r
+* Receive work request.\r
+*\r
+* local_ds\r
+* Local data segments. The second segment is only used if a buffer\r
+* spans physical pages.\r
+*\r
+* buf\r
+* Buffer for the receive.\r
+*\r
+* NOTES\r
+* The pool item is always first to allow casting form a cl_pool_item_t or\r
+* cl_list_item_t to the descriptor.\r
+*********/\r
+\r
+\r
+typedef struct _ipoib_send_desc\r
+{\r
+ NDIS_PACKET *p_pkt;\r
+ ipoib_endpt_t *p_endpt;\r
+ send_buf_t *p_buf;\r
+ ib_send_wr_t wr;\r
+ ipoib_hdr_t pkt_hdr;\r
+ ib_local_ds_t local_ds[MAX_SEND_SGE]; /* Must be last. */\r
+\r
+} ipoib_send_desc_t;\r
+/*\r
+* FIELDS\r
+* p_pkt\r
+* Pointer to the NDIS_PACKET associated with the send operation.\r
+*\r
+* p_endpt\r
+* Endpoint for this send.\r
+*\r
+* p_buf\r
+* Buffer for the send, if allocated.\r
+*\r
+* wr\r
+* Send work request.\r
+*\r
+* pkt_hdr\r
+* IPoIB packet header, pointed to by the first local datasegment.\r
+*\r
+* local_ds\r
+* Local data segment array. Placed last to allow allocating beyond the\r
+* end of the descriptor for additional datasegments.\r
+*\r
+* NOTES\r
+* The pool item is always first to allow casting form a cl_pool_item_t or\r
+* cl_list_item_t to the descriptor.\r
+*********/\r
+\r
+\r
+typedef struct _ipoib_recv_mgr\r
+{\r
+ int32_t depth;\r
+\r
+ NDIS_PACKET **recv_pkt_array;\r
+\r
+ cl_qlist_t done_list;\r
+\r
+} ipoib_recv_mgr_t;\r
+/*\r
+* FIELDS\r
+* depth\r
+* Current number of WRs posted.\r
+*\r
+* p_head\r
+* Pointer to work completion in descriptor at the head of the QP.\r
+*\r
+* p_tail\r
+* Pointer to the work completion in the descriptor at the tail of the QP.\r
+*\r
+* recv_pkt_array\r
+* Array of pointers to NDIS_PACKET used to indicate receives.\r
+*\r
+* done_list\r
+* List of receive descriptors that need to be indicated to NDIS.\r
+*********/\r
+\r
+\r
+typedef struct _ipoib_send_mgr\r
+{\r
+ atomic32_t depth;\r
+ cl_qlist_t pending_list;\r
+\r
+} ipoib_send_mgr_t;\r
+/*\r
+* FIELDS\r
+* depth\r
+* Current number of WRs posted, used to queue pending requests.\r
+*\r
+* pending_list\r
+* List of NDIS_PACKET structures that are awaiting available WRs to send.\r
+*********/\r
+\r
+\r
+typedef struct _ipoib_endpt_mgr\r
+{\r
+ cl_qmap_t mac_endpts;\r
+ cl_fmap_t gid_endpts;\r
+ cl_qmap_t lid_endpts;\r
+\r
+} ipoib_endpt_mgr_t;\r
+/*\r
+* FIELDS\r
+* mac_endpts\r
+* Map of enpoints, keyed by MAC address.\r
+*\r
+* gid_endpts\r
+* Map of enpoints, keyed by GID.\r
+*\r
+* lid_endpts\r
+* Map of enpoints, keyed by LID. Only enpoints on the same subnet\r
+* are inserted in the LID map.\r
+*********/\r
+\r
+\r
+typedef struct _ipoib_port\r
+{\r
+ cl_obj_t obj;\r
+ cl_obj_rel_t rel;\r
+\r
+ ib_qp_state_t state;\r
+\r
+ cl_spinlock_t recv_lock;\r
+ cl_spinlock_t send_lock;\r
+\r
+ struct _ipoib_adapter *p_adapter;\r
+ uint8_t port_num;\r
+\r
+ KEVENT sa_event;\r
+\r
+ atomic32_t mcast_cnt;\r
+ KEVENT leave_mcast_event;\r
+ \r
+ ipoib_ib_mgr_t ib_mgr;\r
+\r
+ ipoib_buf_mgr_t buf_mgr;\r
+\r
+ ipoib_recv_mgr_t recv_mgr;\r
+ ipoib_send_mgr_t send_mgr;\r
+\r
+ ipoib_endpt_mgr_t endpt_mgr;\r
+\r
+ ipoib_endpt_t *p_local_endpt;\r
+\r
+#if DBG\r
+ atomic32_t ref[ref_array_size];\r
+#endif\r
+\r
+ atomic32_t endpt_rdr;\r
+\r
+ atomic32_t hdr_idx;\r
+ ipoib_hdr_t hdr[1]; /* Must be last! */\r
+\r
+} ipoib_port_t;\r
+/*\r
+* FIELDS\r
+* obj\r
+* Complib object for reference counting, relationships,\r
+* and destruction synchronization.\r
+*\r
+* rel\r
+* Relationship to associate the port with the adapter.\r
+*\r
+* state\r
+* State of the port object. Tracks QP state fairly closely.\r
+*\r
+* recv_lock\r
+* Spinlock to protect receive operations.\r
+*\r
+* send_lock\r
+* Spinlock to protect send operations.\r
+*\r
+* p_adapter\r
+* Parent adapter. Used to get AL handle.\r
+*\r
+* port_num\r
+* Port number of this adapter.\r
+*\r
+* ib_mgr\r
+* IB resource manager.\r
+*\r
+* recv_mgr\r
+* Receive manager.\r
+*\r
+* send_mgr\r
+* Send manager.\r
+*\r
+* endpt_mgr\r
+* Endpoint manager.\r
+*********/\r
+\r
+\r
+ib_api_status_t\r
+ipoib_create_port(\r
+ IN struct _ipoib_adapter* const p_adapter,\r
+ IN ib_pnp_port_rec_t* const p_pnp_rec,\r
+ OUT ipoib_port_t** const pp_port );\r
+\r
+void\r
+ipoib_port_destroy(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+void\r
+ipoib_port_up(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const ib_pnp_port_rec_t* const p_pnp_rec );\r
+\r
+void\r
+ipoib_port_down(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+ib_api_status_t\r
+ipoib_port_join_mcast(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac,\r
+ IN const uint8_t state );\r
+\r
+\r
+void\r
+ipoib_leave_mcast_cb(\r
+ IN void *context );\r
+\r
+\r
+void\r
+ipoib_port_remove_endpt(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac );\r
+\r
+void\r
+ipoib_port_flush_endpts(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+void\r
+ipoib_port_send(\r
+ IN ipoib_port_t* const p_port,\r
+ IN NDIS_PACKET **p_packet_array,\r
+ IN uint32_t num_packets );\r
+\r
+void\r
+ipoib_return_packet(\r
+ IN NDIS_HANDLE adapter_context,\r
+ IN NDIS_PACKET *p_packet );\r
+\r
+void\r
+ipoib_port_resume(\r
+ IN ipoib_port_t* const p_port );\r
+\r
+NTSTATUS\r
+ipoib_mac_to_gid(\r
+ IN ipoib_port_t* const p_port,\r
+ IN const mac_addr_t mac,\r
+ OUT ib_gid_t* p_gid );\r
+\r
+inline void ipoib_port_ref(\r
+ IN ipoib_port_t * p_port, \r
+ IN int type);\r
+\r
+inline void ipoib_port_deref(\r
+ IN ipoib_port_t * p_port,\r
+ IN int type);\r
+\r
+\r
+#endif /* _IPOIB_PORT_H_ */\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+#ifndef _IPOIB_XFR_MGR_H_\r
+#define _IPOIB_XFR_MGR_H_\r
+\r
+\r
+#include <iba/ib_al.h>\r
+#include <complib/cl_types.h>\r
+#include <complib/cl_qpool.h>\r
+#include <complib/cl_spinlock.h>\r
+#include <complib/cl_qlist.h>\r
+#include <complib/cl_qpool.h>\r
+#include <complib/cl_list.h>\r
+\r
+\r
+#include "ipoib_driver.h"\r
+#include "ip_stats.h"\r
+#include <ip_packet.h>\r
+\r
+\r
+#include <complib/cl_packon.h>\r
+/****s* IPoIB Driver/ipoib_hw_addr_t\r
+* NAME\r
+* ipoib_hw_addr_t\r
+*\r
+* DESCRIPTION\r
+* The ipoib_hw_addr_t structure defines an IPoIB compatible hardware\r
+* address. Values in this structure are stored in network order.\r
+*\r
+* SYNOPSIS\r
+*/\r
+typedef struct _ipoib_hw_addr\r
+{\r
+ uint32_t flags_qpn;\r
+ ib_gid_t gid;\r
+\r
+} PACK_SUFFIX ipoib_hw_addr_t;\r
+/*\r
+* FIELDS\r
+* flags_qpn\r
+* Flags and queue pair number. Use ipoib_addr_get_flags,\r
+* ipoib_addr_set_flags, ipoib_addr_set_qpn, and ipoib_addr_get_qpn\r
+* to manipulate the contents.\r
+*\r
+* gid\r
+* IB GID value.\r
+*\r
+* SEE ALSO\r
+* IPoIB, ipoib_addr_get_flags, ipoib_addr_set_flags, ipoib_addr_set_qpn,\r
+* ipoib_addr_get_qpn\r
+*********/\r
+#include <complib/cl_packoff.h>\r
+\r
+\r
+\r
+#ifdef __cplusplus\r
+extern "C"\r
+{\r
+#endif\r
+\r
+\r
+/*\r
+ * Address accessors\r
+ */\r
+\r
+static inline uint8_t\r
+ipoib_addr_get_flags(\r
+ IN const ipoib_hw_addr_t* const p_addr )\r
+{\r
+ return (uint8_t)(cl_ntoh32( p_addr->flags_qpn ) >> 24);\r
+}\r
+\r
+static inline void\r
+ipoib_addr_set_flags(\r
+ IN ipoib_hw_addr_t* const p_addr,\r
+ IN const uint8_t flags )\r
+{\r
+ p_addr->flags_qpn &= cl_ntoh32( 0xFFFFFF00 );\r
+ p_addr->flags_qpn |= cl_ntoh32( flags );\r
+}\r
+\r
+static inline net32_t\r
+ipoib_addr_get_qpn(\r
+ IN const ipoib_hw_addr_t* const p_addr )\r
+{\r
+ return cl_ntoh32( cl_ntoh32( p_addr->flags_qpn ) >> 8 );\r
+}\r
+\r
+static inline void\r
+ipoib_addr_set_qpn(\r
+ IN ipoib_hw_addr_t* const p_addr,\r
+ IN const net32_t qpn )\r
+{\r
+ p_addr->flags_qpn = cl_ntoh32( (cl_ntoh32(\r
+ p_addr->flags_qpn ) & 0x000000FF ) | (cl_ntoh32( qpn ) << 8) );\r
+}\r
+\r
+\r
+/****f* IPOIB/ipoib_mac_from_sst_guid\r
+* NAME\r
+* ipoib_mac_from_sst_guid\r
+*\r
+* DESCRIPTION\r
+* Generates an ethernet MAC address given a SilverStorm port GUID.\r
+*\r
+* SYNOPSIS\r
+*/\r
+static inline ib_api_status_t\r
+ipoib_mac_from_sst_guid(\r
+ IN const net64_t port_guid,\r
+ OUT mac_addr_t* const p_mac_addr )\r
+{\r
+ const uint8_t *p_guid = (const uint8_t*)&port_guid;\r
+ uint32_t low24;\r
+\r
+ /* Port guid is in network byte order. OUI is in lower 3 bytes. */\r
+ ASSERT( p_guid[0] == 0x00 && p_guid[1] == 0x06 && p_guid[2] == 0x6a );\r
+\r
+ /*\r
+ * We end up using only the lower 23-bits of the GUID. Trap that\r
+ * the 24th (bit 23) through 27th (bit 26) bit aren't set.\r
+ */\r
+ if( port_guid & CL_HTON64( 0x0000000007800000 ) )\r
+ return IB_INVALID_GUID;\r
+\r
+ low24 = 0x00FFF000 -\r
+ ((((uint32_t)cl_ntoh64( port_guid ) & 0x00FFFFFF) - 0x101) * 2);\r
+ low24 -= p_guid[3]; /* minus port number */\r
+\r
+ p_mac_addr->addr[0] = p_guid[0];\r
+ p_mac_addr->addr[1] = p_guid[1];\r
+ p_mac_addr->addr[2] = p_guid[2];\r
+ p_mac_addr->addr[3] = (uint8_t)(low24 >> 16);\r
+ p_mac_addr->addr[4] = (uint8_t)(low24 >> 8);\r
+ p_mac_addr->addr[5] = (uint8_t)low24;\r
+ \r
+ return IB_SUCCESS;\r
+}\r
+/*\r
+* PARAMETERS\r
+* port_guid\r
+* The port GUID, in network byte order, for which to generate a\r
+* MAC address.\r
+*\r
+* p_mac_addr\r
+* Pointer to a mac address in which to store the results.\r
+*\r
+* RETURN VALUES\r
+* IB_SUCCESS\r
+* The MAC address was successfully converted.\r
+*\r
+* IB_INVALID_GUID\r
+* The port GUID provided was not a known GUID format.\r
+*\r
+* NOTES\r
+* The algorithm to convert portGuid to MAC address is as per DN0074, and\r
+* assumes a 2 port HCA.\r
+*\r
+* SEE ALSO\r
+* IPOIB\r
+*********/\r
+\r
+\r
+/****f* IPOIB/ipoib_mac_from_mlx_guid\r
+* NAME\r
+* ipoib_mac_from_mlx_guid\r
+*\r
+* DESCRIPTION\r
+* Generates an ethernet MAC address given a Mellanox port GUID.\r
+*\r
+* SYNOPSIS\r
+*/\r
+static inline ib_api_status_t\r
+ipoib_mac_from_mlx_guid(\r
+ IN const net64_t port_guid,\r
+ OUT mac_addr_t* const p_mac_addr )\r
+{\r
+ const uint8_t *p_guid = (const uint8_t*)&port_guid;\r
+ uint32_t low24;\r
+\r
+ /* Port guid is in network byte order. OUI is in lower 3 bytes. */\r
+ ASSERT( p_guid[0] == 0x00 && p_guid[1] == 0x02 && p_guid[2] == 0xc9 );\r
+\r
+ if( (port_guid & CL_HTON64( 0x000000ffff000000 )) !=\r
+ CL_HTON64(0x0000000200000000))\r
+ {\r
+ return IB_INVALID_GUID;\r
+ }\r
+\r
+ low24 = ((uint32_t)cl_ntoh64( port_guid ) & 0x00FFFFFF);\r
+\r
+ p_mac_addr->addr[0] = p_guid[0];\r
+ p_mac_addr->addr[1] = p_guid[1];\r
+ p_mac_addr->addr[2] = p_guid[2];\r
+ p_mac_addr->addr[3] = (uint8_t)(low24 >> 16);\r
+ p_mac_addr->addr[4] = (uint8_t)(low24 >> 8);\r
+ p_mac_addr->addr[5] = (uint8_t)low24;\r
+ \r
+ return IB_SUCCESS;\r
+}\r
+/*\r
+* PARAMETERS\r
+* port_guid\r
+* The port GUID, in network byte order, for which to generate a\r
+* MAC address.\r
+*\r
+* p_mac_addr\r
+* Pointer to a mac address in which to store the results.\r
+*\r
+* RETURN VALUES\r
+* IB_SUCCESS\r
+* The MAC address was successfully converted.\r
+*\r
+* IB_INVALID_GUID\r
+* The port GUID provided was not a known GUID format.\r
+*\r
+* SEE ALSO\r
+* IPOIB\r
+*********/\r
+\r
+\r
+/****f* IPOIB/ipoib_mac_from_voltaire_guid\r
+* NAME\r
+* ipoib_mac_from_voltaire_guid\r
+*\r
+* DESCRIPTION\r
+* Generates an ethernet MAC address given a Voltaire port GUID.\r
+*\r
+* SYNOPSIS\r
+*/\r
+static inline ib_api_status_t\r
+ipoib_mac_from_voltaire_guid(\r
+ IN const net64_t port_guid,\r
+ OUT mac_addr_t* const p_mac_addr )\r
+{\r
+ const uint8_t *p_guid = (const uint8_t*)&port_guid;\r
+\r
+ /* Port guid is in network byte order. OUI is in lower 3 bytes. */\r
+ ASSERT( p_guid[0] == 0x00 && p_guid[1] == 0x08 && p_guid[2] == 0xf1 );\r
+\r
+ p_mac_addr->addr[0] = p_guid[0];\r
+ p_mac_addr->addr[1] = p_guid[1];\r
+ p_mac_addr->addr[2] = p_guid[2];\r
+ p_mac_addr->addr[3] = p_guid[4] ^ p_guid[6];\r
+ p_mac_addr->addr[4] = p_guid[5] ^ p_guid[7];\r
+ p_mac_addr->addr[5] = p_guid[5] + p_guid[6] + p_guid[7];\r
+\r
+ return IB_SUCCESS;\r
+}\r
+\r
+/****f* IPOIB/ipoib_mac_from_supermicro_guid\r
+* NAME\r
+* ipoib_mac_from_supermicro_guid\r
+*\r
+* DESCRIPTION\r
+* Generates an ethernet MAC address given a supermicro port GUID.\r
+*\r
+* SYNOPSIS\r
+*/\r
+static inline ib_api_status_t\r
+ipoib_mac_from_supermicro_guid(\r
+ IN const net64_t port_guid,\r
+ OUT mac_addr_t* const p_mac_addr )\r
+{\r
+ const uint8_t *p_guid = (const uint8_t*)&port_guid;\r
+\r
+ /* Port guid is in network byte order. OUI is in lower 3 bytes. */\r
+ ASSERT( p_guid[0] == 0x00 && p_guid[1] == 0x30 && p_guid[2] == 0x48 \r
+ && p_guid[3] == 0xff && p_guid[4] == 0xff);\r
+\r
+ p_mac_addr->addr[0] = 0;\r
+ p_mac_addr->addr[1] = 0x30;\r
+ p_mac_addr->addr[2] = 0x48; \r
+ p_mac_addr->addr[3] = p_guid[5];\r
+ p_mac_addr->addr[4] = p_guid[6];\r
+ p_mac_addr->addr[5] = p_guid[7];\r
+\r
+ return IB_SUCCESS;\r
+}\r
+\r
+/****f* IPOIB/ipoib_mac_from_cisco_guid\r
+* NAME\r
+* ipoib_mac_from_cisco_guid\r
+*\r
+* DESCRIPTION\r
+* Generates an ethernet MAC address given a Cisco port GUID.\r
+*\r
+* SYNOPSIS\r
+*/\r
+static inline ib_api_status_t\r
+ipoib_mac_from_cisco_guid(\r
+ IN const net64_t port_guid,\r
+ OUT mac_addr_t* const p_mac_addr )\r
+{\r
+ const uint8_t *p_guid = (const uint8_t*)&port_guid;\r
+\r
+ /* Port guid is in network byte order. OUI is in lower 3 bytes. */\r
+ ASSERT( p_guid[0] == 0x00 && p_guid[1] == 0x5 && p_guid[2] == 0xad);\r
+\r
+ p_mac_addr->addr[0] = 0;\r
+ p_mac_addr->addr[1] = 0x5;\r
+ p_mac_addr->addr[2] = 0xad; \r
+ p_mac_addr->addr[3] = p_guid[5];\r
+ p_mac_addr->addr[4] = p_guid[6];\r
+ p_mac_addr->addr[5] = p_guid[7];\r
+\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+/*\r
+* PARAMETERS\r
+* port_guid\r
+* The port GUID, in network byte order, for which to generate a\r
+* MAC address.\r
+*\r
+* p_mac_addr\r
+* Pointer to a mac address in which to store the results.\r
+*\r
+* RETURN VALUES\r
+* IB_SUCCESS\r
+* The MAC address was successfully converted.\r
+*\r
+* SEE ALSO\r
+* IPOIB\r
+*********/\r
+\r
+\r
+/****f* IPOIB/ipoib_mac_from_guid\r
+* NAME\r
+* ipoib_mac_from_guid\r
+*\r
+* DESCRIPTION\r
+* Generates an ethernet MAC address given a port GUID.\r
+*\r
+* SYNOPSIS\r
+*/\r
+static inline ib_api_status_t\r
+ipoib_mac_from_guid(\r
+ IN const net64_t port_guid,\r
+ OUT mac_addr_t* const p_mac_addr )\r
+{\r
+ ib_api_status_t status;\r
+ const uint8_t *p_guid = (const uint8_t*)&port_guid;\r
+ uint32_t laa;\r
+\r
+ if( p_guid[0] == 0 ) \r
+ {\r
+ if( p_guid[1] == 0x02 && p_guid[2] == 0xc9 )\r
+ {\r
+ status = ipoib_mac_from_mlx_guid( port_guid, p_mac_addr );\r
+ if( status == IB_SUCCESS )\r
+ return IB_SUCCESS;\r
+ }\r
+ else if( p_guid[1] == 0x08 && p_guid[2] == 0xf1 )\r
+ {\r
+ status = ipoib_mac_from_voltaire_guid( port_guid, p_mac_addr );\r
+ if( status == IB_SUCCESS )\r
+ return IB_SUCCESS;\r
+ }\r
+ else if( p_guid[1] == 0x30 && p_guid[2] == 0x48 )\r
+ {\r
+ status = ipoib_mac_from_supermicro_guid( port_guid, p_mac_addr );\r
+ if( status == IB_SUCCESS )\r
+ return IB_SUCCESS;\r
+ }\r
+ else if( p_guid[1] == 0x05 && p_guid[2] == 0xad )\r
+ {\r
+ status = ipoib_mac_from_cisco_guid( port_guid, p_mac_addr );\r
+ if( status == IB_SUCCESS )\r
+ return IB_SUCCESS;\r
+ } \r
+ /* Port guid is in network byte order. OUI is in lower 3 bytes. */\r
+ else if( p_guid[1] == 0x06 && p_guid[2] == 0x6a )\r
+ {\r
+ status = ipoib_mac_from_sst_guid( port_guid, p_mac_addr );\r
+ if( status == IB_SUCCESS )\r
+ return IB_SUCCESS;\r
+ }\r
+ \r
+ }\r
+ /* Value of zero is reserved. */\r
+ laa = cl_atomic_inc( &g_ipoib.laa_idx );\r
+\r
+ if( !laa )\r
+ return IB_INVALID_GUID;\r
+\r
+ p_mac_addr->addr[0] = 2; /* LAA bit */\r
+ p_mac_addr->addr[1] = 0;\r
+ p_mac_addr->addr[2] = (uint8_t)(laa >> 24);\r
+ p_mac_addr->addr[3] = (uint8_t)(laa >> 16);\r
+ p_mac_addr->addr[4] = (uint8_t)(laa >> 8);\r
+ p_mac_addr->addr[5] = (uint8_t)laa;\r
+ \r
+ return IB_SUCCESS;\r
+}\r
+/*\r
+* PARAMETERS\r
+* port_guid\r
+* The port GUID, in network byte order, for which to generate a\r
+* MAC address.\r
+*\r
+* p_mac_addr\r
+* Pointer to a mac address in which to store the results.\r
+*\r
+* RETURN VALUES\r
+* IB_SUCCESS\r
+* The MAC address was successfully converted.\r
+*\r
+* IB_INVALID_GUID\r
+* The port GUID provided was not a known GUID format.\r
+*\r
+* NOTES\r
+* Creates a locally administered address using a global incrementing counter.\r
+*\r
+* SEE ALSO\r
+* IPOIB\r
+*********/\r
+\r
+\r
+/****f* IPOIB/ipoib_sst_guid_from_mac\r
+* NAME\r
+* ipoib_sst_guid_from_mac\r
+*\r
+* DESCRIPTION\r
+* Generates a port GUID given an ethernet MAC address.\r
+*\r
+* SYNOPSIS\r
+*/\r
+static inline ib_api_status_t\r
+ipoib_sst_guid_from_mac(\r
+ IN const mac_addr_t mac,\r
+ OUT net64_t* const p_port_guid )\r
+{\r
+ uint8_t *p_guid = (uint8_t*)p_port_guid;\r
+ uint32_t low24;\r
+\r
+ /* MAC address is in network byte order. OUI is in lower 3 bytes. */\r
+ if( mac.addr[0] != 0x00 || \r
+ mac.addr[1] != 0x06 || \r
+ mac.addr[2] != 0x6a )\r
+ {\r
+ return IB_INVALID_GUID;\r
+ }\r
+\r
+ low24 = mac.addr[3] << 16 || mac.addr[4] << 8 || mac.addr[5];\r
+\r
+ low24 = 0x00FFF000 - low24;\r
+ /* Divide by two */\r
+ low24 >>= 1;\r
+ /* Add the serial number base offset. */\r
+ low24 += 0x101;\r
+\r
+ /* OUI */\r
+ p_guid[0] = mac.addr[0];\r
+ p_guid[1] = mac.addr[1];\r
+ p_guid[2] = mac.addr[2];\r
+ /* Port number */\r
+ p_guid[3] = mac.addr[5] & 0x01;\r
+ /* Type */\r
+ p_guid[4] = 0x98;\r
+ /* Serial Number */\r
+ p_guid[5] = (uint8_t)(low24 >> 16);\r
+ p_guid[6] = (uint8_t)(low24 >> 8);\r
+ p_guid[7] = (uint8_t)low24;\r
+ \r
+ return IB_SUCCESS;\r
+}\r
+/*\r
+* PARAMETERS\r
+* port_guid\r
+* The port GUID, in network byte order, for which to generate a\r
+* MAC address.\r
+*\r
+* p_mac_addr\r
+* Pointer to a mac address in which to store the results.\r
+*\r
+* RETURN VALUES\r
+* IB_SUCCESS\r
+* The MAC address was successfully converted.\r
+*\r
+* IB_INVALID_GUID\r
+* The port GUID provided was not a known GUID format.\r
+*\r
+* NOTES\r
+* The algorithm to convert portGuid to MAC address is as per DN0074, and\r
+* assumes a 2 port HCA.\r
+*\r
+* SEE ALSO\r
+* IPOIB\r
+*********/\r
+\r
+\r
+/****f* IPOIB/ipoib_mlx_guid_from_mac\r
+* NAME\r
+* ipoib_mlx_guid_from_mac\r
+*\r
+* DESCRIPTION\r
+* Generates a port GUID given an ethernet MAC address.\r
+*\r
+* SYNOPSIS\r
+*/\r
+static inline ib_api_status_t\r
+ipoib_mlx_guid_from_mac(\r
+ IN const mac_addr_t mac,\r
+ OUT net64_t* const p_port_guid )\r
+{\r
+ uint8_t *p_guid = (uint8_t*)p_port_guid;\r
+ uint32_t low24;\r
+\r
+ /* MAC address is in network byte order. OUI is in lower 3 bytes. */\r
+ if( mac.addr[0] != 0x00 || \r
+ mac.addr[1] != 0x02 || \r
+ mac.addr[2] != 0xc9 )\r
+ {\r
+ return IB_INVALID_GUID;\r
+ }\r
+\r
+ low24 = mac.addr[3] << 16 || mac.addr[4] << 8 || mac.addr[5];\r
+\r
+ /* OUI */\r
+ p_guid[0] = mac.addr[0];\r
+ p_guid[1] = mac.addr[1];\r
+ p_guid[2] = mac.addr[2];\r
+ p_guid[3] = 0x02;\r
+ p_guid[4] = 0x00;\r
+ /* Serial Number */\r
+ p_guid[5] = (uint8_t)(low24 >> 16);\r
+ p_guid[6] = (uint8_t)(low24 >> 8);\r
+ p_guid[7] = (uint8_t)low24;\r
+ \r
+ return IB_SUCCESS;\r
+}\r
+/*\r
+* PARAMETERS\r
+* port_guid\r
+* The port GUID, in network byte order, for which to generate a\r
+* MAC address.\r
+*\r
+* p_mac_addr\r
+* Pointer to a mac address in which to store the results.\r
+*\r
+* RETURN VALUES\r
+* IB_SUCCESS\r
+* The MAC address was successfully converted.\r
+*\r
+* IB_INVALID_GUID\r
+* The port GUID provided was not a known GUID format.\r
+*\r
+* NOTES\r
+* The algorithm to convert portGuid to MAC address is as \r
+*\r
+* SEE ALSO\r
+* IPOIB\r
+*********/\r
+\r
+\r
+/****f* IPOIB/ipoib_is_voltaire_router_gid\r
+* NAME\r
+* ipoib_is_voltaire_router_gid\r
+*\r
+* DESCRIPTION\r
+* Checks whether the GID belongs to Voltaire IP router\r
+*\r
+* SYNOPSIS\r
+*/\r
+boolean_t\r
+static inline\r
+ipoib_is_voltaire_router_gid(\r
+ IN const ib_gid_t *p_gid )\r
+{\r
+ static const uint8_t VOLTAIRE_GUID_PREFIX[] = {0, 0x08, 0xf1, 0, 0x1};\r
+\r
+ return !cl_memcmp( &p_gid->unicast.interface_id, VOLTAIRE_GUID_PREFIX,\r
+ sizeof(VOLTAIRE_GUID_PREFIX) );\r
+}\r
+\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* _IPOIB_XFR_MGR_H_ */\r
--- /dev/null
+#\r
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source\r
+# file to this component. This file merely indirects to the real make file\r
+# that is shared by all the driver components of the OpenIB Windows project.\r
+#\r
+\r
+!INCLUDE ..\..\..\inc\openib.def\r
--- /dev/null
+; OpenIB Internet Protocol over InfiniBand Adapter\r
+; Copyright 2005 SilverStorm Technologies all Rights Reserved.\r
+; Copyright 2006 Mellanox Technologies all Rights Reserved.\r
+\r
+[Version]\r
+Signature = "$Windows NT$"\r
+Class = Net\r
+ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}\r
+Provider = %OPENIB%\r
+DriverVer=05/15/2008,1.1.0000.1177\r
+CatalogFile=ipoib.cat\r
+\r
+[Manufacturer]\r
+%OPENIB% = OPENIB,ntx86,ntamd64,ntia64\r
+\r
+[ControlFlags]\r
+ExcludeFromSelect = IBA\IPoIB\r
+\r
+[OPENIB]\r
+; empty since we don't support W9x/Me\r
+\r
+[OPENIB.ntx86]\r
+%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter\r
+\r
+[OPENIB.ntamd64]\r
+%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter\r
+\r
+[OPENIB.ntia64]\r
+%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter\r
+\r
+[Ipoib.DDInstall.ntx86]\r
+Characteristics = 0x81 ; NCF_HAS_UI | NCF_VIRTUAL\r
+AddReg = IpoibAddReg\r
+CopyFiles = IpoibCopyFiles\r
+CopyFiles = WsdCopyFiles\r
+\r
+[Ipoib.DDInstall.ntamd64]\r
+Characteristics = 0x81 ; NCF_HAS_UI | NCF_VIRTUAL\r
+AddReg = IpoibAddReg\r
+CopyFiles = IpoibCopyFiles\r
+CopyFiles = WsdCopyFiles\r
+CopyFiles = WOW64CopyFiles\r
+\r
+[Ipoib.DDInstall.ntia64]\r
+Characteristics = 0x81 ; NCF_HAS_UI | NCF_VIRTUAL\r
+AddReg = IpoibAddReg\r
+CopyFiles = IpoibCopyFiles\r
+CopyFiles = WsdCopyFiles\r
+CopyFiles = WOW64CopyFiles\r
+\r
+[Ipoib.DDInstall.ntx86.Services]\r
+AddService = ipoib, 2, IpoibService, IpoibEventLog\r
+\r
+[Ipoib.DDInstall.ntamd64.Services]\r
+AddService = ipoib, 2, IpoibService, IpoibEventLog\r
+\r
+[Ipoib.DDInstall.ntia64.Services]\r
+AddService = ipoib, 2, IpoibService, IpoibEventLog\r
+\r
+[IpoibAddReg]\r
+HKR, Ndi, Service, 0, "ipoib"\r
+HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"\r
+HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"\r
+\r
+HKR, Ndi\Params\RqDepth, ParamDesc, 0, "Receive Queue Depth"\r
+HKR, Ndi\Params\RqDepth, Type, 0, "dword"\r
+HKR, Ndi\Params\RqDepth, Default, 0, "512"\r
+HKR, Ndi\Params\RqDepth, Optional, 0, "0"\r
+HKR, Ndi\Params\RqDepth, Min, 0, "128"\r
+HKR, Ndi\Params\RqDepth, Max, 0, "1024"\r
+HKR, Ndi\Params\RqDepth, Step, 0, "128"\r
+\r
+HKR, Ndi\Params\RqLowWatermark, ParamDesc, 0, "Receive Queue Low Watermark"\r
+HKR, Ndi\Params\RqLowWatermark, Type, 0, "dword"\r
+HKR, Ndi\Params\RqLowWatermark, Default, 0, "4"\r
+HKR, Ndi\Params\RqLowWatermark, Optional, 0, "1"\r
+HKR, Ndi\Params\RqLowWatermark, Min, 0, "2"\r
+HKR, Ndi\Params\RqLowWatermark, Max, 0, "8"\r
+HKR, Ndi\Params\RqLowWatermark, Step, 0, "1"\r
+\r
+HKR, Ndi\Params\SqDepth, ParamDesc, 0, "Send Queue Depth"\r
+HKR, Ndi\Params\SqDepth, Type, 0, "dword"\r
+HKR, Ndi\Params\SqDepth, Default, 0, "512"\r
+HKR, Ndi\Params\SqDepth, Optional, 0, "0"\r
+HKR, Ndi\Params\SqDepth, Min, 0, "128"\r
+HKR, Ndi\Params\SqDepth, Max, 0, "1024"\r
+HKR, Ndi\Params\SqDepth, Step, 0, "128"\r
+\r
+HKR, Ndi\Params\SendChksum, ParamDesc, 0, "Send Checksum Offload"\r
+HKR, Ndi\Params\SendChksum, Type, 0, "enum"\r
+HKR, Ndi\Params\SendChksum, Default, 0, "0"\r
+HKR, Ndi\Params\SendChksum, Optional, 0, "0"\r
+HKR, Ndi\Params\SendChksum\enum, "0", 0, "Disabled"\r
+HKR, Ndi\Params\SendChksum\enum, "1", 0, "Enabled"\r
+\r
+HKR, Ndi\Params\RecvChksum, ParamDesc, 0, "Recv Checksum Offload"\r
+HKR, Ndi\Params\RecvChksum, Type, 0, "enum"\r
+HKR, Ndi\Params\RecvChksum, Default, 0, "0"\r
+HKR, Ndi\Params\RecvChksum, Optional, 0, "0"\r
+HKR, Ndi\Params\RecvChksum\enum, "0", 0, "Disabled"\r
+HKR, Ndi\Params\RecvChksum\enum, "1", 0, "Enabled"\r
+\r
+HKR, Ndi\Params\SaTimeout, ParamDesc, 0, "SA Query Timeout (ms)"\r
+HKR, Ndi\Params\SaTimeout, Type, 0, "dword"\r
+HKR, Ndi\Params\SaTimeout, Default, 0, "1000"\r
+HKR, Ndi\Params\SaTimeout, Optional, 0, "0"\r
+HKR, Ndi\Params\SaTimeout, Min, 0, "500"\r
+HKR, Ndi\Params\SaTimeout, Step, 0, "250"\r
+\r
+HKR, Ndi\Params\SaRetries, ParamDesc, 0, "SA Query Retry Count"\r
+HKR, Ndi\Params\SaRetries, Type, 0, "dword"\r
+HKR, Ndi\Params\SaRetries, Default, 0, "10"\r
+HKR, Ndi\Params\SaRetries, Optional, 0, "0"\r
+HKR, Ndi\Params\SaRetries, Min, 0, "1"\r
+\r
+HKR, Ndi\Params\RecvRatio, ParamDesc, 0, "Receive Pool Ratio"\r
+HKR, Ndi\Params\RecvRatio, Type, 0, "dword"\r
+HKR, Ndi\Params\RecvRatio, Default, 0, "1"\r
+HKR, Ndi\Params\RecvRatio, Optional, 0, "0"\r
+HKR, Ndi\Params\RecvRatio, Min, 0, "1"\r
+HKR, Ndi\Params\RecvRatio, Max, 0, "10"\r
+\r
+HKR, Ndi\Params\PayloadMtu, ParamDesc, 0, "Payload Mtu size"\r
+HKR, Ndi\Params\PayloadMtu, Type, 0, "dword"\r
+HKR, Ndi\Params\PayloadMtu, Default, 0, "2044"\r
+HKR, Ndi\Params\PayloadMtu, Min, 0, "60"\r
+HKR, Ndi\Params\PayloadMtu, Max, 0, "2044"\r
+\r
+[IpoibService]\r
+DisplayName = %IpoibServiceDispName%\r
+ServiceType = 1 ;%SERVICE_KERNEL_DRIVER%\r
+StartType = 3 ;%SERVICE_DEMAND_START%\r
+ErrorControl = 1 ;%SERVICE_ERROR_NORMAL%\r
+ServiceBinary = %12%\ipoib.sys\r
+LoadOrderGroup = NDIS\r
+AddReg = Ipoib.ParamsReg\r
+\r
+[Ipoib.ParamsReg]\r
+HKR,"Parameters","DebugLevel",%REG_DWORD_NO_CLOBBER%,0x00000002\r
+HKR,"Parameters","DebugFlags",%REG_DWORD_NO_CLOBBER%,0x00000fff\r
+HKR,"Parameters","bypass_check_bcast_rate",%REG_DWORD_NO_CLOBBER%,0x00000000\r
+\r
+[IpoibEventLog]\r
+AddReg = IpoibAddEventLogReg\r
+\r
+[IpoibAddEventLogReg]\r
+HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll;%%SystemRoot%%\System32\drivers\ipoib.sys"\r
+HKR, , TypesSupported, 0x00010001, 7\r
+\r
+\r
+[IpoibCopyFiles]\r
+ipoib.sys,,,2\r
+\r
+[WsdCopyFiles]\r
+ibwsd.dll,,,0x00000002\r
+\r
+[WOW64CopyFiles]\r
+ibwsd.dll,ibwsd32.dll,,0x00000002\r
+\r
+[SourceDisksNames.x86]\r
+1 = %IcsDisk1%,,,""\r
+\r
+[SourceDisksNames.amd64]\r
+1 = %IcsDisk1%,,,""\r
+\r
+[SourceDisksNames.ia64]\r
+1 = %IcsDisk1%,,,""\r
+\r
+[SourceDisksFiles.x86]\r
+ipoib.sys = 1\r
+ibwsd.dll = 1\r
+\r
+[SourceDisksFiles.amd64]\r
+ipoib.sys = 1\r
+ibwsd.dll = 1\r
+ibwsd32.dll = 1\r
+\r
+[SourceDisksFiles.ia64]\r
+ipoib.sys = 1\r
+ibwsd.dll = 1\r
+ibwsd32.dll = 1\r
+\r
+[DestinationDirs]\r
+IpoibCopyFiles = %DIRID_DRIVERS%\r
+WsdCopyFiles = %DIRID_SYSTEM%\r
+WOW64CopyFiles = %DIRID_SYSTEM_X86%\r
+DefaultDestDir = %DIRID_SYSTEM%\r
+\r
+[Strings]\r
+OPENIB = "OpenIB Alliance"\r
+IpoibDesc = "OpenIB IPoIB Adapter"\r
+IpoibServiceDispName = "IPoIB"\r
+IcsDisk1 = "OpenIB IPoIB Disk #1"\r
+DIRID_SYSTEM = 11\r
+DIRID_DRIVERS = 12\r
+DIRID_SYSTEM_X86 = 16425\r
+REG_DWORD_NO_CLOBBER = 0x00010003\r