From 4db6459e0c9a315aca1a57181fd34fb6e194422d Mon Sep 17 00:00:00 2001 From: stansmith Date: Thu, 20 Mar 2008 23:20:41 +0000 Subject: [PATCH] [IBFD] KMDF Bus driver almost ready to start testing. git-svn-id: svn://openib.tc.cornell.edu/gen1@1003 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86 --- branches/IBFD/core/bus/kmdf/SOURCES | 14 +- branches/IBFD/core/bus/kmdf/bus_driver.c | 664 ++++ branches/IBFD/core/bus/kmdf/bus_driver.h | 408 +++ branches/IBFD/core/bus/kmdf/bus_iou_mgr.c | 1502 +++++++++ branches/IBFD/core/bus/kmdf/bus_iou_mgr.h | 66 + .../core/bus/kmdf/{buspdo.c => bus_pdo.c} | 40 +- branches/IBFD/core/bus/kmdf/bus_pnp.c | 2921 +++++++++++++++++ branches/IBFD/core/bus/kmdf/bus_pnp.h | 89 + branches/IBFD/core/bus/kmdf/bus_port_mgr.c | 1494 +++++++++ branches/IBFD/core/bus/kmdf/bus_port_mgr.h | 66 + branches/IBFD/core/bus/kmdf/busenum.c | 1158 ------- branches/IBFD/core/bus/kmdf/driver.h | 6 +- branches/IBFD/core/bus/kmdf/ib_bus.cdf | 6 +- branches/IBFD/core/bus/kmdf/ib_bus.inx | 230 +- branches/IBFD/core/bus/kmdf/ib_bus.rc | 4 +- branches/IBFD/core/bus/kmdf/ib_bus_public.h | 166 + branches/IBFD/core/bus/kmdf/trace.h | 16 +- branches/IBFD/core/bus/kmdf/wmi.c | 18 +- 18 files changed, 7599 insertions(+), 1269 deletions(-) create mode 100644 branches/IBFD/core/bus/kmdf/bus_driver.c create mode 100644 branches/IBFD/core/bus/kmdf/bus_driver.h create mode 100644 branches/IBFD/core/bus/kmdf/bus_iou_mgr.c create mode 100644 branches/IBFD/core/bus/kmdf/bus_iou_mgr.h rename branches/IBFD/core/bus/kmdf/{buspdo.c => bus_pdo.c} (90%) create mode 100644 branches/IBFD/core/bus/kmdf/bus_pnp.c create mode 100644 branches/IBFD/core/bus/kmdf/bus_pnp.h create mode 100644 branches/IBFD/core/bus/kmdf/bus_port_mgr.c create mode 100644 branches/IBFD/core/bus/kmdf/bus_port_mgr.h delete mode 100644 branches/IBFD/core/bus/kmdf/busenum.c create mode 100644 branches/IBFD/core/bus/kmdf/ib_bus_public.h diff --git a/branches/IBFD/core/bus/kmdf/SOURCES b/branches/IBFD/core/bus/kmdf/SOURCES index 4ad2c4d7..5c3f6a2f 100644 --- a/branches/IBFD/core/bus/kmdf/SOURCES +++ b/branches/IBFD/core/bus/kmdf/SOURCES @@ -1,4 +1,4 @@ -TARGETNAME=ib_bus +TARGETNAME=ibbus TARGETPATH=..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) TARGETTYPE=DRIVER @@ -13,13 +13,15 @@ ENABLE_EVENT_TRACING=1 !endif -SOURCES= ib_bus.rc \ - busenum.c \ - buspdo.c \ +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; +INCLUDES=$(INCLUDES);..\..\..\inc;..\..\..\inc\kernel;..\..\al;..\..\al\kernel; C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -DNEED_CL_OBJ diff --git a/branches/IBFD/core/bus/kmdf/bus_driver.c b/branches/IBFD/core/bus/kmdf/bus_driver.c new file mode 100644 index 00000000..4174657e --- /dev/null +++ b/branches/IBFD/core/bus/kmdf/bus_driver.c @@ -0,0 +1,664 @@ +/* + * 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_ENTER( 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 ); + + 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 callback ?? + 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/IBFD/core/bus/kmdf/bus_driver.h b/branches/IBFD/core/bus/kmdf/bus_driver.h new file mode 100644 index 00000000..7e3afff0 --- /dev/null +++ b/branches/IBFD/core/bus/kmdf/bus_driver.h @@ -0,0 +1,408 @@ +/* + * 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 + + +#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 + +//#define BUS_PRINT( lvl, msg ) \ +// if ( ((lvl) & bus_globals.dbl_lvl) ) KbPrint( ( msg ) ) + + +/* + * 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; + + +#endif /* !defined _IB_BUS_DRIVER_H_ */ diff --git a/branches/IBFD/core/bus/kmdf/bus_iou_mgr.c b/branches/IBFD/core/bus/kmdf/bus_iou_mgr.c new file mode 100644 index 00000000..240a0dfe --- /dev/null +++ b/branches/IBFD/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/IBFD/core/bus/kmdf/bus_iou_mgr.h b/branches/IBFD/core/bus/kmdf/bus_iou_mgr.h new file mode 100644 index 00000000..b181ba04 --- /dev/null +++ b/branches/IBFD/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/IBFD/core/bus/kmdf/buspdo.c b/branches/IBFD/core/bus/kmdf/bus_pdo.c similarity index 90% rename from branches/IBFD/core/bus/kmdf/buspdo.c rename to branches/IBFD/core/bus/kmdf/bus_pdo.c index 4a54d6ce..dfd20c5d 100644 --- a/branches/IBFD/core/bus/kmdf/buspdo.c +++ b/branches/IBFD/core/bus/kmdf/bus_pdo.c @@ -45,7 +45,9 @@ Environment: --*/ -#include "ib_fabric.h" +#include "bus_driver.h" +#include +#include "driver.h" #if defined(EVENT_TRACING) #include "buspdo.tmh @@ -54,9 +56,21 @@ Environment: // 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_EvtDeviceListCreatePdo) +#pragma alloc_text(PAGE, Bus_DeviceListCreatePdo) #endif /*++ @@ -89,7 +103,7 @@ Return Value: --*/ NTSTATUS -Bus_EvtChildListIdentificationDescriptionDuplicate( +Bus_ChildListIdentificationDescriptionDuplicate( WDFCHILDLIST DeviceList, PWDF_CHILD_ID_DESC_HDR SourceIdentificationDescription, PWDF_CHILD_ID_DESC_HDR DestinationIdentificationDescription ) @@ -157,7 +171,7 @@ Return Value: --*/ BOOLEAN -Bus_EvtChildListIdentificationDescriptionCompare( +Bus_ChildListIdentificationDescriptionCompare( WDFCHILDLIST DeviceList, PWDF_CHILD_ID_DESC_HDR FirstIdentificationDescription, PWDF_CHILD_ID_DESC_HDR SecondIdentificationDescription ) @@ -195,7 +209,7 @@ Return Value: --*/ VOID -Bus_EvtChildListIdentificationDescriptionCleanup( +Bus_ChildListIdentificationDescriptionCleanup( WDFCHILDLIST DeviceList, PWDF_CHILD_ID_DESC_HDR IdentificationDescription ) { @@ -239,9 +253,9 @@ Return Value: --*/ NTSTATUS -Bus_EvtDeviceListCreatePdo( WDFCHILDLIST DeviceList, - PWDF_CHILD_ID_DESC_HDR IdentificationDescription, - PWDFDEVICE_INIT ChildInit ) +Bus_DeviceListCreatePdo( WDFCHILDLIST DeviceList, + PWDF_CHILD_ID_DESC_HDR IdentificationDescription, + PWDFDEVICE_INIT ChildInit ) { PPDO_IDENTIFICATION_DESCRIPTION pDesc; @@ -273,10 +287,10 @@ Return Value: --*/ NTSTATUS Bus_CreatePdo( - __in WDFDEVICE Device, - __in PWDFDEVICE_INIT DeviceInit, - __in PWCHAR HardwareIds, - __in ULONG SerialNo ) + __in WDFDEVICE Device, + __in PWDFDEVICE_INIT DeviceInit, + __in PWCHAR HardwareIds, + __in ULONG SerialNo ) { NTSTATUS status; PPDO_DEVICE_DATA pdoData = NULL; @@ -285,7 +299,7 @@ Bus_CreatePdo( WDF_OBJECT_ATTRIBUTES pdoAttributes; WDF_DEVICE_PNP_CAPABILITIES pnpCaps; WDF_DEVICE_POWER_CAPABILITIES powerCaps; - IBF_INTERFACE_STANDARD FabricInterface; + 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); diff --git a/branches/IBFD/core/bus/kmdf/bus_pnp.c b/branches/IBFD/core/bus/kmdf/bus_pnp.c new file mode 100644 index 00000000..bd703f40 --- /dev/null +++ b/branches/IBFD/core/bus/kmdf/bus_pnp.c @@ -0,0 +1,2921 @@ +/* + * 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_EvtDriverObjCleanup( IN WDFOBJECT Driver ); + +static VOID +Bus_EvtIoDeviceControl( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t OutputBufferLength, + IN size_t InputBufferLength, + IN ULONG IoControlCode ); + +static VOID +Bus_EvtDeviceFileCreate ( IN WDFDEVICE Device, + IN WDFREQUEST Request, + IN WDFFILEOBJECT FileObject ); +static VOID +Bus_EvtFileClose ( 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 +__query_al_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ); + +static NTSTATUS +__get_relations( + IN const net64_t ca_guid, + IN IRP* const p_irp ); + +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 ); + +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_EvtDriverObjCleanup) +#pragma alloc_text (PAGE, Bus_EvtDevicePrepareHardware) +#pragma alloc_text (PAGE, Bus_EvtDeviceReleaseHardware) + +#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", + fdo_start, // D0Entry + cl_irp_skip, + cl_irp_skip, + cl_do_sync_pnp, + fdo_query_remove, // DeviceQueryRemoval + fdo_release_resources, // D0 Exit + cl_do_remove, + cl_do_sync_pnp, + cl_irp_skip, + fdo_query_capabilities, // ? + cl_irp_skip, + cl_irp_skip, + cl_do_sync_pnp, + cl_irp_ignore, + cl_irp_ignore, + fdo_query_remove_relations, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + fdo_query_interface, /* QueryInterface */ + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + __fdo_query_power, /* QueryPower */ + __fdo_set_power, /* SetPower */ + 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; + } + + 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); + + // 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_EvtFileClose, + WDF_NO_EVENT_CALLBACK // No cleanup callback function + ); + + 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_EvtDriverObjCleanup; + + // 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; + + 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 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 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; +} + + +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 +__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; +} + + +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; +} + + +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); + + 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 +} + + +/*++ + +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; + + 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; + + /* 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( &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; + } + + /* 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; + } + + status = IoSetDeviceInterfaceState( &fdo->al_ifc_name, TRUE ); + ASSERT( NT_SUCCESS( status ) ); + + status = IoSetDeviceInterfaceState( &fdo->ci_ifc_name, TRUE ); + ASSERT( NT_SUCCESS( status ) ); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<-- %s()\n", __FUNCTION__); + + 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", Device)); + + PAGED_CODE (); + + CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); + + // + // 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_EvtFileClose ( IN WDFFILEOBJECT FileObject ) +{ + PFDO_BUS_DATA fdoData; + + PAGED_CODE (); + KdPrint(("%s()--->\n",__FUNCTION__)); + + fdoData = FdoGetData(WdfFileObjectGetDevice(FileObject)); + + KdPrint(("%s()<---\n",__FUNCTION__)); + + return; +} + + +/*++ + +Routine Description: + + EvtDeviceCleanup is the dispatch routine for IRP_MJ_CLENAUP. + + +Arguments: + + +Return Value: + + +--*/ + +static VOID +Bus_EvtDriverObjCleanup( IN WDFOBJECT Driver ) +{ + PFDO_BUS_DATA fdoData; + + PAGED_CODE (); + KdPrint(("--> %s()\n",__FUNCTION__)); + + fdoData = FdoGetData(Driver); + + 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 ); +} + diff --git a/branches/IBFD/core/bus/kmdf/bus_pnp.h b/branches/IBFD/core/bus/kmdf/bus_pnp.h new file mode 100644 index 00000000..8f78d27d --- /dev/null +++ b/branches/IBFD/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/IBFD/core/bus/kmdf/bus_port_mgr.c b/branches/IBFD/core/bus/kmdf/bus_port_mgr.c new file mode 100644 index 00000000..ef1a8f49 --- /dev/null +++ b/branches/IBFD/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/IBFD/core/bus/kmdf/bus_port_mgr.h b/branches/IBFD/core/bus/kmdf/bus_port_mgr.h new file mode 100644 index 00000000..122733b5 --- /dev/null +++ b/branches/IBFD/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/IBFD/core/bus/kmdf/busenum.c b/branches/IBFD/core/bus/kmdf/busenum.c deleted file mode 100644 index 77c35ac8..00000000 --- a/branches/IBFD/core/bus/kmdf/busenum.c +++ /dev/null @@ -1,1158 +0,0 @@ -/* - * 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: - - BUSENUM.C - -Abstract: - - Provide the driver entry points for the InfiniBand Bus Driver. - This module contains routies to handle the function driver - aspect of the bus driver. This sample is functionally - equivalent to the WDM toaster bus driver. - Whever you read the word 'bus', think InfiniBand Fabric (aka, 'bus'). - -Environment: - - kernel mode only - ---*/ - -#include "ib_fabric.h" -#include - -#ifdef WINIB -#define DEFAULT_NODE_DESC "Mellanox Windows® Host" -#else -#define DEFAULT_NODE_DESC "OpenIB Windows® Host" -#endif - -#if defined(EVENT_TRACING) -/* - * The .c file specific trace message header (.tmh) file must be included in a - * source file before any WPP macro calls and after defining a WPP_CONTROL_GUIDS - * macro (defined in toaster.h). During the compilation, WPP scans the source - * files for DoTraceMessage() calls and builds a .tmh file which stores a unique - * data GUID for each message, the text resource string for each message, - * and the data types of the variables passed in for each message. This file - * is automatically generated and used during post-processing. - */ - -#ifdef offsetof -#undef offsetof -#endif -#include "busenum.tmh" - -ULONG DebugLevel = TRACE_LEVEL_INFORMATION; -ULONG DebugFlag = 0x2f;//0x46;//0x4FF; //0x00000006; - -#else - -ULONG DebugLevel = ~0UL; // Initial DEBUG level for bringup. -ULONG DebugFlag = ~0UL; - -#endif /* EVENT_TRACING */ - -char node_desc[IB_NODE_DESCRIPTION_SIZE]; - -bus_globals_t bus_globals = { - ~0U/*BUS_DBG_ERROR*/, - TRUE, - NULL, - NULL -}; - -int g_smi_poll_interval; -int g_ioc_poll_interval; -int g_ioc_query_retries; -int g_ioc_query_timeout; - -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 ); - - -#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_EvtDeviceAdd) -#pragma alloc_text (PAGE, Bus_EvtIoDeviceControl) -#pragma alloc_text (PAGE, Bus_PlugInDevice) -#pragma alloc_text (PAGE, Bus_UnPlugDevice) -#pragma alloc_text (PAGE, Bus_EjectDevice) -#pragma alloc_text (PAGE, Bus_EvtDriverUnload) -#endif - -/*++ -Routine Description: - - Initialize the call backs structure of Driver Framework. - -Arguments: - - DriverObject - pointer to the driver object - - RegistryPath - pointer to a unicode string representing the path, - to driver-specific key in the registry. - -Return Value: - - NT Status Code - ---*/ -NTSTATUS -DriverEntry( - IN PDRIVER_OBJECT DriverObject, - IN PUNICODE_STRING RegistryPath ) -{ - WDF_DRIVER_CONFIG config; - NTSTATUS status; - WDFDRIVER driver; - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> %s()\n", __FUNCTION__); - - KdPrint(("WDF InfiniBand Fabric Dynamic Bus Enumerator.\n")); - KdPrint(("Built %s %s\n", __DATE__, __TIME__)); - -#if defined(EVENT_TRACING) - WPP_INIT_TRACING(DriverObject ,RegistryPath); -#endif - - 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 = DriverObject; - - /* Get the registry values. */ - status = __read_registry( RegistryPath ); - if( !NT_SUCCESS(status) ) - { - CL_DEINIT; - BUS_TRACE_EXIT( BUS_DBG_ERROR, - ("__read_registry returned %08x.\n", status) ); - return status; - } - // - // 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(DriverObject, - RegistryPath, - WDF_NO_OBJECT_ATTRIBUTES, - &config, - &driver); - - if (!NT_SUCCESS(status)) { - KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status)); - } - - TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, - "<-- %s() ret %x\n", __FUNCTION__, status); - return status; -} - - -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_ENTER( 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; -} - - -/*++ -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 ) -{ - WDF_CHILD_LIST_CONFIG config; - WDF_OBJECT_ATTRIBUTES fdoAttributes; - NTSTATUS status; - WDFDEVICE device; - WDF_IO_QUEUE_CONFIG queueConfig; - PNP_BUS_INFORMATION busInfo; - PFDO_DEVICE_DATA deviceData; - WDFQUEUE queue; - - WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; - WDF_POWER_POLICY_EVENT_CALLBACKS powerPolicyCallbacks; - - UNREFERENCED_PARAMETER(Driver); - - PAGED_CODE (); - - KdPrint(("Bus_EvtDeviceAdd: 0x%p\n", Driver)); - - // 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); - - // 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. -#if 0 - pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = - PciDrvEvtDeviceSelfManagedIoInit; - pnpPowerCallbacks.EvtDeviceSelfManagedIoCleanup = - PciDrvEvtDeviceSelfManagedIoCleanup; - pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = - PciDrvEvtDeviceSelfManagedIoSuspend; - pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = - PciDrvEvtDeviceSelfManagedIoRestart; - - // Register the PnP and power callbacks. Power policy related callbacks will - // be registered later. - - WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); -#endif - - // 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 bunch of callbacks to compare, copy, or free - // any other resources associated with the description. - - WDF_CHILD_LIST_CONFIG_INIT( &config, - sizeof(PDO_IDENTIFICATION_DESCRIPTION), - Bus_EvtDeviceListCreatePdo ); - // 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_EvtChildListIdentificationDescriptionDuplicate; - - // - // 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_EvtChildListIdentificationDescriptionCompare; - // - // 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_EvtChildListIdentificationDescriptionCleanup; - - // - // 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); - - // Initialize attributes structure to specify size and accessor function - // for storing device context. - - WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DEVICE_DATA); - - // Create a framework device object. In response to this call, framework - // creates a WDM deviceobject and attaches to the PDO. - - status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &device); - - if (!NT_SUCCESS(status)) { - KdPrint(("Error creating WdfDeviceCreate 0x%x, line#%d\n", - status,__LINE__)); - return status; - } - - // 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 ); - - queueConfig.EvtIoDeviceControl = Bus_EvtIoDeviceControl; - - 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 context. - - deviceData = FdoGetData(device); - deviceData->WdfDevice = device; // record framework device object ptr. - - // - // 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. - // - status = WdfDeviceCreateDeviceInterface( device, - &GUID_DEVINTERFACE_BUSENUM_IBF, - NULL ); - // NULL == No Reference String. If you provide one it will appended to - // the symbolic link. Some drivers register multiple interfaces for the - // same device and use the reference string to distinguish between them - - if (!NT_SUCCESS(status)) { - return status; - } - - // - // 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; // XXX correct? - - WdfDeviceSetBusInformationForChildren(device, &busInfo); - - status = Bus_WmiRegistration(device); - if (!NT_SUCCESS(status)) { - return status; - } - - return status; -} - - -/*++ -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 - ---*/ - -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; - PBUSENUM_PLUGIN_HARDWARE plugIn = NULL; - PBUSENUM_UNPLUG_HARDWARE unPlug = NULL; - PBUSENUM_EJECT_HARDWARE eject = NULL; - - - UNREFERENCED_PARAMETER(OutputBufferLength); - - PAGED_CODE (); - - hDevice = WdfIoQueueGetDevice(Queue); - - KdPrint(("Bus_EvtIoDeviceControl: 0x%p\n", hDevice)); - - 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); -} - - -/*++ - -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 internaly 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_DEVICE_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: - - 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 ); - return; -} - - -/*++ - -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 <= DebugLevel && - ((TraceEventsFlag & DebugFlag) == 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/IBFD/core/bus/kmdf/driver.h b/branches/IBFD/core/bus/kmdf/driver.h index cb80ceae..b587fb3b 100644 --- a/branches/IBFD/core/bus/kmdf/driver.h +++ b/branches/IBFD/core/bus/kmdf/driver.h @@ -65,14 +65,14 @@ BOOLEAN ); // -// InfiniBand Fabric Interface for getting and setting power level etc., +// InfiniBand Fabric Bus Interface // -typedef struct _IBF_INTERFACE_STANDARD { +typedef struct _IB_BUS_INTERFACE_STANDARD { INTERFACE InterfaceHeader; PIBF_GET_CRISPINESS_LEVEL GetCrispinessLevel; PIBF_SET_CRISPINESS_LEVEL SetCrispinessLevel; PIBF_IS_CHILD_PROTECTED IsSafetyLockEnabled; -} IBF_INTERFACE_STANDARD, *PIBF_INTERFACE_STANDARD; +} IB_BUS_INTERFACE_STANDARD, *PIB_BUS_INTERFACE_STANDARD; #endif diff --git a/branches/IBFD/core/bus/kmdf/ib_bus.cdf b/branches/IBFD/core/bus/kmdf/ib_bus.cdf index c16b2531..ac428f1d 100644 --- a/branches/IBFD/core/bus/kmdf/ib_bus.cdf +++ b/branches/IBFD/core/bus/kmdf/ib_bus.cdf @@ -1,11 +1,11 @@ [CatalogHeader] -Name=ib_fabric.cat +Name=ib_bus.cat PublicVersion=0x0000001 EncodingType=0x00010001 CATATTR1=0x10010001:OSAttr:2:6.0 [CatalogFiles] -ib_fabric.inf=ib_fabric.inf -ibfabric.sys=ibfabric.sys +ib_bus.inf=ib_bus.inf +ibbus.sys=ibbus.sys ibiou.sys=ibiou.sys ibal.dll=ibal.dll complib.dll=complib.dll diff --git a/branches/IBFD/core/bus/kmdf/ib_bus.inx b/branches/IBFD/core/bus/kmdf/ib_bus.inx index c5809ae8..d2575607 100644 --- a/branches/IBFD/core/bus/kmdf/ib_bus.inx +++ b/branches/IBFD/core/bus/kmdf/ib_bus.inx @@ -1,30 +1,21 @@ -;/*++ -; -;Copyright (c) 2008 Intel Corporation All rights Reserved -;Copyright (c) 1990-1999 Microsoft Corporation All rights Reserved -; -;Module Name: -; -; ib_fabric.INF -; -;Abstract: -; INF file for installing the Infinband Fabric bus enumerator driver -; -;Installation Notes: -; Using Devcon: Type "devcon install ib_fabric.inf root\ib_fabric" to install -; -;--*/ +; OpenIB InfiniBand Fabric Bus Driver. +; Copyright 2008 SilverStorm Technologies all Rights Reserved. +; Copyright 2005 SilverStorm Technologies all Rights Reserved. +; Copyright 2006 Mellanox Technologies all Rights Reserved. + [Version] -Signature="$WINDOWS NT$" +Signature="$Windows NT$" Class=System ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318} Provider=%OPENIB% -DriverVer=04/15/2008, 1.0.0000.999 +DriverVer=03/08/2006,1.0.0000.614 CatalogFile=ib_bus.cat +; ================= Device Install section ===================== +; 64-bit platforms also copy 32-bit user-mode binaries. [DestinationDirs] -DefaultDestDir = %DIRID_DRIVERS% +DefaultDestDir=%DIRID_DRIVERS% Ibbus.UMCopyFiles=%DIRID_SYSTEM% Ibbus.WOW64CopyFiles=%DIRID_SYSTEM_X86% @@ -69,63 +60,158 @@ cl32.dll=1 ibal32d.dll=1 ibal32.dll=1 -;***************************************** -; IbFabricDynamicBus Install Section -;***************************************** - [Manufacturer] -%StdMfg%=Standard,NT$ARCH$ +%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 -; For Win2K because it cannot parse decorated sections -[Standard] ; -; These are the toaster bus pnp ids +; ============= Service Install section ============== ; -%IbFabricDynamicBus.DeviceDesc%=IbFabricDynamicBus_Device, root\ib_bus - -; For XP and later -[Standard.NT$ARCH$] -%IbFabricDynamicBus.DeviceDesc%=IbFabricDynamicBus_Device, root\ib_bus - -[IbFabricDynamicBus_Device.NT] -CopyFiles=Drivers_Dir - -[IbFabricDynamicBus_Device.NT.HW] -AddReg=IbFabricDynamicBus_Device.NT.AddReg - -[IbFabricDynamicBus_Device.NT.AddReg] -HKR,,DeviceCharacteristics,0x10001,0x0100 ; Use same security checks on relative opens -HKR,,Security,,"D:P(A;;GA;;;BA)(A;;GA;;;SY)" ; Allow generic-all access to Built-in administrators and Local system - -[Drivers_Dir] -ib_bus.sys - - -;-------------- Service installation -[IbFabricDynamicBus_Device.NT.Services] -AddService = ib_bus,%SPSVCINST_ASSOCSERVICE%, ib_bus_Service_Inst - -; -------------- IB bus driver install sections -[dynambus_Service_Inst] -DisplayName = %ib_bus.SVCDESC% -ServiceType = 1 ; SERVICE_KERNEL_DRIVER -StartType = 3 ; SERVICE_DEMAND_START -ErrorControl = 1 ; SERVICE_ERROR_NORMAL -ServiceBinary = %12%\ib_bus.sys -LoadOrderGroup = Extended Base - - -[IB_Bus_Device.NT.Wdf] -KmdfService = ib_bus, ib_bus_wdfsect -[ib_bus_wdfsect] -KmdfLibraryVersion = $KMDFVERSION$ +[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 [Strings] -SPSVCINST_ASSOCSERVICE= 0x00000002 -MSFT = "Microsoft" -StdMfg = "(Standard system devices)" -DiskId1 = "InfiniBand Fabric Dynamic Bus Installation Disk #1" -IB_Bus.DeviceDesc = "InfiniBand Fabric Dynamic Bus Enumerator" -ib_bus.SVCDESC = "InfiniBand Fabric Dynamic Bus Enumerator" - +OPENIB = "OpenIB Alliance" +SST = "SilverStorm Technologies" +IbFabric.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" +IbFabric.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/IBFD/core/bus/kmdf/ib_bus.rc b/branches/IBFD/core/bus/kmdf/ib_bus.rc index 967be5c1..e6f549c7 100644 --- a/branches/IBFD/core/bus/kmdf/ib_bus.rc +++ b/branches/IBFD/core/bus/kmdf/ib_bus.rc @@ -41,8 +41,8 @@ #define VER_FILEDESCRIPTION_STR "InfiniBand Fabric Dynamic Bus Enumerator" #endif -#define VER_INTERNALNAME_STR "ib_bus.sys" -#define VER_ORIGINALFILENAME_STR "ib_bus.sys" +#define VER_INTERNALNAME_STR "ibbus.sys" +#define VER_ORIGINALFILENAME_STR "ibbus.sys" #include diff --git a/branches/IBFD/core/bus/kmdf/ib_bus_public.h b/branches/IBFD/core/bus/kmdf/ib_bus_public.h new file mode 100644 index 00000000..0f606747 --- /dev/null +++ b/branches/IBFD/core/bus/kmdf/ib_bus_public.h @@ -0,0 +1,166 @@ +/*++ +Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved + +Module Name: + + 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/IBFD/core/bus/kmdf/trace.h b/branches/IBFD/core/bus/kmdf/trace.h index 27d8ed8b..2bbddde9 100644 --- a/branches/IBFD/core/bus/kmdf/trace.h +++ b/branches/IBFD/core/bus/kmdf/trace.h @@ -31,8 +31,8 @@ Environment: // TODO: These defines are missing in evntrace.h // in some DDK build environments (XP). // -#if !defined(TRACE_LEVEL_NONE) #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 @@ -43,8 +43,6 @@ Environment: #define TRACE_LEVEL_RESERVED7 7 #define TRACE_LEVEL_RESERVED8 8 #define TRACE_LEVEL_RESERVED9 9 -#endif - // // Define Debug Flags @@ -62,6 +60,18 @@ Environment: #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 ( diff --git a/branches/IBFD/core/bus/kmdf/wmi.c b/branches/IBFD/core/bus/kmdf/wmi.c index f2883a4e..c578e5e0 100644 --- a/branches/IBFD/core/bus/kmdf/wmi.c +++ b/branches/IBFD/core/bus/kmdf/wmi.c @@ -22,7 +22,7 @@ Environment: --*/ -#include "ib_fabric.h" +#include "bus_driver.h" #include "ib_busMof.h" #if defined(EVENT_TRACING) @@ -48,9 +48,9 @@ NTSTATUS Bus_WmiRegistration( WDFDEVICE Device ) { WDF_WMI_PROVIDER_CONFIG providerConfig; - WDF_WMI_INSTANCE_CONFIG instanceConfig; - PFDO_DEVICE_DATA deviceData; - NTSTATUS status; + WDF_WMI_INSTANCE_CONFIG instanceConfig; + PFDO_BUS_DATA deviceData; + NTSTATUS status; DECLARE_CONST_UNICODE_STRING(busRsrcName, BUSRESOURCENAME); PAGED_CODE(); @@ -135,7 +135,7 @@ Bus_EvtStdDataSetItem( IN ULONG InBufferSize, IN PVOID InBuffer ) { - PFDO_DEVICE_DATA fdoData; + PFDO_BUS_DATA fdoData; PAGED_CODE(); @@ -151,7 +151,7 @@ Bus_EvtStdDataSetItem( return STATUS_BUFFER_TOO_SMALL; } - DebugLevel = fdoData->StdBusData.DebugPrintLevel = *((PULONG)InBuffer); + bus_globals.dbg_lvl = fdoData->StdBusData.DebugPrintLevel = *((PULONG)InBuffer); return STATUS_SUCCESS; } @@ -189,7 +189,7 @@ Bus_EvtStdDataSetInstance( IN ULONG InBufferSize, IN PVOID InBuffer ) { - PFDO_DEVICE_DATA fdoData; + PFDO_BUS_DATA fdoData; UNREFERENCED_PARAMETER(InBufferSize); @@ -200,7 +200,7 @@ Bus_EvtStdDataSetInstance( // // We will update only writable elements. // - DebugLevel = fdoData->StdBusData.DebugPrintLevel = + bus_globals.dbg_lvl = fdoData->StdBusData.DebugPrintLevel = ((PIBF_BUS_WMI_STD_DATA)InBuffer)->DebugPrintLevel; return STATUS_SUCCESS; @@ -238,7 +238,7 @@ Bus_EvtStdDataQueryInstance( IN PVOID OutBuffer, OUT PULONG BufferUsed ) { - PFDO_DEVICE_DATA fdoData; + PFDO_BUS_DATA fdoData; UNREFERENCED_PARAMETER(OutBufferSize); -- 2.41.0