-TARGETNAME=ib_bus\r
+TARGETNAME=ibbus\r
TARGETPATH=..\..\..\bin\kernel\obj$(BUILD_ALT_DIR)\r
TARGETTYPE=DRIVER\r
\r
!endif\r
\r
\r
-SOURCES= ib_bus.rc \\r
- busenum.c \\r
- buspdo.c \\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);\\r
- .;..\..\..\inc;..\..\..\inc\kernel;..\..\al;..\..\al\kernel;\r
+INCLUDES=$(INCLUDES);..\..\..\inc;..\..\..\inc\kernel;..\..\al;..\..\al\kernel;\r
\r
C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -DNEED_CL_OBJ\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_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_ENTER( 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
+ 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 callback ??\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
+#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
+\r
+//#define BUS_PRINT( lvl, msg ) \\r
+// if ( ((lvl) & bus_globals.dbl_lvl) ) KbPrint( ( msg ) )\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(\r
+ WDFDEVICE Device\r
+ );\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
+\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
+#include <initguid.h>\r
+#include "driver.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
+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(("Entered Bus_CreatePdo\n"));\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_HCA%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
+\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
+ //\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
+ }\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
+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_EvtDriverObjCleanup( IN WDFOBJECT Driver );\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_EvtDeviceFileCreate ( IN WDFDEVICE Device,\r
+ IN WDFREQUEST Request,\r
+ IN WDFFILEOBJECT FileObject );\r
+static VOID\r
+Bus_EvtFileClose ( 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
+__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
+__get_relations(\r
+ IN const net64_t ca_guid,\r
+ IN IRP* const p_irp );\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
+\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_EvtDriverObjCleanup)\r
+#pragma alloc_text (PAGE, Bus_EvtDevicePrepareHardware)\r
+#pragma alloc_text (PAGE, Bus_EvtDeviceReleaseHardware)\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
+ fdo_start, // D0Entry\r
+ cl_irp_skip,\r
+ cl_irp_skip,\r
+ cl_do_sync_pnp,\r
+ fdo_query_remove, // DeviceQueryRemoval\r
+ fdo_release_resources, // D0 Exit\r
+ cl_do_remove,\r
+ cl_do_sync_pnp,\r
+ cl_irp_skip,\r
+ fdo_query_capabilities, // ?\r
+ cl_irp_skip,\r
+ cl_irp_skip,\r
+ cl_do_sync_pnp,\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ fdo_query_remove_relations,\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ fdo_query_interface, /* QueryInterface */\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ cl_irp_ignore,\r
+ __fdo_query_power, /* QueryPower */\r
+ __fdo_set_power, /* SetPower */\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, NULL, &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, NULL, &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
+ 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);\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_EvtFileClose,\r
+ WDF_NO_EVENT_CALLBACK // No cleanup callback function\r
+ );\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_EvtDriverObjCleanup;\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
+\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 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 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
+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
+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
+\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
+\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
+\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
+ 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
+}\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
+ 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
+ /* 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( &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
+\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
+\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
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<-- %s()\n", __FUNCTION__);\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\r
+ when the 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", Device));\r
+\r
+ PAGED_CODE ();\r
+\r
+ CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );\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_EvtFileClose ( 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
+ EvtDeviceCleanup is the dispatch routine for IRP_MJ_CLENAUP.\r
+\r
+\r
+Arguments:\r
+\r
+\r
+Return Value:\r
+\r
+\r
+--*/\r
+\r
+static VOID\r
+Bus_EvtDriverObjCleanup( IN WDFOBJECT Driver )\r
+{\r
+ PFDO_BUS_DATA fdoData;\r
+\r
+ PAGED_CODE ();\r
+ KdPrint(("--> %s()\n",__FUNCTION__));\r
+\r
+ fdoData = FdoGetData(Driver);\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
--- /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
- * 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
- BUSENUM.C\r
-\r
-Abstract:\r
-\r
- Provide the driver entry points for the InfiniBand Bus Driver.\r
- This module contains routies to handle the function driver\r
- aspect of the bus driver. This sample is functionally\r
- equivalent to the WDM toaster bus driver.\r
- Whever you read the word 'bus', think InfiniBand Fabric (aka, 'bus').\r
-\r
-Environment:\r
-\r
- kernel mode only\r
-\r
---*/\r
-\r
-#include "ib_fabric.h"\r
-#include <complib/cl_init.h>\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
-#if defined(EVENT_TRACING)\r
-/*\r
- * The .c file specific trace message header (.tmh) file must be included in a\r
- * source file before any WPP macro calls and after defining a WPP_CONTROL_GUIDS\r
- * macro (defined in toaster.h). During the compilation, WPP scans the source\r
- * files for DoTraceMessage() calls and builds a .tmh file which stores a unique\r
- * data GUID for each message, the text resource string for each message,\r
- * and the data types of the variables passed in for each message. This file\r
- * is automatically generated and used during post-processing.\r
- */\r
-\r
-#ifdef offsetof\r
-#undef offsetof\r
-#endif\r
-#include "busenum.tmh"\r
-\r
-ULONG DebugLevel = TRACE_LEVEL_INFORMATION;\r
-ULONG DebugFlag = 0x2f;//0x46;//0x4FF; //0x00000006;\r
-\r
-#else\r
-\r
-ULONG DebugLevel = ~0UL; // Initial DEBUG level for bringup.\r
-ULONG DebugFlag = ~0UL;\r
-\r
-#endif /* EVENT_TRACING */\r
-\r
-char node_desc[IB_NODE_DESCRIPTION_SIZE];\r
-\r
-bus_globals_t bus_globals = {\r
- ~0U/*BUS_DBG_ERROR*/,\r
- TRUE,\r
- NULL,\r
- NULL\r
-};\r
-\r
-int g_smi_poll_interval;\r
-int g_ioc_poll_interval;\r
-int g_ioc_query_retries;\r
-int g_ioc_query_timeout;\r
-\r
-DRIVER_INITIALIZE DriverEntry;\r
-\r
-static VOID 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
-\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_EvtDeviceAdd)\r
-#pragma alloc_text (PAGE, Bus_EvtIoDeviceControl)\r
-#pragma alloc_text (PAGE, Bus_PlugInDevice)\r
-#pragma alloc_text (PAGE, Bus_UnPlugDevice)\r
-#pragma alloc_text (PAGE, Bus_EjectDevice)\r
-#pragma alloc_text (PAGE, Bus_EvtDriverUnload)\r
-#endif\r
-\r
-/*++\r
-Routine Description:\r
-\r
- Initialize the call backs structure of Driver Framework.\r
-\r
-Arguments:\r
-\r
- DriverObject - pointer to the driver object\r
-\r
- RegistryPath - pointer to a unicode string representing the path,\r
- to driver-specific key in the registry.\r
-\r
-Return Value:\r
-\r
- NT Status Code\r
-\r
---*/\r
-NTSTATUS\r
-DriverEntry(\r
- IN PDRIVER_OBJECT DriverObject,\r
- IN PUNICODE_STRING RegistryPath )\r
-{\r
- WDF_DRIVER_CONFIG config;\r
- NTSTATUS status;\r
- WDFDRIVER driver;\r
-\r
- TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> %s()\n", __FUNCTION__);\r
-\r
- KdPrint(("WDF InfiniBand Fabric Dynamic Bus Enumerator.\n"));\r
- KdPrint(("Built %s %s\n", __DATE__, __TIME__));\r
-\r
-#if defined(EVENT_TRACING)\r
- WPP_INIT_TRACING(DriverObject ,RegistryPath);\r
-#endif\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 = DriverObject;\r
-\r
- /* Get the registry values. */\r
- status = __read_registry( RegistryPath );\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
- // 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(DriverObject,\r
- RegistryPath,\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
- TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,\r
- "<-- %s() ret %x\n", __FUNCTION__, status);\r
- return status;\r
-}\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_ENTER( 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
-/*++\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
- WDF_CHILD_LIST_CONFIG config;\r
- WDF_OBJECT_ATTRIBUTES fdoAttributes;\r
- NTSTATUS status;\r
- WDFDEVICE device;\r
- WDF_IO_QUEUE_CONFIG queueConfig;\r
- PNP_BUS_INFORMATION busInfo;\r
- PFDO_DEVICE_DATA deviceData;\r
- WDFQUEUE queue;\r
-\r
- WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;\r
- WDF_POWER_POLICY_EVENT_CALLBACKS powerPolicyCallbacks;\r
-\r
- UNREFERENCED_PARAMETER(Driver);\r
-\r
- PAGED_CODE ();\r
-\r
- KdPrint(("Bus_EvtDeviceAdd: 0x%p\n", Driver));\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);\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
-#if 0\r
- pnpPowerCallbacks.EvtDeviceSelfManagedIoInit =\r
- PciDrvEvtDeviceSelfManagedIoInit;\r
- pnpPowerCallbacks.EvtDeviceSelfManagedIoCleanup =\r
- PciDrvEvtDeviceSelfManagedIoCleanup;\r
- pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend =\r
- PciDrvEvtDeviceSelfManagedIoSuspend;\r
- pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart =\r
- PciDrvEvtDeviceSelfManagedIoRestart;\r
-\r
- // Register the PnP and power callbacks. Power policy related callbacks will\r
- // be registered later.\r
-\r
- WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);\r
-#endif\r
-\r
- // Init the power policy callbacks\r
-\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 bunch of callbacks to compare, copy, or free\r
- // any other resources associated with the description.\r
-\r
- WDF_CHILD_LIST_CONFIG_INIT( &config,\r
- sizeof(PDO_IDENTIFICATION_DESCRIPTION),\r
- Bus_EvtDeviceListCreatePdo );\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_EvtChildListIdentificationDescriptionDuplicate;\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_EvtChildListIdentificationDescriptionCompare;\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_EvtChildListIdentificationDescriptionCleanup;\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
- // Initialize attributes structure to specify size and accessor function\r
- // for storing device context.\r
-\r
- WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DEVICE_DATA);\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, &fdoAttributes, &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
- // 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
- queueConfig.EvtIoDeviceControl = Bus_EvtIoDeviceControl;\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 context.\r
-\r
- deviceData = FdoGetData(device);\r
- deviceData->WdfDevice = device; // record framework device object ptr.\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
- status = WdfDeviceCreateDeviceInterface( device,\r
- &GUID_DEVINTERFACE_BUSENUM_IBF,\r
- NULL );\r
- // NULL == No Reference String. If you provide one it will appended to\r
- // the symbolic link. Some drivers register multiple interfaces for the\r
- // same device and use the reference string to distinguish between them\r
-\r
- if (!NT_SUCCESS(status)) {\r
- return status;\r
- }\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; // XXX correct?\r
-\r
- WdfDeviceSetBusInformationForChildren(device, &busInfo);\r
-\r
- status = Bus_WmiRegistration(device);\r
- if (!NT_SUCCESS(status)) {\r
- return status;\r
- }\r
-\r
- return status;\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
-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
-{\r
- NTSTATUS status = STATUS_INVALID_PARAMETER;\r
- WDFDEVICE hDevice;\r
- size_t length = 0;\r
- PBUSENUM_PLUGIN_HARDWARE plugIn = NULL;\r
- PBUSENUM_UNPLUG_HARDWARE unPlug = NULL;\r
- PBUSENUM_EJECT_HARDWARE eject = NULL;\r
-\r
-\r
- UNREFERENCED_PARAMETER(OutputBufferLength);\r
-\r
- PAGED_CODE ();\r
-\r
- hDevice = WdfIoQueueGetDevice(Queue);\r
-\r
- KdPrint(("Bus_EvtIoDeviceControl: 0x%p\n", hDevice));\r
-\r
- switch (IoControlCode) {\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
-\r
- WdfRequestCompleteWithInformation(Request, status, length);\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
-\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 internaly 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), &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
-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_DEVICE_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
-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
- return;\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",\r
- status);\r
- return;\r
- }\r
- if (TraceEventsLevel <= TRACE_LEVEL_INFORMATION ||\r
- (TraceEventsLevel <= DebugLevel &&\r
- ((TraceEventsFlag & DebugFlag) == TraceEventsFlag))) {\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) 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 "ib_fabric.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
-#ifdef ALLOC_PRAGMA\r
-#pragma alloc_text(PAGE, Bus_CreatePdo)\r
-#pragma alloc_text(PAGE, Bus_EvtDeviceListCreatePdo)\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_EvtChildListIdentificationDescriptionDuplicate(\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_EvtChildListIdentificationDescriptionCompare(\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_EvtChildListIdentificationDescriptionCleanup(\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_EvtDeviceListCreatePdo( 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
-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
- IBF_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(("Entered Bus_CreatePdo\n"));\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_HCA%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
-\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
- //\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
- }\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
-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
);\r
\r
//\r
-// InfiniBand Fabric Interface for getting and setting power level etc.,\r
+// InfiniBand Fabric Bus Interface\r
//\r
-typedef struct _IBF_INTERFACE_STANDARD {\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
-} IBF_INTERFACE_STANDARD, *PIBF_INTERFACE_STANDARD;\r
+} IB_BUS_INTERFACE_STANDARD, *PIB_BUS_INTERFACE_STANDARD;\r
\r
\r
#endif\r
[CatalogHeader]\r
-Name=ib_fabric.cat\r
+Name=ib_bus.cat\r
PublicVersion=0x0000001\r
EncodingType=0x00010001\r
CATATTR1=0x10010001:OSAttr:2:6.0\r
[CatalogFiles]\r
-<hash>ib_fabric.inf=ib_fabric.inf\r
-<hash>ibfabric.sys=ibfabric.sys\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
-;/*++\r
-;\r
-;Copyright (c) 2008 Intel Corporation All rights Reserved\r
-;Copyright (c) 1990-1999 Microsoft Corporation All rights Reserved\r
-;\r
-;Module Name:\r
-;\r
-; ib_fabric.INF\r
-;\r
-;Abstract:\r
-; INF file for installing the Infinband Fabric bus enumerator driver\r
-;\r
-;Installation Notes:\r
-; Using Devcon: Type "devcon install ib_fabric.inf root\ib_fabric" to install\r
-;\r
-;--*/\r
+; OpenIB InfiniBand Fabric Bus Driver.\r
+; Copyright 2008 SilverStorm Technologies all Rights Reserved.\r
+; Copyright 2005 SilverStorm Technologies all Rights Reserved.\r
+; Copyright 2006 Mellanox Technologies all Rights Reserved.\r
+\r
[Version]\r
-Signature="$WINDOWS NT$"\r
+Signature="$Windows NT$"\r
Class=System\r
ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318}\r
Provider=%OPENIB%\r
-DriverVer=04/15/2008, 1.0.0000.999\r
+DriverVer=03/08/2006,1.0.0000.614\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
+DefaultDestDir=%DIRID_DRIVERS%\r
Ibbus.UMCopyFiles=%DIRID_SYSTEM%\r
Ibbus.WOW64CopyFiles=%DIRID_SYSTEM_X86%\r
\r
ibal32d.dll=1\r
ibal32.dll=1\r
\r
-;*****************************************\r
-; IbFabricDynamicBus Install Section\r
-;*****************************************\r
-\r
[Manufacturer]\r
-%StdMfg%=Standard,NT$ARCH$\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
-; For Win2K because it cannot parse decorated sections\r
-[Standard]\r
;\r
-; These are the toaster bus pnp ids\r
+; ============= Service Install section ==============\r
;\r
-%IbFabricDynamicBus.DeviceDesc%=IbFabricDynamicBus_Device, root\ib_bus\r
-\r
-; For XP and later\r
-[Standard.NT$ARCH$]\r
-%IbFabricDynamicBus.DeviceDesc%=IbFabricDynamicBus_Device, root\ib_bus\r
-\r
-[IbFabricDynamicBus_Device.NT]\r
-CopyFiles=Drivers_Dir\r
-\r
-[IbFabricDynamicBus_Device.NT.HW]\r
-AddReg=IbFabricDynamicBus_Device.NT.AddReg\r
-\r
-[IbFabricDynamicBus_Device.NT.AddReg] \r
-HKR,,DeviceCharacteristics,0x10001,0x0100 ; Use same security checks on relative opens\r
-HKR,,Security,,"D:P(A;;GA;;;BA)(A;;GA;;;SY)" ; Allow generic-all access to Built-in administrators and Local system \r
-\r
-[Drivers_Dir]\r
-ib_bus.sys\r
-\r
-\r
-;-------------- Service installation\r
-[IbFabricDynamicBus_Device.NT.Services]\r
-AddService = ib_bus,%SPSVCINST_ASSOCSERVICE%, ib_bus_Service_Inst\r
-\r
-; -------------- IB bus driver install sections\r
-[dynambus_Service_Inst]\r
-DisplayName = %ib_bus.SVCDESC%\r
-ServiceType = 1 ; SERVICE_KERNEL_DRIVER\r
-StartType = 3 ; SERVICE_DEMAND_START \r
-ErrorControl = 1 ; SERVICE_ERROR_NORMAL\r
-ServiceBinary = %12%\ib_bus.sys\r
-LoadOrderGroup = Extended Base\r
-\r
-\r
-[IB_Bus_Device.NT.Wdf]\r
-KmdfService = ib_bus, ib_bus_wdfsect\r
-[ib_bus_wdfsect]\r
-KmdfLibraryVersion = $KMDFVERSION$\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
[Strings]\r
-SPSVCINST_ASSOCSERVICE= 0x00000002\r
-MSFT = "Microsoft"\r
-StdMfg = "(Standard system devices)"\r
-DiskId1 = "InfiniBand Fabric Dynamic Bus Installation Disk #1"\r
-IB_Bus.DeviceDesc = "InfiniBand Fabric Dynamic Bus Enumerator"\r
-ib_bus.SVCDESC = "InfiniBand Fabric Dynamic Bus Enumerator"\r
-\r
+OPENIB = "OpenIB Alliance"\r
+SST = "SilverStorm Technologies"\r
+IbFabric.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
+IbFabric.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
#define VER_FILEDESCRIPTION_STR "InfiniBand Fabric Dynamic Bus Enumerator"\r
#endif\r
\r
-#define VER_INTERNALNAME_STR "ib_bus.sys"\r
-#define VER_ORIGINALFILENAME_STR "ib_bus.sys"\r
+#define VER_INTERNALNAME_STR "ibbus.sys"\r
+#define VER_ORIGINALFILENAME_STR "ibbus.sys"\r
\r
#include <common.ver>\r
\r
--- /dev/null
+/*++\r
+Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved\r
+\r
+Module Name:\r
+\r
+ 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
// TODO: These defines are missing in evntrace.h\r
// in some DDK build environments (XP).\r
//\r
-#if !defined(TRACE_LEVEL_NONE)\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_RESERVED7 7\r
#define TRACE_LEVEL_RESERVED8 8\r
#define TRACE_LEVEL_RESERVED9 9\r
-#endif\r
-\r
\r
//\r
// Define Debug Flags\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
\r
--*/\r
\r
-#include "ib_fabric.h"\r
+#include "bus_driver.h"\r
#include "ib_busMof.h"\r
\r
#if defined(EVENT_TRACING)\r
Bus_WmiRegistration( WDFDEVICE Device )\r
{\r
WDF_WMI_PROVIDER_CONFIG providerConfig;\r
- WDF_WMI_INSTANCE_CONFIG instanceConfig;\r
- PFDO_DEVICE_DATA deviceData;\r
- NTSTATUS status;\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
IN ULONG InBufferSize,\r
IN PVOID InBuffer )\r
{\r
- PFDO_DEVICE_DATA fdoData;\r
+ PFDO_BUS_DATA fdoData;\r
\r
PAGED_CODE();\r
\r
return STATUS_BUFFER_TOO_SMALL;\r
}\r
\r
- DebugLevel = fdoData->StdBusData.DebugPrintLevel = *((PULONG)InBuffer);\r
+ bus_globals.dbg_lvl = fdoData->StdBusData.DebugPrintLevel = *((PULONG)InBuffer);\r
\r
return STATUS_SUCCESS;\r
}\r
IN ULONG InBufferSize,\r
IN PVOID InBuffer )\r
{\r
- PFDO_DEVICE_DATA fdoData;\r
+ PFDO_BUS_DATA fdoData;\r
\r
UNREFERENCED_PARAMETER(InBufferSize);\r
\r
//\r
// We will update only writable elements.\r
//\r
- DebugLevel = fdoData->StdBusData.DebugPrintLevel =\r
+ bus_globals.dbg_lvl = fdoData->StdBusData.DebugPrintLevel =\r
((PIBF_BUS_WMI_STD_DATA)InBuffer)->DebugPrintLevel;\r
\r
return STATUS_SUCCESS;\r
IN PVOID OutBuffer,\r
OUT PULONG BufferUsed )\r
{\r
- PFDO_DEVICE_DATA fdoData;\r
+ PFDO_BUS_DATA fdoData;\r
\r
UNREFERENCED_PARAMETER(OutBufferSize);\r
\r