--- /dev/null
+TARGETNAME=ibbus\r
+TARGETPATH=..\..\..\bin\kernel\obj$(BUILD_ALT_DIR)\r
+TARGETTYPE=DRIVER\r
+\r
+KMDF_VERSION_MAJOR=1\r
+INF_NAME=ib_bus\r
+\r
+NTTARGETFILE0=$(OBJ_PATH)\$(O)\$(INF_NAME).bmf\r
+\r
+NTTARGETFILES=$(OBJ_PATH)\$(O)\$(INF_NAME).inf\r
+\r
+MISCFILES=$(NTTARGETFILES)\r
+\r
+!if $(FREEBUILD)\r
+ENABLE_EVENT_TRACING=1\r
+!else\r
+#ENABLE_EVENT_TRACING=1\r
+!endif\r
+\r
+\r
+SOURCES= ib_bus.rc \\r
+ bus_driver.c \\r
+ bus_pnp.c \\r
+ bus_pdo.c \\r
+ bus_port_mgr.c \\r
+ bus_iou_mgr.c \\r
+ wmi.c\r
+\r
+INCLUDES=$(INCLUDES);..\..\..\inc;..\..\..\inc\kernel;..\..\al;..\..\al\kernel;\r
+\r
+C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -DNEED_CL_OBJ\r
+\r
+TARGETLIBS= \\r
+ $(TARGETPATH)\*\complib.lib \\r
+ $(TARGETPATH)\*\ibal.lib \\r
+ $(DDK_LIB_PATH)\ntstrsafe.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
+\r
+!ENDIF\r
+\r
+\r
+MSC_WARNING_LEVEL= /W4\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: bus_driver.c 939 2008-02-10 15:25:55Z leonidk $\r
+ */\r
+\r
+\r
+/*\r
+ * Provides the driver entry points for the InfiniBand Bus Driver.\r
+ */\r
+\r
+#include <complib/cl_types.h>\r
+#include "bus_driver.h"\r
+#include "bus_pnp.h"\r
+#include "al_mgr.h"\r
+#include "al_dev.h"\r
+#include "al_debug.h"\r
+#include <complib/cl_init.h>\r
+\r
+\r
+#if defined(EVENT_TRACING)\r
+#ifdef offsetof\r
+#undef offsetof\r
+#endif\r
+#include "bus_driver.tmh"\r
+#endif\r
+\r
+#ifdef WINIB\r
+#define DEFAULT_NODE_DESC "Mellanox Windows® Host"\r
+#else\r
+#define DEFAULT_NODE_DESC "OpenIB Windows® Host"\r
+#endif\r
+\r
+char node_desc[IB_NODE_DESCRIPTION_SIZE];\r
+\r
+bus_globals_t bus_globals = {\r
+ TRACE_LEVEL_VERBOSE,\r
+ DBG_ALL,\r
+ TRUE,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+// Extern\r
+\r
+EVT_WDF_DRIVER_DEVICE_ADD Bus_EvtDeviceAdd; // bus_pnp.c\r
+\r
+// Forward references\r
+\r
+DRIVER_INITIALIZE DriverEntry;\r
+\r
+static VOID\r
+Bus_EvtDriverUnload( IN WDFDRIVER Driver );\r
+\r
+static void\r
+__read_machine_name( void );\r
+\r
+static NTSTATUS\r
+__read_registry(\r
+ IN UNICODE_STRING* const p_Param_Path );\r
+\r
+static NTSTATUS\r
+bus_drv_open(\r
+ IN DEVICE_OBJECT *p_dev_obj,\r
+ IN IRP *p_irp );\r
+\r
+static NTSTATUS\r
+bus_drv_cleanup(\r
+ IN DEVICE_OBJECT *p_dev_obj,\r
+ IN IRP *p_irp );\r
+\r
+static NTSTATUS\r
+bus_drv_close(\r
+ IN DEVICE_OBJECT *p_dev_obj,\r
+ IN IRP *p_irp );\r
+\r
+static NTSTATUS\r
+bus_drv_ioctl(\r
+ IN DEVICE_OBJECT *p_dev_obj,\r
+ IN IRP *p_irp );\r
+\r
+/***f* InfiniBand Bus Driver/bus_drv_sysctl\r
+* NAME\r
+* bus_drv_sysctl\r
+*\r
+* DESCRIPTION\r
+* Entry point for handling WMI IRPs.\r
+*\r
+* SYNOPSIS\r
+*/\r
+static NTSTATUS\r
+bus_drv_sysctl(\r
+ IN DEVICE_OBJECT *p_dev_obj,\r
+ IN IRP *p_irp );\r
+/**********/\r
+\r
+static void\r
+bus_drv_unload(\r
+ IN DRIVER_OBJECT *p_driver_obj );\r
+\r
+\r
+#ifdef ALLOC_PRAGMA\r
+#pragma alloc_text (INIT, DriverEntry)\r
+#pragma alloc_text (INIT, __read_machine_name)\r
+#pragma alloc_text (INIT, __read_registry)\r
+#pragma alloc_text (PAGE, Bus_EvtDriverUnload)\r
+#pragma alloc_text (PAGE, bus_drv_open)\r
+#pragma alloc_text (PAGE, bus_drv_close)\r
+#pragma alloc_text (PAGE, bus_drv_ioctl)\r
+#pragma alloc_text (PAGE_PNP, bus_drv_sysctl)\r
+#endif\r
+\r
+\r
+static void\r
+__read_machine_name( void )\r
+{\r
+ NTSTATUS status;\r
+ /* Remember the terminating entry in the table below. */\r
+ RTL_QUERY_REGISTRY_TABLE table[2];\r
+ UNICODE_STRING hostNamePath;\r
+ UNICODE_STRING hostNameW;\r
+ ANSI_STRING hostName;\r
+\r
+ BUS_ENTER( BUS_DBG_DRV );\r
+\r
+ /* Get the host name. */\r
+ RtlInitUnicodeString( &hostNamePath, L"ComputerName\\ComputerName" );\r
+ RtlInitUnicodeString( &hostNameW, NULL );\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
+ cl_memclr( node_desc, sizeof(node_desc) );\r
+\r
+ /* Setup the table entries. */\r
+ table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;\r
+ table[0].Name = L"ComputerName";\r
+ table[0].EntryContext = &hostNameW;\r
+ table[0].DefaultType = REG_SZ;\r
+ table[0].DefaultData = &hostNameW;\r
+ table[0].DefaultLength = 0;\r
+\r
+ /* Have at it! */\r
+ status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL, \r
+ hostNamePath.Buffer, table, NULL, NULL );\r
+ if( NT_SUCCESS( status ) )\r
+ {\r
+ /* Convert the UNICODE host name to UTF-8 (ASCII). */\r
+ hostName.Length = 0;\r
+ hostName.MaximumLength = sizeof(node_desc);\r
+ hostName.Buffer = node_desc;\r
+ status = RtlUnicodeStringToAnsiString( &hostName, &hostNameW, FALSE );\r
+ RtlFreeUnicodeString( &hostNameW );\r
+ }\r
+ else\r
+ {\r
+ BUS_TRACE(BUS_DBG_ERROR , ("Failed to get host name.\n") );\r
+ /* Use the default name... */\r
+ RtlStringCbCopyNA( node_desc, sizeof(node_desc),\r
+ DEFAULT_NODE_DESC, sizeof(DEFAULT_NODE_DESC) );\r
+ }\r
+\r
+ BUS_EXIT( BUS_DBG_DRV );\r
+}\r
+\r
+\r
+static NTSTATUS\r
+__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[9];\r
+ UNICODE_STRING param_path;\r
+\r
+ BUS_ENTER( BUS_DBG_DRV );\r
+\r
+ __read_machine_name();\r
+\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
+ BUS_TRACE_EXIT( BUS_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"ReportPortNIC";\r
+ table[0].EntryContext = &bus_globals.b_report_port_nic;\r
+ table[0].DefaultType = REG_DWORD;\r
+ table[0].DefaultData = &bus_globals.b_report_port_nic;\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 = &bus_globals.dbg_lvl;\r
+ table[1].DefaultType = REG_DWORD;\r
+ table[1].DefaultData = &bus_globals.dbg_lvl;\r
+ table[1].DefaultLength = sizeof(ULONG);\r
+\r
+ table[2].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
+ table[2].Name = L"IbalDebugLevel";\r
+ table[2].EntryContext = &g_al_dbg_level;\r
+ table[2].DefaultType = REG_DWORD;\r
+ table[2].DefaultData = &g_al_dbg_level;\r
+ table[2].DefaultLength = sizeof(ULONG);\r
+\r
+ table[3].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
+ table[3].Name = L"IbalDebugFlags";\r
+ table[3].EntryContext = &g_al_dbg_flags;\r
+ table[3].DefaultType = REG_DWORD;\r
+ table[3].DefaultData = &g_al_dbg_flags;\r
+ table[3].DefaultLength = sizeof(ULONG);\r
+ \r
+\r
+ table[4].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
+ table[4].Name = L"SmiPollInterval";\r
+ table[4].EntryContext = &g_smi_poll_interval;\r
+ table[4].DefaultType = REG_DWORD;\r
+ table[4].DefaultData = &g_smi_poll_interval;\r
+ table[4].DefaultLength = sizeof(ULONG);\r
+\r
+ table[5].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
+ table[5].Name = L"IocQueryTimeout";\r
+ table[5].EntryContext = &g_ioc_query_timeout;\r
+ table[5].DefaultType = REG_DWORD;\r
+ table[5].DefaultData = &g_ioc_query_timeout;\r
+ table[5].DefaultLength = sizeof(ULONG);\r
+\r
+ table[6].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
+ table[6].Name = L"IocQueryRetries";\r
+ table[6].EntryContext = &g_ioc_query_retries;\r
+ table[6].DefaultType = REG_DWORD;\r
+ table[6].DefaultData = &g_ioc_query_retries;\r
+ table[6].DefaultLength = sizeof(ULONG);\r
+\r
+ table[7].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
+ table[7].Name = L"IocPollInterval";\r
+ table[7].EntryContext = &g_ioc_poll_interval;\r
+ table[7].DefaultType = REG_DWORD;\r
+ table[7].DefaultData = &g_ioc_poll_interval;\r
+ table[7].DefaultLength = sizeof(ULONG);\r
+\r
+ /* Have at it! */\r
+ status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
+ param_path.Buffer, table, NULL, NULL );\r
+\r
+#if DBG\r
+ if( g_al_dbg_flags & AL_DBG_ERR )\r
+ g_al_dbg_flags |= CL_DBG_ERROR;\r
+#endif\r
+\r
+ BUS_TRACE(BUS_DBG_DRV ,\r
+ ("debug level %d debug flags 0x%.8x\n",\r
+ g_al_dbg_level,\r
+ g_al_dbg_flags));\r
+\r
+ cl_free( param_path.Buffer );\r
+ BUS_EXIT( BUS_DBG_DRV );\r
+ return status;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+bus_drv_open(\r
+ IN DEVICE_OBJECT *p_dev_obj,\r
+ IN IRP *p_irp )\r
+{\r
+ BUS_ENTER( BUS_DBG_DRV );\r
+\r
+ UNUSED_PARAM( p_dev_obj );\r
+\r
+ CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );\r
+\r
+ /* We always succeed file handles creation. */\r
+ p_irp->IoStatus.Status = STATUS_SUCCESS;\r
+ p_irp->IoStatus.Information = 0;\r
+ IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+\r
+ BUS_EXIT( BUS_DBG_DRV );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+bus_drv_cleanup(\r
+ IN DEVICE_OBJECT *p_dev_obj,\r
+ IN IRP *p_irp )\r
+{\r
+ NTSTATUS status;\r
+\r
+ BUS_ENTER( BUS_DBG_DRV );\r
+\r
+ UNUSED_PARAM( p_dev_obj );\r
+\r
+ CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );\r
+\r
+ /*\r
+ * Note that we don't acquire the remove and stop lock on close to allow\r
+ * applications to close the device when the locks are already held.\r
+ */\r
+ status = cl_to_ntstatus( al_dev_close( p_irp ) );\r
+\r
+ /* Complete the IRP. */\r
+ p_irp->IoStatus.Status = status;\r
+ p_irp->IoStatus.Information = 0;\r
+ IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+\r
+ BUS_EXIT( BUS_DBG_DRV );\r
+ return status;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+bus_drv_close( IN DEVICE_OBJECT *p_dev_obj,\r
+ IN IRP *p_irp )\r
+{\r
+ UNUSED_PARAM( p_dev_obj );\r
+\r
+ p_irp->IoStatus.Status = STATUS_SUCCESS;\r
+ p_irp->IoStatus.Information = 0;\r
+ IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+bus_drv_ioctl(\r
+ IN DEVICE_OBJECT *p_dev_obj,\r
+ IN IRP *p_irp )\r
+{\r
+ NTSTATUS status;\r
+ bus_fdo_ext_t *p_ext;\r
+ PIO_STACK_LOCATION p_io_stack;\r
+\r
+ BUS_ENTER( BUS_DBG_DRV );\r
+\r
+ /* Get the extension. */\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ /* Get the stack location. */\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+ /* Acquire the stop lock. */\r
+ status = IoAcquireRemoveLock( &p_ext->cl_ext.stop_lock, p_irp );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ p_irp->IoStatus.Status = status;\r
+ p_irp->IoStatus.Information = 0;\r
+ IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+ BUS_EXIT( BUS_DBG_DRV );\r
+ return status;\r
+ }\r
+\r
+ /* Acquire the remove lock. */\r
+ status = IoAcquireRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ IoReleaseRemoveLock( &p_ext->cl_ext.stop_lock, p_irp );\r
+ p_irp->IoStatus.Status = status;\r
+ p_irp->IoStatus.Information = 0;\r
+ IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+ BUS_EXIT( BUS_DBG_DRV );\r
+ return status;\r
+ }\r
+ \r
+ status = cl_to_ntstatus( al_dev_ioctl( p_irp ) );\r
+ \r
+ /* Only pass down if not handled and not PDO device. */\r
+ if( status == STATUS_INVALID_DEVICE_REQUEST && p_ext->cl_ext.p_next_do )\r
+ {\r
+ IoSkipCurrentIrpStackLocation( p_irp );\r
+ status = IoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
+ }\r
+\r
+ /* Release the remove and stop locks. */\r
+ IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
+ IoReleaseRemoveLock( &p_ext->cl_ext.stop_lock, p_irp );\r
+\r
+ BUS_EXIT( BUS_DBG_DRV );\r
+ return status;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+bus_drv_sysctl(\r
+ IN DEVICE_OBJECT *p_dev_obj,\r
+ IN IRP *p_irp )\r
+{\r
+ NTSTATUS status;\r
+ bus_fdo_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_DRV );\r
+\r
+ CL_ASSERT( p_dev_obj );\r
+ CL_ASSERT( p_irp );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ if( p_ext->cl_ext.p_next_do )\r
+ {\r
+ IoSkipCurrentIrpStackLocation( p_irp );\r
+ status = IoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
+ }\r
+ else\r
+ {\r
+ status = p_irp->IoStatus.Status;\r
+ IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+ }\r
+\r
+ BUS_EXIT( BUS_DBG_DRV );\r
+ return status;\r
+}\r
+\r
+\r
+#ifdef _REPLACED\r
+static void\r
+bus_drv_unload(\r
+ IN DRIVER_OBJECT *p_driver_obj )\r
+{\r
+ BUS_ENTER( BUS_DBG_DRV );\r
+\r
+ UNUSED_PARAM( p_driver_obj );\r
+\r
+ CL_DEINIT;\r
+\r
+ WPP_CLEANUP(p_driver_obj);\r
+\r
+ BUS_EXIT( BUS_DBG_DRV );\r
+ \r
+}\r
+#endif\r
+\r
+/*++\r
+Routine Description:\r
+\r
+ This routine is called when the IB Bus driver is unloaded.\r
+\r
+Arguments:\r
+\r
+ Driver - pointer to a KMDF Driver object\r
+\r
+\r
+Return Value:\r
+\r
+--*/\r
+static VOID\r
+Bus_EvtDriverUnload( IN WDFDRIVER Driver )\r
+{\r
+ BUS_ENTER( BUS_DBG_DRV );\r
+\r
+ CL_DEINIT;\r
+\r
+#if defined(EVENT_TRACING)\r
+ WPP_CLEANUP( WdfDriverWdmGetDriverObject(Driver) );\r
+#else\r
+ UNREFERENCED_PARAMETER(Driver);\r
+#endif\r
+\r
+ BUS_EXIT( BUS_DBG_DRV ); \r
+}\r
+\r
+\r
+NTSTATUS\r
+DriverEntry( IN DRIVER_OBJECT *p_driver_obj,\r
+ IN UNICODE_STRING *p_registry_path )\r
+{\r
+ NTSTATUS status;\r
+ WDF_DRIVER_CONFIG config;\r
+ WDFDRIVER driver;\r
+\r
+ BUS_ENTER( BUS_DBG_DRV );\r
+\r
+ DbgPrint(("DBG - WDF InfiniBand Fabric Bus Driver.\n"));\r
+ KdPrint(("WDF InfiniBand Fabric Bus Driver.\n"));\r
+ KdPrint(("Built %s %s\n", __DATE__, __TIME__));\r
+\r
+ WPP_INIT_TRACING(p_driver_obj ,p_registry_path);\r
+\r
+ status = CL_INIT;\r
+ if( !NT_SUCCESS(status) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("cl_init returned %08X.\n", status) );\r
+ return status;\r
+ }\r
+\r
+ /* Store the driver object pointer in the global parameters. */\r
+ bus_globals.p_driver_obj = p_driver_obj;\r
+\r
+ /* Get the registry values. */\r
+ status = __read_registry( p_registry_path );\r
+ if( !NT_SUCCESS(status) )\r
+ {\r
+ CL_DEINIT;\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("__read_registry returned %08x.\n", status) );\r
+ return status;\r
+ }\r
+\r
+ /* Setup the entry points. */\r
+#if 0\r
+ // handled by KMDF callback bus_pnp.c:Bus_EvtDeviceFileCreate\r
+ p_driver_obj->MajorFunction[IRP_MJ_CREATE] = bus_drv_open;\r
+\r
+ p_driver_obj->MajorFunction[IRP_MJ_CLEANUP] = bus_drv_cleanup;\r
+\r
+ // handled by KMDF callback bus_pnp.c:Bus_EvtDeviceFileClose\r
+ p_driver_obj->MajorFunction[IRP_MJ_CLOSE] = bus_drv_close;\r
+\r
+ // handled by the Framework (KMDF), no callbacks\r
+ p_driver_obj->MajorFunction[IRP_MJ_PNP] = cl_pnp;\r
+\r
+ // handled by the Framework (KMDF), no callbacks\r
+ p_driver_obj->MajorFunction[IRP_MJ_POWER] = cl_power;\r
+\r
+ // handled by callback bus_pnp.c: Bus_EvtIoDeviceControl\r
+ p_driver_obj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = bus_drv_ioctl;\r
+\r
+ // handled by WMI interface FIXME ASAP!\r
+ p_driver_obj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = bus_drv_sysctl;\r
+\r
+ // handled via Framework callbacks\r
+ p_driver_obj->DriverUnload = bus_drv_unload;\r
+ p_driver_obj->DriverExtension->AddDevice = bus_add_device;\r
+#endif\r
+\r
+ // Initiialize driver config to control the attributes that\r
+ // are global to the driver. Note that framework by default\r
+ // provides a driver unload routine. If you create any resources\r
+ // in the DriverEntry and want to be cleaned in driver unload,\r
+ // you can override that by specifing one in the Config structure.\r
+\r
+ WDF_DRIVER_CONFIG_INIT( &config, Bus_EvtDeviceAdd );\r
+\r
+ config.EvtDriverUnload = Bus_EvtDriverUnload;\r
+\r
+ // Create a framework driver object to represent our driver.\r
+ status = WdfDriverCreate(p_driver_obj,\r
+ p_registry_path,\r
+ WDF_NO_OBJECT_ATTRIBUTES,\r
+ &config,\r
+ &driver);\r
+\r
+ if (!NT_SUCCESS(status)) {\r
+ KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status));\r
+ }\r
+\r
+ BUS_EXIT( BUS_DBG_DRV );\r
+ return status;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Debug print for the sample driver.\r
+\r
+Arguments:\r
+\r
+ TraceEventsLevel - print level between 0 and 3, with 3 the most verbose\r
+\r
+Return Value:\r
+\r
+ None.\r
+\r
+ --*/\r
+\r
+#if !defined(EVENT_TRACING)\r
+\r
+VOID\r
+TraceEvents (\r
+ IN ULONG TraceEventsLevel,\r
+ IN ULONG TraceEventsFlag,\r
+ IN PCCHAR DebugMessage,\r
+ ... )\r
+{\r
+#if 1 // always for starters DBG\r
+#define TEMP_BUFFER_SIZE 512\r
+ va_list list;\r
+ CHAR debugMessageBuffer[TEMP_BUFFER_SIZE];\r
+ NTSTATUS status;\r
+\r
+ va_start(list, DebugMessage);\r
+\r
+ if (DebugMessage) {\r
+\r
+ //\r
+ // Using new safe string functions instead of _vsnprintf.\r
+ // This function takes care of NULL terminating if the message\r
+ // is longer than the buffer.\r
+ //\r
+ status = RtlStringCbVPrintfA( debugMessageBuffer,\r
+ sizeof(debugMessageBuffer),\r
+ DebugMessage,\r
+ list );\r
+ if(!NT_SUCCESS(status)) {\r
+\r
+ DbgPrint(_DRIVER_NAME_": RtlStringCbVPrintfA failed %x\n", status);\r
+ return;\r
+ }\r
+ if (TraceEventsLevel <= TRACE_LEVEL_INFORMATION ||\r
+ (TraceEventsLevel <= bus_globals.dbg_lvl &&\r
+ (TraceEventsFlag & bus_globals.dbg_flags) )) // any bit set\r
+// ((TraceEventsFlag & bus_globals.dbg_flags) == TraceEventsFlag) ))\r
+ {\r
+ DbgPrint(debugMessageBuffer);\r
+ }\r
+ }\r
+ va_end(list);\r
+\r
+ return;\r
+#else\r
+ UNREFERENCED_PARAMETER(TraceEventsLevel);\r
+ UNREFERENCED_PARAMETER(TraceEventsFlag);\r
+ UNREFERENCED_PARAMETER(DebugMessage);\r
+#endif\r
+}\r
+\r
+#endif /* !defined(EVENT_TRACING) */\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2008 Intel Corporation. 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
+ * Main header for IB Fabric Bus driver.\r
+ *\r
+ * InfiniBand Fabric (IBF) dynamic bus enumerator - based on MS Toaster\r
+ * Dynamic bus enum example.\r
+ * Whenever you see the term 'bus', think Infiniband Fabric (a.k.a. 'bus'.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+#if !defined _IB_BUS_DRIVER_H_\r
+#define _IB_BUS_DRIVER_H_ 1\r
+\r
+#include <ntddk.h>\r
+#include <wdf.h>\r
+#include <ntstrsafe.h>\r
+#include <ntintsafe.h>\r
+\r
+#include "driver.h"\r
+#include "ib_bus_public.h"\r
+\r
+#include "complib/cl_types.h"\r
+#include "complib/cl_atomic.h"\r
+#include "complib/cl_debug.h"\r
+#include "complib/cl_mutex.h"\r
+#include "complib/cl_qlist.h"\r
+#include "complib/cl_ptr_vector.h"\r
+#include "complib/cl_pnp_po.h"\r
+#include "iba/ib_al.h"\r
+#include "bus_port_mgr.h"\r
+#include "bus_iou_mgr.h"\r
+\r
+#include "trace.h"\r
+\r
+#define _DRIVER_NAME_ "IB_BUS"\r
+#define BUS_TAG 'rbaF'\r
+#define BUSRESOURCENAME L"MofResourceName"\r
+#define MOFRESOURCENAME L"IBFabricWMI"\r
+\r
+#define DEF_STATICALLY_ENUMERATED_IB_DEVICES 0\r
+#define MAX_STATICALLY_ENUMERATED_IB_DEVICES 50\r
+#define MAX_INSTANCE_ID_LEN 80\r
+\r
+#ifndef min\r
+#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b))\r
+#endif\r
+\r
+#ifndef max\r
+#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b))\r
+#endif\r
+\r
+\r
+#if 1\r
+\r
+#define BUS_ENTER( lvl ) KdPrint( ("[Ibbus] %s() -->\n",__FUNCTION__) )\r
+#define BUS_EXIT( lvl ) KdPrint( ("[Ibbus] %s() <-- \n",__FUNCTION__) )\r
+#define BUS_PRINT( lvl, msg ) KdPrint((msg))\r
+#define BUS_TRACE( lvl, msg ) KdPrint(msg)\r
+#define BUS_TRACE_EXIT( lvl, msg ) KdPrint(msg)\r
+\r
+#else\r
+\r
+#define BUS_ENTER( lvl ) \\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, lvl, "--> %s()\n", __FUNCTION__)\r
+\r
+#define BUS_EXIT( lvl ) \\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, lvl, "<-- %s()\n", __FUNCTION__)\r
+\r
+#if 1\r
+#define BUS_TRACE( lvl, msg ) \\r
+ CL_TRACE( lvl, bus_globals.dbg_lvl, msg )\r
+\r
+#define BUS_TRACE_EXIT( lvl, msg ) \\r
+ CL_TRACE_EXIT( lvl, bus_globals.dbg_lvl, msg )\r
+\r
+#define BUS_PRINT( lvl, msg ) \\r
+ CL_PRINT( lvl, bus_globals.dbl_lvl, msg )\r
+\r
+#else\r
+\r
+#define BUS_TRACE( lvl, msg ) \\r
+ TraceEvents( TRACE_LEVEL_INFORMATION, lvl, (msg) )\r
+\r
+#define BUS_TRACE_EXIT( lvl, msg ) \\r
+ TraceEvents( TRACE_LEVEL_INFORMATION, lvl, msg )\r
+#endif\r
+#endif\r
+\r
+\r
+/*\r
+ * ALLOC_PRAGMA sections:\r
+ * PAGE\r
+ * Default pagable code. Won't be locked in memory.\r
+ *\r
+ * PAGE_PNP\r
+ * Code that needs to be locked in memory when the device is\r
+ * in the paging, crash dump, or hibernation path.\r
+ *\r
+ * INIT\r
+ * Code pages which are called once during driver initialization\r
+ * (e.g., DriverEntry) that the system may page out.\r
+ */\r
+//\r
+// Structure for reporting data to WMI\r
+//\r
+\r
+typedef struct _IBF_BUS_WMI_STD_DATA {\r
+\r
+ //\r
+ // The error Count\r
+ //\r
+ UINT32 ErrorCount;\r
+\r
+ //\r
+ // Debug Print Level\r
+ //\r
+\r
+ UINT32 DebugPrintLevel;\r
+\r
+} IBF_BUS_WMI_STD_DATA, * PIBF_BUS_WMI_STD_DATA;\r
+\r
+/*\r
+ The goal of the identification and address description abstractions is that\r
+ enough information is stored for a discovered device so that when it appears\r
+ on the bus, the framework (with the help of the driver writer) can determine\r
+ if it is a new or existing device. The identification and address descriptions\r
+ are opaque structures to the framework, they are private to the driver writer.\r
+ The only thing the framework knows about these descriptions is what their\r
+ size is.\r
+ The identification contains the bus specific information required to\r
+ recognize an instance of a device on its the bus. The identification\r
+ information usually contains device IDs along with any serial or slot numbers.\r
+ For some buses (like USB and PCI), the identification of the device is\r
+ sufficient to address the device on the bus; in these instances there is no\r
+ need for a separate address description. Once reported, the identification\r
+ description remains static for the lifetime of the device. For example, the\r
+ identification description that the PCI bus driver would use for a child would\r
+ contain the vendor ID, device ID, subsystem ID, revision, and class for the\r
+ device. This sample uses only identification description.\r
+ On other busses (like 1394 and auto LUN SCSI), the device is assigned a\r
+ dynamic address by the hardware (which may reassigned and updated periodically\r
+ in these instances the driver will use the address description to encapsulate\r
+ this dynamic piece of data.\r
+ For example in a 1394 driver, the address description would contain the\r
+ devices current generation count while the identification description would\r
+ contain vendor name, model name, unit spec ID, and unit software version.\r
+*/\r
+\r
+typedef struct _PDO_IDENTIFICATION_DESCRIPTION\r
+{\r
+ WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Header; // should have header\r
+\r
+ // Unique serial number of the device on the bus\r
+ ULONG SerialNo;\r
+\r
+ size_t CchHardwareIds;\r
+\r
+ __field_bcount(CchHardwareIds) PWCHAR HardwareIds;\r
+\r
+} PDO_IDENTIFICATION_DESCRIPTION, *PPDO_IDENTIFICATION_DESCRIPTION;\r
+\r
+\r
+/*\r
+ * Device extension for the device object that serves as entry point for \r
+ * the interface and IOCTL requests.\r
+ * The device extension of the InfiniBand Fabric bus itself.\r
+ * From whence the PDO's are born. \r
+ */\r
+typedef struct _bus_fdo_ext\r
+{\r
+ cl_pnp_po_ext_t cl_ext; // wants to be 1st...\r
+\r
+ WDFDEVICE WdfDevice; // for DrvQueuePassiveLevelCallback()\r
+\r
+ WDFWMIINSTANCE WmiDeviceArrivalEvent;\r
+\r
+ IB_BUS_INTERFACE_STANDARD BusInterface;\r
+\r
+ IBF_BUS_WMI_STD_DATA StdBusData;\r
+\r
+ BOOLEAN SupportsPowerMgmt;\r
+ CHAR Identity[8];\r
+\r
+ /* Device power map returned by the bus driver for the device, used \r
+ * when sending IRP_MN_SET_POWER for device state in response to \r
+ * IRP_MN_SET_POWER for system state.\r
+ */\r
+ DEVICE_POWER_STATE po_state[PowerSystemMaximum];\r
+\r
+ // Current power state of the device(D0 - D3)\r
+ WDF_POWER_DEVICE_STATE DevPowerState;\r
+ WDF_POWER_DEVICE_STATE DevPreviousPowerState;\r
+\r
+ port_mgr_t *p_port_mgr;\r
+ iou_mgr_t *p_iou_mgr;\r
+\r
+ /* Interface names are generated by IoRegisterDeviceInterface. */\r
+ UNICODE_STRING al_ifc_name;\r
+ UNICODE_STRING ci_ifc_name;\r
+\r
+ /* Number of references on the upper interface. */\r
+ atomic32_t n_al_ifc_ref;\r
+ /* Number of references on the CI interface. */\r
+ atomic32_t n_ci_ifc_ref;\r
+\r
+} bus_fdo_ext_t, FDO_BUS_DATA, *PFDO_BUS_DATA;\r
+\r
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_BUS_DATA, FdoGetData)\r
+\r
+\r
+// General purpose workitem context used in dispatching work to\r
+// system worker thread to be executed at PASSIVE_LEVEL.\r
+\r
+typedef struct _WORKER_ITEM_CONTEXT {\r
+ PFDO_BUS_DATA FdoData;\r
+ PVOID Argument1;\r
+ PVOID Argument2;\r
+} WORKER_ITEM_CONTEXT, *PWORKER_ITEM_CONTEXT;\r
+\r
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WORKER_ITEM_CONTEXT, GetWorkItemContext)\r
+\r
+\r
+/*\r
+ * The PDO device extension.\r
+ */\r
+typedef struct _bus_pdo_ext\r
+{\r
+ // Unique serial number of the device on the bus.\r
+ ULONG SerialNo;\r
+\r
+ cl_pnp_po_ext_t cl_ext;\r
+\r
+ cl_list_item_t list_item;\r
+\r
+ /* All reported PDOs are children of an HCA. */\r
+ ib_ca_handle_t h_ca;\r
+\r
+ /*\r
+ * CA GUID copy - in case we get IRPs after the CA\r
+ * handle has been released.\r
+ */\r
+ net64_t ca_guid;\r
+\r
+ POWER_STATE dev_po_state;\r
+\r
+ /*\r
+ * Pointer to the bus root device extension. Used to manage access to\r
+ * child PDO pointer vector when a child is removed politely.\r
+ */\r
+ bus_fdo_ext_t *p_parent_ext;\r
+\r
+ /*\r
+ * The following two flags are exclusively set, but can both be FALSE.\r
+ * Flag that indicates whether the device is present in the system or not.\r
+ * This affects how a IRP_MN_REMOVE_DEVICE IRP is handled for a child PDO.\r
+ * This flag is cleared when:\r
+ * - an HCA (for IPoIB devices) is removed from the system for all port\r
+ * devices loaded for that HCA\r
+ * - an IOU is reported as removed by the CIA.\r
+ */\r
+ boolean_t b_present;\r
+\r
+ /*\r
+ * Flag that indicates whether the device has been reported to the PnP\r
+ * manager as having been removed. That is, the device was reported\r
+ * in a previous BusRelations query and not in a subsequent one.\r
+ * This flag is set when\r
+ * - the device is in the surprise remove state when the parent bus\r
+ * device is removed\r
+ * - the device is found to be not present during a BusRelations query\r
+ * and thus not reported.\r
+ */\r
+ boolean_t b_reported_missing;\r
+\r
+ /* Flag to control the behaviour of the driver during hibernation */\r
+ uint32_t b_hibernating;\r
+\r
+ /* work item for handling Power Management request */\r
+ PIO_WORKITEM p_po_work_item;\r
+ \r
+} bus_pdo_ext_t, PDO_DEVICE_DATA, *PPDO_DEVICE_DATA;\r
+\r
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PDO_DEVICE_DATA, PdoGetData)\r
+\r
+\r
+/*\r
+ * Global Driver parameters.\r
+ */\r
+typedef struct _bus_globals\r
+{\r
+ /* Debug level. */\r
+ uint32_t dbg_lvl;\r
+ uint32_t dbg_flags;\r
+\r
+ /* Flag to control loading of Ip Over Ib driver for each HCA port. */\r
+ uint32_t b_report_port_nic;\r
+\r
+ /* Driver object. Used for registering of Plug and Play notifications. */\r
+ DRIVER_OBJECT *p_driver_obj;\r
+\r
+ /* Pointer to the one and only bus root (FDO_BUS_DATA*). */\r
+ bus_fdo_ext_t *p_bus_ext;\r
+\r
+} bus_globals_t;\r
+\r
+\r
+extern bus_globals_t bus_globals;\r
+extern NTSTATUS ib_bus_init(PDRIVER_OBJECT,PUNICODE_STRING);\r
+\r
+//EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL Bus_EvtIoDeviceControl;\r
+\r
+EVT_WDF_CHILD_LIST_CREATE_DEVICE Bus_EvtDeviceListCreatePdo;\r
+EVT_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE Bus_EvtChildListIdentificationDescriptionCompare;\r
+EVT_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP Bus_EvtChildListIdentificationDescriptionCleanup;\r
+EVT_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE Bus_EvtChildListIdentificationDescriptionDuplicate;\r
+\r
+NTSTATUS\r
+Bus_PlugInDevice(\r
+ __in WDFDEVICE Device,\r
+ __in PWCHAR HardwareIds,\r
+ __in size_t CchHardwareIds,\r
+ __in ULONG SerialNo\r
+ );\r
+\r
+NTSTATUS\r
+Bus_UnPlugDevice(\r
+ WDFDEVICE Device,\r
+ ULONG SerialNo\r
+ );\r
+\r
+\r
+NTSTATUS\r
+Bus_EjectDevice(\r
+ WDFDEVICE Device,\r
+ ULONG SerialNo\r
+ );\r
+\r
+NTSTATUS\r
+Bus_CreatePdo(\r
+ __in WDFDEVICE Device,\r
+ __in PWDFDEVICE_INIT ChildInit,\r
+ __in PWCHAR HardwareIds,\r
+ __in ULONG SerialNo\r
+ );\r
+\r
+NTSTATUS\r
+Bus_DoStaticEnumeration(\r
+ IN WDFDEVICE Device\r
+ );\r
+\r
+\r
+//\r
+// Interface functions\r
+//\r
+\r
+BOOLEAN\r
+Bus_GetCrispinessLevel(\r
+ IN WDFDEVICE ChildDevice,\r
+ OUT PUCHAR Level\r
+ );\r
+\r
+BOOLEAN\r
+Bus_SetCrispinessLevel(\r
+ IN WDFDEVICE ChildDevice,\r
+ OUT UCHAR Level\r
+ );\r
+\r
+BOOLEAN\r
+Bus_IsSafetyLockEnabled(\r
+ IN PVOID Context\r
+ );\r
+\r
+//\r
+// Defined in wmi.c\r
+//\r
+\r
+NTSTATUS\r
+Bus_WmiRegistration( WDFDEVICE Device );\r
+\r
+EVT_WDF_WMI_INSTANCE_SET_ITEM Bus_EvtStdDataSetItem;\r
+EVT_WDF_WMI_INSTANCE_SET_INSTANCE Bus_EvtStdDataSetInstance;\r
+EVT_WDF_WMI_INSTANCE_QUERY_INSTANCE Bus_EvtStdDataQueryInstance;\r
+\r
+NTSTATUS\r
+Enable_IBAL_InterfaceQuery( WDFDEVICE Device );\r
+\r
+NTSTATUS\r
+Enable_CI_InterfaceQuery( WDFDEVICE Device );\r
+\r
+#endif /* !defined _IB_BUS_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: bus_iou_mgr.c 931 2008-01-31 09:20:41Z leonidk $\r
+ */\r
+\r
+\r
+#include <iba/ib_types.h>\r
+#include <complib/cl_async_proc.h>\r
+#include <complib/cl_bus_ifc.h>\r
+#include "ib_common.h"\r
+#include "al_ca.h"\r
+#include "al_mgr.h"\r
+#include "bus_pnp.h"\r
+#include "bus_iou_mgr.h"\r
+#include <initguid.h>\r
+#include <wdmguid.h>\r
+#include "iba/iou_ifc.h"\r
+\r
+\r
+/* {5A9649F4-0101-4a7c-8337-796C48082DA2} */\r
+DEFINE_GUID(GUID_BUS_TYPE_IBA, \r
+0x5a9649f4, 0x101, 0x4a7c, 0x83, 0x37, 0x79, 0x6c, 0x48, 0x8, 0x2d, 0xa2);\r
+\r
+\r
+/*\r
+ * Size of device descriptions, in the format:\r
+ * IBA\VxxxxxxPxxxxxxxxvxxxxxxxx\r
+ */\r
+#define IOU_DEV_ID_SIZE sizeof(L"IBA\\VxxxxxxPxxxxvxxxxxxxx")\r
+#define IOU_DEV_ID_STRING1 L"IBA\\V%06xP%04hxv%08x"\r
+#define IOU_DEV_ID_STRING2 L"IBA\\V%06xP%04hx"\r
+#define IOU_HW_ID_SIZE \\r
+ sizeof(L"IBA\\VxxxxxxPxxxxvxxxxxxxx\0IBA\\VxxxxxxPxxxx\0\0")\r
+#define IOU_COMPAT_ID L"IBA\\IB_IOU\0\0"\r
+#define IOU_LOCATION_SIZE \\r
+ sizeof(L"Chassis 0xxxxxxxxxxxxxxxxx, Slot xx")\r
+\r
+/*\r
+ * Device extension for IOU PDOs.\r
+ */\r
+typedef struct _bus_iou_ext\r
+{\r
+ bus_pdo_ext_t pdo;\r
+\r
+ net64_t chassis_guid;\r
+ uint8_t slot;\r
+ net64_t guid;\r
+ net32_t vend_id;\r
+ net16_t dev_id;\r
+ net32_t revision;\r
+ char desc[IB_NODE_DESCRIPTION_SIZE + 1];\r
+\r
+ /* Number of references on the upper interface. */\r
+ atomic32_t n_ifc_ref;\r
+\r
+} bus_iou_ext_t;\r
+\r
+\r
+iou_mgr_t* gp_iou_mgr = NULL;\r
+\r
+\r
+/*\r
+ * Function prototypes.\r
+ */\r
+void\r
+destroying_iou_mgr(\r
+ IN cl_obj_t* p_obj );\r
+\r
+void\r
+free_iou_mgr(\r
+ IN cl_obj_t* p_obj );\r
+\r
+ib_api_status_t\r
+bus_reg_iou_pnp( void );\r
+\r
+ib_api_status_t\r
+iou_mgr_pnp_cb(\r
+ IN ib_pnp_rec_t* p_pnp_rec );\r
+\r
+ib_api_status_t\r
+iou_mgr_iou_add(\r
+ IN ib_pnp_iou_rec_t* p_pnp_rec );\r
+\r
+void\r
+iou_mgr_iou_remove(\r
+ IN ib_pnp_iou_rec_t* p_pnp_rec );\r
+\r
+static NTSTATUS\r
+iou_start(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+iou_query_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static void\r
+iou_release_resources(\r
+ IN DEVICE_OBJECT* const p_dev_obj );\r
+\r
+static NTSTATUS\r
+iou_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+iou_surprise_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+iou_query_capabilities(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+iou_query_target_relations(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+iou_query_device_id(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp );\r
+\r
+static NTSTATUS\r
+iou_query_hardware_ids(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp );\r
+\r
+static NTSTATUS\r
+iou_query_compatible_ids(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp );\r
+\r
+static NTSTATUS\r
+iou_query_unique_id(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp );\r
+\r
+static NTSTATUS\r
+iou_query_description(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp );\r
+\r
+static NTSTATUS\r
+iou_query_location(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp );\r
+\r
+static NTSTATUS\r
+iou_query_bus_info(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+iou_query_interface(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+iou_set_power(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+\r
+/* All PnP code is called at passive, so it can all be paged out. */\r
+#ifdef ALLOC_PRAGMA\r
+#pragma alloc_text (PAGE, iou_start)\r
+#pragma alloc_text (PAGE, iou_query_remove)\r
+#pragma alloc_text (PAGE, iou_release_resources)\r
+#pragma alloc_text (PAGE, iou_remove)\r
+#pragma alloc_text (PAGE, iou_surprise_remove)\r
+#pragma alloc_text (PAGE, iou_query_capabilities)\r
+#pragma alloc_text (PAGE, iou_query_target_relations)\r
+#pragma alloc_text (PAGE, iou_query_device_id)\r
+#pragma alloc_text (PAGE, iou_query_hardware_ids)\r
+#pragma alloc_text (PAGE, iou_query_compatible_ids)\r
+#pragma alloc_text (PAGE, iou_query_unique_id)\r
+#pragma alloc_text (PAGE, iou_query_description)\r
+#pragma alloc_text (PAGE, iou_query_location)\r
+#pragma alloc_text (PAGE, iou_query_bus_info)\r
+#pragma alloc_text (PAGE, iou_query_interface)\r
+#pragma alloc_text (PAGE_PNP, iou_set_power)\r
+#pragma alloc_text (PAGE, iou_mgr_iou_add)\r
+#pragma alloc_text (PAGE, iou_mgr_iou_remove)\r
+#endif\r
+\r
+\r
+/*\r
+ * Global virtual function pointer tables shared between all \r
+ * instances of Port PDOs.\r
+ */\r
+static const cl_vfptr_pnp_po_t vfptr_iou_pnp = {\r
+ "IB IOU",\r
+ iou_start,\r
+ cl_irp_succeed,\r
+ cl_irp_succeed,\r
+ cl_irp_succeed,\r
+ iou_query_remove,\r
+ iou_release_resources,\r
+ iou_remove,\r
+ cl_irp_succeed,\r
+ iou_surprise_remove,\r
+ iou_query_capabilities,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ cl_irp_succeed,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ iou_query_target_relations,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ iou_query_bus_info,\r
+ iou_query_interface,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ cl_irp_succeed, // QueryPower\r
+ iou_set_power, // SetPower\r
+ cl_irp_unsupported, // PowerSequence\r
+ cl_irp_unsupported // WaitWake\r
+};\r
+\r
+\r
+static const cl_vfptr_query_txt_t vfptr_iou_query_txt = {\r
+ iou_query_device_id,\r
+ iou_query_hardware_ids,\r
+ iou_query_compatible_ids,\r
+ iou_query_unique_id,\r
+ iou_query_description,\r
+ iou_query_location\r
+};\r
+\r
+\r
+/*\r
+ * Create the AL load service.\r
+ */\r
+ib_api_status_t\r
+create_iou_mgr(\r
+ OUT iou_mgr_t** const pp_iou_mgr )\r
+{\r
+ ib_api_status_t status;\r
+ cl_status_t cl_status;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ CL_ASSERT( !gp_iou_mgr );\r
+\r
+ gp_iou_mgr = cl_zalloc( sizeof(iou_mgr_t) );\r
+ if( !gp_iou_mgr )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("Failed to allocate port manager.\n") );\r
+ return IB_INSUFFICIENT_MEMORY;\r
+ }\r
+\r
+ /* Construct the load service. */\r
+ cl_obj_construct( &gp_iou_mgr->obj, AL_OBJ_TYPE_LOADER );\r
+ cl_mutex_construct( &gp_iou_mgr->pdo_mutex );\r
+ cl_qlist_init( &gp_iou_mgr->iou_list );\r
+\r
+ cl_status = cl_mutex_init( &gp_iou_mgr->pdo_mutex );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ free_iou_mgr( &gp_iou_mgr->obj );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("cl_mutex_init returned %#x.\n", cl_status) );\r
+ return ib_convert_cl_status( cl_status );\r
+ }\r
+\r
+ /* Initialize the load service object. */\r
+ cl_status = cl_obj_init( &gp_iou_mgr->obj, CL_DESTROY_SYNC,\r
+ destroying_iou_mgr, NULL, free_iou_mgr );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ free_iou_mgr( &gp_iou_mgr->obj );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("cl_obj_init returned %#x.\n", cl_status) );\r
+ return ib_convert_cl_status( cl_status );\r
+ }\r
+\r
+ /* Register for port PnP events. */\r
+ status = bus_reg_iou_pnp();\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ cl_obj_destroy( &gp_iou_mgr->obj );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("bus_reg_iou_pnp returned %s.\n", ib_get_err_str(status)) );\r
+ return status;\r
+ }\r
+\r
+ *pp_iou_mgr = gp_iou_mgr;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+/*\r
+ * Pre-destroy the load service.\r
+ */\r
+void\r
+destroying_iou_mgr(\r
+ IN cl_obj_t* p_obj )\r
+{\r
+ ib_api_status_t status;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ CL_ASSERT( p_obj );\r
+ CL_ASSERT( gp_iou_mgr == PARENT_STRUCT( p_obj, iou_mgr_t, obj ) );\r
+ UNUSED_PARAM( p_obj );\r
+\r
+ /* Deregister for port PnP events. */\r
+ if( gp_iou_mgr->h_pnp )\r
+ {\r
+ status = ib_dereg_pnp( gp_iou_mgr->h_pnp,\r
+ (ib_pfn_destroy_cb_t)cl_obj_deref );\r
+ CL_ASSERT( status == IB_SUCCESS );\r
+ }\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+/*\r
+ * Free the load service.\r
+ */\r
+void\r
+free_iou_mgr(\r
+ IN cl_obj_t* p_obj )\r
+{\r
+ bus_pdo_ext_t *p_ext;\r
+ cl_list_item_t *p_list_item;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ CL_ASSERT( p_obj );\r
+ CL_ASSERT( gp_iou_mgr == PARENT_STRUCT( p_obj, iou_mgr_t, obj ) );\r
+\r
+ /*\r
+ * Mark all IPoIB PDOs as no longer present. This will cause them\r
+ * to be removed when they process the IRP_MN_REMOVE_DEVICE.\r
+ */\r
+ p_list_item = cl_qlist_remove_head( &gp_iou_mgr->iou_list );\r
+ while( p_list_item != cl_qlist_end( &gp_iou_mgr->iou_list ) )\r
+ {\r
+ p_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
+ p_list_item = cl_qlist_remove_head( &gp_iou_mgr->iou_list );\r
+ if( p_ext->cl_ext.pnp_state == SurpriseRemoved )\r
+ {\r
+ CL_ASSERT( !p_ext->b_present );\r
+ p_ext->b_reported_missing = TRUE;\r
+ BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n",\r
+ p_ext->cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->b_present, p_ext->b_reported_missing ) );\r
+ continue;\r
+ }\r
+ if( p_ext->h_ca )\r
+ {\r
+ /* Invalidate bus relations for the HCA. */\r
+ IoInvalidateDeviceRelations(\r
+ p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
+\r
+ /* Release the reference on the CA object. */\r
+ deref_al_obj( &p_ext->h_ca->obj );\r
+ }\r
+ IoDeleteDevice( p_ext->cl_ext.p_self_do );\r
+ }\r
+\r
+ cl_mutex_destroy( &gp_iou_mgr->pdo_mutex );\r
+ cl_obj_deinit( p_obj );\r
+ cl_free( gp_iou_mgr );\r
+ gp_iou_mgr = NULL;\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+/*\r
+ * Register the load service for the given PnP class events.\r
+ */\r
+ib_api_status_t\r
+bus_reg_iou_pnp( void )\r
+{\r
+ ib_pnp_req_t pnp_req;\r
+ ib_api_status_t status;\r
+\r
+ cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) );\r
+ pnp_req.pnp_class = IB_PNP_IOU | IB_PNP_FLAG_REG_SYNC;\r
+ pnp_req.pnp_context = gp_iou_mgr;\r
+ pnp_req.pfn_pnp_cb = iou_mgr_pnp_cb;\r
+\r
+ status = ib_reg_pnp( gh_al, &pnp_req, &gp_iou_mgr->h_pnp );\r
+\r
+ if( status == IB_SUCCESS )\r
+ {\r
+ /* Reference the load service on behalf of the ib_reg_pnp call. */\r
+ cl_obj_ref( &gp_iou_mgr->obj );\r
+ }\r
+\r
+ return status;\r
+}\r
+\r
+\r
+/*\r
+ * Load service PnP event callback.\r
+ */\r
+ib_api_status_t\r
+iou_mgr_pnp_cb(\r
+ IN ib_pnp_rec_t* p_pnp_rec )\r
+{\r
+ ib_api_status_t status;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ CL_ASSERT( p_pnp_rec );\r
+ CL_ASSERT( gp_iou_mgr == p_pnp_rec->pnp_context );\r
+\r
+ switch( p_pnp_rec->pnp_event )\r
+ {\r
+ case IB_PNP_IOU_ADD:\r
+ status = iou_mgr_iou_add( (ib_pnp_iou_rec_t*)p_pnp_rec );\r
+ break;\r
+\r
+ case IB_PNP_IOU_REMOVE:\r
+ iou_mgr_iou_remove( (ib_pnp_iou_rec_t*)p_pnp_rec );\r
+\r
+ default:\r
+ status = IB_SUCCESS;\r
+ break;\r
+ }\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+\r
+/*\r
+ * Called to get child relations for the bus root.\r
+ */\r
+NTSTATUS\r
+iou_mgr_get_bus_relations(\r
+ IN const net64_t ca_guid,\r
+ IN IRP* const p_irp )\r
+{\r
+ NTSTATUS status;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ cl_mutex_acquire( &gp_iou_mgr->pdo_mutex );\r
+ status = bus_get_relations( &gp_iou_mgr->iou_list, ca_guid, p_irp );\r
+ cl_mutex_release( &gp_iou_mgr->pdo_mutex );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+\r
+static ib_api_status_t\r
+__iou_was_hibernated(\r
+ IN ib_pnp_iou_rec_t* p_pnp_rec )\r
+{\r
+ NTSTATUS status;\r
+ cl_list_item_t *p_list_item;\r
+ bus_iou_ext_t *p_iou_ext;\r
+ bus_pdo_ext_t *p_pdo_ext = NULL;\r
+ size_t n_devs = 0;\r
+ cl_qlist_t* p_pdo_list = &gp_iou_mgr->iou_list;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+ \r
+ cl_mutex_acquire( &gp_iou_mgr->pdo_mutex );\r
+ \r
+ /* Count the number of child devices. */\r
+ for( p_list_item = cl_qlist_head( p_pdo_list );\r
+ p_list_item != cl_qlist_end( p_pdo_list );\r
+ p_list_item = cl_qlist_next( p_list_item ) )\r
+ {\r
+ p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
+ p_iou_ext = (bus_iou_ext_t*)p_pdo_ext;\r
+\r
+ /* TODO: maybe we need more search patterns like vend_id, dev_id ... */\r
+ if( p_pdo_ext->b_present && p_pdo_ext->b_hibernating &&\r
+ (p_iou_ext->guid == p_pnp_rec->pnp_rec.guid) )\r
+ {\r
+ n_devs++;\r
+ break;\r
+ }\r
+\r
+ BUS_TRACE( BUS_DBG_PNP, \r
+ ("Skipped PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
+ p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, \r
+ p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
+ p_pdo_ext->b_hibernating, p_iou_ext->guid ) );\r
+ }\r
+\r
+ if (n_devs)\r
+ {\r
+ /* Take a reference on the parent HCA. */\r
+ p_pdo_ext->h_ca = acquire_ca( p_pnp_rec->ca_guid );\r
+ if( !p_pdo_ext->h_ca )\r
+ {\r
+ BUS_TRACE( BUS_DBG_ERROR, ("acquire_ca failed to find CA by guid %I64x\n",\r
+ p_pnp_rec->ca_guid ) );\r
+ status = IB_INVALID_GUID;\r
+ }\r
+ else \r
+ {\r
+ p_pdo_ext->b_hibernating = FALSE;\r
+ p_pnp_rec->pnp_rec.context = p_pdo_ext;\r
+ status = IB_SUCCESS;\r
+ p_iou_ext = (bus_iou_ext_t*)p_pdo_ext;\r
+ BUS_TRACE( BUS_DBG_PNP, \r
+ ("Found PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
+ p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, \r
+ p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
+ p_pdo_ext->b_hibernating, p_iou_ext->guid ) );\r
+ }\r
+ }\r
+ else \r
+ {\r
+ BUS_TRACE( BUS_DBG_PNP, ("Failed to find PDO for guid %I64x .\n",\r
+ p_pnp_rec->pnp_rec.guid ) );\r
+ status = IB_NOT_FOUND;\r
+ }\r
+\r
+ cl_mutex_release( &gp_iou_mgr->pdo_mutex );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+ib_api_status_t\r
+iou_mgr_iou_add(\r
+ IN ib_pnp_iou_rec_t* p_pnp_rec )\r
+{\r
+ NTSTATUS status;\r
+ DEVICE_OBJECT *p_pdo;\r
+ bus_iou_ext_t *p_iou_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ /* Upon hibernating of the computer IB_BUS driver doesn't remove PDO, but\r
+ marks with a flag. So we first try to find an existing PDO for this port,\r
+ marked with this flag. If it was found, we turn off the flag and use this PDO */\r
+ status = __iou_was_hibernated(p_pnp_rec);\r
+ if( status != IB_NOT_FOUND )\r
+ {\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+ }\r
+\r
+ /* Create the PDO for the new port device. */\r
+ status = IoCreateDevice( bus_globals.p_driver_obj, sizeof(bus_iou_ext_t),\r
+ NULL, FILE_DEVICE_CONTROLLER, \r
+ FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,\r
+ FALSE, &p_pdo );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("IoCreateDevice returned %08x.\n", status) );\r
+ return IB_ERROR;\r
+ }\r
+\r
+ /* Initialize the device extension. */\r
+ cl_init_pnp_po_ext( p_pdo, NULL, p_pdo, bus_globals.dbg_lvl,\r
+ &vfptr_iou_pnp, &vfptr_iou_query_txt );\r
+\r
+ /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */\r
+ p_pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;\r
+ \r
+ p_iou_ext = p_pdo->DeviceExtension;\r
+ p_iou_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0;\r
+ p_iou_ext->pdo.p_parent_ext = bus_globals.p_bus_ext;\r
+ p_iou_ext->pdo.b_present = TRUE;\r
+ p_iou_ext->pdo.b_reported_missing = FALSE;\r
+ BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n",\r
+ p_iou_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_iou_ext, p_iou_ext->pdo.b_present, p_iou_ext->pdo.b_reported_missing ) );\r
+\r
+ p_iou_ext->guid = p_pnp_rec->guid;\r
+ p_iou_ext->chassis_guid = p_pnp_rec->chassis_guid;\r
+ p_iou_ext->slot = p_pnp_rec->slot;\r
+ p_iou_ext->vend_id = cl_ntoh32( p_pnp_rec->vend_id );\r
+ if( p_iou_ext->vend_id == 0x00066a )\r
+ p_iou_ext->dev_id = (net16_t)(p_pnp_rec->pnp_rec.guid >> 32) & 0x00FF;\r
+ else\r
+ p_iou_ext->dev_id = cl_ntoh16( p_pnp_rec->dev_id );\r
+ p_iou_ext->revision = cl_ntoh32( p_pnp_rec->revision );\r
+ cl_memcpy( p_iou_ext->desc, p_pnp_rec->desc,\r
+ IB_NODE_DESCRIPTION_SIZE + 1 );\r
+\r
+ /* Cache the CA GUID. */\r
+ p_iou_ext->pdo.ca_guid = p_pnp_rec->ca_guid;\r
+\r
+ /* Take a reference on the parent HCA. */\r
+ p_iou_ext->pdo.h_ca = acquire_ca( p_pnp_rec->ca_guid );\r
+ if( !p_iou_ext->pdo.h_ca )\r
+ {\r
+ IoDeleteDevice( p_pdo );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("acquire_ca failed to find CA.\n") );\r
+ return IB_INVALID_GUID;\r
+ }\r
+\r
+ /* Store the device extension in the PDO list for future queries. */\r
+ cl_mutex_acquire( &gp_iou_mgr->pdo_mutex );\r
+ cl_qlist_insert_tail( &gp_iou_mgr->iou_list,\r
+ &p_iou_ext->pdo.list_item );\r
+ cl_mutex_release( &gp_iou_mgr->pdo_mutex );\r
+\r
+ /*\r
+ * Set the context of the PNP event. The context is passed in for future\r
+ * events on the same port.\r
+ */\r
+ p_pnp_rec->pnp_rec.context = p_iou_ext;\r
+\r
+ /* Tell the PnP Manager to rescan for the HCA's bus relations. */\r
+ IoInvalidateDeviceRelations(\r
+ p_iou_ext->pdo.h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
+\r
+ /* Invalidate removal relations for the bus driver. */\r
+ IoInvalidateDeviceRelations(\r
+ bus_globals.p_bus_ext->cl_ext.p_pdo, RemovalRelations );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+void\r
+iou_mgr_iou_remove(\r
+ IN ib_pnp_iou_rec_t* p_pnp_rec )\r
+{\r
+ bus_pdo_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ /* The PNP record's context is the port extension. */\r
+ p_ext = p_pnp_rec->pnp_rec.context;\r
+ CL_ASSERT( p_ext );\r
+\r
+ /*\r
+ * Flag the port PDO as no longer being present. We have to wait until\r
+ * the PnP manager removes it to clean up. However, we do release the\r
+ * reference on the CA object in order to allow the removal of the HCA\r
+ * to proceed should it occur before the port's PDO is cleaned up.\r
+ */\r
+ cl_mutex_acquire( &gp_iou_mgr->pdo_mutex );\r
+ CL_ASSERT( p_ext->h_ca );\r
+\r
+ if( p_ext->b_hibernating )\r
+ {\r
+ BUS_TRACE( BUS_DBG_PNP, ("Skip port removing for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d .\n",\r
+ p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, \r
+ p_ext->b_reported_missing, p_ext->b_hibernating ) );\r
+ goto hca_deref;\r
+ }\r
+\r
+ p_ext->b_present = FALSE;\r
+ BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n",\r
+ p_ext->cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->b_present, p_ext->b_reported_missing ) );\r
+\r
+ /* Invalidate removal relations for the bus driver. */\r
+ IoInvalidateDeviceRelations( bus_globals.p_bus_ext->cl_ext.p_pdo,\r
+ RemovalRelations );\r
+\r
+ /* Invalidate bus relations for the HCA. */\r
+ IoInvalidateDeviceRelations(\r
+ p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
+\r
+hca_deref:\r
+ deref_al_obj( &p_ext->h_ca->obj );\r
+ p_ext->h_ca = NULL;\r
+ cl_mutex_release( &gp_iou_mgr->pdo_mutex );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_start(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ bus_pdo_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( p_irp );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ /* Notify the Power Manager that the device is started. */\r
+ PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
+\r
+ *p_action = IrpComplete;\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_query_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ bus_iou_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( p_irp );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ *p_action = IrpComplete;\r
+ if( p_ext->n_ifc_ref )\r
+ {\r
+ /*\r
+ * Our interface is still being held by someone.\r
+ * Rollback the PnP state that was changed in the complib handler.\r
+ */\r
+ cl_rollback_pnp_state( &p_ext->pdo.cl_ext );\r
+\r
+ /* Fail the query. */\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, ("Failing IRP_MN_QUERY_REMOVE_DEVICE:\n"\r
+ "\tInterface has %d reference\n", p_ext->n_ifc_ref ) );\r
+ return STATUS_UNSUCCESSFUL;\r
+ }\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static void\r
+iou_release_resources(\r
+ IN DEVICE_OBJECT* const p_dev_obj )\r
+{\r
+ bus_iou_ext_t *p_ext;\r
+ POWER_STATE po_state;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ /* Remove this PDO from its list. */\r
+ cl_mutex_acquire( &gp_iou_mgr->pdo_mutex );\r
+ BUS_TRACE( BUS_DBG_PNP, ("Removing IOU from list.\n") );\r
+ cl_qlist_remove_item( &gp_iou_mgr->iou_list, &p_ext->pdo.list_item );\r
+ cl_mutex_release( &gp_iou_mgr->pdo_mutex );\r
+ po_state.DeviceState = PowerDeviceD3;\r
+ PoSetPowerState( p_ext->pdo.cl_ext.p_pdo, DevicePowerState, po_state );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ bus_iou_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ if( p_ext->pdo.b_present )\r
+ {\r
+ CL_ASSERT( p_ext->pdo.cl_ext.pnp_state != NotStarted );\r
+ CL_ASSERT( !p_ext->pdo.b_reported_missing );\r
+ /* Reset the state to NotStarted. CompLib set it to Deleted. */\r
+ cl_set_pnp_state( &p_ext->pdo.cl_ext, NotStarted );\r
+ /* Don't delete the device. It may simply be disabled. */\r
+ *p_action = IrpComplete;\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device still present.\n") );\r
+ return STATUS_SUCCESS;\r
+ }\r
+\r
+ if( !p_ext->pdo.b_reported_missing )\r
+ {\r
+ /* Reset the state to RemovePending. Complib set it to Deleted. */\r
+ cl_rollback_pnp_state( &p_ext->pdo.cl_ext );\r
+ *p_action = IrpComplete;\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device not reported missing yet.\n") );\r
+ return STATUS_SUCCESS;\r
+ }\r
+\r
+ /* Wait for all I/O operations to complete. */\r
+ IoReleaseRemoveLockAndWait( &p_ext->pdo.cl_ext.remove_lock, p_irp );\r
+\r
+ /* Release resources if it was not done yet. */\r
+ if( p_ext->pdo.cl_ext.last_pnp_state != SurpriseRemoved )\r
+ p_ext->pdo.cl_ext.vfptr_pnp_po->pfn_release_resources( p_dev_obj );\r
+\r
+ p_irp->IoStatus.Status = STATUS_SUCCESS;\r
+ IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+\r
+ IoDeleteDevice( p_dev_obj );\r
+\r
+ *p_action = IrpDoNothing;\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_surprise_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ bus_iou_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( p_irp );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+ p_ext->pdo.b_present = FALSE;\r
+ p_ext->pdo.b_reported_missing = TRUE;\r
+ BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n",\r
+ p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) );\r
+\r
+ *p_action = IrpComplete;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_query_capabilities(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ DEVICE_CAPABILITIES *p_caps;\r
+ IO_STACK_LOCATION *p_io_stack;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( p_dev_obj );\r
+\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+ p_caps = p_io_stack->Parameters.DeviceCapabilities.Capabilities;\r
+\r
+ p_caps->DeviceD1 = FALSE;\r
+ p_caps->DeviceD2 = FALSE;\r
+ p_caps->LockSupported = FALSE;\r
+ p_caps->EjectSupported = FALSE;\r
+ p_caps->Removable = TRUE;\r
+ p_caps->DockDevice = FALSE;\r
+ p_caps->UniqueID = TRUE;\r
+ p_caps->SilentInstall = TRUE;\r
+ p_caps->RawDeviceOK = FALSE;\r
+ p_caps->SurpriseRemovalOK = FALSE;\r
+ p_caps->WakeFromD0 = FALSE;\r
+ p_caps->WakeFromD1 = FALSE;\r
+ p_caps->WakeFromD2 = FALSE;\r
+ p_caps->WakeFromD3 = FALSE;\r
+ p_caps->HardwareDisabled = FALSE;\r
+ p_caps->DeviceState[PowerSystemWorking] = PowerDeviceD0;\r
+ p_caps->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;\r
+ p_caps->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;\r
+ p_caps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;\r
+ p_caps->DeviceState[PowerSystemHibernate] = PowerDeviceD3;\r
+ p_caps->DeviceState[PowerSystemShutdown] = PowerDeviceD3;\r
+ p_caps->SystemWake = PowerSystemUnspecified;\r
+ p_caps->DeviceWake = PowerDeviceUnspecified;\r
+ p_caps->D1Latency = 0;\r
+ p_caps->D2Latency = 0;\r
+ p_caps->D3Latency = 0;\r
+\r
+ *p_action = IrpComplete;\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_query_target_relations(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ NTSTATUS status;\r
+ DEVICE_RELATIONS *p_rel;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ *p_action = IrpComplete;\r
+\r
+ status = cl_alloc_relations( p_irp, 1 );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("cl_alloc_relations returned 0x%08x.\n", status) );\r
+ return status;\r
+ }\r
+\r
+ p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
+ p_rel->Count = 1;\r
+ p_rel->Objects[0] = p_dev_obj;\r
+\r
+ ObReferenceObject( p_dev_obj );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_query_device_id(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ OUT IRP* const p_irp )\r
+{\r
+ NTSTATUS status;\r
+ bus_iou_ext_t *p_ext;\r
+ WCHAR *p_string;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = (bus_iou_ext_t*)p_dev_obj->DeviceExtension;\r
+ if( !p_ext->pdo.b_present )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ /* Device ID is "IBA\SID_<sid> where <sid> is the IPoIB Service ID. */\r
+ p_string = ExAllocatePoolWithTag( PagedPool, IOU_DEV_ID_SIZE, 'didq' );\r
+ if( !p_string )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("Failed to allocate device ID buffer (%d bytes).\n",\r
+ IOU_DEV_ID_SIZE) );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ status =\r
+ RtlStringCbPrintfW( p_string, IOU_DEV_ID_SIZE, IOU_DEV_ID_STRING1,\r
+ p_ext->vend_id, p_ext->dev_id, p_ext->revision );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ ExFreePool( p_string );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to format device ID string.\n") );\r
+ return status;\r
+ }\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_query_hardware_ids(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ OUT IRP* const p_irp )\r
+{\r
+ NTSTATUS status;\r
+ bus_iou_ext_t *p_ext;\r
+ WCHAR *p_string, *p_start;\r
+ size_t size;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = (bus_iou_ext_t*)p_dev_obj->DeviceExtension;\r
+ if( !p_ext->pdo.b_present )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ p_string = ExAllocatePoolWithTag( PagedPool, IOU_HW_ID_SIZE, 'dihq' );\r
+ if( !p_string )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("Failed to allocate hardware ID buffer (%d bytes).\n",\r
+ IOU_HW_ID_SIZE) );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ p_start = p_string;\r
+ size = IOU_HW_ID_SIZE;\r
+ /* Fill in the first HW ID. */\r
+ status = RtlStringCbPrintfExW( p_start, size, &p_start, &size,\r
+ STRSAFE_FILL_BEHIND_NULL | STRSAFE_NO_TRUNCATION, IOU_DEV_ID_STRING1,\r
+ p_ext->vend_id, p_ext->dev_id, p_ext->revision );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ ExFreePool( p_string );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to format device ID string.\n") );\r
+ return status;\r
+ }\r
+ /* Fill in the second HW ID. */\r
+ CL_ASSERT( *p_start == L'\0' );\r
+ p_start++;\r
+ size -= sizeof(WCHAR);\r
+ status = RtlStringCbPrintfExW( p_start, size, NULL, NULL,\r
+ STRSAFE_FILL_BEHIND_NULL | STRSAFE_NO_TRUNCATION, IOU_DEV_ID_STRING2,\r
+ p_ext->vend_id, p_ext->dev_id );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ ExFreePool( p_string );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to format device ID string.\n") );\r
+ return status;\r
+ }\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_query_compatible_ids(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ OUT IRP* const p_irp )\r
+{\r
+ WCHAR *p_string;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( p_dev_obj );\r
+\r
+ p_string = ExAllocatePoolWithTag( PagedPool, sizeof(IOU_COMPAT_ID), 'dicq' );\r
+ if( !p_string )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("Failed to allocate compatible ID buffer (%d bytes).\n",\r
+ IOU_HW_ID_SIZE) );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ cl_memcpy( p_string, IOU_COMPAT_ID, sizeof(IOU_COMPAT_ID) );\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_query_unique_id(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ OUT IRP* const p_irp )\r
+{\r
+ NTSTATUS status;\r
+ WCHAR *p_string;\r
+ bus_iou_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+ \r
+ p_ext = p_dev_obj->DeviceExtension;\r
+ if( !p_ext->pdo.b_present )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ /* The instance ID is the port GUID. */\r
+ p_string = ExAllocatePoolWithTag( PagedPool, sizeof(WCHAR) * 33, 'diuq' );\r
+ if( !p_string )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("Failed to allocate instance ID buffer (%d bytes).\n",\r
+ sizeof(WCHAR) * 17) );\r
+ return STATUS_NO_MEMORY;\r
+ }\r
+\r
+ status = RtlStringCchPrintfW( p_string, 33, L"%016I64x%016I64x",\r
+ p_ext->guid, p_ext->pdo.ca_guid );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ CL_ASSERT( NT_SUCCESS( status ) );\r
+ ExFreePool( p_string );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("RtlStringCchPrintfW returned %08x.\n", status) );\r
+ return status;\r
+ }\r
+\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_query_description(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ OUT IRP* const p_irp )\r
+{\r
+ NTSTATUS status;\r
+ WCHAR *p_string;\r
+ bus_iou_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+ \r
+ p_ext = p_dev_obj->DeviceExtension;\r
+ if( !p_ext->pdo.b_present )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ /* The instance ID is the port GUID. */\r
+ p_string = ExAllocatePoolWithTag( PagedPool,\r
+ sizeof(WCHAR) * sizeof(p_ext->desc),\r
+ 'sedq' );\r
+ if( !p_string )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("Failed to allocate device description buffer (%d bytes).\n",\r
+ sizeof(WCHAR) * sizeof(p_ext->desc)) );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ status = RtlStringCchPrintfW( p_string, sizeof(p_ext->desc),\r
+ L"%S", p_ext->desc );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ CL_ASSERT( NT_SUCCESS( status ) );\r
+ ExFreePool( p_string );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("RtlStringCchPrintfW returned %08x.\n", status) );\r
+ return status;\r
+ }\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_query_location(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ OUT IRP* const p_irp )\r
+{\r
+ NTSTATUS status;\r
+ bus_iou_ext_t *p_ext;\r
+ WCHAR *p_string;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = (bus_iou_ext_t*)p_dev_obj->DeviceExtension;\r
+ if( !p_ext->pdo.b_present )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ p_string = ExAllocatePoolWithTag( PagedPool, IOU_LOCATION_SIZE, 'colq' );\r
+ if( !p_string )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("Failed to allocate location buffer (%d bytes).\n",\r
+ IOU_LOCATION_SIZE) );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ status = RtlStringCbPrintfW( p_string, IOU_LOCATION_SIZE,\r
+ L"Chassis 0x%016I64x, Slot %d", p_ext->chassis_guid, p_ext->slot );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ ExFreePool( p_string );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to format device ID string.\n") );\r
+ return status;\r
+ }\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_query_bus_info(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ PNP_BUS_INFORMATION *p_bus_info;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( p_dev_obj );\r
+\r
+ *p_action = IrpComplete;\r
+\r
+ p_bus_info = ExAllocatePoolWithTag( PagedPool, sizeof(PNP_BUS_INFORMATION), 'subq' );\r
+ if( !p_bus_info )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to allocate PNP_BUS_INFORMATION (%d bytes).\n",\r
+ sizeof(PNP_BUS_INFORMATION)) );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ p_bus_info->BusTypeGuid = GUID_BUS_TYPE_IBA;\r
+ //TODO: Memory from Intel - storage miniport would not stay loaded unless\r
+ //TODO: bus type was PCI. Look here if SRP is having problems staying\r
+ //TODO: loaded.\r
+ p_bus_info->LegacyBusType = PNPBus;\r
+ p_bus_info->BusNumber = 0;\r
+\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_bus_info;\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_query_iou_ifc(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IO_STACK_LOCATION* const p_io_stack )\r
+{\r
+ NTSTATUS status;\r
+ ib_al_ifc_t *p_ifc;\r
+ ib_al_ifc_data_t *p_ifc_data;\r
+ iou_ifc_data_t *p_iou_data;\r
+ bus_iou_ext_t *p_ext;\r
+ const GUID *p_guid;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ /* Get the interface. */\r
+ status = cl_fwd_query_ifc(\r
+ p_ext->pdo.p_parent_ext->cl_ext.p_self_do, p_io_stack );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to forward interface query: %08X\n", status) );\r
+ return status;\r
+ }\r
+\r
+ if( !p_io_stack->Parameters.QueryInterface.InterfaceSpecificData )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("No interface specific data!\n") );\r
+ return status;\r
+ }\r
+\r
+ p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
+\r
+ p_ifc_data = (ib_al_ifc_data_t*)\r
+ p_io_stack->Parameters.QueryInterface.InterfaceSpecificData;\r
+ p_guid = p_ifc_data->type;\r
+ if( !IsEqualGUID( p_guid, &GUID_IOU_INTERFACE_DATA ) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, ("Unsupported interface data: \n\t"\r
+ "0x%08x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x,"\r
+ "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x.\n",\r
+ p_guid->Data1, p_guid->Data2, p_guid->Data3,\r
+ p_guid->Data4[0], p_guid->Data4[1], p_guid->Data4[2],\r
+ p_guid->Data4[3], p_guid->Data4[4], p_guid->Data4[5],\r
+ p_guid->Data4[6], p_guid->Data4[7]) );\r
+ return status;\r
+ }\r
+\r
+ if( p_ifc_data->version != IOU_INTERFACE_DATA_VERSION )\r
+ {\r
+ p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Unsupported version %d, expected %d\n",\r
+ p_ifc_data->version, IOU_INTERFACE_DATA_VERSION) );\r
+ return STATUS_NOT_SUPPORTED;\r
+ }\r
+\r
+ ASSERT( p_ifc_data->p_data );\r
+\r
+ if( p_ifc_data->size != sizeof(iou_ifc_data_t) )\r
+ {\r
+ p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context );\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP,\r
+ ("Buffer too small (%d given, %d required).\n",\r
+ p_ifc_data->size,\r
+ sizeof(iou_ifc_data_t)) );\r
+ return STATUS_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ /* Set the interface data. */\r
+ p_iou_data = (iou_ifc_data_t*)p_ifc_data->p_data;\r
+\r
+ p_iou_data->ca_guid = p_ext->pdo.ca_guid;\r
+ p_iou_data->chassis_guid = p_ext->chassis_guid;\r
+ p_iou_data->slot = p_ext->slot;\r
+ p_iou_data->guid = p_ext->guid;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+iou_query_interface(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ bus_pdo_ext_t *p_ext;\r
+ NTSTATUS status;\r
+ IO_STACK_LOCATION *p_io_stack;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
+\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+ \r
+ /* Bottom of the stack - IRP must be completed. */\r
+ *p_action = IrpComplete;\r
+\r
+ /* Compare requested GUID with our supported interface GUIDs. */\r
+ if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
+ &GUID_IB_AL_INTERFACE ) )\r
+ {\r
+ status = iou_query_iou_ifc( p_dev_obj, p_io_stack );\r
+ }\r
+ else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
+ &GUID_BUS_INTERFACE_STANDARD ) )\r
+ {\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+ if( !p_ext->h_ca ||\r
+ !p_ext->b_present ||\r
+ p_ext->b_reported_missing )\r
+ {\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+\r
+ status = cl_fwd_query_ifc(\r
+ p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, p_io_stack );\r
+ }\r
+ else\r
+ {\r
+ status = p_irp->IoStatus.Status;\r
+ }\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+\r
+\r
+/* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
+static void\r
+__HibernateUpWorkItem(\r
+ IN DEVICE_OBJECT* p_dev_obj,\r
+ IN void* context )\r
+{\r
+ IO_STACK_LOCATION *p_io_stack;\r
+ bus_pdo_ext_t *p_ext;\r
+ IRP *p_irp;\r
+ POWER_STATE powerState;\r
+\r
+ BUS_ENTER( BUS_DBG_POWER );\r
+\r
+ p_ext = (bus_pdo_ext_t*)p_dev_obj->DeviceExtension;\r
+ p_irp = (IRP*)context;\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+ IoFreeWorkItem( p_ext->p_po_work_item );\r
+ p_ext->p_po_work_item = NULL;\r
+\r
+ while (!p_ext->h_ca) {\r
+ BUS_TRACE( BUS_DBG_PNP, ("Waiting for the end of HCA registration ... \n"));\r
+ cl_thread_suspend( 200 ); /* suspend for 200 ms */\r
+ }\r
+\r
+ p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
+ powerState = PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
+\r
+ BUS_TRACE( BUS_DBG_POWER, \r
+ ("PoSetPowerState: old state %d, new state to %d\n", \r
+ powerState.DeviceState, p_ext->dev_po_state ));\r
+\r
+ p_irp->IoStatus.Status = STATUS_SUCCESS;\r
+ PoStartNextPowerIrp( p_irp );\r
+ IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+ IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
+\r
+ BUS_EXIT( BUS_DBG_POWER );\r
+}\r
+\r
+/*\r
+ * The PDOs created by the IB Bus driver are software devices. As such,\r
+ * all power states are supported. It is left to the HCA power policy \r
+ * owner to handle which states can be supported by the HCA.\r
+ */\r
+static NTSTATUS\r
+iou_set_power(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ NTSTATUS status = STATUS_SUCCESS;\r
+ IO_STACK_LOCATION *p_io_stack;\r
+ bus_pdo_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_POWER );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+ BUS_TRACE( BUS_DBG_POWER, \r
+ ("SET_POWER for PDO %p (ext %p): type %s, state %d, action %d \n",\r
+ p_dev_obj, p_ext,\r
+ (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
+ p_io_stack->Parameters.Power.State.DeviceState, \r
+ p_io_stack->Parameters.Power.ShutdownType ));\r
+\r
+ if ((p_io_stack->Parameters.Power.Type == SystemPowerState) &&\r
+ (p_io_stack->Parameters.Power.State.SystemState ==PowerSystemHibernate ||\r
+ p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 ))\r
+ {\r
+ BUS_TRACE( BUS_DBG_POWER, ("Setting b_hibernating flag for PDO %p \n", p_dev_obj));\r
+ p_ext->b_hibernating = TRUE;\r
+ }\r
+\r
+ if( p_io_stack->Parameters.Power.Type == DevicePowerState )\r
+ {\r
+ /* after hibernation PDO is not ready for work. we need to wait for finishing of the HCA registration */\r
+ if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && p_ext->b_hibernating)\r
+ {\r
+ /* Process in a work item - deregister_ca and HcaDeinit block. */\r
+ ASSERT( !p_ext->p_po_work_item );\r
+ p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj );\r
+ if( !p_ext->p_po_work_item )\r
+ status = STATUS_INSUFFICIENT_RESOURCES;\r
+ else {\r
+ /* Process in work item callback. */\r
+ IoMarkIrpPending( p_irp );\r
+ IoQueueWorkItem(\r
+ p_ext->p_po_work_item, __HibernateUpWorkItem, DelayedWorkQueue, p_irp );\r
+ *p_action = IrpDoNothing;\r
+ BUS_EXIT( BUS_DBG_POWER );\r
+ return STATUS_PENDING;\r
+ }\r
+ }\r
+\r
+ /* Notify the power manager. */\r
+ p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
+ PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
+ }\r
+\r
+ *p_action = IrpComplete;\r
+ BUS_EXIT( BUS_DBG_POWER );\r
+ return STATUS_SUCCESS;\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: bus_iou_mgr.h 9 2005-05-23 22:38:08Z ftillier $\r
+ */\r
+\r
+\r
+#if !defined( __BUS_IOU_MGR_H__ )\r
+#define __BUS_IOU_MGR_H__\r
+\r
+#include <iba/ib_al.h>\r
+#include <complib/cl_mutex.h>\r
+#include <complib/cl_obj.h>\r
+\r
+\r
+/* Global load service */\r
+typedef struct _iou_mgr\r
+{\r
+ cl_obj_t obj;\r
+ ib_pnp_handle_t h_pnp; /* Handle for iou PnP events */\r
+\r
+ /* Mutex protects both pointer vectors. */\r
+ cl_mutex_t pdo_mutex;\r
+\r
+ /* Pointer vector of child IOU PDOs. */\r
+ cl_qlist_t iou_list;\r
+\r
+} iou_mgr_t;\r
+\r
+\r
+ib_api_status_t\r
+create_iou_mgr(\r
+ OUT iou_mgr_t** const pp_iou_mgr );\r
+\r
+\r
+NTSTATUS\r
+iou_mgr_get_bus_relations(\r
+ IN const net64_t ca_guid,\r
+ IN IRP* const p_irp );\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2008 Intel Corporation All Rights Reserved\r
+ * Copyright (c) 2008 Microsoft Corporation 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
+Module Name:\r
+\r
+ BusPdo.c\r
+\r
+Abstract:\r
+\r
+ This module handles plug & play calls for the child device (PDO).\r
+\r
+Environment:\r
+\r
+ kernel mode only\r
+\r
+--*/\r
+\r
+#include "bus_driver.h"\r
+\r
+#include <initguid.h>\r
+#include "driver.h"\r
+\r
+#include <iba\ib_al_ifc.h>\r
+#include <iba\ib_ci_ifc.h>\r
+\r
+#if defined(EVENT_TRACING)\r
+#include "buspdo.tmh\r
+#endif\r
+\r
+// short-hand notation...\r
+#define PWDF_CHILD_ID_DESC_HDR PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER \r
+\r
+NTSTATUS\r
+Bus_DeviceListCreatePdo( WDFCHILDLIST DeviceList,\r
+ PWDF_CHILD_ID_DESC_HDR IdentificationDescription,\r
+ PWDFDEVICE_INIT ChildInit );\r
+\r
+NTSTATUS\r
+Bus_CreatePdo(\r
+ __in WDFDEVICE Device,\r
+ __in PWDFDEVICE_INIT DeviceInit,\r
+ __in PWCHAR HardwareIds,\r
+ __in ULONG SerialNo );\r
+\r
+#ifdef ALLOC_PRAGMA\r
+#pragma alloc_text(PAGE, Bus_CreatePdo)\r
+#pragma alloc_text(PAGE, Bus_DeviceListCreatePdo)\r
+#endif\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ It is called when the framework needs to make a copy of a description.\r
+ This happens when a request is made to create a new child device by\r
+ calling WdfChildListAddOrUpdateChildDescriptionAsPresent.\r
+ If this function is left unspecified, RtlCopyMemory will be used to copy the\r
+ source description to destination. Memory for the description is managed by\r
+ the framework.\r
+\r
+ NOTE: Callback is invoked with an internal lock held. So do not call out\r
+ to any WDF function which will require this lock\r
+ (basically any other WDFCHILDLIST api)\r
+\r
+Arguments:\r
+\r
+ DeviceList - Handle to the default WDFCHILDLIST created by the framework.\r
+ SourceIdentificationDescription - Description of the child being created\r
+ - memory in the calling thread stack.\r
+ DestinationIdentificationDescription - Created by the framework in nonpaged\r
+ - pool.\r
+\r
+Return Value:\r
+\r
+ NT Status code.\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_ChildListIdentificationDescriptionDuplicate(\r
+ WDFCHILDLIST DeviceList,\r
+ PWDF_CHILD_ID_DESC_HDR SourceIdentificationDescription,\r
+ PWDF_CHILD_ID_DESC_HDR DestinationIdentificationDescription )\r
+{\r
+ PPDO_IDENTIFICATION_DESCRIPTION src, dst;\r
+ size_t safeMultResult;\r
+ NTSTATUS status;\r
+\r
+ UNREFERENCED_PARAMETER(DeviceList);\r
+\r
+ src = CONTAINING_RECORD(SourceIdentificationDescription,\r
+ PDO_IDENTIFICATION_DESCRIPTION,\r
+ Header);\r
+ dst = CONTAINING_RECORD(DestinationIdentificationDescription,\r
+ PDO_IDENTIFICATION_DESCRIPTION,\r
+ Header);\r
+\r
+ dst->SerialNo = src->SerialNo;\r
+ dst->CchHardwareIds = src->CchHardwareIds;\r
+ status = RtlSizeTMult(dst->CchHardwareIds,\r
+ sizeof(WCHAR),\r
+ &safeMultResult\r
+ );\r
+ if(!NT_SUCCESS(status)){\r
+ return status;\r
+ }\r
+\r
+ dst->HardwareIds = (PWCHAR) ExAllocatePoolWithTag(\r
+ NonPagedPool,\r
+ safeMultResult,\r
+ BUS_TAG);\r
+\r
+ if (dst->HardwareIds == NULL) {\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ RtlCopyMemory(dst->HardwareIds,\r
+ src->HardwareIds,\r
+ dst->CchHardwareIds * sizeof(WCHAR));\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This is called when the framework needs to compare one description with\r
+ another. Typically this happens whenever a request is made to add a new\r
+ child device. If this function is left unspecified, RtlCompareMemory will\r
+ be used to compare the descriptions.\r
+\r
+ NOTE: Callback is invoked with an internal lock held. So do not call out\r
+ to any WDF function which will require this lock\r
+ (basically any other WDFCHILDLIST api)\r
+\r
+Arguments:\r
+\r
+ DeviceList - Handle to the default WDFCHILDLIST created by the framework.\r
+\r
+Return Value:\r
+\r
+ TRUE or FALSE.\r
+\r
+--*/\r
+\r
+BOOLEAN\r
+Bus_ChildListIdentificationDescriptionCompare(\r
+ WDFCHILDLIST DeviceList,\r
+ PWDF_CHILD_ID_DESC_HDR FirstIdentificationDescription,\r
+ PWDF_CHILD_ID_DESC_HDR SecondIdentificationDescription )\r
+{\r
+ PPDO_IDENTIFICATION_DESCRIPTION lhs, rhs;\r
+\r
+ UNREFERENCED_PARAMETER(DeviceList);\r
+\r
+ lhs = CONTAINING_RECORD(FirstIdentificationDescription,\r
+ PDO_IDENTIFICATION_DESCRIPTION,\r
+ Header);\r
+ rhs = CONTAINING_RECORD(SecondIdentificationDescription,\r
+ PDO_IDENTIFICATION_DESCRIPTION,\r
+ Header);\r
+\r
+ return (lhs->SerialNo == rhs->SerialNo) ? TRUE : FALSE;\r
+}\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ It is called to free up any memory resources allocated as part of the\r
+ description. This happens when a child device is unplugged or ejected from\r
+ the bus. Memory for the description itself will be freed by the framework.\r
+\r
+Arguments:\r
+\r
+ DeviceList - Handle to the default WDFCHILDLIST created by the framework.\r
+\r
+ IdentificationDescription - Description of the child being deleted\r
+\r
+Return Value:\r
+\r
+--*/\r
+\r
+VOID\r
+Bus_ChildListIdentificationDescriptionCleanup(\r
+ WDFCHILDLIST DeviceList,\r
+ PWDF_CHILD_ID_DESC_HDR IdentificationDescription )\r
+{\r
+ PPDO_IDENTIFICATION_DESCRIPTION pDesc;\r
+\r
+\r
+ UNREFERENCED_PARAMETER(DeviceList);\r
+\r
+ pDesc = CONTAINING_RECORD(IdentificationDescription,\r
+ PDO_IDENTIFICATION_DESCRIPTION,\r
+ Header);\r
+\r
+ if (pDesc->HardwareIds != NULL) {\r
+ ExFreePool(pDesc->HardwareIds);\r
+ pDesc->HardwareIds = NULL;\r
+ }\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Called by the framework in response to Query-Device relation when\r
+ a new PDO for a child device needs to be created.\r
+\r
+Arguments:\r
+\r
+ DeviceList - Handle to the default WDFCHILDLIST created by the framework\r
+ as part of FDO.\r
+\r
+ IdentificationDescription - Decription of the new child device.\r
+\r
+ ChildInit - It's a opaque structure used in collecting device settings\r
+ and passed in as a parameter to CreateDevice.\r
+\r
+Return Value:\r
+\r
+ NT Status code.\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_DeviceListCreatePdo( WDFCHILDLIST DeviceList,\r
+ PWDF_CHILD_ID_DESC_HDR IdentificationDescription,\r
+ PWDFDEVICE_INIT ChildInit )\r
+{\r
+ PPDO_IDENTIFICATION_DESCRIPTION pDesc;\r
+\r
+ PAGED_CODE();\r
+\r
+ pDesc = CONTAINING_RECORD(IdentificationDescription,\r
+ PDO_IDENTIFICATION_DESCRIPTION,\r
+ Header);\r
+\r
+ return Bus_CreatePdo(WdfChildListGetDevice(DeviceList),\r
+ ChildInit,\r
+ pDesc->HardwareIds,\r
+ pDesc->SerialNo);\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine creates and initialize a PDO.\r
+\r
+Arguments:\r
+\r
+Return Value:\r
+\r
+ NT Status code.\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_CreatePdo(\r
+ __in WDFDEVICE Device,\r
+ __in PWDFDEVICE_INIT DeviceInit,\r
+ __in PWCHAR HardwareIds,\r
+ __in ULONG SerialNo )\r
+{\r
+ NTSTATUS status;\r
+ PPDO_DEVICE_DATA pdoData = NULL;\r
+ WDFDEVICE hChild = NULL;\r
+// WDF_QUERY_INTERFACE_CONFIG qiConfig;\r
+ WDF_OBJECT_ATTRIBUTES pdoAttributes;\r
+ WDF_DEVICE_PNP_CAPABILITIES pnpCaps;\r
+ WDF_DEVICE_POWER_CAPABILITIES powerCaps;\r
+// IB_BUS_INTERFACE_STANDARD FabricInterface;\r
+ DECLARE_CONST_UNICODE_STRING(compatId, BUSENUM_COMPATIBLE_IDS);\r
+ DECLARE_CONST_UNICODE_STRING(deviceLocation, L"InfiniBand Fabric 0");\r
+ DECLARE_UNICODE_STRING_SIZE(buffer, MAX_INSTANCE_ID_LEN);\r
+ DECLARE_UNICODE_STRING_SIZE(deviceId, MAX_INSTANCE_ID_LEN);\r
+\r
+ PAGED_CODE();\r
+\r
+ UNREFERENCED_PARAMETER(Device);\r
+\r
+ KdPrint(("--> %s()\n", __FUNCTION__));\r
+\r
+ //\r
+ // Set DeviceType\r
+ //\r
+ WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);\r
+\r
+ //\r
+ // Provide DeviceID, HardwareIDs, CompatibleIDs and InstanceId\r
+ //\r
+ RtlInitUnicodeString(&deviceId, HardwareIds);\r
+\r
+ status = WdfPdoInitAssignDeviceID(DeviceInit, &deviceId);\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+\r
+ //\r
+ // NOTE: same string is used to initialize hardware id too\r
+ //\r
+ status = WdfPdoInitAddHardwareID(DeviceInit, &deviceId);\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+\r
+ status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId );\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+\r
+ status = RtlUnicodeStringPrintf(&buffer, L"%02d", SerialNo);\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+\r
+ status = WdfPdoInitAssignInstanceID(DeviceInit, &buffer);\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+\r
+ //\r
+ // Provide a description about the device. This text is usually read from\r
+ // the device. In the case of USB device, this text comes from the string\r
+ // descriptor. This text is displayed momentarily by the PnP manager while\r
+ // it's looking for a matching INF. If it finds one, it uses the Device\r
+ // Description from the INF file or the friendly name created by\r
+ // coinstallers to display in the device manager. FriendlyName takes\r
+ // precedence over the DeviceDesc from the INF file.\r
+ //\r
+ status = RtlUnicodeStringPrintf( &buffer,\r
+ L"InfiniBand_Bus_Dev%02d",\r
+ SerialNo ); // XXX?\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+\r
+ //\r
+ // You can call WdfPdoInitAddDeviceText multiple times, adding device\r
+ // text for multiple locales. When the system displays the text, it\r
+ // chooses the text that matches the current locale, if available.\r
+ // Otherwise it will use the string for the default locale.\r
+ // The driver can specify the driver's default locale by calling\r
+ // WdfPdoInitSetDefaultLocale.\r
+ //\r
+ status = WdfPdoInitAddDeviceText(DeviceInit,\r
+ &buffer,\r
+ &deviceLocation,\r
+ 0x409 );\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+\r
+ WdfPdoInitSetDefaultLocale(DeviceInit, 0x409);\r
+\r
+ //\r
+ // Initialize the attributes to specify the size of PDO device extension.\r
+ // All the state information private to the PDO will be tracked here.\r
+ //\r
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, PDO_DEVICE_DATA);\r
+\r
+ status = WdfDeviceCreate(&DeviceInit, &pdoAttributes, &hChild);\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+\r
+ //\r
+ // Get the device context.\r
+ //\r
+ pdoData = PdoGetData(hChild);\r
+\r
+ pdoData->SerialNo = SerialNo;\r
+\r
+ //\r
+ // Set some properties for the child device.\r
+ //\r
+ WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps);\r
+ pnpCaps.Removable = WdfTrue;\r
+ pnpCaps.EjectSupported = WdfTrue;\r
+ pnpCaps.SurpriseRemovalOK = WdfTrue;\r
+ // XXX ? pnpCaps.SilentInstall = WdfTrue;\r
+\r
+ pnpCaps.Address = SerialNo;\r
+ pnpCaps.UINumber = SerialNo;\r
+\r
+ WdfDeviceSetPnpCapabilities(hChild, &pnpCaps);\r
+\r
+ WDF_DEVICE_POWER_CAPABILITIES_INIT(&powerCaps);\r
+\r
+ powerCaps.DeviceD1 = WdfTrue;\r
+ powerCaps.WakeFromD1 = WdfTrue;\r
+ powerCaps.DeviceWake = PowerDeviceD1;\r
+\r
+ powerCaps.DeviceState[PowerSystemWorking] = PowerDeviceD1;\r
+ powerCaps.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;\r
+ powerCaps.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;\r
+ powerCaps.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;\r
+ powerCaps.DeviceState[PowerSystemHibernate] = PowerDeviceD3;\r
+ powerCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3;\r
+\r
+ WdfDeviceSetPowerCapabilities(hChild, &powerCaps);\r
+\r
+#ifdef NOT_USED // XXX\r
+ //\r
+ // Create a custom interface so that other drivers can\r
+ // query (IRP_MN_QUERY_INTERFACE) and use our callbacks directly.\r
+ //\r
+ RtlZeroMemory(&FabricInterface, sizeof(FabricInterface));\r
+\r
+ FabricInterface.InterfaceHeader.Size = sizeof(FabricInterface);\r
+ FabricInterface.InterfaceHeader.Version = 1;\r
+ FabricInterface.InterfaceHeader.Context = (PVOID) hChild;\r
+\r
+ //\r
+ // Let the framework handle reference counting.\r
+ //\r
+ FabricInterface.InterfaceHeader.InterfaceReference\r
+ = WdfDeviceInterfaceReferenceNoOp;\r
+ FabricInterface.InterfaceHeader.InterfaceDereference\r
+ = WdfDeviceInterfaceDereferenceNoOp;\r
+\r
+ FabricInterface.GetCrispinessLevel = Bus_GetCrispinessLevel;\r
+ FabricInterface.SetCrispinessLevel = Bus_SetCrispinessLevel;\r
+ FabricInterface.IsSafetyLockEnabled = Bus_IsSafetyLockEnabled;\r
+\r
+ WDF_QUERY_INTERFACE_CONFIG_INIT(&qiConfig,\r
+ (PINTERFACE) &FabricInterface,\r
+ &GUID_IBF_INTERFACE_STANDARD,\r
+ NULL);\r
+ //\r
+ // If you have multiple interfaces, you can call WdfDeviceAddQueryInterface\r
+ // multiple times to add additional interfaces.\r
+ //\r
+ status = WdfDeviceAddQueryInterface(hChild, &qiConfig);\r
+\r
+ if (!NT_SUCCESS(status)) {\r
+ KdPrint(("WdfDeviceAddQueryInterface() rc 0x%x\n",status));\r
+ return status;\r
+ }\r
+#endif\r
+\r
+ // enable the InfiniBand Access Layer Interface query\r
+ status = Enable_IBAL_InterfaceQuery( hChild );\r
+ if (!NT_SUCCESS(status)) {\r
+ KdPrint(("Enable_IBAL_InterfaceQuery() rc 0x%x\n",status));\r
+ }\r
+\r
+ // enable the IBAL Channel Interface query\r
+ status = Enable_CI_InterfaceQuery( hChild );\r
+ if (!NT_SUCCESS(status)) {\r
+ KdPrint(("Enable_IBAL_InterfaceQuery() rc 0x%x\n",status));\r
+ }\r
+\r
+ KdPrint(("<-- %s()\n", __FUNCTION__));\r
+\r
+ return status;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine gets the current crispiness level of the toaster.\r
+\r
+Arguments:\r
+\r
+ Context pointer to PDO device extension\r
+ Level crispiness level of the device\r
+\r
+Return Value:\r
+\r
+ TRUE or FALSE\r
+\r
+--*/\r
+\r
+BOOLEAN\r
+Bus_GetCrispinessLevel( IN WDFDEVICE ChildDevice,\r
+ OUT PUCHAR Level )\r
+{\r
+ UNREFERENCED_PARAMETER(ChildDevice);\r
+\r
+ //\r
+ // Validate the context to see if it's really a pointer\r
+ // to PDO's device extension. You can store some kind\r
+ // of signature in the PDO for this purpose\r
+ //\r
+\r
+ KdPrint(("GetCrispnessLevel\n"));\r
+\r
+ *Level = 10;\r
+ return TRUE;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine sets the current crispiness level of the toaster.\r
+\r
+Arguments:\r
+\r
+ Context pointer to PDO device extension\r
+ Level crispiness level of the device\r
+\r
+Return Value:\r
+\r
+ TRUE or FALSE\r
+\r
+--*/\r
+\r
+BOOLEAN\r
+Bus_SetCrispinessLevel( IN WDFDEVICE ChildDevice,\r
+ IN UCHAR Level )\r
+{\r
+ UNREFERENCED_PARAMETER(ChildDevice);\r
+ UNREFERENCED_PARAMETER(Level);\r
+\r
+ KdPrint(("SetCrispnessLevel\n"));\r
+\r
+ return TRUE;\r
+}\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Routine to check whether safety lock is enabled\r
+\r
+Arguments:\r
+\r
+ Context - pointer to PDO device extension\r
+\r
+Return Value:\r
+\r
+ TRUE or FALSE\r
+\r
+--*/\r
+BOOLEAN\r
+Bus_IsSafetyLockEnabled( IN WDFDEVICE ChildDevice )\r
+{\r
+ UNREFERENCED_PARAMETER(ChildDevice);\r
+\r
+ KdPrint(("IsSafetyLockEnabled\n"));\r
+\r
+ return TRUE;\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: bus_pnp.c 744 2007-07-31 19:04:15Z leonidk $\r
+ */\r
+\r
+\r
+\r
+/*\r
+ * Implemenation of all PnP functionality for FDO (power policy owners).\r
+ */\r
+\r
+\r
+#include "bus_pnp.h"\r
+#include "al_ca.h"\r
+#include "al_init.h"\r
+#include "al_dev.h"\r
+#include "bus_port_mgr.h"\r
+#include "bus_iou_mgr.h"\r
+#include "complib/cl_memory.h"\r
+#include <initguid.h>\r
+#include "iba/ib_ci_ifc.h"\r
+\r
+#include "ib_bus_public.h"\r
+\r
+EVT_WDF_DRIVER_DEVICE_ADD Bus_EvtDeviceAdd;\r
+\r
+EVT_WDF_CHILD_LIST_CREATE_DEVICE Bus_DeviceListCreatePdo;\r
+\r
+EVT_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE\r
+ Bus_ChildListIdentificationDescriptionCompare;\r
+\r
+EVT_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP\r
+ Bus_ChildListIdentificationDescriptionCleanup;\r
+\r
+EVT_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE\r
+ Bus_ChildListIdentificationDescriptionDuplicate;\r
+\r
+EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT Bus_EvtDeviceSelfManagedIoInit;\r
+EVT_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP Bus_EvtDeviceSelfManagedIoCleanup;\r
+EVT_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND Bus_EvtDeviceSelfManagedIoSuspend;\r
+EVT_WDF_DEVICE_SELF_MANAGED_IO_RESTART Bus_EvtDeviceSelfManagedIoRestart; \r
+\r
+EVT_WDF_DEVICE_SURPRISE_REMOVAL Bus_EvtDeviceSurpriseRemoval;\r
+EVT_WDF_DEVICE_QUERY_REMOVE Bus_EvtDeviceQueryRemove;\r
+EVT_WDF_DEVICE_QUERY_STOP Bus_EvtDeviceQueryStop;\r
+\r
+EVT_WDF_DEVICE_USAGE_NOTIFICATION Bus_EvtDeviceUsageNotify;\r
+EVT_WDF_DEVICE_RELATIONS_QUERY Bus_EvtDeviceRelationsQuery;\r
+\r
+static VOID\r
+Bus_EvtDriverCleanup( IN WDFOBJECT Driver );\r
+\r
+static VOID\r
+Bus_EvtDeviceObjContextCleanup ( IN WDFOBJECT Object );\r
+\r
+static VOID\r
+Bus_EvtIoDeviceControl(\r
+ IN WDFQUEUE Queue,\r
+ IN WDFREQUEST Request,\r
+ IN size_t OutputBufferLength,\r
+ IN size_t InputBufferLength,\r
+ IN ULONG IoControlCode );\r
+\r
+static VOID\r
+Bus_EvtIoStop (\r
+ IN WDFQUEUE Queue,\r
+ IN WDFREQUEST Request,\r
+ IN ULONG ActionFlags );\r
+\r
+static VOID\r
+Bus_EvtDeviceFileCreate ( IN WDFDEVICE Device,\r
+ IN WDFREQUEST Request,\r
+ IN WDFFILEOBJECT FileObject );\r
+\r
+// implies extern EVT_WDF_FILE_CLOSE EvtDeviceFileClose;\r
+static VOID\r
+Bus_EvtDeviceFileClose ( IN WDFFILEOBJECT FileObject );\r
+\r
+static VOID\r
+Bus_EvtDeviceFileCleanup ( IN WDFFILEOBJECT FileObject );\r
+\r
+static NTSTATUS\r
+Bus_EvtDeviceD0Entry(\r
+ IN WDFDEVICE Device,\r
+ IN WDF_POWER_DEVICE_STATE PreviousState );\r
+\r
+static NTSTATUS\r
+Bus_EvtDeviceD0Exit(\r
+ IN WDFDEVICE Device,\r
+ IN WDF_POWER_DEVICE_STATE TargetState );\r
+\r
+static NTSTATUS\r
+Bus_EvtDevicePrepareHardware (\r
+ WDFDEVICE Device,\r
+ WDFCMRESLIST ResourcesRaw,\r
+ WDFCMRESLIST ResourcesTranslated );\r
+\r
+static NTSTATUS\r
+Bus_EvtDeviceReleaseHardware(\r
+ IN WDFDEVICE Device,\r
+ IN WDFCMRESLIST ResourcesTranslated );\r
+\r
+static NTSTATUS\r
+fdo_start(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static void\r
+fdo_release_resources(\r
+ IN DEVICE_OBJECT* const p_dev_obj );\r
+\r
+static NTSTATUS\r
+fdo_query_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+fdo_query_capabilities(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+fdo_query_remove_relations(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+__get_relations(\r
+ IN const net64_t ca_guid,\r
+ IN IRP* const p_irp );\r
+\r
+#ifdef NOT_USED\r
+static NTSTATUS\r
+__query_al_ifc(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IO_STACK_LOCATION* const p_io_stack );\r
+\r
+static NTSTATUS\r
+__query_ci_ifc(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IO_STACK_LOCATION* const p_io_stack );\r
+\r
+static NTSTATUS\r
+fdo_query_interface(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action );\r
+#endif /* NOT_USED */\r
+\r
+static NTSTATUS\r
+__fdo_query_power(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+__fdo_set_power(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+\r
+/* All PnP code is called at passive, so it can all be paged out. */\r
+#ifdef ALLOC_PRAGMA\r
+#pragma alloc_text (PAGE, Bus_EvtDeviceAdd)\r
+#pragma alloc_text (PAGE, Bus_EvtIoDeviceControl)\r
+#pragma alloc_text (PAGE, Bus_EvtIoStop)\r
+#pragma alloc_text (PAGE, Bus_EvtDriverCleanup)\r
+#pragma alloc_text (PAGE, Bus_EvtDevicePrepareHardware)\r
+#pragma alloc_text (PAGE, Bus_EvtDeviceReleaseHardware)\r
+#pragma alloc_text (PAGE, Bus_EvtDeviceFileCreate)\r
+#pragma alloc_text (PAGE, Bus_EvtDeviceFileClose)\r
+#pragma alloc_text (PAGE, Bus_EvtDeviceFileCleanup)\r
+\r
+#pragma alloc_text (PAGE, fdo_start)\r
+#pragma alloc_text (PAGE, fdo_query_remove)\r
+#pragma alloc_text (PAGE, fdo_release_resources)\r
+#pragma alloc_text (PAGE, fdo_query_capabilities)\r
+#pragma alloc_text (PAGE, fdo_query_remove_relations)\r
+//#pragma alloc_text (PAGE, __query_al_ifc)\r
+//#pragma alloc_text (PAGE, __query_ci_ifc)\r
+#pragma alloc_text (PAGE, __get_relations)\r
+//#pragma alloc_text (PAGE, fdo_query_interface)\r
+#pragma alloc_text (PAGE_PNP, __fdo_query_power)\r
+#pragma alloc_text (PAGE_PNP, __fdo_set_power)\r
+#endif\r
+\r
+\r
+/* Global virtual function pointer tables shared between all instances of FDO. */\r
+static const cl_vfptr_pnp_po_t vfptr_fdo_pnp = {\r
+ "IB Bus",\r
+ cl_irp_unsupported /*fdo_start*/, // D0Entry\r
+ cl_irp_skip,\r
+ cl_irp_skip,\r
+ cl_do_sync_pnp,\r
+ cl_irp_unsupported /*fdo_query_remove*/ , // DeviceQueryRemove\r
+ NULL /*fdo_release_resources*/ , // D0 Exit\r
+ cl_irp_unsupported, //cl_do_remove /Bus_EvtDeviceReleaseHardware \r
+ cl_do_sync_pnp,\r
+ cl_irp_skip,\r
+ cl_irp_unsupported,//fdo_query_capabilities IRP_MN_QUERY_CAPABILITIES framework?\r
+ cl_irp_skip,\r
+ cl_irp_skip,\r
+ cl_do_sync_pnp,\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ cl_irp_unsupported /*fdo_query_remove_relations*/,// EvtDeviceRelationsQuery\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ cl_irp_unsupported /*fdo_query_interface*/, /* QueryInterface Enable_IBAL */\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ cl_irp_unsupported /*__fdo_query_power*/, /* QueryPower */ // D0Exit\r
+ cl_irp_unsupported /*__fdo_set_power*/, /* SetPower */ //D0Entry\r
+ cl_irp_ignore, /* PowerSequence */\r
+ cl_irp_ignore /* WaitWake */\r
+};\r
+\r
+\r
+#ifdef _REPLACED\r
+\r
+NTSTATUS\r
+bus_add_device(\r
+ IN DRIVER_OBJECT *p_driver_obj,\r
+ IN DEVICE_OBJECT *p_pdo )\r
+{\r
+ NTSTATUS status;\r
+ DEVICE_OBJECT *p_dev_obj, *p_next_do;\r
+ bus_fdo_ext_t *p_ext;\r
+ UNICODE_STRING dev_name, dos_name;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ if( bus_globals.p_bus_ext )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Bus root already exists. Only one bus root allowed.\n") );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ RtlInitUnicodeString( &dev_name, AL_DEVICE_NAME );\r
+ RtlInitUnicodeString( &dos_name, L"\\DosDevices\\Global\\ibal" );\r
+\r
+ /* Create the FDO device object to attach to the stack. */\r
+ status = IoCreateDevice( p_driver_obj, sizeof(bus_fdo_ext_t),\r
+ &dev_name, FILE_DEVICE_BUS_EXTENDER,\r
+ FILE_DEVICE_SECURE_OPEN, FALSE, &p_dev_obj );\r
+ if( !NT_SUCCESS(status) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("Failed to create bus root FDO device.\n") );\r
+ return status;\r
+ }\r
+\r
+ IoDeleteSymbolicLink( &dos_name );\r
+ status = IoCreateSymbolicLink( &dos_name, &dev_name );\r
+ if( !NT_SUCCESS(status) )\r
+ {\r
+ IoDeleteDevice( p_dev_obj );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to create symlink for dos name.\n") );\r
+ return status;\r
+ }\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ p_next_do = IoAttachDeviceToDeviceStack( p_dev_obj, p_pdo );\r
+ if( !p_next_do )\r
+ {\r
+ IoDeleteDevice( p_dev_obj );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("IoAttachToDeviceStack failed.\n") );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ cl_init_pnp_po_ext( p_dev_obj, p_next_do, p_pdo, bus_globals.dbg_lvl,\r
+ &vfptr_fdo_pnp, NULL );\r
+\r
+ /* Register the upper interface (the one used by clients). */\r
+ status = IoRegisterDeviceInterface( p_pdo, \r
+ &GUID_IB_AL_INTERFACE,\r
+ NULL,\r
+ &p_ext->al_ifc_name );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ IoDetachDevice( p_ext->cl_ext.p_next_do );\r
+ IoDeleteDevice( p_dev_obj );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("IoRegisterDeviceInterface for upper interface returned %08x\n",\r
+ status) );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ /* Register the lower interface (the one used by HCA VPDs). */\r
+ status = IoRegisterDeviceInterface( p_pdo, \r
+ &GUID_IB_CI_INTERFACE,\r
+ NULL,\r
+ &p_ext->ci_ifc_name );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ RtlFreeUnicodeString( &p_ext->al_ifc_name );\r
+ IoDetachDevice( p_ext->cl_ext.p_next_do );\r
+ IoDeleteDevice( p_dev_obj );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("IoRegisterDeviceInterface for lower interface returned %08x\n",\r
+ status) );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ bus_globals.p_bus_ext = p_ext;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+#endif\r
+\r
+static NTSTATUS\r
+GetDeviceUnicodeName( WDFDEVICE Device, const GUID *guid, PUNICODE_STRING dst )\r
+{\r
+ NTSTATUS status;\r
+ WDFSTRING string;\r
+\r
+ status = WdfStringCreate( WDF_NO_OBJECT_ATTRIBUTES, NULL, &string );\r
+\r
+ if (!NT_SUCCESS(status))\r
+ return status ;\r
+\r
+ status = WdfDeviceRetrieveDeviceInterfaceString( Device,\r
+ guid,\r
+ NULL,\r
+ string );\r
+ if (!NT_SUCCESS(status))\r
+ return status;\r
+\r
+ WdfStringGetUnicodeString( string, dst );\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+/*++\r
+Routine Description:\r
+\r
+ Bus_EvtDeviceAdd is called by the framework in response to AddDevice\r
+ call from the PnP manager. We create and initialize a device object to\r
+ represent a new instance of InfiniBand Fabric device (I/O Unit, e.g., vnic\r
+ or SRP iou, etc.).\r
+\r
+Arguments:\r
+\r
+ Driver - Handle to a framework driver object created in DriverEntry\r
+\r
+ DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.\r
+\r
+Return Value:\r
+\r
+ NTSTATUS\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_EvtDeviceAdd( IN WDFDRIVER Driver,\r
+ IN PWDFDEVICE_INIT DeviceInit )\r
+{\r
+ NTSTATUS status;\r
+ WDFDEVICE device;\r
+ WDF_CHILD_LIST_CONFIG config;\r
+ WDF_FILEOBJECT_CONFIG FileObjConfig;\r
+ WDF_OBJECT_ATTRIBUTES Attributes;\r
+ WDF_IO_QUEUE_CONFIG queueConfig;\r
+ PNP_BUS_INFORMATION busInfo;\r
+ WDFQUEUE queue;\r
+ FDO_BUS_DATA *p_ext;\r
+ UNICODE_STRING dev_name, dos_name;\r
+\r
+ WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;\r
+ WDF_POWER_POLICY_EVENT_CALLBACKS powerPolicyCallbacks;\r
+\r
+ PAGED_CODE ();\r
+\r
+ KdPrint(("--> %s(): 0x%p\n", __FUNCTION__, Driver));\r
+\r
+ if( bus_globals.p_bus_ext )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Bus root already exists. Only one bus root allowed.\n") );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+#ifdef NOT_YET\r
+ //\r
+ // Get some property of the device you are about to attach and check\r
+ // to see if that's the one you are interested. For demonstration\r
+ // we will get the UINumber of the device. The bus driver reports the\r
+ // serial number as the UINumber.\r
+\r
+ status = WdfFdoInitQueryProperty(DeviceInit,\r
+ DevicePropertyUINumber,\r
+ sizeof(serialNo),\r
+ &serialNo,\r
+ &returnSize);\r
+ if(!NT_SUCCESS(status)){\r
+ KdPrint(("Failed to get the property of PDO: 0x%p\n", DeviceInit));\r
+\r
+ }\r
+#endif\r
+\r
+ //\r
+ // Tell the framework that you are filter driver. Framework\r
+ // takes care of inherting all the device flags & characterstics\r
+ // from the lower device you are attaching to.\r
+ // Lower device Guid is specified in ib_bus.inx\r
+\r
+ WdfFdoInitSetFilter(DeviceInit);\r
+\r
+ // initialize names for the IBAL interface\r
+ RtlInitUnicodeString( &dev_name, AL_DEVICE_NAME );\r
+ RtlInitUnicodeString( &dos_name, L"\\DosDevices\\Global\\ibal" );\r
+\r
+ // Initialize all the properties specific to the device.\r
+ // Framework has default values for the one that are not\r
+ // set explicitly here. So please read the doc and make sure\r
+ // you are okay with the defaults.\r
+\r
+ WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);\r
+ //WdfDeviceInitSetExclusive(DeviceInit, TRUE); XXX?\r
+\r
+ // This is an InifiniBand bus enumerator, we need to register for those\r
+ // PNP/Power callbacks of interest. Framework will take the default action\r
+ // for all the PNP and Power IRPs which are not registered here.\r
+\r
+// XXX consider surprise_remove, etc.\r
+\r
+ // Initialize the PnpPowerCallbacks structure.\r
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);\r
+\r
+ // Set Callbacks for any of the functions we are interested in.\r
+ // If no callback is set, Framework will take the default action\r
+ // by itself. This sample provides many of the possible callbacks,\r
+ // mostly because it's a fairly complex sample that drives full-featured\r
+ // hardware. Drivers derived from this sample will often be able to\r
+ // provide only some of these.\r
+\r
+ // This next group of five callbacks allow a driver to become involved in\r
+ // starting and stopping operations within a driver as the driver moves\r
+ // through various PnP/Power states. These functions are not necessary\r
+ // if the Framework is managing all the device's queues and there is no\r
+ // activity going on that isn't queue-based.\r
+\r
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoInit =\r
+ Bus_EvtDeviceSelfManagedIoInit;\r
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoCleanup =\r
+ Bus_EvtDeviceSelfManagedIoCleanup;\r
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend =\r
+ Bus_EvtDeviceSelfManagedIoSuspend;\r
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart =\r
+ Bus_EvtDeviceSelfManagedIoRestart;\r
+\r
+ // These two callbacks set up and tear down hardware state,\r
+ // specifically that which only has to be done once.\r
+\r
+ pnpPowerCallbacks.EvtDevicePrepareHardware = Bus_EvtDevicePrepareHardware;\r
+ pnpPowerCallbacks.EvtDeviceReleaseHardware = Bus_EvtDeviceReleaseHardware;\r
+\r
+ // These two callbacks set up and tear down hardware state that must be\r
+ // done every time the device moves in and out of the D0-working state.\r
+ // (aka, start & stop the device).\r
+\r
+ pnpPowerCallbacks.EvtDeviceD0Entry = Bus_EvtDeviceD0Entry;\r
+ pnpPowerCallbacks.EvtDeviceD0Exit = Bus_EvtDeviceD0Exit;\r
+\r
+ pnpPowerCallbacks.EvtDeviceQueryStop = Bus_EvtDeviceQueryStop;\r
+ pnpPowerCallbacks.EvtDeviceQueryRemove = Bus_EvtDeviceQueryRemove;\r
+ pnpPowerCallbacks.EvtDeviceSurpriseRemoval = Bus_EvtDeviceSurpriseRemoval;\r
+\r
+// pnpPowerCallbacks.EvtDeviceUsageNotification = Bus_EvtDeviceUsageNotify;\r
+ pnpPowerCallbacks.EvtDeviceRelationsQuery = Bus_EvtDeviceRelationsQuery;\r
+\r
+ // Register the PnP and power callbacks.\r
+ WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);\r
+\r
+ // Init the power policy callbacks\r
+ WDF_POWER_POLICY_EVENT_CALLBACKS_INIT(&powerPolicyCallbacks);\r
+\r
+ // no power issues at this level - device specific driver handles power \r
+\r
+ // WDF_ DEVICE_LIST_CONFIG describes how the framework should handle\r
+ // dynamic child enumeration on behalf of the driver writer.\r
+ // Since we are a bus driver, we need to specify identification description\r
+ // for our child devices. This description will serve as the identity of our\r
+ // child device. Since the description is opaque to the framework, we\r
+ // have to provide a set of callbacks to compare, copy, or free any\r
+ // additional resources associated with the description.\r
+\r
+ WDF_CHILD_LIST_CONFIG_INIT( &config,\r
+ sizeof(PDO_IDENTIFICATION_DESCRIPTION),\r
+ Bus_DeviceListCreatePdo );\r
+ // callback to create a child device.\r
+\r
+ // This function pointer will be called when the framework needs to copy a\r
+ // identification description from one location to another.\r
+ // An implementation of this function is only necessary if the description\r
+ // contains description relative pointer values (like LIST_ENTRY for\r
+ // instance).\r
+ // If set to NULL, the framework will use RtlCopyMemory to copy an\r
+ // identification description. In this sample, it's not required to provide\r
+ // these callbacks they are added just for illustration.\r
+ //\r
+ config.EvtChildListIdentificationDescriptionDuplicate =\r
+ Bus_ChildListIdentificationDescriptionDuplicate;\r
+\r
+ //\r
+ // This function pointer will be called when the framework needs to compare\r
+ // two identificaiton descriptions. If left NULL a call to RtlCompareMemory\r
+ // will be used to compare two identificaiton descriptions.\r
+ //\r
+ config.EvtChildListIdentificationDescriptionCompare =\r
+ Bus_ChildListIdentificationDescriptionCompare;\r
+ //\r
+ // This function pointer will be called when the framework needs to free a\r
+ // identification description. An implementation of this function is only\r
+ // necessary if the description contains dynamically allocated memory\r
+ // (by the driver writer) that needs to be freed. The actual identification\r
+ // description pointer itself will be freed by the framework.\r
+ //\r
+ config.EvtChildListIdentificationDescriptionCleanup =\r
+ Bus_ChildListIdentificationDescriptionCleanup;\r
+\r
+ //\r
+ // Tell the framework to use the built-in childlist to track the state\r
+ // of the device based on the configuration we just created.\r
+ //\r
+ WdfFdoInitSetDefaultChildListConfig(DeviceInit,\r
+ &config,\r
+ WDF_NO_OBJECT_ATTRIBUTES);\r
+\r
+\r
+ // setup callbacks to hande IRP_MJ_CREATE & IRP_MJ_CLOSE\r
+\r
+ WDF_FILEOBJECT_CONFIG_INIT(\r
+ &FileObjConfig,\r
+ Bus_EvtDeviceFileCreate,\r
+ Bus_EvtDeviceFileClose,\r
+ Bus_EvtDeviceFileCleanup );\r
+\r
+ WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);\r
+\r
+ Attributes.SynchronizationScope = WdfSynchronizationScopeNone;\r
+ Attributes.ExecutionLevel = WdfExecutionLevelPassive;\r
+\r
+ WdfDeviceInitSetFileObjectConfig( DeviceInit,\r
+ &FileObjConfig,\r
+ &Attributes );\r
+\r
+ // Initialize attributes structure to specify size and accessor function\r
+ // for storing device context.\r
+\r
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, FDO_BUS_DATA);\r
+\r
+ // Register a cleanup callback on the device to free up some resources at\r
+ // the time the device is deleted.\r
+ Attributes.EvtCleanupCallback = Bus_EvtDeviceObjContextCleanup;\r
+\r
+ // By opting for SynchronizationScopeDevice, we tell the framework to\r
+ // synchronize callbacks events of all the objects directly associated\r
+ // with the device. In this driver, we will associate queues.\r
+ // By doing that we don't have to worrry about synchronizing\r
+ // access to device-context by various io Events.\r
+ // Framework will serialize them by using an internal device-lock.\r
+ Attributes.SynchronizationScope = WdfSynchronizationScopeDevice;\r
+\r
+ // Create a framework device object. In response to this call, framework\r
+ // creates a WDM deviceobject and attaches to the PDO.\r
+\r
+ status = WdfDeviceCreate(&DeviceInit, &Attributes, &device);\r
+\r
+ if (!NT_SUCCESS(status)) {\r
+ KdPrint(("Error creating WdfDeviceCreate 0x%x, line#%d\n",\r
+ status,__LINE__));\r
+ return status;\r
+ }\r
+\r
+ IoDeleteSymbolicLink( &dos_name );\r
+ status = IoCreateSymbolicLink( &dos_name, &dev_name );\r
+ if( !NT_SUCCESS(status) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to create symlink for dos name.\n") );\r
+ return status;\r
+ }\r
+ KdPrint(("%s() Created symlink for dos name\n",__FUNCTION__));\r
+\r
+ // Configure a default queue so that requests that are not\r
+ // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto\r
+ // other queues get dispatched here.\r
+\r
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( &queueConfig,\r
+ WdfIoQueueDispatchParallel );\r
+\r
+ // handle IRP_MJ_DEVICE_CONTROL with this callback\r
+ queueConfig.EvtIoDeviceControl = Bus_EvtIoDeviceControl;\r
+ queueConfig.EvtIoStop = Bus_EvtIoStop;\r
+\r
+ status = WdfIoQueueCreate( device,\r
+ &queueConfig,\r
+ WDF_NO_OBJECT_ATTRIBUTES,\r
+ &queue );\r
+\r
+ if (!NT_SUCCESS(status)) {\r
+ KdPrint(("WdfIoQueueCreate failed status 0x%x\n", status));\r
+ return status;\r
+ }\r
+\r
+ // Get the device object 'dev extention data' ptr & initialize the FDO\r
+ // extension data.\r
+\r
+ p_ext = FdoGetData(device);\r
+\r
+ RtlZeroMemory( (VOID*)p_ext, sizeof(*p_ext) );\r
+\r
+ RtlStringCbCopyA( p_ext->Identity, sizeof("IB Bus"), "IB Bus" );\r
+\r
+ p_ext->WdfDevice = device; // record framework device object ptr.\r
+\r
+ p_ext->SupportsPowerMgmt = TRUE;\r
+ p_ext->DevPowerState = WdfPowerDeviceInvalid;\r
+ p_ext->DevPreviousPowerState = WdfPowerDeviceInvalid;\r
+\r
+ /* replicate what was previously done in \r
+ cl_init_pnp_po_ext( p_dev_obj, p_next_do, p_pdo, bus_globals.dbg_lvl,\r
+ &vfptr_fdo_pnp, NULL );\r
+ to prevent any oops. FLW.\r
+ */\r
+ p_ext->cl_ext.dbg_lvl = bus_globals.dbg_lvl;\r
+\r
+ /* Store the pointer to our own device. */\r
+ p_ext->cl_ext.p_self_do = WdfDeviceWdmGetDeviceObject(device);\r
+ IoInitializeRemoveLock( &p_ext->cl_ext.remove_lock, 'bilc', 15, 1000 );\r
+\r
+ /* Initialize the PnP states. */\r
+ p_ext->cl_ext.pnp_state = NotStarted;\r
+ p_ext->cl_ext.last_pnp_state = NotStarted;\r
+\r
+ /* Store the pointer to the next device in the stack. */\r
+ p_ext->cl_ext.p_next_do = NULL;\r
+\r
+ /* Store the pointer to the underlying PDO. */\r
+ p_ext->cl_ext.p_pdo = WdfDeviceWdmGetPhysicalDevice(device);\r
+\r
+ /* Store the PnP virtual function pointer table. */\r
+ p_ext->cl_ext.vfptr_pnp_po = &vfptr_fdo_pnp;\r
+\r
+ /* Store the Power Management virtual function pointer table. */\r
+ p_ext->cl_ext.vfptr_query_txt = NULL;\r
+ // end cl_init_pnp_po_ext()\r
+\r
+ //\r
+ // Create device interface for this device. The interface will be\r
+ // enabled by the framework when we return from StartDevice successfully.\r
+ // Clients of this driver will open this interface and send ioctls.\r
+ //\r
+ /* Register the upper Device interface (the one used by clients). */\r
+ status = WdfDeviceCreateDeviceInterface( device,\r
+ &GUID_IB_AL_INTERFACE,\r
+ NULL );\r
+ if (!NT_SUCCESS(status)) {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("WdfDeviceCreateDeviceInterface for upper interface AL "\r
+ "returned 0x%08x\n", status) );\r
+ return status /*STATUS_NO_SUCH_DEVICE*/;\r
+ }\r
+ status = GetDeviceUnicodeName( device,\r
+ (const GUID*)&GUID_IB_AL_INTERFACE,\r
+ &p_ext->al_ifc_name );\r
+ if (!NT_SUCCESS(status)) {\r
+ BUS_TRACE_EXIT(BUS_DBG_ERROR,\r
+ ("GetDeviceUnicodeName() ret %x\n", status));\r
+ return status;\r
+ }\r
+\r
+ /* Register the lower Device interface (the one used by HCA VPDs). */\r
+ status = WdfDeviceCreateDeviceInterface( device,\r
+ &GUID_IB_CI_INTERFACE,\r
+ NULL );\r
+\r
+ if (!NT_SUCCESS(status)) {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("WdfDeviceCreateDeviceInterface for lower interface CI "\r
+ "ret 0x%08x\n", status) );\r
+ return status /*STATUS_NO_SUCH_DEVICE*/;\r
+ }\r
+\r
+ status = GetDeviceUnicodeName( device,\r
+ (const GUID*)&GUID_IB_CI_INTERFACE,\r
+ &p_ext->ci_ifc_name );\r
+ if (!NT_SUCCESS(status)) {\r
+ BUS_TRACE_EXIT(BUS_DBG_ERROR,\r
+ ("GetDeviceUnicodeName() ret %x\n", status));\r
+ return status;\r
+ }\r
+\r
+ bus_globals.p_bus_ext = p_ext; // save our FDO data extension ptr.\r
+\r
+ //\r
+ // This value is used in responding to the IRP_MN_QUERY_BUS_INFORMATION\r
+ // for the child devices. This is an optional information provided to\r
+ // uniquely idenitfy the bus the device is connected.\r
+ //\r
+ busInfo.BusTypeGuid = GUID_DEVCLASS_IB_FABRIC;\r
+ busInfo.LegacyBusType = PNPBus;\r
+ busInfo.BusNumber = 0; // only 1 IB fabric bus instance.\r
+\r
+ WdfDeviceSetBusInformationForChildren(device, &busInfo);\r
+\r
+ status = Bus_WmiRegistration(device);\r
+ if (!NT_SUCCESS(status)) {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("Bus_WmiRegistration() failed returned 0x%08x\n", status) );\r
+ return status;\r
+ }\r
+\r
+ KdPrint(("<-- %s(): 0x%p status 0x%x\n", __FUNCTION__, Driver, status));\r
+\r
+ return status;\r
+}\r
+\r
+\r
+\r
+static NTSTATUS\r
+fdo_start(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ NTSTATUS status;\r
+ bus_fdo_ext_t *p_ext;\r
+ ib_api_status_t ib_status;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ /* Handled on the way up. */\r
+ status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("Lower drivers failed IRP_MN_START_DEVICE.\n") );\r
+ return status;\r
+ }\r
+\r
+ /* Initialize AL */\r
+ ib_status = al_initialize();\r
+ if( ib_status != IB_SUCCESS )\r
+ {\r
+ al_cleanup();\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("al_initialize returned %s.\n",\r
+ ib_get_err_str(ib_status)) );\r
+ return STATUS_UNSUCCESSFUL;\r
+ }\r
+\r
+ /* Initialize the port manager. */\r
+ ib_status = create_port_mgr( &p_ext->p_port_mgr );\r
+ if( ib_status != IB_SUCCESS )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("create_port_mgr returned %s.\n",\r
+ ib_get_err_str(ib_status)) );\r
+ return STATUS_UNSUCCESSFUL;\r
+ }\r
+\r
+ /* Initialize the IOU manager. */\r
+ ib_status = create_iou_mgr( &p_ext->p_iou_mgr );\r
+ if( ib_status != IB_SUCCESS )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("create_iou_mgr returned %s.\n",\r
+ ib_get_err_str(ib_status)) );\r
+ return STATUS_UNSUCCESSFUL;\r
+ }\r
+\r
+ status = IoSetDeviceInterfaceState( &p_ext->al_ifc_name, TRUE );\r
+ ASSERT( NT_SUCCESS( status ) );\r
+\r
+ status = IoSetDeviceInterfaceState( &p_ext->ci_ifc_name, TRUE );\r
+ ASSERT( NT_SUCCESS( status ) );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+fdo_query_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ bus_fdo_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ if( p_ext->n_ci_ifc_ref )\r
+ {\r
+ /*\r
+ * Our interface is still being held by someone.\r
+ * Rollback the PnP state that was changed in the cl_ext handler.\r
+ */\r
+ cl_rollback_pnp_state( &p_ext->cl_ext );\r
+\r
+ /* Fail the query. */\r
+ *p_action = IrpComplete;\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, \r
+ ("Failing IRP_MN_QUERY_REMOVE_DEVICE:\n"\r
+ "\tLowerInterface has %d references\n", \r
+ p_ext->n_ci_ifc_ref ) );\r
+ return STATUS_UNSUCCESSFUL;\r
+ }\r
+\r
+ *p_action = IrpSkip;\r
+ /* The FDO driver must set the status even when passing down. */\r
+ p_irp->IoStatus.Status = STATUS_SUCCESS;\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+/*\r
+ * This function gets called after releasing the remove lock and waiting\r
+ * for all other threads to release the lock. No more modifications will\r
+ * occur to the PDO pointer vectors.\r
+ */\r
+static void\r
+fdo_release_resources(\r
+ IN DEVICE_OBJECT* const p_dev_obj )\r
+{\r
+ bus_fdo_ext_t *p_ext;\r
+ NTSTATUS status;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ //TODO: Fail outstanding I/O operations.\r
+\r
+ /* Disable any exported interfaces. */\r
+ status = IoSetDeviceInterfaceState( &p_ext->al_ifc_name, FALSE );\r
+ ASSERT( NT_SUCCESS( status ) );\r
+ status = IoSetDeviceInterfaceState( &p_ext->ci_ifc_name, FALSE );\r
+ ASSERT( NT_SUCCESS( status ) );\r
+\r
+ /* Release the memory allocated for the interface symbolic names. */\r
+ RtlFreeUnicodeString( &p_ext->ci_ifc_name );\r
+ RtlFreeUnicodeString( &p_ext->al_ifc_name );\r
+\r
+ cl_obj_destroy( &p_ext->p_port_mgr->obj );\r
+ cl_obj_destroy( &p_ext->p_iou_mgr->obj );\r
+\r
+ al_cleanup();\r
+\r
+ bus_globals.p_bus_ext = NULL;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+static NTSTATUS\r
+fdo_query_capabilities(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ NTSTATUS status;\r
+ bus_fdo_ext_t *p_ext;\r
+ IO_STACK_LOCATION *p_io_stack;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ /* Process on the way up. */\r
+ status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
+\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("cl_do_sync_pnp returned %08x.\n", status) );\r
+ return status;\r
+ }\r
+\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+ /*\r
+ * Store the device power maping into our extension since we're\r
+ * the power policy owner. The mapping is used when handling\r
+ * IRP_MN_SET_POWER IRPs.\r
+ */\r
+ cl_memcpy( p_ext->po_state, \r
+ p_io_stack->Parameters.DeviceCapabilities.Capabilities->DeviceState,\r
+ sizeof( p_ext->po_state ) );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+fdo_query_remove_relations(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ NTSTATUS status;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( p_dev_obj );\r
+\r
+ status = port_mgr_get_bus_relations( 0, p_irp );\r
+ if( status == STATUS_SUCCESS || \r
+ status == STATUS_NO_SUCH_DEVICE )\r
+ {\r
+ status = iou_mgr_get_bus_relations( 0, p_irp );\r
+ }\r
+ if( status == STATUS_NO_SUCH_DEVICE )\r
+ status = STATUS_SUCCESS;\r
+\r
+ switch( status )\r
+ {\r
+ case STATUS_NO_SUCH_DEVICE:\r
+ *p_action = IrpSkip;\r
+ status = STATUS_SUCCESS;\r
+ break;\r
+\r
+ case STATUS_SUCCESS:\r
+ *p_action = IrpPassDown;\r
+ break;\r
+\r
+ default:\r
+ *p_action = IrpComplete;\r
+ break;\r
+ }\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+__get_relations(\r
+ IN const net64_t ca_guid,\r
+ IN IRP* const p_irp )\r
+{\r
+ NTSTATUS status;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ /* TODO: For IOUs, filter relations based on multi-HCA support. */\r
+ status = port_mgr_get_bus_relations( ca_guid, p_irp );\r
+ if( status == STATUS_SUCCESS || \r
+ status == STATUS_NO_SUCH_DEVICE )\r
+ {\r
+ status = iou_mgr_get_bus_relations( ca_guid, p_irp );\r
+ }\r
+ if( status == STATUS_NO_SUCH_DEVICE )\r
+ status = STATUS_SUCCESS;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+#ifdef NOT_USED\r
+\r
+void\r
+al_ref_ifc(\r
+ IN DEVICE_OBJECT* p_dev_obj )\r
+{\r
+ bus_fdo_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ cl_atomic_inc( &p_ext->n_al_ifc_ref );\r
+ ObReferenceObject( p_dev_obj );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+void\r
+al_deref_ifc(\r
+ IN DEVICE_OBJECT* p_dev_obj )\r
+{\r
+ bus_fdo_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ cl_atomic_dec( &p_ext->n_al_ifc_ref );\r
+ ObDereferenceObject( p_dev_obj );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+void\r
+al_ref_ci_ifc(\r
+ IN DEVICE_OBJECT* p_dev_obj )\r
+{\r
+ bus_fdo_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ cl_atomic_inc( &p_ext->n_ci_ifc_ref );\r
+ ObReferenceObject( p_dev_obj );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+void\r
+al_deref_ci_ifc(\r
+ IN DEVICE_OBJECT* p_dev_obj )\r
+{\r
+ bus_fdo_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ cl_atomic_dec( &p_ext->n_ci_ifc_ref );\r
+ ObDereferenceObject( p_dev_obj );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+static NTSTATUS\r
+__query_al_ifc(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IO_STACK_LOCATION* const p_io_stack )\r
+{\r
+ ib_al_ifc_t *p_ifc;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ if( p_io_stack->Parameters.QueryInterface.Version != \r
+ AL_INTERFACE_VERSION )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n",\r
+ p_io_stack->Parameters.QueryInterface.Version ) );\r
+ return STATUS_NOT_SUPPORTED;\r
+ }\r
+\r
+ if( p_io_stack->Parameters.QueryInterface.Size < sizeof(ib_al_ifc_t) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, \r
+ ("Buffer too small (%d given, %d required).\n",\r
+ p_io_stack->Parameters.QueryInterface.Size, sizeof(ib_al_ifc_t)) );\r
+ return STATUS_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ // Copy the interface.\r
+ p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
+\r
+ p_ifc->wdm.Size = sizeof(ib_al_ifc_t);\r
+ p_ifc->wdm.Version = AL_INTERFACE_VERSION;\r
+ p_ifc->wdm.Context = p_dev_obj;\r
+ p_ifc->wdm.InterfaceReference = al_ref_ifc;\r
+ p_ifc->wdm.InterfaceDereference = al_deref_ifc;\r
+\r
+ al_set_ifc( p_ifc );\r
+\r
+ // take the reference before returning.\r
+ al_ref_ifc( p_dev_obj );\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+void\r
+al_set_ifc(\r
+ OUT ib_al_ifc_t* const p_ifc )\r
+{\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ifc->wdm.Size = sizeof(ib_al_ifc_t);\r
+ p_ifc->wdm.InterfaceReference = al_ref_ifc;\r
+ p_ifc->wdm.InterfaceDereference = al_deref_ifc;\r
+\r
+ p_ifc->sync_destroy = ib_sync_destroy;\r
+ p_ifc->open_ca = ib_open_ca;\r
+ p_ifc->query_ca = ib_query_ca;\r
+ p_ifc->get_dev = get_ca_dev;\r
+ p_ifc->close_ca = ib_close_ca;\r
+ p_ifc->alloc_pd = ib_alloc_pd;\r
+ p_ifc->dealloc_pd = ib_dealloc_pd;\r
+ p_ifc->create_av = ib_create_av;\r
+ p_ifc->query_av = ib_query_av;\r
+ p_ifc->modify_av = ib_modify_av;\r
+ p_ifc->destroy_av = ib_destroy_av;\r
+ p_ifc->create_qp = ib_create_qp;\r
+ p_ifc->get_spl_qp = ib_get_spl_qp;\r
+ p_ifc->query_qp = ib_query_qp;\r
+ p_ifc->modify_qp = ib_modify_qp;\r
+ p_ifc->destroy_qp = ib_destroy_qp;\r
+ p_ifc->create_cq = ib_create_cq;\r
+ p_ifc->modify_cq = ib_modify_cq;\r
+ p_ifc->query_cq = ib_query_cq;\r
+ p_ifc->destroy_cq = ib_destroy_cq;\r
+ p_ifc->reg_mem = ib_reg_mem;\r
+ p_ifc->reg_phys = ib_reg_phys;\r
+ p_ifc->query_mr = ib_query_mr;\r
+ p_ifc->rereg_mem = ib_rereg_mem;\r
+ p_ifc->reg_shmid = ib_reg_shmid;\r
+ p_ifc->dereg_mr = ib_dereg_mr;\r
+ p_ifc->create_mw = ib_create_mw;\r
+ p_ifc->query_mw = ib_query_mw;\r
+ p_ifc->bind_mw = ib_bind_mw;\r
+ p_ifc->destroy_mw = ib_destroy_mw;\r
+ p_ifc->post_send = ib_post_send;\r
+ p_ifc->post_recv = ib_post_recv;\r
+ p_ifc->send_mad = ib_send_mad;\r
+ p_ifc->cancel_mad = ib_cancel_mad;\r
+ p_ifc->poll_cq = ib_poll_cq;\r
+ p_ifc->rearm_cq = ib_rearm_cq;\r
+ p_ifc->join_mcast = ib_join_mcast;\r
+ p_ifc->leave_mcast = ib_leave_mcast;\r
+ p_ifc->local_mad = ib_local_mad;\r
+ p_ifc->cm_listen = ib_cm_listen;\r
+ p_ifc->cm_cancel = ib_cm_cancel;\r
+ p_ifc->cm_req = ib_cm_req;\r
+ p_ifc->cm_rep = ib_cm_rep;\r
+ p_ifc->cm_rtu = ib_cm_rtu;\r
+ p_ifc->cm_rej = ib_cm_rej;\r
+ p_ifc->cm_mra = ib_cm_mra;\r
+ p_ifc->cm_lap = ib_cm_lap;\r
+ p_ifc->cm_apr = ib_cm_apr;\r
+ p_ifc->force_apm = ib_force_apm;\r
+ p_ifc->cm_dreq = ib_cm_dreq;\r
+ p_ifc->cm_drep = ib_cm_drep;\r
+ p_ifc->cm_handoff = ib_cm_handoff;\r
+ p_ifc->create_ioc = ib_create_ioc;\r
+ p_ifc->destroy_ioc = ib_destroy_ioc;\r
+ p_ifc->reg_ioc = ib_reg_ioc;\r
+ p_ifc->add_svc_entry = ib_add_svc_entry;\r
+ p_ifc->remove_svc_entry = ib_remove_svc_entry;\r
+ p_ifc->get_ca_guids = ib_get_ca_guids;\r
+ p_ifc->get_ca_by_gid = ib_get_ca_by_gid;\r
+ p_ifc->get_port_by_gid = ib_get_port_by_gid;\r
+ p_ifc->create_mad_pool = ib_create_mad_pool;\r
+ p_ifc->destroy_mad_pool = ib_destroy_mad_pool;\r
+ p_ifc->reg_mad_pool = ib_reg_mad_pool;\r
+ p_ifc->dereg_mad_pool = ib_dereg_mad_pool;\r
+ p_ifc->get_mad = ib_get_mad;\r
+ p_ifc->put_mad = ib_put_mad;\r
+ p_ifc->init_dgrm_svc = ib_init_dgrm_svc;\r
+ p_ifc->reg_mad_svc = ib_reg_mad_svc;\r
+ p_ifc->reg_svc = ib_reg_svc;\r
+ p_ifc->dereg_svc = ib_dereg_svc;\r
+ p_ifc->query = ib_query;\r
+ p_ifc->cancel_query = ib_cancel_query;\r
+ p_ifc->reg_pnp = ib_reg_pnp;\r
+ p_ifc->dereg_pnp = ib_dereg_pnp;\r
+ p_ifc->subscribe = ib_subscribe;\r
+ p_ifc->unsubscribe = ib_unsubscribe;\r
+ p_ifc->reject_ioc = ib_reject_ioc;\r
+ p_ifc->ci_call = ib_ci_call;\r
+ p_ifc->open_al = ib_open_al;\r
+ p_ifc->close_al = ib_close_al;\r
+ p_ifc->get_err_str = ib_get_err_str;\r
+ p_ifc->get_wc_status_str = ib_get_wc_status_str;\r
+ p_ifc->create_mlnx_fmr = mlnx_create_fmr;\r
+ p_ifc->map_phys_mlnx_fmr = mlnx_map_phys_fmr;\r
+ p_ifc->unmap_mlnx_fmr = mlnx_unmap_fmr;\r
+ p_ifc->destroy_mlnx_fmr = mlnx_destroy_fmr;\r
+ p_ifc->create_mlnx_fmr_pool = mlnx_create_fmr_pool;\r
+ p_ifc->destroy_mlnx_fmr_pool = mlnx_destroy_fmr_pool;\r
+ p_ifc->map_phys_mlnx_fmr_pool = mlnx_map_phys_fmr_pool;\r
+ p_ifc->unmap_mlnx_fmr_pool = mlnx_unmap_fmr_pool;\r
+ p_ifc->flush_mlnx_fmr_pool = mlnx_flush_fmr_pool;\r
+ p_ifc->create_srq = ib_create_srq;\r
+ p_ifc->modify_srq = ib_modify_srq;\r
+ p_ifc->query_srq = ib_query_srq;\r
+ p_ifc->destroy_srq = ib_destroy_srq;\r
+ p_ifc->post_srq_recv = ib_post_srq_recv;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+\r
+static NTSTATUS\r
+__query_ci_ifc(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IO_STACK_LOCATION* const p_io_stack )\r
+{\r
+ ib_ci_ifc_t *p_ifc;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ if( p_io_stack->Parameters.QueryInterface.Version != \r
+ IB_CI_INTERFACE_VERSION )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n",\r
+ p_io_stack->Parameters.QueryInterface.Version ) );\r
+ return STATUS_NOT_SUPPORTED;\r
+ }\r
+\r
+ if( p_io_stack->Parameters.QueryInterface.Size < sizeof(ib_ci_ifc_t) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, \r
+ ("Buffer too small (%d given, %d required).\n",\r
+ p_io_stack->Parameters.QueryInterface.Size, sizeof(ib_ci_ifc_t)) );\r
+ return STATUS_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ /* Copy the interface. */\r
+ p_ifc = (ib_ci_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
+\r
+ p_ifc->wdm.Size = sizeof(ib_ci_ifc_t);\r
+ p_ifc->wdm.Version = IB_CI_INTERFACE_VERSION;\r
+ p_ifc->wdm.Context = p_dev_obj;\r
+ p_ifc->wdm.InterfaceReference = al_ref_ci_ifc;\r
+ p_ifc->wdm.InterfaceDereference = al_deref_ci_ifc;\r
+\r
+ /* Set the entry points. */\r
+ p_ifc->register_ca = ib_register_ca;\r
+ p_ifc->deregister_ca = ib_deregister_ca;\r
+ p_ifc->get_relations = __get_relations;\r
+ p_ifc->get_err_str = ib_get_err_str;\r
+\r
+ /* take the reference before returning. */\r
+ al_ref_ci_ifc( p_dev_obj );\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static NTSTATUS\r
+fdo_query_interface(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ NTSTATUS status;\r
+ IO_STACK_LOCATION *p_io_stack;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+//#pragma warning( push, 3 )\r
+ PAGED_CODE();\r
+//#pragma warning( pop )\r
+\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+ \r
+ /* Compare requested GUID with our supported interface GUIDs. */\r
+ if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
+ &GUID_IB_AL_INTERFACE ) )\r
+ {\r
+ status = __query_al_ifc( p_dev_obj, p_io_stack );\r
+ }\r
+ else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
+ &GUID_IB_CI_INTERFACE ) )\r
+ {\r
+ status = __query_ci_ifc( p_dev_obj, p_io_stack );\r
+ }\r
+ else\r
+ {\r
+ status = p_irp->IoStatus.Status;\r
+ }\r
+\r
+ if( NT_SUCCESS( status ) )\r
+ *p_action = IrpSkip;\r
+ else if( status == STATUS_BUFFER_TOO_SMALL )\r
+ *p_action = IrpComplete;\r
+ else\r
+ *p_action = IrpIgnore;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+#endif /* NOT_USED */\r
+\r
+\r
+/* NOT required as the KMDF interface does the validation work - debug only */\r
+NTSTATUS\r
+AL_ValidateInterfaceQuery (\r
+ IN WDFDEVICE Device,\r
+ IN LPGUID InterfaceType,\r
+ IN OUT PINTERFACE ExposedInterface,\r
+ IN OUT PVOID ExposedInterfaceSpecificData )\r
+{\r
+ UNREFERENCED_PARAMETER( Device );\r
+ UNREFERENCED_PARAMETER( InterfaceType );\r
+ UNREFERENCED_PARAMETER( ExposedInterface );\r
+ UNREFERENCED_PARAMETER( ExposedInterfaceSpecificData );\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+ // DEBUG XXX\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+/* NOT required as the KMDF interface does the validation work - debug only */\r
+NTSTATUS\r
+CI_ValidateInterfaceQuery (\r
+ IN WDFDEVICE Device,\r
+ IN LPGUID InterfaceType,\r
+ IN OUT PINTERFACE ExposedInterface,\r
+ IN OUT PVOID ExposedInterfaceSpecificData )\r
+{\r
+ UNREFERENCED_PARAMETER( Device );\r
+ UNREFERENCED_PARAMETER( InterfaceType );\r
+ UNREFERENCED_PARAMETER( ExposedInterface );\r
+ UNREFERENCED_PARAMETER( ExposedInterfaceSpecificData );\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+ // DEBUG XXX\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Enable IBAL 'InfiniBand Access Layer' Interface query; called in response to\r
+ IRP_MN_QUERY_INTERFACE for GUID_AL_INTERFACE.\r
+\r
+Arguments:\r
+\r
+ Device - WDF child device\r
+\r
+Return Value:\r
+\r
+ NT Status code.\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Enable_IBAL_InterfaceQuery( WDFDEVICE Device )\r
+{\r
+ NTSTATUS status;\r
+ ib_al_ifc_t AL;\r
+ WDF_QUERY_INTERFACE_CONFIG qiConfig;\r
+\r
+ KdPrint(("--> %s()\n", __FUNCTION__));\r
+\r
+ // Create a custom interface so that other drivers can\r
+ // query (IRP_MN_QUERY_INTERFACE) and use our callbacks directly.\r
+ //\r
+ RtlZeroMemory(&AL, sizeof(AL));\r
+\r
+ AL.wdm.Size = sizeof(AL);\r
+ AL.wdm.Version = AL_INTERFACE_VERSION;\r
+ AL.wdm.Context = Device;\r
+\r
+ //\r
+ // Let the framework handle reference counting.\r
+ //\r
+ AL.wdm.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;\r
+ AL.wdm.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;\r
+\r
+ AL.sync_destroy = ib_sync_destroy;\r
+ AL.open_ca = ib_open_ca;\r
+ AL.query_ca = ib_query_ca;\r
+ AL.get_dev = get_ca_dev;\r
+ AL.close_ca = ib_close_ca;\r
+ AL.alloc_pd = ib_alloc_pd;\r
+ AL.dealloc_pd = ib_dealloc_pd;\r
+ AL.create_av = ib_create_av;\r
+ AL.query_av = ib_query_av;\r
+ AL.modify_av = ib_modify_av;\r
+ AL.destroy_av = ib_destroy_av;\r
+ AL.create_qp = ib_create_qp;\r
+ AL.get_spl_qp = ib_get_spl_qp;\r
+ AL.query_qp = ib_query_qp;\r
+ AL.modify_qp = ib_modify_qp;\r
+ AL.destroy_qp = ib_destroy_qp;\r
+ AL.create_cq = ib_create_cq;\r
+ AL.modify_cq = ib_modify_cq;\r
+ AL.query_cq = ib_query_cq;\r
+ AL.destroy_cq = ib_destroy_cq;\r
+ AL.reg_mem = ib_reg_mem;\r
+ AL.reg_phys = ib_reg_phys;\r
+ AL.query_mr = ib_query_mr;\r
+ AL.rereg_mem = ib_rereg_mem;\r
+ AL.reg_shmid = ib_reg_shmid;\r
+ AL.dereg_mr = ib_dereg_mr;\r
+ AL.create_mw = ib_create_mw;\r
+ AL.query_mw = ib_query_mw;\r
+ AL.bind_mw = ib_bind_mw;\r
+ AL.destroy_mw = ib_destroy_mw;\r
+ AL.post_send = ib_post_send;\r
+ AL.post_recv = ib_post_recv;\r
+ AL.send_mad = ib_send_mad;\r
+ AL.cancel_mad = ib_cancel_mad;\r
+ AL.poll_cq = ib_poll_cq;\r
+ AL.rearm_cq = ib_rearm_cq;\r
+ AL.join_mcast = ib_join_mcast;\r
+ AL.leave_mcast = ib_leave_mcast;\r
+ AL.local_mad = ib_local_mad;\r
+ AL.cm_listen = ib_cm_listen;\r
+ AL.cm_cancel = ib_cm_cancel;\r
+ AL.cm_req = ib_cm_req;\r
+ AL.cm_rep = ib_cm_rep;\r
+ AL.cm_rtu = ib_cm_rtu;\r
+ AL.cm_rej = ib_cm_rej;\r
+ AL.cm_mra = ib_cm_mra;\r
+ AL.cm_lap = ib_cm_lap;\r
+ AL.cm_apr = ib_cm_apr;\r
+ AL.force_apm = ib_force_apm;\r
+ AL.cm_dreq = ib_cm_dreq;\r
+ AL.cm_drep = ib_cm_drep;\r
+ AL.cm_handoff = ib_cm_handoff;\r
+ AL.create_ioc = ib_create_ioc;\r
+ AL.destroy_ioc = ib_destroy_ioc;\r
+ AL.reg_ioc = ib_reg_ioc;\r
+ AL.add_svc_entry = ib_add_svc_entry;\r
+ AL.remove_svc_entry = ib_remove_svc_entry;\r
+ AL.get_ca_guids = ib_get_ca_guids;\r
+ AL.get_ca_by_gid = ib_get_ca_by_gid;\r
+ AL.get_port_by_gid = ib_get_port_by_gid;\r
+ AL.create_mad_pool = ib_create_mad_pool;\r
+ AL.destroy_mad_pool = ib_destroy_mad_pool;\r
+ AL.reg_mad_pool = ib_reg_mad_pool;\r
+ AL.dereg_mad_pool = ib_dereg_mad_pool;\r
+ AL.get_mad = ib_get_mad;\r
+ AL.put_mad = ib_put_mad;\r
+ AL.init_dgrm_svc = ib_init_dgrm_svc;\r
+ AL.reg_mad_svc = ib_reg_mad_svc;\r
+ AL.reg_svc = ib_reg_svc;\r
+ AL.dereg_svc = ib_dereg_svc;\r
+ AL.query = ib_query;\r
+ AL.cancel_query = ib_cancel_query;\r
+ AL.reg_pnp = ib_reg_pnp;\r
+ AL.dereg_pnp = ib_dereg_pnp;\r
+ AL.subscribe = ib_subscribe;\r
+ AL.unsubscribe = ib_unsubscribe;\r
+ AL.reject_ioc = ib_reject_ioc;\r
+ AL.ci_call = ib_ci_call;\r
+ AL.open_al = ib_open_al;\r
+ AL.close_al = ib_close_al;\r
+ AL.get_err_str = ib_get_err_str;\r
+ AL.get_wc_status_str = ib_get_wc_status_str;\r
+ AL.create_mlnx_fmr = mlnx_create_fmr;\r
+ AL.map_phys_mlnx_fmr = mlnx_map_phys_fmr;\r
+ AL.unmap_mlnx_fmr = mlnx_unmap_fmr;\r
+ AL.destroy_mlnx_fmr = mlnx_destroy_fmr;\r
+ AL.create_mlnx_fmr_pool = mlnx_create_fmr_pool;\r
+ AL.destroy_mlnx_fmr_pool = mlnx_destroy_fmr_pool;\r
+ AL.map_phys_mlnx_fmr_pool = mlnx_map_phys_fmr_pool;\r
+ AL.unmap_mlnx_fmr_pool = mlnx_unmap_fmr_pool;\r
+ AL.flush_mlnx_fmr_pool = mlnx_flush_fmr_pool;\r
+ AL.create_srq = ib_create_srq;\r
+ AL.modify_srq = ib_modify_srq;\r
+ AL.query_srq = ib_query_srq;\r
+ AL.destroy_srq = ib_destroy_srq;\r
+ AL.post_srq_recv = ib_post_srq_recv;\r
+\r
+ WDF_QUERY_INTERFACE_CONFIG_INIT(&qiConfig,\r
+ (PINTERFACE) &AL,\r
+ &GUID_IB_AL_INTERFACE,\r
+ AL_ValidateInterfaceQuery /*NULL*/ );\r
+\r
+ //\r
+ // If you have multiple interfaces, you can call WdfDeviceAddQueryInterface\r
+ // multiple times to add additional interfaces.\r
+ //\r
+ status = WdfDeviceAddQueryInterface(Device, &qiConfig);\r
+\r
+ if (!NT_SUCCESS(status)) {\r
+ KdPrint(("WdfDeviceAddQueryInterface(IBAL) rc 0x%x\n",status));\r
+ return status;\r
+ }\r
+ KdPrint(("<-- %s() ret %x\n", __FUNCTION__, status));\r
+\r
+ return status;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Enable IBAL 'Channel Interface' query; handle IRP_MN_QUERY_INTERFACE for\r
+ GUID_IB_CI_INTERFACE.\r
+\r
+Arguments:\r
+\r
+ Device - WDF child device\r
+\r
+Return Value:\r
+\r
+ NT Status code.\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Enable_CI_InterfaceQuery( WDFDEVICE Device )\r
+{\r
+ NTSTATUS status;\r
+ ib_ci_ifc_t CI;\r
+ WDF_QUERY_INTERFACE_CONFIG qiConfig;\r
+\r
+ KdPrint(("--> %s()\n", __FUNCTION__));\r
+\r
+ // Create a custom interface so that other drivers can\r
+ // query (IRP_MN_QUERY_INTERFACE) and use our callbacks directly.\r
+ //\r
+ RtlZeroMemory(&CI, sizeof(CI));\r
+\r
+ CI.wdm.Size = sizeof(CI);\r
+ CI.wdm.Version = IB_CI_INTERFACE_VERSION;\r
+ CI.wdm.Context = Device;\r
+\r
+ //\r
+ // Let the framework handle reference counting.\r
+ //\r
+ CI.wdm.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;\r
+ CI.wdm.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;\r
+\r
+\r
+ /* Set the entry points. */\r
+ CI.register_ca = ib_register_ca;\r
+ CI.deregister_ca = ib_deregister_ca;\r
+ CI.get_relations = __get_relations;\r
+ CI.get_err_str = ib_get_err_str;\r
+\r
+ WDF_QUERY_INTERFACE_CONFIG_INIT( &qiConfig,\r
+ (PINTERFACE) &CI,\r
+ &GUID_IB_CI_INTERFACE,\r
+ CI_ValidateInterfaceQuery /*NULL*/ );\r
+ //\r
+ // If you have multiple interfaces, you can call WdfDeviceAddQueryInterface\r
+ // multiple times to add additional interfaces.\r
+ //\r
+ status = WdfDeviceAddQueryInterface( Device, &qiConfig );\r
+\r
+ if (!NT_SUCCESS(status)) {\r
+ KdPrint(("WdfDeviceAddQueryInterface(CI) rc 0x%x\n",status));\r
+ return status;\r
+ }\r
+ KdPrint(("<-- %s() ret %x\n", __FUNCTION__, status));\r
+\r
+ return status;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+__fdo_query_power(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ NTSTATUS status = STATUS_SUCCESS;\r
+ IO_STACK_LOCATION *p_io_stack;\r
+\r
+ BUS_ENTER( BUS_DBG_POWER );\r
+\r
+ UNUSED_PARAM( p_dev_obj );\r
+\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+ switch( p_io_stack->Parameters.Power.Type )\r
+ {\r
+ case SystemPowerState:\r
+ /* Fail any requests to hibernate or sleep the system. */\r
+ switch( p_io_stack->Parameters.Power.State.SystemState )\r
+ {\r
+ case PowerSystemHibernate:\r
+ case PowerSystemSleeping1: // STANDBY support\r
+ case PowerSystemWorking:\r
+ case PowerSystemShutdown:\r
+ break;\r
+\r
+ default:\r
+ status = STATUS_NOT_SUPPORTED;\r
+ }\r
+ break;\r
+\r
+ case DevicePowerState:\r
+ /* Fail any query for low power states. */\r
+ switch( p_io_stack->Parameters.Power.State.DeviceState )\r
+ {\r
+ case PowerDeviceD0:\r
+ case PowerDeviceD3:\r
+ /* We only support fully powered or off power states. */\r
+ break;\r
+\r
+ default:\r
+ status = STATUS_NOT_SUPPORTED;\r
+ }\r
+ break;\r
+ }\r
+\r
+ if( status == STATUS_NOT_SUPPORTED )\r
+ *p_action = IrpComplete;\r
+ else\r
+ *p_action = IrpSkip;\r
+\r
+ BUS_EXIT( BUS_DBG_POWER );\r
+ return status;\r
+}\r
+\r
+\r
+static void\r
+__request_power_completion(\r
+ IN DEVICE_OBJECT *p_dev_obj,\r
+ IN UCHAR minor_function,\r
+ IN POWER_STATE power_state,\r
+ IN void *context,\r
+ IN IO_STATUS_BLOCK *p_io_status )\r
+{\r
+ IRP *p_irp;\r
+ cl_pnp_po_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( minor_function );\r
+ UNUSED_PARAM( power_state );\r
+\r
+ p_irp = (IRP*)context;\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ /* Propagate the device IRP status to the system IRP status. */\r
+ p_irp->IoStatus.Status = p_io_status->Status;\r
+\r
+ /* Continue Power IRP processing. */\r
+ PoStartNextPowerIrp( p_irp );\r
+ IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+ IoReleaseRemoveLock( &p_ext->remove_lock, p_irp );\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+/*NOTE: Completion routines must NEVER be pageable. */\r
+static NTSTATUS\r
+__set_power_completion(\r
+ IN DEVICE_OBJECT *p_dev_obj,\r
+ IN IRP *p_irp,\r
+ IN void *context )\r
+{\r
+ NTSTATUS status;\r
+ POWER_STATE state;\r
+ bus_fdo_ext_t *p_ext;\r
+ IO_STACK_LOCATION *p_io_stack;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( context );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+ if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
+ {\r
+ PoStartNextPowerIrp( p_irp );\r
+ IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
+ ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n",\r
+ p_irp->IoStatus.Status) );\r
+ return STATUS_SUCCESS;\r
+ }\r
+\r
+ state.DeviceState = \r
+ p_ext->po_state[p_io_stack->Parameters.Power.State.SystemState];\r
+\r
+ /*\r
+ * Send a device power IRP to our devnode. Using our device object will\r
+ * only work on win2k and other NT based systems.\r
+ */\r
+ status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
+ __request_power_completion, p_irp, NULL );\r
+\r
+ if( status != STATUS_PENDING )\r
+ {\r
+ PoStartNextPowerIrp( p_irp );\r
+ /* Propagate the failure. */\r
+ p_irp->IoStatus.Status = status;\r
+ IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+ IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
+ BUS_TRACE( BUS_DBG_ERROR,\r
+ ("PoRequestPowerIrp returned %08x.\n", status) );\r
+ }\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_MORE_PROCESSING_REQUIRED;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+__fdo_set_power(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ NTSTATUS status;\r
+ IO_STACK_LOCATION *p_io_stack;\r
+ bus_fdo_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_POWER );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+ BUS_TRACE( BUS_DBG_POWER, \r
+ ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d \n",\r
+ p_dev_obj, p_ext,\r
+ (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
+ p_io_stack->Parameters.Power.State.DeviceState, \r
+ p_io_stack->Parameters.Power.ShutdownType ));\r
+\r
+ switch( p_io_stack->Parameters.Power.Type )\r
+ {\r
+ case SystemPowerState:\r
+ /*\r
+ * Process on the way up the stack. We cannot block since the \r
+ * power dispatch function can be called at elevated IRQL if the\r
+ * device is in a paging/hibernation/crash dump path.\r
+ */\r
+ IoMarkIrpPending( p_irp );\r
+ IoCopyCurrentIrpStackLocationToNext( p_irp );\r
+#pragma warning( push, 3 )\r
+ IoSetCompletionRoutine( p_irp, __set_power_completion, NULL, \r
+ TRUE, TRUE, TRUE );\r
+#pragma warning( pop )\r
+ PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
+\r
+ *p_action = IrpDoNothing;\r
+ status = STATUS_PENDING;\r
+ break;\r
+\r
+ case DevicePowerState:\r
+ default:\r
+ /* Pass down and let the PDO driver handle it. */\r
+ *p_action = IrpIgnore;\r
+ status = STATUS_SUCCESS;\r
+ break;\r
+ }\r
+\r
+ BUS_EXIT( BUS_DBG_POWER );\r
+ return status;\r
+}\r
+\r
+\r
+/*\r
+ * A CA GUID of zero means that all devices should be reported.\r
+ */\r
+NTSTATUS\r
+bus_get_relations(\r
+ IN cl_qlist_t* const p_pdo_list,\r
+ IN const net64_t ca_guid,\r
+ IN IRP* const p_irp )\r
+{\r
+ NTSTATUS status;\r
+ DEVICE_RELATIONS *p_rel;\r
+ cl_list_item_t *p_list_item;\r
+ bus_pdo_ext_t *p_pdo_ext;\r
+ size_t n_devs = 0;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ /* Count the number of child devices. */\r
+ for( p_list_item = cl_qlist_head( p_pdo_list );\r
+ p_list_item != cl_qlist_end( p_pdo_list );\r
+ p_list_item = cl_qlist_next( p_list_item ) )\r
+ {\r
+ p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
+\r
+ if( !p_pdo_ext->b_present )\r
+ continue;\r
+ \r
+ if( ca_guid && p_pdo_ext->ca_guid != ca_guid )\r
+ continue;\r
+\r
+ n_devs++;\r
+ }\r
+\r
+ if( !n_devs )\r
+ {\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ BUS_TRACE( BUS_DBG_PNP, ("Found %d PDOs .\n", n_devs ));\r
+\r
+ /* Add space for our child IOUs. */\r
+ status = cl_alloc_relations( p_irp, n_devs );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("cl_alloc_relations returned %08x.\n", status) );\r
+ return status;\r
+ }\r
+\r
+ p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
+\r
+ for( p_list_item = cl_qlist_head( p_pdo_list );\r
+ p_list_item != cl_qlist_end( p_pdo_list );\r
+ p_list_item = cl_qlist_next( p_list_item ) )\r
+ {\r
+ p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
+\r
+ if( !p_pdo_ext->b_present )\r
+ {\r
+ /*\r
+ * We don't report a PDO that is no longer present. This is how\r
+ * the PDO will get cleaned up.\r
+ */\r
+ p_pdo_ext->b_reported_missing = TRUE;\r
+ BUS_TRACE( BUS_DBG_PNP, ("Don't report PDO! %s: PDO %p, ext %p, present %d, missing %d .\n",\r
+ p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, \r
+ p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing ) );\r
+ continue;\r
+ }\r
+\r
+ if( ca_guid && p_pdo_ext->ca_guid != ca_guid )\r
+ continue;\r
+\r
+ BUS_TRACE( BUS_DBG_PNP, ("Reported PDO %p(=%p), ext %p.\n", \r
+ p_pdo_ext->cl_ext.p_self_do, p_pdo_ext->cl_ext.p_pdo, p_pdo_ext ));\r
+ \r
+ p_rel->Objects[p_rel->Count] = p_pdo_ext->cl_ext.p_pdo;\r
+ ObReferenceObject( p_rel->Objects[p_rel->Count++] );\r
+ }\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/*++\r
+Routine Description:\r
+\r
+ Handle user mode PlugIn, UnPlug and device Eject requests.\r
+\r
+Arguments:\r
+\r
+ Queue - Handle to the framework queue object that is associated\r
+ with the I/O request.\r
+\r
+ Request - Handle to a framework request object. This one represents\r
+ the IRP_MJ_DEVICE_CONTROL IRP received by the framework.\r
+\r
+ OutputBufferLength - Length, in bytes, of the request's output buffer,\r
+ if an output buffer is available.\r
+\r
+ InputBufferLength - Length, in bytes, of the request's input buffer,\r
+ if an input buffer is available.\r
+ IoControlCode - Driver-defined or system-defined I/O control code (IOCTL)\r
+ that is associated with the request.\r
+\r
+Return Value:\r
+\r
+ VOID\r
+\r
+--*/\r
+\r
+static VOID\r
+Bus_EvtIoDeviceControl (\r
+ IN WDFQUEUE Queue,\r
+ IN WDFREQUEST Request,\r
+ IN size_t OutputBufferLength,\r
+ IN size_t InputBufferLength,\r
+ IN ULONG IoControlCode )\r
+{\r
+ NTSTATUS status = STATUS_INVALID_PARAMETER;\r
+ WDFDEVICE hDevice;\r
+// size_t length = 0;\r
+\r
+ BOOLEAN xferStatus;\r
+ PIRP irp;\r
+ PIO_STACK_LOCATION NextStack;\r
+ WDFIOTARGET hTarget;\r
+\r
+ UNREFERENCED_PARAMETER(OutputBufferLength);\r
+ UNREFERENCED_PARAMETER(InputBufferLength);\r
+\r
+ BUS_ENTER( DBG_PNP );\r
+\r
+ PAGED_CODE ();\r
+\r
+ hDevice = WdfIoQueueGetDevice(Queue);\r
+\r
+ KdPrint(("%s() 0x%p IOCTL 0x%x\n", __FUNCTION__, hDevice,IoControlCode));\r
+\r
+ irp = WdfRequestWdmGetIrp(Request);\r
+\r
+ //CurStack = IoGetCurrentIrpStackLocation(irp);\r
+\r
+ status = cl_to_ntstatus( al_dev_ioctl( irp ) ); \r
+ switch( status )\r
+ {\r
+ case STATUS_SUCCESS:\r
+ // already completed.\r
+ break;\r
+\r
+ case STATUS_INVALID_DEVICE_REQUEST:\r
+ // pass down the stack?\r
+ hTarget = WdfDeviceGetIoTarget(hDevice);\r
+ if ( hTarget )\r
+ {\r
+ NextStack = IoGetNextIrpStackLocation(irp);\r
+ WdfRequestWdmFormatUsingStackLocation( Request, NextStack );\r
+ xferStatus = WdfRequestSend( Request, hTarget, NULL );\r
+ if ( xferStatus == FALSE )\r
+ WdfRequestComplete(Request, status);\r
+ }\r
+ else\r
+ WdfRequestComplete(Request, status);\r
+ break;\r
+\r
+ case STATUS_PENDING:\r
+ // callback already set?\r
+ break;\r
+\r
+ default:\r
+ WdfRequestComplete(Request, status);\r
+ break;\r
+ }\r
+\r
+#if 0\r
+ PBUSENUM_PLUGIN_HARDWARE plugIn = NULL;\r
+ PBUSENUM_UNPLUG_HARDWARE unPlug = NULL;\r
+ PBUSENUM_EJECT_HARDWARE eject = NULL;\r
+\r
+ switch (IoControlCode)\r
+ {\r
+ case IOCTL_BUSENUM_PLUGIN_HARDWARE:\r
+\r
+ status = WdfRequestRetrieveInputBuffer (Request,\r
+ sizeof (BUSENUM_PLUGIN_HARDWARE) +\r
+ (sizeof(UNICODE_NULL) * 2),\r
+ // 2 for double NULL termination (MULTI_SZ)\r
+ &plugIn, &length);\r
+ if( !NT_SUCCESS(status) ) {\r
+ KdPrint(("WdfRequestRetrieveInputBuffer failed 0x%x\n", status));\r
+ break;\r
+ }\r
+\r
+ ASSERT(length == InputBufferLength);\r
+\r
+ if (sizeof (BUSENUM_PLUGIN_HARDWARE) == plugIn->Size)\r
+ {\r
+\r
+ length = (InputBufferLength - sizeof (BUSENUM_PLUGIN_HARDWARE))\r
+ / sizeof(WCHAR);\r
+ //\r
+ // Make sure the IDs is two NULL terminated.\r
+ //\r
+ if ((UNICODE_NULL != plugIn->HardwareIDs[length - 1]) ||\r
+ (UNICODE_NULL != plugIn->HardwareIDs[length - 2])) {\r
+\r
+ status = STATUS_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ status = Bus_PlugInDevice( hDevice,\r
+ plugIn->HardwareIDs,\r
+ length,\r
+ plugIn->SerialNo );\r
+ }\r
+\r
+ break;\r
+\r
+ case IOCTL_BUSENUM_UNPLUG_HARDWARE:\r
+\r
+ status = WdfRequestRetrieveInputBuffer( Request,\r
+ sizeof(BUSENUM_UNPLUG_HARDWARE),\r
+ &unPlug,\r
+ &length );\r
+ if( !NT_SUCCESS(status) ) {\r
+ KdPrint(("WdfRequestRetrieveInputBuffer failed 0x%x\n", status));\r
+ break;\r
+ }\r
+\r
+ if (unPlug->Size == InputBufferLength)\r
+ {\r
+\r
+ status= Bus_UnPlugDevice(hDevice, unPlug->SerialNo );\r
+\r
+ }\r
+\r
+ break;\r
+\r
+ case IOCTL_BUSENUM_EJECT_HARDWARE:\r
+\r
+ status = WdfRequestRetrieveInputBuffer (Request,\r
+ sizeof (BUSENUM_EJECT_HARDWARE),\r
+ &eject, &length);\r
+ if( !NT_SUCCESS(status) ) {\r
+ KdPrint(("WdfRequestRetrieveInputBuffer failed 0x%x\n", status));\r
+ break;\r
+ }\r
+\r
+ if (eject->Size == InputBufferLength)\r
+ {\r
+ status= Bus_EjectDevice(hDevice, eject->SerialNo);\r
+\r
+ }\r
+\r
+ break;\r
+\r
+ default:\r
+ break; // default status is STATUS_INVALID_PARAMETER\r
+ }\r
+ WdfRequestCompleteWithInformation(Request, status, length);\r
+#endif\r
+ BUS_EXIT( DBG_PNP );\r
+}\r
+\r
+\r
+static VOID\r
+Bus_EvtIoStop (\r
+ IN WDFQUEUE Queue,\r
+ IN WDFREQUEST Request,\r
+ IN ULONG ActionFlags )\r
+{\r
+ UNREFERENCED_PARAMETER( Queue );\r
+ UNREFERENCED_PARAMETER( Request );\r
+ UNREFERENCED_PARAMETER( ActionFlags );\r
+\r
+ BUS_ENTER( DBG_PNP );\r
+\r
+ /*request's I/O queue is being stopped */\r
+ WdfRequestComplete( Request, STATUS_CANCELLED );\r
+\r
+\r
+ BUS_EXIT( DBG_PNP );\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ The user application has told us that a new device on the bus has arrived.\r
+ We therefore create a description structure in stack, fill in information\r
+ about the child device and call\r
+ WdfChildListAddOrUpdateChildDescriptionAsPresent()\r
+ to add the device.\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_PlugInDevice(\r
+ __in WDFDEVICE Device,\r
+ __in PWCHAR HardwareIds,\r
+ __in size_t CchHardwareIds,\r
+ __in ULONG SerialNo )\r
+{\r
+ PDO_IDENTIFICATION_DESCRIPTION description;\r
+ NTSTATUS status;\r
+\r
+ PAGED_CODE ();\r
+\r
+ //\r
+ // Initialize the description with the information about the newly\r
+ // plugged in device.\r
+ //\r
+ WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(\r
+ &description.Header,\r
+ sizeof(description) );\r
+\r
+ description.SerialNo = SerialNo;\r
+ description.CchHardwareIds = CchHardwareIds;\r
+ description.HardwareIds = HardwareIds;\r
+\r
+ //\r
+ // Call the framework to add this child to the childlist. This call\r
+ // will internally call our DescriptionCompare callback to check\r
+ // whether this device is a new device or existing device. If\r
+ // it's a new device, the framework will call DescriptionDuplicate to create\r
+ // a copy of this description in nonpaged pool.\r
+ // The actual creation of the child device will happen when the framework\r
+ // receives QUERY_DEVICE_RELATION request from the PNP manager in\r
+ // response to InvalidateDeviceRelations call made as part of adding\r
+ // a new child.\r
+ //\r
+ status = WdfChildListAddOrUpdateChildDescriptionAsPresent(\r
+ WdfFdoGetDefaultChildList(Device),\r
+ &description.Header,\r
+ NULL); // AddressDescription\r
+\r
+ if (status == STATUS_OBJECT_NAME_EXISTS) {\r
+ //\r
+ // The description is already present in the list, the serial number is\r
+ // not unique, return error.\r
+ //\r
+ status = STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ return status;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ The application has told us a device has departed from the bus.\r
+\r
+ We therefore need to flag the PDO as no longer present.\r
+\r
+Arguments:\r
+\r
+\r
+Returns:\r
+\r
+ STATUS_SUCCESS upon successful removal from the list\r
+ STATUS_INVALID_PARAMETER if the removal was unsuccessful\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_UnPlugDevice(\r
+ WDFDEVICE Device,\r
+ ULONG SerialNo )\r
+{\r
+ NTSTATUS status;\r
+ WDFCHILDLIST list;\r
+\r
+ PAGED_CODE ();\r
+\r
+ list = WdfFdoGetDefaultChildList(Device);\r
+\r
+ if (0 == SerialNo) {\r
+ //\r
+ // Unplug everybody: do this by starting a scan and then not reporting\r
+ // any children upon its completion\r
+ //\r
+ status = STATUS_SUCCESS;\r
+\r
+ WdfChildListBeginScan(list);\r
+\r
+ // A call to WdfChildListBeginScan indicates to the framework that the\r
+ // driver is about to scan for dynamic children. After this call has\r
+ // returned, all previously reported children associated with this will\r
+ // be marked as potentially missing. A call to either\r
+ // WdfChildListUpdateChildDescriptionAsPresent or\r
+ // WdfChildListMarkAllChildDescriptionsPresent will mark all previuosly\r
+ // reported missing children as present. If any children currently\r
+ // present are not reported present by calling\r
+ // WdfChildListUpdateChildDescriptionAsPresent at the time of\r
+ // WdfChildListEndScan, they will be reported as missing to the PnP\r
+ // subsystem After WdfChildListEndScan call has returned, the framework\r
+ // will invalidate the device relations for the FDO associated with the\r
+ // list and report the changes\r
+ //\r
+ WdfChildListEndScan(list);\r
+ }\r
+ else {\r
+ PDO_IDENTIFICATION_DESCRIPTION description;\r
+\r
+ WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(\r
+ &description.Header,\r
+ sizeof(description)\r
+ );\r
+\r
+ description.SerialNo = SerialNo;\r
+\r
+ // WdfFdoUpdateChildDescriptionAsMissing indicates to the framework\r
+ // that a child device that was previuosly detected is no longer present\r
+ // on the bus.\r
+ // This API can be called by itself or after a call to\r
+ // WdfChildListBeginScan().\r
+ // After this call has returned, the framework will invalidate the\r
+ // device relations for the FDO associated with the list and report the\r
+ // changes.\r
+\r
+ status = WdfChildListUpdateChildDescriptionAsMissing(\r
+ list,\r
+ &description.Header );\r
+ if (status == STATUS_NO_SUCH_DEVICE) {\r
+ // serial number didn't exist. Remap it to a status that user\r
+ // application can understand when it gets translated to win32\r
+ // error code.\r
+ status = STATUS_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ return status;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ The user application has told us to eject the device from the bus.\r
+ In a real situation the driver gets notified by an interrupt when the\r
+ user presses the Eject button on the device.\r
+\r
+Arguments:\r
+\r
+\r
+Returns:\r
+\r
+ STATUS_SUCCESS upon successful removal from the list\r
+ STATUS_INVALID_PARAMETER if the ejection was unsuccessful\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_EjectDevice( WDFDEVICE Device, ULONG SerialNo )\r
+{\r
+ WDFDEVICE hChild;\r
+ NTSTATUS status = STATUS_INVALID_PARAMETER;\r
+ WDFCHILDLIST list;\r
+\r
+ PAGED_CODE ();\r
+\r
+ list = WdfFdoGetDefaultChildList(Device);\r
+\r
+ //\r
+ // A zero serial number means eject all children\r
+ //\r
+ if (0 == SerialNo) {\r
+ WDF_CHILD_LIST_ITERATOR iterator;\r
+\r
+ WDF_CHILD_LIST_ITERATOR_INIT( &iterator,\r
+ WdfRetrievePresentChildren );\r
+\r
+ WdfChildListBeginIteration(list, &iterator);\r
+\r
+ for ( ; ; ) {\r
+ WDF_CHILD_RETRIEVE_INFO childInfo;\r
+ PDO_IDENTIFICATION_DESCRIPTION description;\r
+ BOOLEAN ret;\r
+\r
+ //\r
+ // Init the structures.\r
+ //\r
+ WDF_CHILD_RETRIEVE_INFO_INIT(&childInfo, &description.Header);\r
+\r
+ WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(\r
+ &description.Header,\r
+ sizeof(description)\r
+ );\r
+ //\r
+ // Get the device identification description\r
+ //\r
+ status = WdfChildListRetrieveNextDevice(list,\r
+ &iterator,\r
+ &hChild,\r
+ &childInfo);\r
+\r
+ if (!NT_SUCCESS(status) || status == STATUS_NO_MORE_ENTRIES) {\r
+ break;\r
+ }\r
+\r
+ ASSERT(childInfo.Status == WdfChildListRetrieveDeviceSuccess);\r
+\r
+ //\r
+ // Use that description to request an eject.\r
+ //\r
+ ret = WdfChildListRequestChildEject(list, &description.Header);\r
+ if(!ret) {\r
+ WDFVERIFY(ret);\r
+ }\r
+\r
+ }\r
+\r
+ WdfChildListEndIteration(list, &iterator);\r
+\r
+ if (status == STATUS_NO_MORE_ENTRIES) {\r
+ status = STATUS_SUCCESS;\r
+ }\r
+\r
+ }\r
+ else {\r
+\r
+ PDO_IDENTIFICATION_DESCRIPTION description;\r
+\r
+ WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(\r
+ &description.Header,\r
+ sizeof(description)\r
+ );\r
+\r
+ description.SerialNo = SerialNo;\r
+\r
+ if (WdfChildListRequestChildEject(list, &description.Header)) {\r
+ status = STATUS_SUCCESS;\r
+ }\r
+ }\r
+ return status;\r
+}\r
+\r
+\r
+/*++\r
+Routine Description:\r
+\r
+ This routine is used to queue workitems so that the callback\r
+ functions can be executed at PASSIVE_LEVEL in the conext of\r
+ a system thread.\r
+\r
+Arguments:\r
+\r
+ FdoData - pointer to a device extenion.\r
+\r
+ CallbackFunction - Function to invoke when at PASSIVE_LEVEL.\r
+\r
+ Context1 & 2 - Meaning of the context values depends on the\r
+ callback function.\r
+\r
+Return Value:\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+DrvQueuePassiveLevelCallback(\r
+ IN PFDO_BUS_DATA FdoData,\r
+ IN PFN_WDF_WORKITEM CallbackFunction,\r
+ IN PVOID Context1,\r
+ IN PVOID Context2 )\r
+{\r
+ NTSTATUS status = STATUS_SUCCESS;\r
+ PWORKER_ITEM_CONTEXT context;\r
+ WDF_OBJECT_ATTRIBUTES attributes;\r
+ WDF_WORKITEM_CONFIG workitemConfig;\r
+ WDFWORKITEM hWorkItem;\r
+\r
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, WORKER_ITEM_CONTEXT);\r
+\r
+ attributes.ParentObject = FdoData->WdfDevice;\r
+\r
+ WDF_WORKITEM_CONFIG_INIT(&workitemConfig, CallbackFunction);\r
+\r
+ status = WdfWorkItemCreate( &workitemConfig,\r
+ &attributes,\r
+ &hWorkItem);\r
+\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+\r
+ context = GetWorkItemContext(hWorkItem);\r
+\r
+ context->FdoData = FdoData;\r
+ context->Argument1 = Context1;\r
+ context->Argument2 = Context2;\r
+\r
+ //\r
+ // Execute this work item.\r
+ //\r
+ WdfWorkItemEnqueue(hWorkItem);\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ EvtDevicePrepareHardware event callback performs operations that are\r
+ necessary to make the driver's device operational. The framework calls the\r
+ driver's EvtDevicePrepareHardware callback when the PnP manager sends an\r
+ IRP_MN_START_DEVICE request to the driver stack.\r
+\r
+ Specifically, most drivers will use this callback to map resources. USB\r
+ drivers may use it to get device descriptors, config descriptors and to\r
+ select configs.\r
+\r
+ Common things to do here:\r
+ Maps physical memory addresses to virtual addresses so the driver can access\r
+ memory that is assigned to the device. \r
+ Determine the device's revision number. \r
+ Configure USB devices. \r
+ Obtain driver-defined interfaces from other drivers. \r
+\r
+Arguments:\r
+\r
+ Device - Handle to a framework device object.\r
+\r
+ ResourcesRaw - Handle to a collection of framework resource objects.\r
+ This collection identifies the raw (bus-relative) hardware\r
+ resources that have been assigned to the device.\r
+\r
+ ResourcesTranslated - Handle to a collection of framework resource objects.\r
+ This collection identifies the translated (system-physical)\r
+ hardware resources that have been assigned to the device.\r
+ The resources appear from the CPU's point of view.\r
+ Use this list of resources to map I/O space and\r
+ device-accessible memory into virtual address space\r
+Return Value:\r
+\r
+ WDF status code\r
+\r
+--*/\r
+\r
+static NTSTATUS\r
+Bus_EvtDevicePrepareHardware (\r
+ WDFDEVICE Device,\r
+ WDFCMRESLIST ResourcesRaw,\r
+ WDFCMRESLIST ResourcesTranslated )\r
+{\r
+ NTSTATUS status = STATUS_SUCCESS;\r
+ PFDO_BUS_DATA fdoData = NULL;\r
+ DEVICE_OBJECT* p_dev_obj;\r
+\r
+ UNREFERENCED_PARAMETER(ResourcesRaw);\r
+ UNREFERENCED_PARAMETER(ResourcesTranslated);\r
+\r
+ PAGED_CODE();\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s()\n", __FUNCTION__);\r
+\r
+ fdoData = FdoGetData(Device);\r
+ p_dev_obj = WdfDeviceWdmGetAttachedDevice(Device),\r
+\r
+ // Map hardware, etc. do not start device.\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,\r
+ "<-- %s() ret %x\n", __FUNCTION__, status);\r
+ return status;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ EvtDeviceReleaseHardware is called by the framework whenever the PnP manager\r
+ is revoking ownership of our resources. This may be in response to either\r
+ IRP_MN_STOP_DEVICE or IRP_MN_REMOVE_DEVICE. The callback is made before\r
+ passing down the IRP to the lower driver.\r
+\r
+ In this callback, do anything necessary to free those resources.\r
+\r
+Arguments:\r
+\r
+ Device - Handle to a framework device object.\r
+\r
+ ResourcesTranslated - Handle to a collection of framework resource objects.\r
+ This collection identifies the translated (system-physical)\r
+ hardware resources that have been assigned to the device.\r
+ The resources appear from the CPU's point of view.\r
+ Use this list of resources to map I/O space and\r
+ device-accessible memory into virtual address space\r
+\r
+Return Value:\r
+\r
+ NTSTATUS - Failures will be logged, but not acted on.\r
+\r
+--*/\r
+\r
+static NTSTATUS\r
+Bus_EvtDeviceReleaseHardware(\r
+ IN WDFDEVICE Device,\r
+ IN WDFCMRESLIST ResourcesTranslated )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+ PDEVICE_OBJECT p_dev_obj;\r
+\r
+ UNREFERENCED_PARAMETER(ResourcesTranslated);\r
+\r
+ PAGED_CODE();\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s()\n", __FUNCTION__);\r
+\r
+ fdoData = FdoGetData(Device);\r
+ p_dev_obj = WdfDeviceWdmGetAttachedDevice(Device),\r
+\r
+ // Basically undo what PrepareHardware did.\r
+ // Unmap any I/O ports. Disconnecting from the interrupt will be done\r
+ // automatically by the framework.\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s()\n", __FUNCTION__);\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static PCHAR\r
+DbgDevicePowerString( IN WDF_POWER_DEVICE_STATE Type )\r
+{\r
+ switch (Type)\r
+ {\r
+ case WdfPowerDeviceInvalid:\r
+ return "WdfPowerDeviceInvalid";\r
+ case WdfPowerDeviceD0:\r
+ return "WdfPowerDeviceD0";\r
+ case PowerDeviceD1:\r
+ return "WdfPowerDeviceD1";\r
+ case WdfPowerDeviceD2:\r
+ return "WdfPowerDeviceD2";\r
+ case WdfPowerDeviceD3:\r
+ return "WdfPowerDeviceD3";\r
+ case WdfPowerDeviceD3Final:\r
+ return "WdfPowerDeviceD3Final";\r
+ case WdfPowerDevicePrepareForHibernation:\r
+ return "WdfPowerDevicePrepareForHibernation";\r
+ case WdfPowerDeviceMaximum:\r
+ return "PowerDeviceMaximum";\r
+ default:\r
+ return "UnKnown Device Power State";\r
+ }\r
+}\r
+\r
+\r
+void\r
+SetPowerLow( FDO_BUS_DATA *fdoData, WDF_POWER_DEVICE_STATE TargetState )\r
+{\r
+ UNREFERENCED_PARAMETER(fdoData);\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER,\r
+ "--> %s() target state %s\n", __FUNCTION__,\r
+ DbgDevicePowerString(TargetState));\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<-- %s()\n", __FUNCTION__);\r
+}\r
+\r
+void\r
+SetPowerD0( FDO_BUS_DATA *fdoData )\r
+{\r
+ UNREFERENCED_PARAMETER(fdoData);\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "--> %s()\n", __FUNCTION__);\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<-- %s()\n", __FUNCTION__);\r
+}\r
+\r
+void\r
+SetPowerShutdown( FDO_BUS_DATA *fdoData )\r
+{\r
+ UNREFERENCED_PARAMETER(fdoData);\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER,\r
+ "--> %s() D3 Final\n", __FUNCTION__);\r
+ // Reset and put the device into a known initial state we're shutting\r
+ // down for the last time.\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<-- %s()\n", __FUNCTION__);\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ EvtDeviceD0Entry event callback must perform any operations that are\r
+ necessary before the specified device is used. It will be called every\r
+ time the hardware needs to be (re-)initialized. This includes after\r
+ IRP_MN_START_DEVICE, IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE,\r
+ IRP_MN_SET_POWER-D0.\r
+\r
+ This function is not marked pageable because this function is in the\r
+ device power up path. When a function is marked pagable and the code\r
+ section is paged out, it will generate a page fault which could impact\r
+ the fast resume behavior because the client driver will have to wait\r
+ until the system drivers can service this page fault.\r
+\r
+ This function runs at PASSIVE_LEVEL, even though it is not paged. A\r
+ driver can optionally make this function pageable if DO_POWER_PAGABLE\r
+ is set. Even if DO_POWER_PAGABLE isn't set, this function still runs\r
+ at PASSIVE_LEVEL. In this case, though, the function absolutely must\r
+ not do anything that will cause a page fault.\r
+\r
+Arguments:\r
+\r
+ Device - Handle to a framework device object.\r
+\r
+ PreviousState - Device power state which the device was in most recently.\r
+ If the device is being newly started, this will be\r
+ PowerDeviceUnspecified.\r
+\r
+Return Value:\r
+\r
+ NTSTATUS\r
+\r
+--*/\r
+\r
+static NTSTATUS\r
+Bus_EvtDeviceD0Entry (\r
+ IN WDFDEVICE Device,\r
+ IN WDF_POWER_DEVICE_STATE PreviousState )\r
+{\r
+ NTSTATUS status;\r
+ PFDO_BUS_DATA fdo;\r
+ ib_api_status_t ib_status;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ PAGED_CODE();\r
+\r
+ fdo = FdoGetData(Device);\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER,\r
+ "--> %s() transition from %s to %s \n", __FUNCTION__,\r
+ DbgDevicePowerString(fdo->DevPowerState),\r
+ DbgDevicePowerString(PreviousState));\r
+\r
+\r
+ ASSERT(PowerDeviceD0 != PreviousState);\r
+\r
+ fdo->DevPreviousPowerState = PreviousState;\r
+ fdo->DevPowerState = PowerDeviceD0;\r
+\r
+ KdPrint(("%s() call al_initialize()\n",__FUNCTION__));\r
+ /* Initialize AL */\r
+ ib_status = al_initialize();\r
+ if( ib_status != IB_SUCCESS )\r
+ {\r
+ al_cleanup();\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("al_initialize returned %s.\n",\r
+ ib_get_err_str(ib_status)) );\r
+ return STATUS_UNSUCCESSFUL;\r
+ }\r
+ KdPrint(("%s() al_initialize() Done.\n",__FUNCTION__));\r
+\r
+ /* Initialize the port manager. */\r
+ ib_status = create_port_mgr( &fdo->p_port_mgr );\r
+ if( ib_status != IB_SUCCESS )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("create_port_mgr returned %s.\n",\r
+ ib_get_err_str(ib_status)) );\r
+ return STATUS_UNSUCCESSFUL;\r
+ }\r
+ KdPrint(("%s() create_port_mgr() Done.\n",__FUNCTION__));\r
+\r
+ /* Initialize the IOU manager. */\r
+ ib_status = create_iou_mgr( &fdo->p_iou_mgr );\r
+ if( ib_status != IB_SUCCESS )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("create_iou_mgr returned %s.\n",\r
+ ib_get_err_str(ib_status)) );\r
+ return STATUS_UNSUCCESSFUL;\r
+ }\r
+ KdPrint(("%s() create_iou_mgr() Done.\n",__FUNCTION__));\r
+\r
+ status = IoSetDeviceInterfaceState( &fdo->al_ifc_name, TRUE );\r
+ ASSERT( NT_SUCCESS( status ) );\r
+\r
+ status = IoSetDeviceInterfaceState( &fdo->ci_ifc_name, TRUE );\r
+ ASSERT( NT_SUCCESS( status ) );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine undoes anything done in EvtDeviceD0Entry. It is called\r
+ whenever the device leaves the D0 state, which happens when the device is\r
+ stopped, when it is removed, and when it is powered off.\r
+\r
+ The device is still in D0 when this callback is invoked, which means that\r
+ the driver can still touch hardware in this routine.\r
+\r
+ Note that interrupts have already been disabled by the time that this\r
+ callback is invoked.\r
+\r
+ EvtDeviceD0Exit event callback must perform any operations that are\r
+ necessary before the specified device is moved out of the D0 state. If the\r
+ driver needs to save hardware state before the device is powered down, then\r
+ that should be done here.\r
+\r
+ This function runs at PASSIVE_LEVEL, though it is generally not paged. A\r
+ driver can optionally make this function pageable if DO_POWER_PAGABLE is set.\r
+\r
+ Even if DO_POWER_PAGABLE isn't set, this function still runs at\r
+ PASSIVE_LEVEL. In this case, though, the function absolutely must not do\r
+ anything that will cause a page fault.\r
+\r
+Arguments:\r
+\r
+ Device - Handle to a framework device object.\r
+\r
+ TargetState - Device power state which the device will be put in once this\r
+ callback is complete.\r
+\r
+Return Value:\r
+\r
+ NTSTATUS - A failure here will indicate a fatal error in the driver.\r
+ The Framework will attempt to tear down the stack.\r
+\r
+--*/\r
+\r
+static NTSTATUS\r
+Bus_EvtDeviceD0Exit (\r
+ IN WDFDEVICE Device,\r
+ IN WDF_POWER_DEVICE_STATE TargetState )\r
+{\r
+ NTSTATUS status;\r
+ PFDO_BUS_DATA fdo;\r
+\r
+ fdo = FdoGetData(Device);\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER,\r
+ "--> %s() current %s - moving to %s\n",\r
+ DbgDevicePowerString(fdo->DevPowerState),\r
+ DbgDevicePowerString(TargetState));\r
+\r
+ fdo->DevPreviousPowerState = fdo->DevPowerState;\r
+ fdo->DevPowerState = TargetState;\r
+\r
+ switch (TargetState)\r
+ {\r
+ case WdfPowerDeviceD1:\r
+ case WdfPowerDeviceD2:\r
+ case WdfPowerDeviceD3:\r
+\r
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER,\r
+ "%s() Entering a deeper sleep state\n", __FUNCTION__);\r
+ break;\r
+\r
+ case WdfPowerDevicePrepareForHibernation:\r
+\r
+ //\r
+ // Fill in any code to save hardware state here. Do not put in any\r
+ // code to shut the device off. If this device cannot support being\r
+ // in the paging path (or being a parent or grandparent of a paging\r
+ // path device) then this whole case can be deleted.\r
+ //\r
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_POWER,\r
+ "%s() Hibernation? not supported.\n", __FUNCTION__);\r
+ break;\r
+\r
+ case WdfPowerDeviceD3Final:\r
+ //\r
+ // Reset and put the device into a known initial state we're shutting\r
+ // down for the last time.\r
+ //\r
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER,\r
+ "%s() Shutdown - D3Final.\n", __FUNCTION__);\r
+ break;\r
+\r
+ default:\r
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_POWER,\r
+ "%s() Unsupported Power state %s\n", __FUNCTION__,\r
+ DbgDevicePowerString(TargetState));\r
+ break;\r
+ }\r
+\r
+ /* Disable any exported interfaces. */\r
+ status = IoSetDeviceInterfaceState( &fdo->al_ifc_name, FALSE );\r
+ //ASSERT( NT_SUCCESS( status ) );\r
+\r
+ status = IoSetDeviceInterfaceState( &fdo->ci_ifc_name, FALSE );\r
+ //ASSERT( NT_SUCCESS( status ) );\r
+\r
+ cl_obj_destroy( &fdo->p_port_mgr->obj );\r
+ cl_obj_destroy( &fdo->p_iou_mgr->obj );\r
+\r
+ al_cleanup();\r
+\r
+ bus_globals.p_bus_ext = NULL;\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<-- %s()\n", __FUNCTION__);\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ The framework calls a driver's EvtDeviceFileCreate callback when the\r
+ framework receives an IRP_MJ_CREATE request.\r
+ The system sends this request when a user application opens the\r
+ device to perform an I/O operation, such as reading or writing to a device.\r
+ This callback is called in the context of the thread\r
+ that created the IRP_MJ_CREATE request.\r
+\r
+Arguments:\r
+\r
+ Device - Handle to a framework device object.\r
+ FileObject - Pointer to fileobject that represents the open handle.\r
+ CreateParams - Parameters for create\r
+\r
+Return Value:\r
+\r
+ NT status code\r
+\r
+--*/\r
+\r
+static VOID\r
+Bus_EvtDeviceFileCreate ( IN WDFDEVICE Device,\r
+ IN WDFREQUEST Request,\r
+ IN WDFFILEOBJECT FileObject )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+\r
+ UNREFERENCED_PARAMETER(FileObject);\r
+\r
+ KdPrint(("%s() --> Dev %p\n", __FUNCTION__, Device));\r
+\r
+ PAGED_CODE ();\r
+\r
+ //\r
+ // Get the device context given the device handle.\r
+ //\r
+ fdoData = FdoGetData(Device);\r
+\r
+ WdfRequestComplete(Request, STATUS_SUCCESS);\r
+\r
+ KdPrint(("%s() <--\n",__FUNCTION__));\r
+ return;\r
+}\r
+\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ EvtFileClose is the dispatch routine for IRP_MJ_CLOSE. It is called when all\r
+ the handles represented by the FileObject are closed and all the references\r
+ to FileObject are removed.\r
+\r
+ This callback may get called in an arbitrary thread context instead of the\r
+ thread that called CloseHandle. If you want to delete any per FileObject\r
+ context that must be done in the context of the user thread that made the\r
+ Create call, you should do that in the EvtDeviceCleanup callback.\r
+\r
+Arguments:\r
+\r
+ FileObject - Pointer to fileobject that represents the open handle.\r
+\r
+Return Value:\r
+\r
+\r
+--*/\r
+\r
+static VOID\r
+Bus_EvtDeviceFileClose ( IN WDFFILEOBJECT FileObject )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+\r
+ PAGED_CODE ();\r
+\r
+ KdPrint(("%s()--->\n",__FUNCTION__));\r
+\r
+ fdoData = FdoGetData(WdfFileObjectGetDevice(FileObject));\r
+\r
+ KdPrint(("%s()<---\n",__FUNCTION__));\r
+\r
+ return;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ EvtFileCleanup is the dispatch routine for IRP_MJ_CLEANUP.\r
+ Needs to close the FileObj and then cleanup (remove AL?)\r
+\r
+Arguments:\r
+\r
+\r
+Return Value:\r
+\r
+\r
+--*/\r
+\r
+static VOID\r
+Bus_EvtDeviceFileCleanup ( IN WDFFILEOBJECT FileObject )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+\r
+ PAGED_CODE ();\r
+ KdPrint(("--> %s()\n",__FUNCTION__));\r
+\r
+ fdoData = FdoGetData(WdfFileObjectGetDevice(FileObject));\r
+\r
+ KdPrint(("<-- %s()\n",__FUNCTION__));\r
+\r
+ return;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ EvtDeviceSelfManagedIoInit is called by the Framework when the device\r
+ enters the D0 state. Its job is to start any I/O-related actions that the\r
+ Framework isn't managing. This might include releasing queues that are not\r
+ power-managed, that is, the Framework is not automatically holding and\r
+ releasing them across PnP/Power transitions. (The default behavior for\r
+ WDFQUEUE is auto-managed, so most queues don't need to be dealt with here.)\r
+ This might also include setting up non-queue-based actions.\r
+\r
+ If you allow the Framework to manage most or all of your queues, then when\r
+ you build a driver from this sample, you can probably delete this function.\r
+\r
+ In this driver, the SelfManagedIo callbacks are used to implement a\r
+ watchdog timer.\r
+\r
+ This function is not marked pagable because this function is in the\r
+ device power up path. When a function is marked pagable and the code\r
+ section is paged out, it will generate a page fault which could impact\r
+ the fast resume behavior because the client driver will have to wait\r
+ until the system drivers can service this page fault.\r
+\r
+Arguments:\r
+\r
+ Device - Handle to a framework device object.\r
+\r
+Return Value:\r
+\r
+ NTSTATUS - Failures will result in the device stack being torn down.\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_EvtDeviceSelfManagedIoInit( IN WDFDEVICE Device )\r
+{\r
+ NTSTATUS status=STATUS_SUCCESS;\r
+ PFDO_BUS_DATA fdoData;\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s()\n", __FUNCTION__);\r
+\r
+ fdoData = FdoGetData(Device);\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,\r
+ "<-- %s() ret %x\n", __FUNCTION__, status);\r
+\r
+ return status;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ EvtDeviceSelfManagedIoSuspend is called by the Framework before the device\r
+ leaves the D0 state. Its job is to stop any I/O-related actions that the\r
+ Framework isn't managing, and which cannot be handled when the device\r
+ hardware isn't available. In general, this means reversing anything that\r
+ was done in EvtDeviceSelfManagedIoStart.\r
+\r
+ If you allow the Framework to manage most or all of your queues, then when\r
+ you build a driver from this sample, you can probably delete this function.\r
+\r
+Arguments:\r
+\r
+ Device - Handle to a framework device object.\r
+\r
+Return Value:\r
+\r
+ NTSTATUS - Failures will result in the device stack being torn down.\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_EvtDeviceSelfManagedIoSuspend( IN WDFDEVICE Device )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+\r
+ PAGED_CODE();\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s()\n", __FUNCTION__);\r
+\r
+ fdoData = FdoGetData(Device);\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s()\n", __FUNCTION__);\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ EvtDeviceSelfManagedIoRestart is called by the Framework before the device\r
+ is restarted for one of the following reasons:\r
+ a) the PnP resources were rebalanced (framework received\r
+ query-stop and stop IRPS )\r
+ b) the device resumed from a low power state to D0.\r
+\r
+ This function is not marked pagable because this function is in the\r
+ device power up path. When a function is marked pagable and the code\r
+ section is paged out, it will generate a page fault which could impact\r
+ the fast resume behavior because the client driver will have to wait\r
+ until the system drivers can service this page fault.\r
+\r
+Arguments:\r
+\r
+ Device - Handle to a framework device object.\r
+\r
+Return Value:\r
+\r
+ NTSTATUS - Failure will cause the device stack to be torn down.\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_EvtDeviceSelfManagedIoRestart( IN WDFDEVICE Device )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s()\n", __FUNCTION__);\r
+\r
+ fdoData = FdoGetData(Device);\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s()\n", __FUNCTION__);\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ EvtDeviceSelfManagedIoCleanup is called by the Framework when the device is\r
+ being torn down, either in response to the WDM IRP_MN_REMOVE_DEVICE\r
+ It will be called only once. Its job is to stop all outstanding I/O in the driver\r
+ that the Framework is not managing.\r
+\r
+Arguments:\r
+\r
+ Device - Handle to a framework device object.\r
+\r
+Return Value:\r
+\r
+ None\r
+\r
+--*/\r
+\r
+VOID\r
+Bus_EvtDeviceSelfManagedIoCleanup( IN WDFDEVICE Device )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+\r
+ PAGED_CODE();\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s()\n",__FUNCTION__);\r
+\r
+ fdoData = FdoGetData(Device);\r
+\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s()\n",__FUNCTION__);\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ EvtDeviceQueryStop event callback function determines whether a specified\r
+ device can be stopped so that the PnP manager can redistribute system\r
+ hardware resources.\r
+\r
+Arguments:\r
+\r
+ Device - Handle to a framework device object.\r
+\r
+Return Value:\r
+\r
+ SUCCESS - OK to stop the device, otherwise NOT advisable to stop device.\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_EvtDeviceQueryStop ( IN WDFDEVICE Device )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ fdoData = FdoGetData(Device);\r
+ // always OK to STOP the device.\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ EvtDeviceQueryRemove event callback function determines whether a specified\r
+ device can be stopped and removed.\r
+\r
+Arguments:\r
+\r
+ Device - Handle to a framework device object.\r
+\r
+Return Value:\r
+\r
+ SUCCESS - OK to stop the device, otherwise NOT advisable to stop device.\r
+\r
+--*/\r
+\r
+\r
+NTSTATUS\r
+Bus_EvtDeviceQueryRemove ( IN WDFDEVICE Device )\r
+{\r
+ NTSTATUS status = STATUS_SUCCESS;\r
+ PFDO_BUS_DATA p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = FdoGetData(Device);\r
+\r
+ if ( p_ext->n_ci_ifc_ref )\r
+ {\r
+ /*\r
+ * Our interface is still being held by someone.\r
+ * Fail the query.\r
+ */\r
+\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, \r
+ ("Failing IRP_MN_QUERY_REMOVE_DEVICE:\n"\r
+ "\tLowerInterface has %d references\n", \r
+ p_ext->n_ci_ifc_ref ) );\r
+ status = STATUS_UNSUCCESSFUL;\r
+ }\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+\r
+ return status;\r
+}\r
+\r
+\r
+VOID\r
+Bus_EvtDeviceSurpriseRemoval ( IN WDFDEVICE Device )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ fdoData = FdoGetData(Device);\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+VOID\r
+Bus_EvtDeviceUsageNotify (\r
+ IN WDFDEVICE Device,\r
+ IN WDF_SPECIAL_FILE_TYPE NotificationType,\r
+ IN BOOLEAN IsInNotificationPath )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+ UNREFERENCED_PARAMETER( NotificationType );\r
+ UNREFERENCED_PARAMETER( IsInNotificationPath );\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ fdoData = FdoGetData(Device);\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Handle IRP_MN_DEVICE_QUERY_RELATIONS.\r
+ EvtDeviceRelationsQuery event callback reports changes in the relationships\r
+ among devices that are supported by the driver.\r
+\r
+Arguments:\r
+\r
+ Device - Handle to a framework device object.\r
+ RelationType - A DEVICE_RELATION_TYPE-typed enumerator value\r
+\r
+Return Value:\r
+\r
+ SUCCESS - \r
+\r
+--*/\r
+\r
+/*\r
+ Documentation clains most driver do NOT use this callback.\r
+ */\r
+VOID\r
+Bus_EvtDeviceRelationsQuery (\r
+ IN WDFDEVICE Device,\r
+ IN DEVICE_RELATION_TYPE RelationType )\r
+{\r
+ PFDO_BUS_DATA p_ext;\r
+ PCHAR WhoAmI;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = FdoGetData(Device);\r
+ WhoAmI = p_ext->Identity;\r
+\r
+ switch( RelationType )\r
+ {\r
+ case BusRelations:\r
+ TraceEvents( TRACE_LEVEL_INFORMATION, DBG_PNP,\r
+ ("BusRelations for %s\n", WhoAmI) );\r
+ // IRP ignore\r
+ break;\r
+\r
+ case EjectionRelations:\r
+ TraceEvents( TRACE_LEVEL_INFORMATION, DBG_PNP,\r
+ ("EjectionRelations for %s\n", WhoAmI) );\r
+ // IRP ignore\r
+ break;\r
+\r
+ case RemovalRelations:\r
+ TraceEvents( TRACE_LEVEL_INFORMATION, DBG_PNP,\r
+ ("RemovalRelations for %s\n", WhoAmI) );\r
+#if 0 // want to call this... how to get irp?\r
+fdo_query_remove_relations(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp, \r
+ OUT cl_irp_action_t* const p_action )\r
+#endif\r
+ break;\r
+\r
+ case TargetDeviceRelation:\r
+ TraceEvents( TRACE_LEVEL_INFORMATION, DBG_PNP,\r
+ ("TargetDeviceRelation for %s\n", WhoAmI) );\r
+ // IRP ignore\r
+ break;\r
+\r
+ default:\r
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,\r
+ ("Unknown Relation 0x%x on %s\n", RelationType, WhoAmI) );\r
+ break;\r
+ }\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+/*\r
+ * WDFDEVICE object cleanup\r
+ */\r
+\r
+static VOID\r
+Bus_EvtDeviceObjContextCleanup ( IN WDFOBJECT Object )\r
+{\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+ UNREFERENCED_PARAMETER( Object );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\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: bus_pnp.h 10 2005-05-24 00:33:03Z ftillier $\r
+ */\r
+\r
+\r
+\r
+#if !defined _BUS_DRV_PNP_H_\r
+#define _BUS_DRV_PNP_H_\r
+\r
+\r
+#include "bus_driver.h"\r
+#include "iba/ib_al_ifc.h"\r
+\r
+\r
+/****f* InfiniBand Bus Driver: Plug and Play/bus_add_device\r
+* NAME\r
+* bus_add_device\r
+*\r
+* DESCRIPTION\r
+* Main AddDevice entrypoint for the IB Bus driver.\r
+* Adds the bus root functional device object to the device node. The\r
+* bus root FDO performs all PnP operations for fabric attached devices.\r
+*\r
+* SYNOPSIS\r
+*/\r
+NTSTATUS\r
+bus_add_device(\r
+ IN PDRIVER_OBJECT p_driver_obj,\r
+ IN PDEVICE_OBJECT p_pdo );\r
+/*\r
+* PARAMETERS\r
+* p_driver_obj\r
+* Driver object for the BUS driver.\r
+*\r
+* p_pdo\r
+* Pointer to the device object representing the PDO for the device on\r
+* which we are loading.\r
+*\r
+* RETURN VBUSUES\r
+* STATUS_SUCCESS if the device was successfully added.\r
+*\r
+* Other NTSTATUS error values if errors are encountered.\r
+*\r
+* SEE ALSO\r
+*********/\r
+\r
+\r
+void\r
+al_set_ifc(\r
+ OUT ib_al_ifc_t* const p_ifc );\r
+\r
+void\r
+al_ref_ifc(\r
+ IN DEVICE_OBJECT* p_dev_obj );\r
+\r
+NTSTATUS\r
+bus_get_relations(\r
+ IN cl_qlist_t* const p_pdo_list,\r
+ IN const net64_t ca_guid,\r
+ IN IRP* const p_irp );\r
+\r
+#endif // !defined _BUS_DRV_PNP_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: bus_port_mgr.c 931 2008-01-31 09:20:41Z leonidk $\r
+ */\r
+\r
+\r
+#include <iba/ib_types.h>\r
+#include <complib/cl_async_proc.h>\r
+#include <complib/cl_bus_ifc.h>\r
+#include "ib_common.h"\r
+#include "bus_pnp.h"\r
+#include "bus_port_mgr.h"\r
+#include "al_ca.h"\r
+#include "al_mgr.h"\r
+#include <initguid.h>\r
+#include <wdmguid.h>\r
+#include "iba/ipoib_ifc.h"\r
+\r
+\r
+#define IPOIB_DEVICE_ID L"IBA\\IPoIB"\r
+#define IPOIB_COMPAT_ID L"IBA\\SID_1000066a00020000\0\0"\r
+/* Hardware ID is a MULTI_SZ, so is terminated with a double NULL. */\r
+#define IPOIB_HARDWARE_ID IPOIB_DEVICE_ID L"\0"\r
+#define IPOIB_DESCRIPTION L"OpenIB IPoIB Adapter"\r
+\r
+/* {5A9649F4-0101-4a7c-8337-796C48082DA2} */\r
+DEFINE_GUID(GUID_BUS_TYPE_IBA,\r
+0x5a9649f4, 0x101, 0x4a7c, 0x83, 0x37, 0x79, 0x6c, 0x48, 0x8, 0x2d, 0xa2);\r
+\r
+\r
+/*\r
+ * Device extension for IPoIB port PDOs.\r
+ */\r
+typedef struct _bus_port_ext\r
+{\r
+ bus_pdo_ext_t pdo;\r
+\r
+ net64_t port_guid;\r
+ uint32_t n_port;\r
+\r
+ /* Number of references on the upper interface. */\r
+ atomic32_t n_ifc_ref;\r
+\r
+} bus_port_ext_t;\r
+\r
+\r
+port_mgr_t* gp_port_mgr = NULL;\r
+\r
+\r
+/*\r
+ * Function prototypes.\r
+ */\r
+void\r
+destroying_port_mgr(\r
+ IN cl_obj_t* p_obj );\r
+\r
+void\r
+free_port_mgr(\r
+ IN cl_obj_t* p_obj );\r
+\r
+ib_api_status_t\r
+bus_reg_port_pnp( void );\r
+\r
+ib_api_status_t\r
+port_mgr_pnp_cb(\r
+ IN ib_pnp_rec_t* p_pnp_rec );\r
+\r
+ib_api_status_t\r
+port_mgr_port_add(\r
+ IN ib_pnp_port_rec_t* p_pnp_rec );\r
+\r
+void\r
+port_mgr_port_remove(\r
+ IN ib_pnp_port_rec_t* p_pnp_rec );\r
+\r
+static NTSTATUS\r
+port_start(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+port_query_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static void\r
+port_release_resources(\r
+ IN DEVICE_OBJECT* const p_dev_obj );\r
+\r
+static NTSTATUS\r
+port_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+port_surprise_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+port_query_capabilities(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+port_query_target_relations(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+port_query_device_id(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp );\r
+\r
+static NTSTATUS\r
+port_query_hardware_ids(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp );\r
+\r
+static NTSTATUS\r
+port_query_compatible_ids(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp );\r
+\r
+static NTSTATUS\r
+port_query_unique_id(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp );\r
+\r
+static NTSTATUS\r
+port_query_description(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp );\r
+\r
+static NTSTATUS\r
+port_query_location(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp );\r
+\r
+static NTSTATUS\r
+port_query_bus_info(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+port_query_ipoib_ifc(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IO_STACK_LOCATION* const p_io_stack );\r
+\r
+static NTSTATUS\r
+port_query_interface(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+static NTSTATUS\r
+port_set_power(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action );\r
+\r
+\r
+/* All PnP code is called at passive, so it can all be paged out. */\r
+#ifdef ALLOC_PRAGMA\r
+#pragma alloc_text (PAGE, port_start)\r
+#pragma alloc_text (PAGE, port_query_remove)\r
+#pragma alloc_text (PAGE, port_release_resources)\r
+#pragma alloc_text (PAGE, port_remove)\r
+#pragma alloc_text (PAGE, port_surprise_remove)\r
+#pragma alloc_text (PAGE, port_query_capabilities)\r
+#pragma alloc_text (PAGE, port_query_target_relations)\r
+#pragma alloc_text (PAGE, port_query_device_id)\r
+#pragma alloc_text (PAGE, port_query_hardware_ids)\r
+#pragma alloc_text (PAGE, port_query_compatible_ids)\r
+#pragma alloc_text (PAGE, port_query_unique_id)\r
+#pragma alloc_text (PAGE, port_query_description)\r
+#pragma alloc_text (PAGE, port_query_location)\r
+#pragma alloc_text (PAGE, port_query_bus_info)\r
+#pragma alloc_text (PAGE, port_query_ipoib_ifc)\r
+#pragma alloc_text (PAGE, port_query_interface)\r
+#pragma alloc_text (PAGE_PNP, port_set_power)\r
+#pragma alloc_text (PAGE, port_mgr_port_add)\r
+#pragma alloc_text (PAGE, port_mgr_port_remove)\r
+#endif\r
+\r
+\r
+/*\r
+ * Global virtual function pointer tables shared between all\r
+ * instances of Port PDOs.\r
+ */\r
+static const cl_vfptr_pnp_po_t vfptr_port_pnp = {\r
+ "IPoIB",\r
+ port_start,\r
+ cl_irp_succeed,\r
+ cl_irp_succeed,\r
+ cl_irp_succeed,\r
+ port_query_remove,\r
+ port_release_resources,\r
+ port_remove,\r
+ cl_irp_succeed,\r
+ port_surprise_remove,\r
+ port_query_capabilities,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ cl_irp_succeed,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ port_query_target_relations,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ port_query_bus_info,\r
+ port_query_interface,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ cl_irp_complete,\r
+ cl_irp_succeed, // QueryPower\r
+ port_set_power, // SetPower\r
+ cl_irp_unsupported, // PowerSequence\r
+ cl_irp_unsupported // WaitWake\r
+};\r
+\r
+\r
+static const cl_vfptr_query_txt_t vfptr_port_query_txt = {\r
+ port_query_device_id,\r
+ port_query_hardware_ids,\r
+ port_query_compatible_ids,\r
+ port_query_unique_id,\r
+ port_query_description,\r
+ port_query_location\r
+};\r
+\r
+\r
+/*\r
+ * Create the AL load service.\r
+ */\r
+ib_api_status_t\r
+create_port_mgr(\r
+ OUT port_mgr_t** const pp_port_mgr )\r
+{\r
+ ib_api_status_t status;\r
+ cl_status_t cl_status;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ CL_ASSERT( !gp_port_mgr );\r
+\r
+ gp_port_mgr = cl_zalloc( sizeof( port_mgr_t ) );\r
+ if( !gp_port_mgr )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to allocate port manager.\n") );\r
+ return IB_INSUFFICIENT_MEMORY;\r
+ }\r
+\r
+ /* Construct the load service. */\r
+ cl_obj_construct( &gp_port_mgr->obj, AL_OBJ_TYPE_LOADER );\r
+ cl_mutex_construct( &gp_port_mgr->pdo_mutex );\r
+ cl_qlist_init( &gp_port_mgr->port_list );\r
+\r
+ cl_status = cl_mutex_init( &gp_port_mgr->pdo_mutex );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ free_port_mgr( &gp_port_mgr->obj );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("cl_mutex_init returned %#x.\n", cl_status) );\r
+ return ib_convert_cl_status( cl_status );\r
+ }\r
+\r
+ /* Initialize the load service object. */\r
+ cl_status = cl_obj_init( &gp_port_mgr->obj, CL_DESTROY_SYNC,\r
+ destroying_port_mgr, NULL, free_port_mgr );\r
+ if( cl_status != CL_SUCCESS )\r
+ {\r
+ free_port_mgr( &gp_port_mgr->obj );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("cl_obj_init returned %#x.\n", cl_status) );\r
+ return ib_convert_cl_status( cl_status );\r
+ }\r
+\r
+ /* Register for port PnP events. */\r
+ status = bus_reg_port_pnp();\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ cl_obj_destroy( &gp_port_mgr->obj );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("bus_reg_port_pnp returned %s.\n", ib_get_err_str(status)) );\r
+ return status;\r
+ }\r
+\r
+ *pp_port_mgr = gp_port_mgr;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+/*\r
+ * Pre-destroy the load service.\r
+ */\r
+void\r
+destroying_port_mgr(\r
+ IN cl_obj_t* p_obj )\r
+{\r
+ ib_api_status_t status;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ CL_ASSERT( p_obj );\r
+ CL_ASSERT( gp_port_mgr == PARENT_STRUCT( p_obj, port_mgr_t, obj ) );\r
+ UNUSED_PARAM( p_obj );\r
+\r
+ /* Deregister for port PnP events. */\r
+ if( gp_port_mgr->h_pnp )\r
+ {\r
+ status = ib_dereg_pnp( gp_port_mgr->h_pnp,\r
+ (ib_pfn_destroy_cb_t)cl_obj_deref );\r
+ CL_ASSERT( status == IB_SUCCESS );\r
+ }\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+/*\r
+ * Free the load service.\r
+ */\r
+void\r
+free_port_mgr(\r
+ IN cl_obj_t* p_obj )\r
+{\r
+ bus_pdo_ext_t *p_ext;\r
+ cl_list_item_t *p_list_item;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ CL_ASSERT( p_obj );\r
+ CL_ASSERT( gp_port_mgr == PARENT_STRUCT( p_obj, port_mgr_t, obj ) );\r
+\r
+ /*\r
+ * Mark all IPoIB PDOs as no longer present. This will cause them\r
+ * to be removed when they process the IRP_MN_REMOVE_DEVICE.\r
+ */\r
+ p_list_item = cl_qlist_remove_head( &gp_port_mgr->port_list );\r
+ while( p_list_item != cl_qlist_end( &gp_port_mgr->port_list ) )\r
+ {\r
+ p_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
+ p_list_item = cl_qlist_remove_head( &gp_port_mgr->port_list );\r
+ if( p_ext->cl_ext.pnp_state == SurpriseRemoved )\r
+ {\r
+ CL_ASSERT( !p_ext->b_present );\r
+ p_ext->b_reported_missing = TRUE;\r
+ BUS_TRACE( BUS_DBG_PNP, ("%s: PDO %p, ext %p, present %d, missing %d .\n",\r
+ p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, p_ext->b_reported_missing ) );\r
+ continue;\r
+ }\r
+ if( p_ext->h_ca )\r
+ {\r
+ /* Invalidate bus relations for the HCA. */\r
+ IoInvalidateDeviceRelations(\r
+ p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
+\r
+ /* Release the reference on the CA object. */\r
+ deref_al_obj( &p_ext->h_ca->obj );\r
+ }\r
+ BUS_TRACE( BUS_DBG_PNP, ("Deleted device %s: PDO %p, ext %p\n",\r
+ p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext ) );\r
+ IoDeleteDevice( p_ext->cl_ext.p_self_do );\r
+ }\r
+\r
+ cl_mutex_destroy( &gp_port_mgr->pdo_mutex );\r
+ cl_obj_deinit( p_obj );\r
+ cl_free( gp_port_mgr );\r
+ gp_port_mgr = NULL;\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+/*\r
+ * Register the load service for the given PnP class events.\r
+ */\r
+ib_api_status_t\r
+bus_reg_port_pnp( void )\r
+{\r
+ ib_pnp_req_t pnp_req;\r
+ ib_api_status_t status;\r
+\r
+ cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) );\r
+ pnp_req.pnp_class = IB_PNP_PORT | IB_PNP_FLAG_REG_SYNC;\r
+ pnp_req.pnp_context = gp_port_mgr;\r
+ pnp_req.pfn_pnp_cb = port_mgr_pnp_cb;\r
+\r
+ status = ib_reg_pnp( gh_al, &pnp_req, &gp_port_mgr->h_pnp );\r
+\r
+ if( status == IB_SUCCESS )\r
+ {\r
+ /* Reference the load service on behalf of the ib_reg_pnp call. */\r
+ cl_obj_ref( &gp_port_mgr->obj );\r
+ }\r
+\r
+ return status;\r
+}\r
+\r
+\r
+/*\r
+ * Load service PnP event callback.\r
+ */\r
+ib_api_status_t\r
+port_mgr_pnp_cb(\r
+ IN ib_pnp_rec_t* p_pnp_rec )\r
+{\r
+ ib_api_status_t status;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ CL_ASSERT( p_pnp_rec );\r
+ CL_ASSERT( gp_port_mgr == p_pnp_rec->pnp_context );\r
+\r
+ switch( p_pnp_rec->pnp_event )\r
+ {\r
+ case IB_PNP_PORT_ADD:\r
+ status = port_mgr_port_add( (ib_pnp_port_rec_t*)p_pnp_rec );\r
+ break;\r
+\r
+ case IB_PNP_PORT_REMOVE:\r
+ port_mgr_port_remove( (ib_pnp_port_rec_t*)p_pnp_rec );\r
+\r
+ default:\r
+ status = IB_SUCCESS;\r
+ break;\r
+ }\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+\r
+/*\r
+ * Called to get bus relations for an HCA.\r
+ */\r
+NTSTATUS\r
+port_mgr_get_bus_relations(\r
+ IN const net64_t ca_guid,\r
+ IN IRP* const p_irp )\r
+{\r
+ NTSTATUS status;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
+ status = bus_get_relations( &gp_port_mgr->port_list, ca_guid, p_irp );\r
+ cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static ib_api_status_t\r
+__port_was_hibernated(\r
+ IN ib_pnp_port_rec_t* p_pnp_rec )\r
+{\r
+ NTSTATUS status;\r
+ cl_list_item_t *p_list_item;\r
+ bus_port_ext_t *p_port_ext;\r
+ bus_pdo_ext_t *p_pdo_ext = NULL;\r
+ size_t n_devs = 0;\r
+ cl_qlist_t* p_pdo_list = &gp_port_mgr->port_list;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+ \r
+ cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
+ \r
+ /* Count the number of child devices. */\r
+ for( p_list_item = cl_qlist_head( p_pdo_list );\r
+ p_list_item != cl_qlist_end( p_pdo_list );\r
+ p_list_item = cl_qlist_next( p_list_item ) )\r
+ {\r
+ p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
+ p_port_ext = (bus_port_ext_t*)p_pdo_ext;\r
+ \r
+ if( p_pdo_ext->b_present && p_pdo_ext->b_hibernating &&\r
+ (p_port_ext->port_guid == p_pnp_rec->p_port_attr->port_guid) )\r
+ {\r
+ n_devs++;\r
+ break;\r
+ }\r
+\r
+ BUS_TRACE( BUS_DBG_PNP, \r
+ ("Skipped PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
+ p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, \r
+ p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
+ p_pdo_ext->b_hibernating, p_port_ext->port_guid ) );\r
+ }\r
+\r
+ if (n_devs)\r
+ {\r
+ /* Take a reference on the parent HCA. */\r
+ p_pdo_ext->h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid );\r
+ if( !p_pdo_ext->h_ca )\r
+ {\r
+ BUS_TRACE( BUS_DBG_ERROR, ("acquire_ca failed to find CA by guid %I64x\n",\r
+ p_pnp_rec->p_ca_attr->ca_guid ) );\r
+ status = IB_INVALID_GUID;\r
+ }\r
+ else \r
+ {\r
+ p_pdo_ext->b_hibernating = FALSE;\r
+ p_pnp_rec->pnp_rec.context = p_pdo_ext;\r
+ status = IB_SUCCESS;\r
+ p_port_ext = (bus_port_ext_t*)p_pdo_ext;\r
+ BUS_TRACE( BUS_DBG_PNP, \r
+ ("Found PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
+ p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, \r
+ p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
+ p_pdo_ext->b_hibernating, p_port_ext->port_guid ) );\r
+ }\r
+ }\r
+ else \r
+ {\r
+ BUS_TRACE( BUS_DBG_PNP, ("Failed to find PDO for guid %I64x .\n",\r
+ p_pnp_rec->p_ca_attr->ca_guid ) );\r
+ status = IB_NOT_FOUND;\r
+ }\r
+\r
+ cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+ib_api_status_t\r
+port_mgr_port_add(\r
+ IN ib_pnp_port_rec_t* p_pnp_rec )\r
+{\r
+ NTSTATUS status;\r
+ DEVICE_OBJECT *p_pdo;\r
+ bus_port_ext_t *p_port_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ if( !bus_globals.b_report_port_nic )\r
+ {\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return IB_NOT_DONE;\r
+ }\r
+\r
+ /* Upon hibernating of the computer IB_BUS driver doesn't remove PDO, but\r
+ marks with a flag. So we first try to find an existing PDO for this port,\r
+ marked with this flag. If it was found, we turn off the flag and use this PDO */\r
+ status = __port_was_hibernated(p_pnp_rec);\r
+ if( status != IB_NOT_FOUND )\r
+ {\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+ }\r
+\r
+ /* Create the PDO for the new port device. */\r
+ status = IoCreateDevice( bus_globals.p_driver_obj, sizeof(bus_port_ext_t),\r
+ NULL, FILE_DEVICE_CONTROLLER,\r
+ FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,\r
+ FALSE, &p_pdo );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("IoCreateDevice returned %08x.\n", status) );\r
+ return IB_ERROR;\r
+ }\r
+\r
+ /* Initialize the device extension. */\r
+ cl_init_pnp_po_ext( p_pdo, NULL, p_pdo, bus_globals.dbg_lvl,\r
+ &vfptr_port_pnp, &vfptr_port_query_txt );\r
+\r
+ /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */\r
+ p_pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;\r
+\r
+ p_port_ext = p_pdo->DeviceExtension;\r
+ p_port_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0;\r
+ p_port_ext->pdo.p_parent_ext = bus_globals.p_bus_ext;\r
+ p_port_ext->pdo.b_present = TRUE;\r
+ p_port_ext->pdo.b_reported_missing = FALSE;\r
+ p_port_ext->pdo.b_hibernating = FALSE;\r
+ p_port_ext->pdo.p_po_work_item = NULL;\r
+ BUS_TRACE( BUS_DBG_PNP, ("Created device for %s: PDO %p,ext %p, present %d, missing %d .\n",\r
+ p_port_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_pdo, p_port_ext, p_port_ext->pdo.b_present, \r
+ p_port_ext->pdo.b_reported_missing ) );\r
+\r
+ /* Cache the CA GUID. */\r
+ p_port_ext->pdo.ca_guid = p_pnp_rec->p_ca_attr->ca_guid;\r
+\r
+ /* Take a reference on the parent HCA. */\r
+ p_port_ext->pdo.h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid );\r
+ if( !p_port_ext->pdo.h_ca )\r
+ {\r
+ BUS_TRACE( BUS_DBG_PNP, ("Deleted device: PDO %p\n", p_pdo ));\r
+ IoDeleteDevice( p_pdo );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("acquire_ca failed to find CA.\n") );\r
+ return IB_INVALID_GUID;\r
+ }\r
+ p_port_ext->port_guid = p_pnp_rec->p_port_attr->port_guid;\r
+ p_port_ext->n_port = p_pnp_rec->p_port_attr->port_num;\r
+\r
+ /* Store the device extension in the port vector for future queries. */\r
+ cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
+ cl_qlist_insert_tail( &gp_port_mgr->port_list,\r
+ &p_port_ext->pdo.list_item );\r
+ cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
+\r
+ /*\r
+ * Set the context of the PNP event. The context is passed in for future\r
+ * events on the same port.\r
+ */\r
+ p_pnp_rec->pnp_rec.context = p_port_ext;\r
+\r
+ /* Tell the PnP Manager to rescan for the HCA's bus relations. */\r
+ IoInvalidateDeviceRelations(\r
+ p_port_ext->pdo.h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
+\r
+ /* Invalidate removal relations for the bus driver. */\r
+ IoInvalidateDeviceRelations(\r
+ bus_globals.p_bus_ext->cl_ext.p_pdo, RemovalRelations );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+void\r
+port_mgr_port_remove(\r
+ IN ib_pnp_port_rec_t* p_pnp_rec )\r
+{\r
+ bus_pdo_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ /* The PNP record's context is the port extension. */\r
+ p_ext = p_pnp_rec->pnp_rec.context;\r
+ CL_ASSERT( p_ext );\r
+\r
+ /*\r
+ * Flag the port PDO as no longer being present. We have to wait until\r
+ * the PnP manager removes it to clean up. However, we do release the\r
+ * reference on the CA object in order to allow the removal of the HCA\r
+ * to proceed should it occur before the port's PDO is cleaned up.\r
+ */\r
+ cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
+ CL_ASSERT( p_ext->h_ca );\r
+\r
+ if( p_ext->b_hibernating )\r
+ {\r
+ BUS_TRACE( BUS_DBG_PNP, ("Skip port removing for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d .\n",\r
+ p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, \r
+ p_ext->b_reported_missing, p_ext->b_hibernating ) );\r
+ goto hca_deref;\r
+ }\r
+\r
+ p_ext->b_present = FALSE;\r
+ BUS_TRACE( BUS_DBG_PNP, ("Mark removing %s: PDO %p, ext %p, present %d, missing %d .\n",\r
+ p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, p_ext->b_reported_missing ) );\r
+\r
+ /* Invalidate removal relations for the bus driver. */\r
+ IoInvalidateDeviceRelations( bus_globals.p_bus_ext->cl_ext.p_pdo,\r
+ RemovalRelations );\r
+\r
+ /* Invalidate bus relations for the HCA. */\r
+ IoInvalidateDeviceRelations(\r
+ p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
+\r
+hca_deref:\r
+ deref_al_obj( &p_ext->h_ca->obj );\r
+ p_ext->h_ca = NULL;\r
+ cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_start(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ bus_pdo_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( p_irp );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ /* Notify the Power Manager that the device is started. */\r
+ PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
+ *p_action = IrpComplete;\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_query_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ bus_port_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( p_irp );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ *p_action = IrpComplete;\r
+ if( p_ext->n_ifc_ref )\r
+ {\r
+ /*\r
+ * Our interface is still being held by someone.\r
+ * Rollback the PnP state that was changed in the complib handler.\r
+ */\r
+ cl_rollback_pnp_state( &p_ext->pdo.cl_ext );\r
+\r
+ /* Fail the query. */\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, ("Failing IRP_MN_QUERY_REMOVE_DEVICE:\n"\r
+ "\tInterface has %d reference\n", p_ext->n_ifc_ref ) );\r
+ return STATUS_UNSUCCESSFUL;\r
+ }\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static void\r
+port_release_resources(\r
+ IN DEVICE_OBJECT* const p_dev_obj )\r
+{\r
+ bus_port_ext_t *p_ext;\r
+ POWER_STATE po_state;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ /* Remove this PDO from its list. */\r
+ cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
+ BUS_TRACE( BUS_DBG_PNP, ("Removing port from vector: PDO %p, ext %p\n", p_dev_obj, p_ext) );\r
+ cl_qlist_remove_item( &gp_port_mgr->port_list, &p_ext->pdo.list_item );\r
+ cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
+ po_state.DeviceState = PowerDeviceD3;\r
+ PoSetPowerState( p_ext->pdo.cl_ext.p_pdo, DevicePowerState, po_state );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ bus_port_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ if( p_ext->pdo.b_present )\r
+ {\r
+ CL_ASSERT( p_ext->pdo.cl_ext.pnp_state != NotStarted );\r
+ CL_ASSERT( !p_ext->pdo.b_reported_missing );\r
+ /* Reset the state to NotStarted. CompLib set it to Deleted. */\r
+ cl_set_pnp_state( &p_ext->pdo.cl_ext, NotStarted );\r
+ /* Don't delete the device. It may simply be disabled. */\r
+ *p_action = IrpComplete;\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device still present: PDO %p, ext %p\n", p_dev_obj, p_ext) );\r
+ return STATUS_SUCCESS;\r
+ }\r
+\r
+ if( !p_ext->pdo.b_reported_missing )\r
+ {\r
+ /* Reset the state to RemovePending. Complib set it to Deleted. */\r
+ cl_rollback_pnp_state( &p_ext->pdo.cl_ext );\r
+ *p_action = IrpComplete;\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device not reported missing yet: PDO %p, ext %p\n", p_dev_obj, p_ext) );\r
+ return STATUS_SUCCESS;\r
+ }\r
+\r
+ /* Wait for all I/O operations to complete. */\r
+ IoReleaseRemoveLockAndWait( &p_ext->pdo.cl_ext.remove_lock, p_irp );\r
+\r
+ /* Release resources if it was not done yet. */\r
+ if( p_ext->pdo.cl_ext.last_pnp_state != SurpriseRemoved )\r
+ p_ext->pdo.cl_ext.vfptr_pnp_po->pfn_release_resources( p_dev_obj );\r
+\r
+ p_irp->IoStatus.Status = STATUS_SUCCESS;\r
+ IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+\r
+ BUS_TRACE( BUS_DBG_PNP, ("Deleted device %s: PDO %p(=%p), ext %p\n",\r
+ p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, p_dev_obj, p_ext ) );\r
+ IoDeleteDevice( p_dev_obj );\r
+\r
+ *p_action = IrpDoNothing;\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_surprise_remove(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ bus_port_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( p_irp );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+ p_ext->pdo.b_present = FALSE;\r
+ p_ext->pdo.b_reported_missing = TRUE;\r
+ BUS_TRACE( BUS_DBG_PNP, ("%s: PDO %p, ext %p, present %d, missing %d .\n",\r
+ p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, \r
+ p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) );\r
+\r
+ *p_action = IrpComplete;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_query_capabilities(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ DEVICE_CAPABILITIES *p_caps;\r
+ IO_STACK_LOCATION *p_io_stack;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( p_dev_obj );\r
+\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+ p_caps = p_io_stack->Parameters.DeviceCapabilities.Capabilities;\r
+\r
+ p_caps->DeviceD1 = FALSE;\r
+ p_caps->DeviceD2 = FALSE;\r
+ p_caps->LockSupported = FALSE;\r
+ p_caps->EjectSupported = FALSE;\r
+ p_caps->Removable = FALSE;\r
+ p_caps->DockDevice = FALSE;\r
+ p_caps->UniqueID = TRUE;\r
+ p_caps->SilentInstall = TRUE;\r
+ p_caps->RawDeviceOK = FALSE;\r
+ p_caps->SurpriseRemovalOK = FALSE;\r
+ p_caps->WakeFromD0 = FALSE;\r
+ p_caps->WakeFromD1 = FALSE;\r
+ p_caps->WakeFromD2 = FALSE;\r
+ p_caps->WakeFromD3 = FALSE;\r
+ p_caps->HardwareDisabled = FALSE;\r
+ p_caps->DeviceState[PowerSystemWorking] = PowerDeviceD0;\r
+ p_caps->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;\r
+ p_caps->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;\r
+ p_caps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;\r
+ p_caps->DeviceState[PowerSystemHibernate] = PowerDeviceD3;\r
+ p_caps->DeviceState[PowerSystemShutdown] = PowerDeviceD3;\r
+ p_caps->SystemWake = PowerSystemUnspecified;\r
+ p_caps->DeviceWake = PowerDeviceUnspecified;\r
+ p_caps->D1Latency = 0;\r
+ p_caps->D2Latency = 0;\r
+ p_caps->D3Latency = 0;\r
+\r
+ *p_action = IrpComplete;\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_query_target_relations(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ NTSTATUS status;\r
+ DEVICE_RELATIONS *p_rel;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ *p_action = IrpComplete;\r
+\r
+ status = cl_alloc_relations( p_irp, 1 );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("cl_alloc_relations returned 0x%08x.\n", status) );\r
+ return status;\r
+ }\r
+\r
+ p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
+ p_rel->Count = 1;\r
+ p_rel->Objects[0] = p_dev_obj;\r
+\r
+ ObReferenceObject( p_dev_obj );\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_query_device_id(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ OUT IRP* const p_irp )\r
+{\r
+ WCHAR *p_string;\r
+ bus_port_ext_t *p_ext;\r
+ \r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ \r
+ p_ext = (bus_port_ext_t*)p_dev_obj->DeviceExtension;\r
+ if( !p_ext->pdo.b_present )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ /* Device ID is "IBA\SID_<sid> where <sid> is the IPoIB Service ID. */\r
+ p_string = ExAllocatePoolWithTag( PagedPool, sizeof(IPOIB_DEVICE_ID), 'vedq' );\r
+ if( !p_string )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to allocate device ID buffer (%d bytes).\n",\r
+ sizeof(IPOIB_DEVICE_ID)) );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+ cl_memcpy( p_string, IPOIB_DEVICE_ID, sizeof(IPOIB_DEVICE_ID) );\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_query_hardware_ids(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ OUT IRP* const p_irp )\r
+{\r
+ WCHAR *p_string;\r
+ bus_port_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+\r
+ p_ext = (bus_port_ext_t*)p_dev_obj->DeviceExtension;\r
+ if( !p_ext->pdo.b_present )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ p_string = ExAllocatePoolWithTag( PagedPool, sizeof(IPOIB_HARDWARE_ID), 'ihqp' );\r
+ if( !p_string )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to allocate hardware ID buffer (%d bytes).\n",\r
+ sizeof(IPOIB_HARDWARE_ID)) );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+ cl_memcpy( p_string, IPOIB_HARDWARE_ID, sizeof(IPOIB_HARDWARE_ID) );\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_query_compatible_ids(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ OUT IRP* const p_irp )\r
+{\r
+ WCHAR *p_string;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( p_dev_obj );\r
+\r
+ p_string = ExAllocatePoolWithTag( PagedPool, sizeof(IPOIB_COMPAT_ID), 'icqp' );\r
+ if( !p_string )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to allocate compatible ID buffer (%d bytes).\n",\r
+ sizeof(IPOIB_COMPAT_ID)) );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+ cl_memcpy( p_string, IPOIB_COMPAT_ID, sizeof(IPOIB_COMPAT_ID) );\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_query_unique_id(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ OUT IRP* const p_irp )\r
+{\r
+ NTSTATUS status;\r
+ WCHAR *p_string;\r
+ bus_port_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ if( !p_ext->pdo.b_present )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ /* The instance ID is the port GUID. */\r
+ p_string = ExAllocatePoolWithTag( PagedPool, sizeof(WCHAR) * 17, 'iuqp' );\r
+ if( !p_string )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to allocate instance ID buffer (%d bytes).\n",\r
+ sizeof(WCHAR) * 17) );\r
+ return STATUS_NO_MEMORY;\r
+ }\r
+\r
+ status = RtlStringCchPrintfW( p_string, 17, L"%016I64x", p_ext->port_guid );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ CL_ASSERT( NT_SUCCESS( status ) );\r
+ ExFreePool( p_string );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("RtlStringCchPrintfW returned %08x.\n", status) );\r
+ return status;\r
+ }\r
+\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_query_description(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ OUT IRP* const p_irp )\r
+{\r
+ WCHAR *p_string;\r
+ bus_port_ext_t *p_ext;\r
+ \r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+ if( !p_ext->pdo.b_present )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+\r
+ /* The instance ID is the port GUID. */\r
+ p_string = ExAllocatePoolWithTag( PagedPool, sizeof(IPOIB_DESCRIPTION), 'edqp' );\r
+ if( !p_string )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to allocate device description buffer (%d bytes).\n",\r
+ sizeof(IPOIB_DESCRIPTION)) );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+ cl_memcpy( p_string, IPOIB_DESCRIPTION, sizeof(IPOIB_DESCRIPTION) );\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_query_location(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ OUT IRP* const p_irp )\r
+{\r
+ WCHAR *p_string;\r
+ bus_port_ext_t *p_ext;\r
+ size_t size;\r
+ ULONG len;\r
+ NTSTATUS status;\r
+ DEVICE_OBJECT *p_hca_dev;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+ if( !p_ext->pdo.b_present )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ p_hca_dev = p_ext->pdo.h_ca->obj.p_ci_ca->verbs.p_hca_dev;\r
+\r
+ /* Get the length of the HCA's location. */\r
+ status = IoGetDeviceProperty( p_hca_dev,\r
+ DevicePropertyLocationInformation, 0, NULL, &len );\r
+ if( status != STATUS_BUFFER_TOO_SMALL )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("IoGetDeviceProperty for device location size returned %08x.\n",\r
+ status) );\r
+ return status;\r
+ }\r
+\r
+ /*\r
+ * Allocate the string buffer to hold the HCA's location along with the\r
+ * port number. The port number is 32-bits, so in decimal it can be at\r
+ * most 10 characters.\r
+ */\r
+ size = len + sizeof(L", port ") + (sizeof(WCHAR) * 10);\r
+ if( size > (USHORT)-1 )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Length beyond limits.\n") );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ p_string = ExAllocatePoolWithTag( PagedPool, size, 'olqp' );\r
+ if( !p_string )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to allocate device location buffer (%d bytes).\n", len) );\r
+ return STATUS_NO_MEMORY;\r
+ }\r
+\r
+ /* Get the HCA's location information. */\r
+ status = IoGetDeviceProperty( p_hca_dev,\r
+ DevicePropertyLocationInformation, len, p_string, &len );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ ExFreePool( p_string );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("IoGetDeviceProperty for device location returned %08x.\n",\r
+ status) );\r
+ return status;\r
+ }\r
+\r
+ /* Append the port number to the HCA's location. */\r
+ status = RtlStringCbPrintfW( p_string + (len/2) - 1, size - len + 1,\r
+ L", port %d", p_ext->n_port );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ CL_ASSERT( NT_SUCCESS( status ) );\r
+ ExFreePool( p_string );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("RtlStringCbPrintfW returned %08x.\n", status) );\r
+ return status;\r
+ }\r
+\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_query_bus_info(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ PNP_BUS_INFORMATION *p_bus_info;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ UNUSED_PARAM( p_dev_obj );\r
+\r
+ *p_action = IrpComplete;\r
+\r
+ p_bus_info = ExAllocatePoolWithTag( PagedPool, sizeof(PNP_BUS_INFORMATION), 'ibqp' );\r
+ if( !p_bus_info )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to allocate PNP_BUS_INFORMATION (%d bytes).\n",\r
+ sizeof(PNP_BUS_INFORMATION)) );\r
+ return STATUS_INSUFFICIENT_RESOURCES;\r
+ }\r
+\r
+ p_bus_info->BusTypeGuid = GUID_BUS_TYPE_IBA;\r
+ //TODO: Memory from Intel - storage miniport would not stay loaded unless\r
+ //TODO: bus type was PCI. Look here if SRP is having problems staying\r
+ //TODO: loaded.\r
+ p_bus_info->LegacyBusType = PNPBus;\r
+ p_bus_info->BusNumber = 0;\r
+\r
+ p_irp->IoStatus.Information = (ULONG_PTR)p_bus_info;\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_query_ipoib_ifc(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IO_STACK_LOCATION* const p_io_stack )\r
+{\r
+ NTSTATUS status;\r
+ ib_al_ifc_t *p_ifc;\r
+ ib_al_ifc_data_t *p_ifc_data;\r
+ ipoib_ifc_data_t *p_ipoib_data;\r
+ bus_port_ext_t *p_ext;\r
+ const GUID *p_guid;\r
+ \r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+\r
+ BUS_TRACE( BUS_DBG_PNP, ("Query i/f for %s: PDO %p (=%p),ext %p, present %d, missing %d .\n",\r
+ p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, \r
+ p_dev_obj, p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) );\r
+\r
+ /* Get the interface. */\r
+ status = cl_fwd_query_ifc(\r
+ p_ext->pdo.p_parent_ext->cl_ext.p_self_do, p_io_stack );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Failed to forward interface query: %08X\n", status) );\r
+ return status;\r
+ }\r
+\r
+ if( !p_io_stack->Parameters.QueryInterface.InterfaceSpecificData )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR, ("No interface specific data!\n") );\r
+ return status;\r
+ }\r
+\r
+ p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
+\r
+ p_ifc_data = (ib_al_ifc_data_t*)\r
+ p_io_stack->Parameters.QueryInterface.InterfaceSpecificData;\r
+ p_guid = p_ifc_data->type;\r
+ if( !IsEqualGUID( p_guid, &GUID_IPOIB_INTERFACE_DATA ) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, ("Unsupported interface data: \n\t"\r
+ "0x%08x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x,"\r
+ "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x.\n",\r
+ p_guid->Data1, p_guid->Data2, p_guid->Data3,\r
+ p_guid->Data4[0], p_guid->Data4[1], p_guid->Data4[2],\r
+ p_guid->Data4[3], p_guid->Data4[4], p_guid->Data4[5],\r
+ p_guid->Data4[6], p_guid->Data4[7]) );\r
+ return status;\r
+ }\r
+\r
+ if( p_ifc_data->version != IPOIB_INTERFACE_DATA_VERSION )\r
+ {\r
+ p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context );\r
+ BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
+ ("Unsupported version %d, expected %d\n",\r
+ p_ifc_data->version, IPOIB_INTERFACE_DATA_VERSION) );\r
+ return STATUS_NOT_SUPPORTED;\r
+ }\r
+\r
+ ASSERT( p_ifc_data->p_data );\r
+\r
+ if( p_ifc_data->size != sizeof(ipoib_ifc_data_t) )\r
+ {\r
+ p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context );\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP,\r
+ ("Buffer too small (%d given, %d required).\n",\r
+ p_ifc_data->size,\r
+ sizeof(ipoib_ifc_data_t)) );\r
+ return STATUS_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ /* Set the interface data. */\r
+ p_ipoib_data = (ipoib_ifc_data_t*)p_ifc_data->p_data;\r
+\r
+ p_ipoib_data->ca_guid = p_ext->pdo.h_ca->obj.p_ci_ca->verbs.guid;\r
+ p_ipoib_data->port_guid = p_ext->port_guid;\r
+ p_ipoib_data->port_num = (uint8_t)p_ext->n_port;\r
+\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS\r
+port_query_interface(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ bus_pdo_ext_t *p_ext;\r
+ NTSTATUS status;\r
+ IO_STACK_LOCATION *p_io_stack;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+#pragma warning( push, 3 )\r
+ PAGED_CODE();\r
+#pragma warning( pop )\r
+\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+ /* Bottom of the stack - IRP must be completed. */\r
+ *p_action = IrpComplete;\r
+\r
+ /* Compare requested GUID with our supported interface GUIDs. */\r
+ if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
+ &GUID_IB_AL_INTERFACE ) )\r
+ {\r
+ status = port_query_ipoib_ifc( p_dev_obj, p_io_stack );\r
+ }\r
+ else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
+ &GUID_BUS_INTERFACE_STANDARD ) )\r
+ {\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+ if( !p_ext->h_ca ||\r
+ !p_ext->b_present ||\r
+ p_ext->b_reported_missing )\r
+ {\r
+ return STATUS_NO_SUCH_DEVICE;\r
+ }\r
+\r
+ status = cl_fwd_query_ifc(\r
+ p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, p_io_stack );\r
+ }\r
+ else\r
+ {\r
+ status = p_irp->IoStatus.Status;\r
+ }\r
+ \r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return status;\r
+}\r
+\r
+\r
+/* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
+static void\r
+__HibernateUpWorkItem(\r
+ IN DEVICE_OBJECT* p_dev_obj,\r
+ IN void* context )\r
+{\r
+ IO_STACK_LOCATION *p_io_stack;\r
+ bus_pdo_ext_t *p_ext;\r
+ IRP *p_irp;\r
+ POWER_STATE powerState;\r
+\r
+ BUS_ENTER( BUS_DBG_POWER );\r
+\r
+ p_ext = (bus_pdo_ext_t*)p_dev_obj->DeviceExtension;\r
+ p_irp = (IRP*)context;\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+ IoFreeWorkItem( p_ext->p_po_work_item );\r
+ p_ext->p_po_work_item = NULL;\r
+\r
+ while (!p_ext->h_ca) {\r
+ BUS_TRACE( BUS_DBG_PNP, ("Waiting for the end of HCA registration ... \n"));\r
+ cl_thread_suspend( 200 ); /* suspend for 200 ms */\r
+ }\r
+\r
+ p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
+ powerState = PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
+\r
+ BUS_TRACE( BUS_DBG_POWER, \r
+ ("PoSetPowerState: old state %d, new state to %d\n", \r
+ powerState.DeviceState, p_ext->dev_po_state ));\r
+\r
+ p_irp->IoStatus.Status = STATUS_SUCCESS;\r
+ PoStartNextPowerIrp( p_irp );\r
+ IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+ IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
+\r
+ BUS_EXIT( BUS_DBG_POWER );\r
+}\r
+\r
+\r
+/*\r
+ * The PDOs created by the IB Bus driver are software devices. As such,\r
+ * all power states are supported. It is left to the HCA power policy\r
+ * owner to handle which states can be supported by the HCA.\r
+ */\r
+static NTSTATUS\r
+port_set_power(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IRP* const p_irp,\r
+ OUT cl_irp_action_t* const p_action )\r
+{\r
+ NTSTATUS status = STATUS_SUCCESS;\r
+ IO_STACK_LOCATION *p_io_stack;\r
+ bus_pdo_ext_t *p_ext;\r
+\r
+ BUS_ENTER( BUS_DBG_POWER );\r
+\r
+ p_ext = p_dev_obj->DeviceExtension;\r
+ p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+ BUS_TRACE( BUS_DBG_POWER, \r
+ ("SET_POWER for PDO %p (ext %p): type %s, state %d, action %d \n",\r
+ p_dev_obj, p_ext,\r
+ (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
+ p_io_stack->Parameters.Power.State.DeviceState, \r
+ p_io_stack->Parameters.Power.ShutdownType ));\r
+\r
+ if ((p_io_stack->Parameters.Power.Type == SystemPowerState) &&\r
+ (p_io_stack->Parameters.Power.State.SystemState ==PowerSystemHibernate ||\r
+ p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 ))\r
+ {\r
+ BUS_TRACE( BUS_DBG_POWER, ("Setting b_hibernating flag for PDO %p \n", p_dev_obj));\r
+ p_ext->b_hibernating = TRUE;\r
+ }\r
+\r
+ if( p_io_stack->Parameters.Power.Type == DevicePowerState )\r
+ {\r
+ /* after hibernation PDO is not ready for work. we need to wait for finishing of the HCA registration */\r
+ if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && p_ext->b_hibernating)\r
+ {\r
+ /* Process in a work item - deregister_ca and HcaDeinit block. */\r
+ ASSERT( !p_ext->p_po_work_item );\r
+ p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj );\r
+ if( !p_ext->p_po_work_item )\r
+ status = STATUS_INSUFFICIENT_RESOURCES;\r
+ else {\r
+ /* Process in work item callback. */\r
+ IoMarkIrpPending( p_irp );\r
+ IoQueueWorkItem(\r
+ p_ext->p_po_work_item, __HibernateUpWorkItem, DelayedWorkQueue, p_irp );\r
+ *p_action = IrpDoNothing;\r
+ BUS_EXIT( BUS_DBG_POWER );\r
+ return STATUS_PENDING;\r
+ }\r
+ }\r
+\r
+ /* Notify the power manager. */\r
+ p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
+ PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
+ }\r
+\r
+ *p_action = IrpComplete;\r
+ BUS_EXIT( BUS_DBG_POWER );\r
+ return status;\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: bus_port_mgr.h 9 2005-05-23 22:38:08Z ftillier $\r
+ */\r
+\r
+\r
+#if !defined( __BUS_PORT_MGR_H__ )\r
+#define __BUS_PORT_MGR_H__\r
+\r
+#include <iba/ib_al.h>\r
+#include <complib/cl_mutex.h>\r
+#include <complib/cl_obj.h>\r
+\r
+\r
+/* Global load service */\r
+typedef struct _port_mgr\r
+{\r
+ cl_obj_t obj;\r
+ ib_pnp_handle_t h_pnp; /* Handle for port PnP events */\r
+\r
+ /* Mutex protects both pointer vectors. */\r
+ cl_mutex_t pdo_mutex;\r
+\r
+ /* Pointer vector of child IPoIB port PDOs. */\r
+ cl_qlist_t port_list;\r
+\r
+} port_mgr_t;\r
+\r
+\r
+ib_api_status_t\r
+create_port_mgr(\r
+ OUT port_mgr_t** const pp_port_mgr );\r
+\r
+\r
+NTSTATUS\r
+port_mgr_get_bus_relations(\r
+ IN const net64_t ca_guid,\r
+ IN IRP* const p_irp );\r
+\r
+#endif\r
--- /dev/null
+/*++\r
+Module Name:\r
+\r
+ driver.h\r
+\r
+Abstract:\r
+\r
+ This module contains the common declarations for the InfiniBand Fabric bus,\r
+ function and filter drivers.\r
+\r
+Environment:\r
+\r
+ kernel mode only\r
+\r
+--*/\r
+\r
+//#include "public.h"\r
+\r
+//\r
+// Define an Interface Guid to access the proprietary InfiniBand Fabric (IBF)\r
+// interface.\r
+// This guid is used to identify a specific interface in IRP_MN_QUERY_INTERFACE\r
+// handler.\r
+//\r
+\r
+DEFINE_GUID(GUID_IBF_INTERFACE_STANDARD,\r
+ 0xe0b27630, 0x5434, 0x11d3, 0xb8, 0x90, 0x0, 0xc0, 0x4f, 0xad, 0x51, 0x71);\r
+// {E0B27630-5434-11d3-B890-00C04FAD5171}\r
+\r
+\r
+//\r
+// GUID definition are required to be outside of header inclusion pragma to avoid\r
+// error during precompiled headers.\r
+//\r
+\r
+#ifndef __DRIVER_H\r
+#define __DRIVER_H\r
+\r
+//\r
+// Define Interface reference/dereference routines for\r
+// Interfaces exported by IRP_MN_QUERY_INTERFACE\r
+//\r
+\r
+typedef VOID (*PINTERFACE_REFERENCE)(PVOID Context);\r
+typedef VOID (*PINTERFACE_DEREFERENCE)(PVOID Context);\r
+\r
+typedef\r
+BOOLEAN\r
+(*PIBF_GET_CRISPINESS_LEVEL)(\r
+ IN PVOID Context,\r
+ OUT PUCHAR Level\r
+ );\r
+\r
+typedef\r
+BOOLEAN\r
+(*PIBF_SET_CRISPINESS_LEVEL)(\r
+ IN PVOID Context,\r
+ OUT UCHAR Level\r
+ );\r
+\r
+typedef\r
+BOOLEAN\r
+(*PIBF_IS_CHILD_PROTECTED)(\r
+ IN PVOID Context\r
+ );\r
+\r
+//\r
+// InfiniBand Fabric Bus Interface\r
+//\r
+typedef struct _IB_BUS_INTERFACE_STANDARD {\r
+ INTERFACE InterfaceHeader;\r
+ PIBF_GET_CRISPINESS_LEVEL GetCrispinessLevel;\r
+ PIBF_SET_CRISPINESS_LEVEL SetCrispinessLevel;\r
+ PIBF_IS_CHILD_PROTECTED IsSafetyLockEnabled;\r
+} IB_BUS_INTERFACE_STANDARD, *PIB_BUS_INTERFACE_STANDARD;\r
+\r
+\r
+#endif\r
+\r
--- /dev/null
+[CatalogHeader]\r
+Name=ib_bus.cat\r
+PublicVersion=0x0000001\r
+EncodingType=0x00010001\r
+CATATTR1=0x10010001:OSAttr:2:6.0\r
+[CatalogFiles]\r
+<hash>ib_bus.inf=ib_bus.inf\r
+<hash>ibbus.sys=ibbus.sys\r
+<hash>ibiou.sys=ibiou.sys\r
+<hash>ibal.dll=ibal.dll\r
+<hash>complib.dll=complib.dll\r
+<hash>ibald.dll=ibald.dll\r
+<hash>complibd.dll=complibd.dll\r
+<hash>cl32d.dll=cl32d.dll\r
+<hash>cl32.dll=cl32.dll\r
+<hash>ibal32d.dll=ibal32d.dll\r
+<hash>ibal32.dll=ibal32.dll\r
+\r
--- /dev/null
+; OpenIB InfiniBand Bus Driver.\r
+; Copyright 2005 SilverStorm Technologies all Rights Reserved.\r
+; Copyright 2006 Mellanox Technologies all Rights Reserved.\r
+;\r
+; install: devcon update mthca.inf PCI\VEN_15B3\r
+; remove: devcon remove PCI\VEN_15B3\r
+;\r
+\r
+[Version]\r
+Signature="$WINDOWS NT$"\r
+;Class=System\r
+;ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318}\r
+Class = InfiniBandHca\r
+ClassGUID = {58517E00-D3CF-40c9-A679-CEE5752F4491}\r
+\r
+Provider=%OPENIB%\r
+DriverVer=03/26/2008,1.0.0000.955\r
+CatalogFile=ib_bus.cat\r
+\r
+; ================= Device Install section =====================\r
+\r
+; 64-bit platforms also copy 32-bit user-mode binaries.\r
+[DestinationDirs]\r
+DefaultDestDir=%DIRID_DRIVERS%\r
+Ibbus.UMCopyFiles=%DIRID_SYSTEM%\r
+Ibbus.WOW64CopyFiles=%DIRID_SYSTEM_X86%\r
+\r
+[SourceDisksNames.x86]\r
+1=%DiskId%,,,""\r
+\r
+[SourceDisksNames.amd64]\r
+1=%DiskId%,,,""\r
+\r
+[SourceDisksNames.ia64]\r
+1=%DiskId%,,,""\r
+\r
+[SourceDisksFiles.x86]\r
+ibbus.sys=1\r
+ibiou.sys=1\r
+ibal.dll=1\r
+complib.dll=1\r
+ibald.dll=1\r
+complibd.dll=1\r
+\r
+[SourceDisksFiles.amd64]\r
+ibbus.sys=1\r
+ibiou.sys=1\r
+ibal.dll=1\r
+complib.dll=1\r
+ibald.dll=1\r
+complibd.dll=1\r
+cl32d.dll=1\r
+cl32.dll=1\r
+ibal32d.dll=1\r
+ibal32.dll=1\r
+\r
+[SourceDisksFiles.ia64]\r
+ibbus.sys=1\r
+ibiou.sys=1\r
+ibal.dll=1\r
+complib.dll=1\r
+ibald.dll=1\r
+complibd.dll=1\r
+cl32d.dll=1\r
+cl32.dll=1\r
+ibal32d.dll=1\r
+ibal32.dll=1\r
+\r
+[Manufacturer]\r
+%OPENIB% = Ibbus.DeviceSection,ntx86,ntamd64,ntia64\r
+%SST% = SST.DeviceSection,ntx86,ntamd64,ntia64\r
+\r
+[Ibbus.DeviceSection]\r
+; empty since we don't support W9x/Me\r
+\r
+[Ibbus.DeviceSection.ntx86]\r
+%Ibbus.DeviceDesc% = Ibbus.DDInstall,{94f41ced-78eb-407c-b5df-958040af0fd8}\r
+%Iou.DeviceDesc% = Iou.DDInstall,IBA\IB_IOU\r
+\r
+[Ibbus.DeviceSection.ntamd64]\r
+%Ibbus.DeviceDesc% = Ibbus.DDInstall,{94f41ced-78eb-407c-b5df-958040af0fd8}\r
+%Iou.DeviceDesc% = Iou.DDInstall,IBA\IB_IOU\r
+\r
+[Ibbus.DeviceSection.ntia64]\r
+%Ibbus.DeviceDesc% = Ibbus.DDInstall,{94f41ced-78eb-407c-b5df-958040af0fd8}\r
+%Iou.DeviceDesc% = Iou.DDInstall,IBA\IB_IOU\r
+\r
+[SST.DeviceSection]\r
+; empty since we don't support W9x/Me\r
+\r
+[SST.DeviceSection.ntx86]\r
+%VFx.DeviceDesc% = Iou.DDInstall,IBA\V00066aP0060,IBA\V00066aP0010\r
+%VEx.DeviceDesc% = Iou.DDInstall,IBA\V00066aP0058\r
+%FVIC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00dd\r
+%EVIC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00de\r
+%BC2FC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00e0\r
+%BC2GE.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00e1\r
+\r
+[SST.DeviceSection.ntamd64]\r
+%VFx.DeviceDesc% = Iou.DDInstall,IBA\V00066aP0060,IBA\V00066aP0010\r
+%VEx.DeviceDesc% = Iou.DDInstall,IBA\V00066aP0058\r
+%FVIC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00dd\r
+%EVIC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00de\r
+%BC2FC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00e0\r
+%BC2GE.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00e1\r
+\r
+[SST.DeviceSection.ntia64]\r
+%VFx.DeviceDesc% = Iou.DDInstall,IBA\V00066aP0060,IBA\V00066aP0010\r
+%VEx.DeviceDesc% = Iou.DDInstall,IBA\V00066aP0058\r
+%FVIC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00dd\r
+%EVIC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00de\r
+%BC2FC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00e0\r
+%BC2GE.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00e1\r
+\r
+[Ibbus.DDInstall.ntx86]\r
+CopyFiles = Ibbus.CopyFiles\r
+CopyFiles = Ibbus.UMCopyFiles\r
+\r
+[Ibbus.DDInstall.ntamd64]\r
+CopyFiles = Ibbus.CopyFiles\r
+CopyFiles = Ibbus.UMCopyFiles\r
+CopyFiles = Ibbus.WOW64CopyFiles\r
+\r
+[Ibbus.DDInstall.ntia64]\r
+CopyFiles = Ibbus.CopyFiles\r
+CopyFiles = Ibbus.UMCopyFiles\r
+CopyFiles = Ibbus.WOW64CopyFiles\r
+\r
+[Ibbus.DDInstall.ntx86.Services]\r
+AddService = ibbus,%SPSVCINST_ASSOCSERVICE%,Ibbus.ServiceInstall\r
+\r
+[Ibbus.DDInstall.ntamd64.Services]\r
+AddService = ibbus,%SPSVCINST_ASSOCSERVICE%,Ibbus.ServiceInstall\r
+\r
+[Ibbus.DDInstall.ntia64.Services]\r
+AddService = ibbus,%SPSVCINST_ASSOCSERVICE%,Ibbus.ServiceInstall\r
+\r
+[Iou.DDInstall.nt]\r
+CopyFiles = Iou.CopyFiles\r
+\r
+[Iou.DDInstall.nt.Services]\r
+AddService = ibiou,%SPSVCINST_ASSOCSERVICE%,Iou.ServiceInstall\r
+\r
+[Ibbus.CopyFiles]\r
+ibbus.sys\r
+\r
+[Ibbus.UMCopyFiles]\r
+complib.dll,,,2\r
+ibal.dll,,,2\r
+complibd.dll,,,2\r
+ibald.dll,,,2\r
+\r
+[Ibbus.WOW64CopyFiles]\r
+complib.dll,cl32.dll,,2\r
+ibal.dll,ibal32.dll,,2\r
+complibd.dll,cl32d.dll,,2\r
+ibald.dll,ibal32d.dll,,2\r
+\r
+[Iou.CopyFiles]\r
+ibiou.sys\r
+\r
+;\r
+; ============= Service Install section ==============\r
+;\r
+\r
+[Ibbus.ServiceInstall]\r
+DisplayName = %Ibbus.ServiceDesc%\r
+ServiceType = %SERVICE_KERNEL_DRIVER%\r
+StartType = %SERVICE_DEMAND_START%\r
+ErrorControl = %SERVICE_ERROR_NORMAL%\r
+ServiceBinary = %12%\ibbus.sys\r
+LoadOrderGroup = extended base\r
+AddReg = Ibbus.ParamsReg\r
+Dependencies = mthca\r
+\r
+[Iou.ServiceInstall]\r
+DisplayName = %Iou.ServiceDesc%\r
+ServiceType = %SERVICE_KERNEL_DRIVER%\r
+StartType = %SERVICE_DEMAND_START%\r
+ErrorControl = %SERVICE_ERROR_NORMAL%\r
+ServiceBinary = %12%\ibiou.sys\r
+AddReg = Iou.ParamsReg\r
+\r
+[Ibbus.ParamsReg]\r
+HKR,"Parameters","DebugFlags",%REG_DWORD%,0x80000000\r
+HKR,"Parameters","ReportPortNIC",%REG_DWORD%,1\r
+HKR,"Parameters","IbalDebugLevel",%REG_DWORD%,2\r
+HKR,"Parameters","IbalDebugFlags",%REG_DWORD%,0x00ffffff\r
+HKR,"Parameters","SmiPollInterval",%REG_DWORD_NO_CLOBBER%,20000\r
+HKR,"Parameters","IocQueryTimeout",%REG_DWORD_NO_CLOBBER%,250\r
+HKR,"Parameters","IocQueryRetries",%REG_DWORD_NO_CLOBBER%,4\r
+HKR,"Parameters","IocPollInterval",%REG_DWORD_NO_CLOBBER%,30000\r
+\r
+[Iou.ParamsReg]\r
+HKR,"Parameters","DebugLevel",%REG_DWORD%,2\r
+HKR,"Parameters","DebugFlags",%REG_DWORD%,0x00ffffff\r
+\r
+;-------------- WDF Coinstaller installation\r
+\r
+[DestinationDirs]\r
+Ibbus.DDInstall.CoInstaller_CopyFiles = 11\r
+\r
+[Ibbus.DDInstall.NT.CoInstallers]\r
+AddReg=Ibbus.DDInstall.CoInstaller_AddReg\r
+CopyFiles=Ibbus.DDInstall.CoInstaller_CopyFiles\r
+\r
+[Ibbus.DDInstall.CoInstaller_CopyFiles]\r
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll\r
+\r
+[SourceDisksFiles.amd64]\r
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1\r
+\r
+[Ibbus.DDInstall.CoInstaller_AddReg]\r
+HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"\r
+\r
+[Ibbus.DDInstall.NT.Wdf]\r
+KmdfService = ibbus, ibbus_wdfsect\r
+[ibbus_wdfsect]\r
+KmdfLibraryVersion = $KMDFVERSION$\r
+\r
+\r
+[Strings]\r
+OPENIB = "OpenIB Alliance"\r
+SST = "SilverStorm Technologies"\r
+Ibbus.DeviceDesc = "InfiniBand Fabric"\r
+VFx.DeviceDesc = "SilverStorm VFx"\r
+VEx.DeviceDesc = "SilverStorm VEx"\r
+FVIC.DeviceDesc = "SilverStorm FVIC"\r
+EVIC.DeviceDesc = "SilverStorm EVIC"\r
+BC2FC.DeviceDesc = "QLogic InfiniBand Fibre Channel Bridge Module"\r
+BC2GE.DeviceDesc = "QLogic InfiniBand Ethernet Bridge Module"\r
+\r
+Iou.DeviceDesc = "InfiniBand I/O Unit"\r
+Ibbus.ServiceDesc = "OpenIB InfiniBand Bus Driver"\r
+Ibal.ServiceDesc = "OpenIB InfiniBand Access Layer"\r
+Iou.ServiceDesc = "OpenIB InfiniBand I/O Unit Driver"\r
+DiskId = "OpenIB InfiniBand Access Layer installation disk"\r
+SPSVCINST_NULL = 0x0\r
+SPSVCINST_ASSOCSERVICE = 0x00000002\r
+SERVICE_KERNEL_DRIVER = 1\r
+SERVICE_DEMAND_START = 3\r
+SERVICE_ERROR_NORMAL = 1\r
+REG_DWORD = 0x00010001\r
+REG_DWORD_NO_CLOBBER = 0x00010003\r
+DIRID_SYSTEM = 11\r
+DIRID_DRIVERS = 12\r
+DIRID_SYSTEM_X86 = 16425\r
--- /dev/null
+#PRAGMA AUTORECOVER\r
+\r
+[Dynamic, Provider("WMIProv"),\r
+ WMI,\r
+ Description("InfiniBand fabric bus driver information"),\r
+ guid("{0006A660-8F12-11d2-B854-00C04FAD5171}"),\r
+ locale("MS\\0x409")]\r
+class IbFabricBusInformation\r
+{\r
+ [key, read]\r
+ string InstanceName;\r
+ [read] boolean Active;\r
+\r
+ [WmiDataId(1),\r
+ read,\r
+ Description("Number of errors that occurred on this device")]\r
+ uint32 ErrorCount;\r
+\r
+ [WmiDataId(2),\r
+ read,\r
+ write,\r
+ Description("The DebugPrintLevel property indicates the debug output level of IB Fabric bus device.")]\r
+ uint32 DebugPrintLevel;\r
+\r
+};\r
+\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2008 Intel Corporation. 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_DRV_SYSTEM\r
+\r
+#ifdef _DEBUG_\r
+#define VER_FILEDESCRIPTION_STR "InfiniBand Fabric Bus Driver [KMDF] (Debug)"\r
+#else\r
+#define VER_FILEDESCRIPTION_STR "InfiniBand Fabric Bus Driver [KMDF]"\r
+#endif\r
+\r
+#define VER_INTERNALNAME_STR "ibbus.sys"\r
+#define VER_ORIGINALFILENAME_STR "ibbus.sys"\r
+\r
+#include <common.ver>\r
+\r
+MofResourceName MOFDATA ib_bus.bmf\r
--- /dev/null
+/*++\r
+Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved\r
+\r
+Module Name:\r
+\r
+ ib_bus_public.h\r
+\r
+Abstract:\r
+\r
+ This module contains the common declarations shared by driver\r
+ and user applications.\r
+\r
+Environment:\r
+\r
+ user and kernel\r
+\r
+--*/\r
+\r
+//\r
+// Define an Interface Guid for bus enumerator class.\r
+// This GUID is used to register (IoRegisterDeviceInterface)\r
+// an instance of an interface so that enumerator application\r
+// can send an ioctl to the bus driver.\r
+//\r
+\r
+DEFINE_GUID (GUID_DEVINTERFACE_BUSENUM_IBF,\r
+ 0xD35F7840, 0x6A0C, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71);\r
+// {D35F7840-6A0C-11d2-B841-00C04FAD5171}\r
+\r
+//\r
+// Define an Interface Guid for toaster device class.\r
+// This GUID is used to register (IoRegisterDeviceInterface)\r
+// an instance of an interface so that user application\r
+// can control the toaster device.\r
+//\r
+\r
+DEFINE_GUID (GUID_DEVINTERFACE_IB_HCA,\r
+ 0x781EF630, 0x72B2, 0x11d2, 0xB8, 0x52, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71);\r
+//{781EF630-72B2-11d2-B852-00C04FAD5171}\r
+\r
+//\r
+// Define a Setup Class GUID for Toaster Class. This is same\r
+// as the TOASTSER CLASS guid in the INF files.\r
+//\r
+\r
+DEFINE_GUID (GUID_DEVCLASS_IB_FABRIC,\r
+ 0xB85B7C50, 0x6A01, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71);\r
+//{B85B7C50-6A01-11d2-B841-00C04FAD5171}\r
+\r
+//\r
+// Define a WMI GUID to get busenum info.\r
+//\r
+\r
+DEFINE_GUID (IBF_BUS_WMI_STD_DATA_GUID,\r
+ 0x0006A660, 0x8F12, 0x11d2, 0xB8, 0x54, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71);\r
+//{0006A660-8F12-11d2-B854-00C04FAD5171}\r
+\r
+//\r
+// Define a WMI GUID to get IB Fabric device info.\r
+\r
+DEFINE_GUID (IBF_WMI_STD_DATA_GUID,\r
+ 0xBBA21300L, 0x6DD3, 0x11d2, 0xB8, 0x44, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71);\r
+\r
+//\r
+// Define a WMI GUID to represent device arrival notification WMIEvent class.\r
+//\r
+\r
+DEFINE_GUID (IBF_NOTIFY_DEVICE_ARRIVAL_EVENT,\r
+ 0x1cdaff1, 0xc901, 0x45b4, 0xb3, 0x59, 0xb5, 0x54, 0x27, 0x25, 0xe2, 0x9c);\r
+// {01CDAFF1-C901-45b4-B359-B5542725E29C}\r
+\r
+\r
+//\r
+// GUID definition is required to be outside of header inclusion pragma to avoid\r
+// error during precompiled headers.\r
+//\r
+\r
+#ifndef __IB_PUBLIC_H\r
+#define __IB_PUBLIC_H\r
+\r
+#define BUS_HARDWARE_IDS L"{B85B7C50-6A01-11d2-B841-00C04FAD5171}\\MsToaster\0"\r
+#define BUS_HARDWARE_IDS_LENGTH sizeof (BUS_HARDWARE_IDS)\r
+\r
+#define BUSENUM_COMPATIBLE_IDS L"{B85B7C50-6A01-11d2-B841-00C04FAD5171}\\MsCompatibleToaster\0"\r
+#define BUSENUM_COMPATIBLE_IDS_LENGTH sizeof(BUSENUM_COMPATIBLE_IDS)\r
+\r
+\r
+#define FILE_DEVICE_BUSENUM FILE_DEVICE_BUS_EXTENDER\r
+\r
+#define BUSENUM_IOCTL(_index_) \\r
+ CTL_CODE (FILE_DEVICE_BUSENUM, _index_, METHOD_BUFFERED, FILE_READ_DATA)\r
+\r
+#define IOCTL_BUSENUM_PLUGIN_HARDWARE BUSENUM_IOCTL (0x0)\r
+#define IOCTL_BUSENUM_UNPLUG_HARDWARE BUSENUM_IOCTL (0x1)\r
+#define IOCTL_BUSENUM_EJECT_HARDWARE BUSENUM_IOCTL (0x2)\r
+#define IOCTL_IBF_DONT_DISPLAY_IN_UI_DEVICE BUSENUM_IOCTL (0x3)\r
+\r
+//\r
+// Data structure used in PlugIn and UnPlug ioctls\r
+//\r
+\r
+typedef struct _BUSENUM_PLUGIN_HARDWARE\r
+{\r
+ //\r
+ // sizeof (struct _BUSENUM_HARDWARE)\r
+ //\r
+ IN ULONG Size;\r
+\r
+ //\r
+ // Unique serial number of the device to be enumerated.\r
+ // Enumeration will be failed if another device on the\r
+ // bus has the same serail number.\r
+ //\r
+\r
+ IN ULONG SerialNo;\r
+\r
+ //\r
+ // An array of (zero terminated wide character strings). The array itself\r
+ // also null terminated (ie, MULTI_SZ)\r
+ //\r
+ #pragma warning(disable:4200) // nonstandard extension used\r
+\r
+ IN WCHAR HardwareIDs[];\r
+\r
+ #pragma warning(default:4200)\r
+\r
+} BUSENUM_PLUGIN_HARDWARE, *PBUSENUM_PLUGIN_HARDWARE;\r
+\r
+typedef struct _BUSENUM_UNPLUG_HARDWARE\r
+{\r
+ //\r
+ // sizeof (struct _REMOVE_HARDWARE)\r
+ //\r
+\r
+ IN ULONG Size;\r
+\r
+ //\r
+ // Serial number of the device to be plugged out\r
+ //\r
+\r
+ ULONG SerialNo;\r
+\r
+ ULONG Reserved[2];\r
+\r
+} BUSENUM_UNPLUG_HARDWARE, *PBUSENUM_UNPLUG_HARDWARE;\r
+\r
+typedef struct _BUSENUM_EJECT_HARDWARE\r
+{\r
+ //\r
+ // sizeof (struct _EJECT_HARDWARE)\r
+ //\r
+\r
+ IN ULONG Size;\r
+\r
+ //\r
+ // Serial number of the device to be ejected\r
+ //\r
+\r
+ ULONG SerialNo;\r
+\r
+ ULONG Reserved[2];\r
+\r
+} BUSENUM_EJECT_HARDWARE, *PBUSENUM_EJECT_HARDWARE;\r
+\r
+#endif\r
+\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
+_LNG=$(LANGUAGE)\r
+_INX=.\r
+STAMP=stampinf -f $@ -a $(_BUILDARCH) -k $(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR)\r
+\r
+$(OBJ_PATH)\$(O)\$(INF_NAME).inf: $(_INX)\$(INF_NAME).inx \r
+ copy $(_INX)\$(@B).inx $@\r
+ $(STAMP)\r
+\r
+$(OBJ_PATH)\$(O)\ib_bus.bmf: ib_bus.mof\r
+ mofcomp -B:$@ ib_bus.mof\r
+ wmimofck $@\r
+ wmimofck -m -h$(OBJ_PATH)\$O\ib_busMof.h -w$(OBJ_PATH)\$(O)\htm $@\r
+ \r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) Microsoft Corporation. All rights reserved.\r
+\r
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY\r
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR\r
+ PURPOSE.\r
+\r
+Module Name:\r
+\r
+ TRACE.h\r
+\r
+Abstract:\r
+\r
+ Header file for the debug tracing related function defintions and macros.\r
+ HEXDUMP is not defined by default. So we have to provide a localwpp.ini file\r
+ that defines type.\r
+\r
+Environment:\r
+\r
+ Kernel mode\r
+\r
+--*/\r
+\r
+#include <evntrace.h> // For TRACE_LEVEL definitions\r
+\r
+#if !defined(EVENT_TRACING)\r
+\r
+//\r
+// TODO: These defines are missing in evntrace.h\r
+// in some DDK build environments (XP).\r
+//\r
+ #define TRACE_LEVEL_NONE 0\r
+ #define TRACE_LEVEL_ALWAYS 0\r
+ #define TRACE_LEVEL_CRITICAL 1\r
+ #define TRACE_LEVEL_FATAL 1\r
+ #define TRACE_LEVEL_ERROR 2\r
+ #define TRACE_LEVEL_WARNING 3\r
+ #define TRACE_LEVEL_INFORMATION 4\r
+ #define TRACE_LEVEL_VERBOSE 5\r
+ #define TRACE_LEVEL_RESERVED6 6\r
+ #define TRACE_LEVEL_RESERVED7 7\r
+ #define TRACE_LEVEL_RESERVED8 8\r
+ #define TRACE_LEVEL_RESERVED9 9\r
+\r
+//\r
+// Define Debug Flags\r
+//\r
+#define DBG_INIT 0x00000001\r
+#define DBG_PNP 0x00000002\r
+#define DBG_POWER 0x00000004\r
+#define DBG_WMI 0x00000008\r
+#define DBG_CREATE_CLOSE 0x00000010\r
+#define DBG_IOCTLS 0x00000020\r
+#define DBG_WRITE 0x00000040\r
+#define DBG_READ 0x00000080\r
+#define DBG_DPC 0x00000100\r
+#define DBG_INTERRUPT 0x00000200\r
+#define DBG_LOCKS 0x00000400\r
+#define DBG_QUEUEING 0x00000800\r
+#define DBG_HW_ACCESS 0x00001000\r
+#define DBG_PORT 0x00002000\r
+#define DBG_IOU 0x00004000\r
+#define DBG_TRACE 0x00008000\r
+#define DBG_ALL 0xFFFFFFFF\r
+\r
+#define BUS_DBG_DRIVER DBG_INIT\r
+#define BUS_DBG_DRV BUS_DBG_DRIVER\r
+#define BUS_DBG_PNP DBG_PNP\r
+#define BUS_DBG_POWER DBG_POWER\r
+\r
+#define BUS_DBG_ERROR 0x80000000 \r
+\r
+\r
+VOID\r
+TraceEvents (\r
+ IN ULONG DebugPrintLevel,\r
+ IN ULONG DebugPrintFlag,\r
+ IN PCCHAR DebugMessage,\r
+ ...\r
+ );\r
+\r
+#define Hexdump(x) // Used for HEXDUMP in case tracing is enabled\r
+#define WPP_INIT_TRACING(DriverObject, RegistryPath)\r
+#define WPP_CLEANUP(DriverObject)\r
+\r
+#else\r
+//\r
+// If software tracing is defined in the sources file..\r
+// WPP_DEFINE_CONTROL_GUID specifies the GUID used for this driver.\r
+// *** REPLACE THE GUID WITH YOUR OWN UNIQUE ID ***\r
+// WPP_DEFINE_BIT allows setting debug bit masks to selectively print.\r
+// The names defined in the WPP_DEFINE_BIT call define the actual names\r
+// that are used to control the level of tracing for the control guid\r
+// specified.\r
+//\r
+// Name of the logger is PciDrv and the guid is\r
+// {BC6C9364-FC67-42c5-ACF7-ABED3B12ECC6}\r
+// (0xbc6c9364, 0xfc67, 0x42c5, 0xac, 0xf7, 0xab, 0xed, 0x3b, 0x12, 0xec, 0xc6);\r
+//\r
+\r
+#define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings\r
+\r
+#define WPP_CONTROL_GUIDS \\r
+ WPP_DEFINE_CONTROL_GUID(PciDrvTraceGuid,(bc6c9364,fc67,42c5,acf7,abed3b12ecc6), \\r
+ WPP_DEFINE_BIT(DBG_INIT) /* bit 0 = 0x00000001 */ \\r
+ WPP_DEFINE_BIT(DBG_PNP) /* bit 1 = 0x00000002 */ \\r
+ WPP_DEFINE_BIT(DBG_POWER) /* bit 2 = 0x00000004 */ \\r
+ WPP_DEFINE_BIT(DBG_WMI) /* bit 3 = 0x00000008 */ \\r
+ WPP_DEFINE_BIT(DBG_CREATE_CLOSE) /* bit 4 = 0x00000010 */ \\r
+ WPP_DEFINE_BIT(DBG_IOCTLS) /* bit 5 = 0x00000020 */ \\r
+ WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \\r
+ WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \\r
+ WPP_DEFINE_BIT(DBG_DPC) /* bit 8 = 0x00000100 */ \\r
+ WPP_DEFINE_BIT(DBG_INTERRUPT) /* bit 9 = 0x00000200 */ \\r
+ WPP_DEFINE_BIT(DBG_LOCKS) /* bit 10 = 0x00000400 */ \\r
+ WPP_DEFINE_BIT(DBG_QUEUEING) /* bit 11 = 0x00000800 */ \\r
+ WPP_DEFINE_BIT(DBG_HW_ACCESS) /* bit 12 = 0x00001000 */ \\r
+ /* You can have up to 32 defines. If you want more than that,\\r
+ you have to provide another trace control GUID */\\r
+ )\r
+\r
+\r
+#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags)\r
+#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)\r
+\r
+#pragma warning(disable:4204) // C4204 nonstandard extension used : non-constant aggregate initializer\r
+\r
+//\r
+// Define the 'xstr' structure for logging buffer and length pairs\r
+// and the 'log_xstr' function which returns it to create one in-place.\r
+// this enables logging of complex data types.\r
+//\r
+typedef struct xstr { char * _buf; short _len; } xstr_t;\r
+__inline xstr_t log_xstr(void * p, short l) { xstr_t xs = {(char*)p,l}; return xs; }\r
+\r
+#pragma warning(default:4204)\r
+\r
+//\r
+// Define the macro required for a hexdump use as:\r
+//\r
+// DebugTraceEx((LEVEL, FLAG,"%!HEXDUMP!\n", log_xstr(buffersize,(char *)buffer) ));\r
+//\r
+//\r
+#define WPP_LOGHEXDUMP(x) WPP_LOGPAIR(2, &((x)._len)) WPP_LOGPAIR((x)._len, (x)._buf)\r
+\r
+#endif\r
+\r
+\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) Microsoft Corporation. All rights reserved.\r
+\r
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY\r
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR\r
+ PURPOSE.\r
+\r
+Module Name:\r
+\r
+ WMI.C\r
+\r
+Abstract:\r
+\r
+ This module handles all the WMI Irps. 'bus' in this context refers to an\r
+ Infiniband Fabric (aka 'bus').\r
+\r
+Environment:\r
+\r
+ Kernel mode\r
+\r
+--*/\r
+\r
+#include "bus_driver.h"\r
+#include "ib_busMof.h"\r
+\r
+#if defined(EVENT_TRACING)\r
+#include "wmi.tmh"\r
+#endif\r
+\r
+#ifdef ALLOC_PRAGMA\r
+#pragma alloc_text(PAGE,Bus_WmiRegistration)\r
+#pragma alloc_text(PAGE,Bus_EvtStdDataSetItem)\r
+#pragma alloc_text(PAGE,Bus_EvtStdDataSetInstance)\r
+#pragma alloc_text(PAGE,Bus_EvtStdDataQueryInstance)\r
+#endif\r
+\r
+/*++\r
+Routine Description\r
+\r
+ Registers with WMI as a data provider for this\r
+ instance of the device\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_WmiRegistration( WDFDEVICE Device )\r
+{\r
+ WDF_WMI_PROVIDER_CONFIG providerConfig;\r
+ WDF_WMI_INSTANCE_CONFIG instanceConfig;\r
+ PFDO_BUS_DATA deviceData;\r
+ NTSTATUS status;\r
+ DECLARE_CONST_UNICODE_STRING(busRsrcName, BUSRESOURCENAME);\r
+\r
+ PAGED_CODE();\r
+\r
+ deviceData = FdoGetData(Device);\r
+\r
+ //\r
+ // Register WMI classes.\r
+ // First specify the resource name which contain the binary mof resource.\r
+ //\r
+ status = WdfDeviceAssignMofResourceName(Device, &busRsrcName);\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+\r
+ WDF_WMI_PROVIDER_CONFIG_INIT(&providerConfig, &IBF_BUS_WMI_STD_DATA_GUID);\r
+ providerConfig.MinInstanceBufferSize = sizeof(IBF_BUS_WMI_STD_DATA);\r
+\r
+ //\r
+ // You would want to create a WDFWMIPROVIDER handle separately if you are\r
+ // going to dynamically create instances on the provider. Since we are\r
+ // statically creating one instance, there is no need to create the provider\r
+ // handle.\r
+ //\r
+\r
+ WDF_WMI_INSTANCE_CONFIG_INIT_PROVIDER_CONFIG(&instanceConfig, &providerConfig);\r
+\r
+ //\r
+ // By setting Regsiter to TRUE, we tell the framework to create a provider\r
+ // as part of the Instance creation call. This eliminates the need to\r
+ // call WdfWmiProviderRegister.\r
+ //\r
+ instanceConfig.Register = TRUE;\r
+ instanceConfig.EvtWmiInstanceQueryInstance = Bus_EvtStdDataQueryInstance;\r
+ instanceConfig.EvtWmiInstanceSetInstance = Bus_EvtStdDataSetInstance;\r
+ instanceConfig.EvtWmiInstanceSetItem = Bus_EvtStdDataSetItem;\r
+\r
+ status = WdfWmiInstanceCreate(\r
+ Device,\r
+ &instanceConfig,\r
+ WDF_NO_OBJECT_ATTRIBUTES,\r
+ WDF_NO_HANDLE\r
+ );\r
+\r
+ if (NT_SUCCESS(status)) {\r
+ deviceData->StdBusData.ErrorCount = 0;\r
+ }\r
+\r
+ return status;\r
+}\r
+\r
+//\r
+// WMI System Call back functions\r
+//\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine is a callback into the driver to set for the contents of\r
+ an instance.\r
+\r
+Arguments:\r
+\r
+ WmiInstance is the instance being set\r
+\r
+ DataItemId has the id of the data item being set\r
+\r
+ InBufferSize has the size of the data item passed\r
+\r
+ InBuffer has the new values for the data item\r
+\r
+Return Value:\r
+\r
+ status\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_EvtStdDataSetItem(\r
+ IN WDFWMIINSTANCE WmiInstance,\r
+ IN ULONG DataItemId,\r
+ IN ULONG InBufferSize,\r
+ IN PVOID InBuffer )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+\r
+ PAGED_CODE();\r
+\r
+ fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance));\r
+\r
+ //\r
+ // TODO: Use generated header's #defines for constants and sizes\r
+ // (for the remainder of the file)\r
+ //\r
+\r
+ if (DataItemId == 2) {\r
+ if (InBufferSize < sizeof(ULONG)) {\r
+ return STATUS_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ bus_globals.dbg_lvl = fdoData->StdBusData.DebugPrintLevel = *((PULONG)InBuffer);\r
+\r
+ return STATUS_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // All other fields are read only\r
+ //\r
+ return STATUS_WMI_READ_ONLY;\r
+}\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine is a callback into the driver to set for the contents of\r
+ an instance.\r
+\r
+Arguments:\r
+\r
+ WmiInstance is the instance being set\r
+\r
+ BufferSize has the size of the data block passed\r
+\r
+ Buffer has the new values for the data block\r
+\r
+Return Value:\r
+\r
+ status\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_EvtStdDataSetInstance(\r
+ IN WDFWMIINSTANCE WmiInstance,\r
+ IN ULONG InBufferSize,\r
+ IN PVOID InBuffer )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+\r
+ UNREFERENCED_PARAMETER(InBufferSize);\r
+\r
+ PAGED_CODE();\r
+\r
+ fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance));\r
+\r
+ //\r
+ // We will update only writable elements.\r
+ //\r
+ bus_globals.dbg_lvl = fdoData->StdBusData.DebugPrintLevel =\r
+ ((PIBF_BUS_WMI_STD_DATA)InBuffer)->DebugPrintLevel;\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine is a callback into the driver to set for the contents of\r
+ a wmi instance\r
+\r
+Arguments:\r
+\r
+ WmiInstance is the instance being set\r
+\r
+ OutBufferSize on has the maximum size available to write the data\r
+ block.\r
+\r
+ OutBuffer on return is filled with the returned data block\r
+\r
+ BufferUsed pointer containing how many bytes are required (upon failure) or\r
+ how many bytes were used (upon success)\r
+\r
+Return Value:\r
+\r
+ status\r
+\r
+--*/\r
+\r
+NTSTATUS\r
+Bus_EvtStdDataQueryInstance(\r
+ IN WDFWMIINSTANCE WmiInstance,\r
+ IN ULONG OutBufferSize,\r
+ IN PVOID OutBuffer,\r
+ OUT PULONG BufferUsed )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+\r
+ UNREFERENCED_PARAMETER(OutBufferSize);\r
+\r
+ PAGED_CODE();\r
+\r
+ fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance));\r
+\r
+ *BufferUsed = sizeof (IBF_BUS_WMI_STD_DATA);\r
+ * (PIBF_BUS_WMI_STD_DATA) OutBuffer = fdoData->StdBusData;\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r