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