[ofw] [RFC] [PATCH 1/3] winmad kernel filter driver

Sean Hefty sean.hefty at intel.com
Tue Jul 1 18:44:31 PDT 2008


The WinMad driver is an upper filter driver for Infiniband HCAs.  It uses the
kernel IBAL MAD interfaces for access to qp 0 and 1.  It exposes a simple file
system interface to userspace for registering and deregistering MAD agents,
and supports file read/write operations to send receive MADs.

WinMad does not implement SMI or GSI interfaces.  It only exposes a userspace
interface to MAD services that is optimized for Windows.

The driver supports asynchronous reads and writes using overlapped I/O, and
handles PnP device removal events with active userspace clients.

File writes results in sending MADs using a specified MAD agent.  File read
operations receive MADs across all registered agents for a single user.

Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
The following source code implements the WinMad driver.  Additional files needed
to build and install the driver are not shown, but will be available once the
files are checked into an SVN branch.

/*
 * Copyright (c) 2008 Intel Corporation. All rights reserved.
 *
 * This software is available to you under the OpenIB.org BSD license
 * below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
 * 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.
 */

#include <ntddk.h>
#include <wdf.h>
#include <wdmsec.h>
#include <ntstatus.h>
#include <initguid.h>

#include "wm_ioctl.h"
#include "wm_driver.h"
#include "wm_provider.h"
#include "wm_reg.h"

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WM_IB_DEVICE, WmIbDeviceGetContext)
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WM_PROVIDER, WmProviderGetContext)

WDFDEVICE				ControlDevice;
static LIST_ENTRY		DevList;
static LIST_ENTRY		ProvList;
static KGUARDED_MUTEX	Lock;

static EVT_WDF_DRIVER_DEVICE_ADD			WmIbDeviceAdd;
static EVT_WDF_OBJECT_CONTEXT_CLEANUP		WmIbDeviceCleanup;
static EVT_WDF_DEVICE_D0_ENTRY				WmPowerD0Entry;
static EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL	WmIoDeviceControl;
static EVT_WDF_IO_QUEUE_IO_READ				WmIoRead;
static EVT_WDF_IO_QUEUE_IO_WRITE			WmIoWrite;
static EVT_WDF_DEVICE_FILE_CREATE			WmFileCreate;
static EVT_WDF_FILE_CLEANUP					WmFileCleanup;
static EVT_WDF_FILE_CLOSE					WmFileClose;

WM_IB_DEVICE *WmIbDeviceGet(UINT64 Guid)
{
	WM_IB_DEVICE	*cur_dev, *dev = NULL;
	LIST_ENTRY		*entry;

	KeAcquireGuardedMutex(&Lock);
	for (entry = DevList.Flink; entry != &DevList; entry = entry->Flink) {
		cur_dev = CONTAINING_RECORD(entry, WM_IB_DEVICE, Entry);
		if (cur_dev->Guid == Guid) {
			InterlockedIncrement(&cur_dev->Ref);
			dev = cur_dev;
			break;
		}
	}
	KeReleaseGuardedMutex(&Lock);
	return dev;
}

void WmIbDevicePut(WM_IB_DEVICE *pDevice)
{
	if (InterlockedDecrement(&pDevice->Ref) == 0) {
		KeSetEvent(&pDevice->Event, 0, FALSE);
	}
}

static VOID WmIoDeviceControl(WDFQUEUE Queue, WDFREQUEST Request,
							  size_t OutLen, size_t InLen, ULONG IoControlCode)
{
	WDFFILEOBJECT	file;
	WM_PROVIDER		*prov;
	UNREFERENCED_PARAMETER(OutLen);
	UNREFERENCED_PARAMETER(InLen);
	UNREFERENCED_PARAMETER(Queue);

	file = WdfRequestGetFileObject(Request);
	prov = WmProviderGetContext(file);

	switch (IoControlCode) {
	case WM_IOCTL_REGISTER:
		WmRegister(prov, Request);
		break;
	case WM_IOCTL_DEREGISTER:
		WmDeregister(prov, Request);
		break;
	case WM_IOCTL_CANCEL:
		// TODO!!!
		WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);
		break;
	default:
		WdfRequestComplete(Request, STATUS_PROCEDURE_NOT_FOUND);
		break;
	}
}

static VOID WmIoRead(WDFQUEUE Queue, WDFREQUEST Request, size_t Length)
{
	WDFFILEOBJECT	file;
	WM_PROVIDER		*prov;
	UNREFERENCED_PARAMETER(Queue);

	file = WdfRequestGetFileObject(Request);
	prov = WmProviderGetContext(file);

	WmProviderRead(prov, Request);
}

static VOID WmIoWrite(WDFQUEUE Queue, WDFREQUEST Request, size_t Length)
{
	WDFFILEOBJECT	file;
	WM_PROVIDER		*prov;
	UNREFERENCED_PARAMETER(Queue);

	file = WdfRequestGetFileObject(Request);
	prov = WmProviderGetContext(file);

	WmProviderWrite(prov, Request);
}

static VOID WmFileCreate(WDFDEVICE Device, WDFREQUEST Request,
						 WDFFILEOBJECT FileObject)
{
	WM_PROVIDER	*prov = WmProviderGetContext(FileObject);
	UNREFERENCED_PARAMETER(Device);

	WmProviderInit(prov);
	KeAcquireGuardedMutex(&Lock);
	InsertHeadList(&ProvList, &prov->Entry);
	KeReleaseGuardedMutex(&Lock);
	WdfRequestComplete(Request, STATUS_SUCCESS);
}

static VOID WmFileCleanup(WDFFILEOBJECT FileObject)
{
	WM_PROVIDER *prov = WmProviderGetContext(FileObject);

	KeAcquireGuardedMutex(&Lock);
	RemoveEntryList(&prov->Entry);
	KeReleaseGuardedMutex(&Lock);
	WmProviderCleanup(prov);
}

static VOID WmFileClose(WDFFILEOBJECT FileObject)
{
	UNREFERENCED_PARAMETER(FileObject);
}

static VOID WmCreateControlDevice(WDFDRIVER Driver)
{
	PWDFDEVICE_INIT			pinit;
	WDF_FILEOBJECT_CONFIG	fileconfig;
	WDF_OBJECT_ATTRIBUTES	attr;
	WDF_IO_QUEUE_CONFIG		ioconfig;
	NTSTATUS				status;
	WDFQUEUE				queue;
	DECLARE_CONST_UNICODE_STRING(name, L"\\Device\\WinMad");
	DECLARE_CONST_UNICODE_STRING(symlink, L"\\DosDevices\\WinMad");

	pinit = WdfControlDeviceInitAllocate(Driver,
	
&SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);
	if (pinit == NULL) {
			return;
	}

	WdfDeviceInitSetExclusive(pinit, FALSE);
	status = WdfDeviceInitAssignName(pinit, &name);
	if (!NT_SUCCESS(status)) {
		goto err1;
	}

	WDF_FILEOBJECT_CONFIG_INIT(&fileconfig, WmFileCreate, WmFileClose,
							   WmFileCleanup);
	WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WM_PROVIDER);
	WdfDeviceInitSetFileObjectConfig(pinit, &fileconfig, &attr);

	WDF_OBJECT_ATTRIBUTES_INIT(&attr);
	status = WdfDeviceCreate(&pinit, &attr, &ControlDevice);
	if (!NT_SUCCESS(status)) {
		goto err1;
	}

	status = WdfDeviceCreateSymbolicLink(ControlDevice, &symlink);
	if (!NT_SUCCESS(status)) {
		goto err2;
	}

	WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioconfig, WdfIoQueueDispatchParallel);
	ioconfig.EvtIoDeviceControl = WmIoDeviceControl;
	ioconfig.EvtIoRead = WmIoRead;
	ioconfig.EvtIoWrite = WmIoWrite;
	status = WdfIoQueueCreate(ControlDevice, &ioconfig,
							  WDF_NO_OBJECT_ATTRIBUTES, &queue);
	if (!NT_SUCCESS(status)) {
		goto err2;
	}

	WdfControlFinishInitializing(ControlDevice);
	return;

err2:
	WdfObjectDelete(ControlDevice);
	return;
err1:
	WdfDeviceInitFree(pinit);
}

static NTSTATUS WmInitIbPorts(WM_IB_DEVICE *pDevice)
{
	NTSTATUS		status;
	ib_api_status_t ib_status;
	ib_ca_attr_t	*attr;
	UINT32			size;
	UINT8			i;

	size = 0;
	ib_status = pDevice->IbInterface.query_ca(pDevice->hDevice, NULL, &size);
	if (ib_status != IB_INSUFFICIENT_MEMORY) {
		return STATUS_UNSUCCESSFUL;
	}

	attr = ExAllocatePoolWithTag(PagedPool, size, 'acmw');
	if (attr == NULL) {
		return STATUS_NO_MEMORY;
	}

	ib_status = pDevice->IbInterface.query_ca(pDevice->hDevice, attr, &size);
	if (ib_status != IB_SUCCESS) {
		status = STATUS_UNSUCCESSFUL;
		goto out;
	}

	size = sizeof(WM_IB_PORT) * attr->num_ports;
	pDevice->pPortArray = ExAllocatePoolWithTag(PagedPool, size, 'pimw');
	if (pDevice->pPortArray == NULL) {
		status = STATUS_NO_MEMORY;
		goto out;
	}

	for (i = 0; i < attr->num_ports; i++) {
		pDevice->pPortArray[i].Guid = attr->p_port_attr[i].port_guid;
	}
	pDevice->PortCount = attr->num_ports;

	status = STATUS_SUCCESS;
out:
	ExFreePool(attr);
	return status;
}

static NTSTATUS WmInitIbDevice(WDFDEVICE Device, WM_IB_DEVICE *pDevice)
{
	NTSTATUS status;
	ib_api_status_t ib_status;

	status = WdfFdoQueryForInterface(Device, &GUID_IB_AL_INTERFACE,
									 (PINTERFACE) &pDevice->IbInterface,
									 sizeof(pDevice->IbInterface),
									 AL_INTERFACE_VERSION, NULL);
	if (!NT_SUCCESS(status)) {
		return status;
	}

	ib_status = pDevice->IbInterface.open_al(&pDevice->hIbal);
	if (ib_status != IB_SUCCESS) {
		goto err1;
	}

	ib_status = pDevice->IbInterface.open_ca(pDevice->hIbal, pDevice->Guid,
											 NULL, pDevice,
&pDevice->hDevice);
	if (ib_status != IB_SUCCESS) {
		goto err2;
	}

	ib_status = pDevice->IbInterface.alloc_pd(pDevice->hDevice, IB_PDT_ALIAS,
											  pDevice, &pDevice->hPd);
	if (ib_status != IB_SUCCESS) {
		goto err3;
	}

	status = WmInitIbPorts(pDevice);
	if (!NT_SUCCESS(status)) {
		goto err4;
	}

	return STATUS_SUCCESS;

err4:
	pDevice->IbInterface.dealloc_pd(pDevice->hPd, NULL);
err3:
	pDevice->IbInterface.close_ca(pDevice->hDevice, NULL);
err2:
	pDevice->IbInterface.close_al(pDevice->hIbal);
	pDevice->hIbal = NULL;
err1:
	pDevice->IbInterface.wdm.InterfaceDereference(pDevice->IbInterface.wdm.Context);
	return STATUS_UNSUCCESSFUL;
}

static NTSTATUS WmPowerD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE PreviousState)
{
	WM_IB_DEVICE	*dev;
	BOOLEAN			create;
	NTSTATUS		status;

	dev = WmIbDeviceGetContext(Device);
	if (dev->hIbal != NULL) {
		return STATUS_SUCCESS;
	}

	status = WdfFdoQueryForInterface(Device, &GUID_RDMA_INTERFACE_VERBS,
									 (PINTERFACE) &dev->VerbsInterface,
									 sizeof(dev->VerbsInterface), VerbsVersion(2,
0),
									 NULL);
	if (!NT_SUCCESS(status)) {
		return status;
	}

	dev->Guid = dev->VerbsInterface.Verbs.guid;
	dev->IbInterface.wdm.InterfaceDereference(dev->IbInterface.wdm.Context);

	status = WmInitIbDevice(Device, dev);
	if (!NT_SUCCESS(status)) {
		return status;
	}

	KeAcquireGuardedMutex(&Lock);
	create = IsListEmpty(&DevList);
	InsertHeadList(&DevList, &dev->Entry);
	KeReleaseGuardedMutex(&Lock);

	if (create) {
		WmCreateControlDevice(WdfGetDriver());
	}

	return STATUS_SUCCESS;
}

static NTSTATUS WmIbDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
{
	WDF_OBJECT_ATTRIBUTES			attr;
	WDF_PNPPOWER_EVENT_CALLBACKS	power;
	WDFDEVICE						dev;
	WM_IB_DEVICE					*pdev;
	NTSTATUS						status;

	WdfFdoInitSetFilter(DeviceInit);

	WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WM_IB_DEVICE);
	attr.EvtCleanupCallback = WmIbDeviceCleanup;

	WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&power);
	power.EvtDeviceD0Entry = WmPowerD0Entry;
	WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &power);

	status = WdfDeviceCreate(&DeviceInit, &attr, &dev);
	if (!NT_SUCCESS(status)) {
		return status;
	}

	pdev = WmIbDeviceGetContext(dev);
	RtlZeroMemory(pdev, sizeof *pdev);
	pdev->Ref = 1;
	KeInitializeEvent(&pdev->Event, NotificationEvent, FALSE);

	return STATUS_SUCCESS;
}

static VOID WmIbDeviceCleanup(WDFDEVICE Device)
{
	WM_PROVIDER			*prov;
	WM_IB_DEVICE		*pdev;
	WM_REGISTRATION		*reg;
	LIST_ENTRY			*entry;
	BOOLEAN				destroy;
	WDFDEVICE			ctrldev;

	pdev = WmIbDeviceGetContext(Device);
	if (pdev->hIbal == NULL) {
		return;
	}

	KeAcquireGuardedMutex(&Lock);
	RemoveEntryList(&pdev->Entry);
	destroy = IsListEmpty(&DevList);
	ctrldev = ControlDevice;

	for (entry = ProvList.Flink; entry != &ProvList; entry = entry->Flink) {
		prov = CONTAINING_RECORD(entry, WM_PROVIDER, Entry);
		WmProviderRemoveHandler(prov, pdev);
	}

	KeReleaseGuardedMutex(&Lock);

	if (InterlockedDecrement(&pdev->Ref) > 0) {
		KeWaitForSingleObject(&pdev->Event, Executive, KernelMode, FALSE, NULL);
	}

	ExFreePool(pdev->pPortArray);
	pdev->IbInterface.dealloc_pd(pdev->hPd, NULL);
	pdev->IbInterface.close_ca(pdev->hDevice, NULL);
	pdev->IbInterface.close_al(pdev->hIbal);
	pdev->IbInterface.wdm.InterfaceDereference(pdev->IbInterface.wdm.Context);

	if (destroy) {
		WdfObjectDelete(ctrldev);
	}
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
	WDF_DRIVER_CONFIG		config;
	NTSTATUS				status;
	WDFDRIVER				driv;

	InitializeListHead(&DevList);
	InitializeListHead(&ProvList);
	KeInitializeGuardedMutex(&Lock);

	WDF_DRIVER_CONFIG_INIT(&config, WmIbDeviceAdd);
	status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
							 &config, &driv);
	if (!NT_SUCCESS(status)) {
		return status;
	}

	return STATUS_SUCCESS;
}
/*
 * Copyright (c) 2008 Intel Corporation. All rights reserved.
 *
 * This software is available to you under the OpenIB.org BSD license
 * below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
 * 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.
 */

#pragma once

#ifndef _WM_DRIVER_H_
#define _WM_DRIVER_H_

#include <ntddk.h>
#include <wdm.h>
#include <wdf.h>

#include <rdma\verbs.h>
#include <iba\ib_al_ifc.h>

extern WDFDEVICE			ControlDevice;

typedef struct _WM_IB_PORT
{
	UINT64					Guid;

}	WM_IB_PORT;

typedef struct _WM_IB_DEVICE
{
	LIST_ENTRY				Entry;
	LONG					Ref;
	KEVENT					Event;
	UINT64					Guid;		// Network byte order
	union
	{
		RDMA_INTERFACE_VERBS	VerbsInterface;
		ib_al_ifc_t				IbInterface;
	};
	ib_al_handle_t			hIbal;
	ib_ca_handle_t			hDevice;
	ib_pd_handle_t			hPd;
	int						PortCount;
	WM_IB_PORT				*pPortArray;

}	WM_IB_DEVICE;

WM_IB_DEVICE *WmIbDeviceGet(UINT64 Guid);
void WmIbDevicePut(WM_IB_DEVICE *pDevice);

#endif // _WM_DRIVER_H_
/*
 * Copyright (c) 2008 Intel Corporation. All rights reserved.
 *
 * This software is available to you under the OpenIB.org BSD license
 * below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
 * 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.
 */

#include "index_list.c"
#include "wm_driver.h"
#include "wm_ioctl.h"
#include "wm_provider.h"
#include "wm_reg.h"

void WmProviderGet(WM_PROVIDER *pProvider)
{
	InterlockedIncrement(&pProvider->Ref);
}

void WmProviderPut(WM_PROVIDER *pProvider)
{
	if (InterlockedDecrement(&pProvider->Ref) == 0) {
		KeSetEvent(&pProvider->Event, 0, FALSE);
	}
}

NTSTATUS WmProviderInit(WM_PROVIDER *pProvider)
{
	WDF_IO_QUEUE_CONFIG	config;
	NTSTATUS status;

	IndexListInit(&pProvider->RegIndex);
	pProvider->MadHead = NULL;
	pProvider->MadTail = NULL;

	KeInitializeGuardedMutex(&pProvider->Lock);
	pProvider->Ref = 1;
	KeInitializeEvent(&pProvider->Event, NotificationEvent, FALSE);

	pProvider->Pending = 0;
	pProvider->Active = 0;
	KeInitializeEvent(&pProvider->SharedEvent, NotificationEvent, FALSE);
	pProvider->Exclusive = 0;
	KeInitializeEvent(&pProvider->ExclusiveEvent, SynchronizationEvent, FALSE);

	WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual);
	status = WdfIoQueueCreate(ControlDevice, &config,
							  WDF_NO_OBJECT_ATTRIBUTES, &pProvider->ReadQueue);
	return status;
}

static void WmInsertMad(WM_PROVIDER *pProvider, ib_mad_element_t *pMad)
{
	if (pProvider->MadHead == NULL) {
		pProvider->MadHead = pMad;
	} else {
		pProvider->MadTail->p_next = pMad;
	}
	pProvider->MadTail = pMad;
}

static ib_mad_element_t *WmRemoveMad(WM_PROVIDER *pProvider)
{
	ib_mad_element_t *mad;

	mad = pProvider->MadHead;
	if (mad != NULL) {
		pProvider->MadHead = (ib_mad_element_t *) mad->p_next;
		mad->p_next = NULL;
	}

	return mad;
}

void WmProviderFlushReceives(WM_PROVIDER *pProvider, WM_REGISTRATION *pRegistration)
{
	ib_mad_element_t	*mad, *next, *list;

	WdfObjectAcquireLock(pProvider->ReadQueue);
	list = pProvider->MadHead;
	pProvider->MadHead = NULL;

	for (mad = list; mad != NULL; mad = next) {
		next = mad->p_next;
		mad->p_next = NULL;

		if (mad->context1 == pRegistration) {
			pRegistration->pDevice->IbInterface.put_mad(mad);
		} else {
			WmInsertMad(pProvider, mad);
		}
	}
	WdfObjectReleaseLock(pProvider->ReadQueue);
}

void WmProviderCleanup(WM_PROVIDER *pProvider)
{
	WM_REGISTRATION		*reg;

	while ((reg = IndexListRemoveHead(&pProvider->RegIndex)) != NULL) {
		RemoveEntryList(&reg->Entry);
		WmRegFree(reg);
	}

	if (InterlockedDecrement(&pProvider->Ref) > 0) {
		KeWaitForSingleObject(&pProvider->Event, Executive, KernelMode, FALSE, NULL);
	}

	WdfIoQueuePurgeSynchronously(pProvider->ReadQueue);
	WdfObjectDelete(pProvider->ReadQueue);

	IndexListDestroy(&pProvider->RegIndex);
}

// See comment above WmProviderRemoveHandler.
static void WmProviderLockRemove(WM_PROVIDER *pProvider)
{
	KeAcquireGuardedMutex(&pProvider->Lock);
	pProvider->Exclusive++;
	KeClearEvent(&pProvider->SharedEvent);
	while (pProvider->Active > 0) {
		KeReleaseGuardedMutex(&pProvider->Lock);
		KeWaitForSingleObject(&pProvider->ExclusiveEvent, Executive, KernelMode,
							  FALSE, NULL);
		KeAcquireGuardedMutex(&pProvider->Lock);
	}
	pProvider->Active++;
	KeReleaseGuardedMutex(&pProvider->Lock);
}

// See comment above WmProviderRemoveHandler.
static void WmProviderUnlockRemove(WM_PROVIDER *pProvider)
{
	KeAcquireGuardedMutex(&pProvider->Lock);
	pProvider->Exclusive--;
	pProvider->Active--;
	if (pProvider->Exclusive > 0) {
		KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE);
	} else if (pProvider->Pending > 0) {
		KeSetEvent(&pProvider->SharedEvent, 0, FALSE);
	}
	KeReleaseGuardedMutex(&pProvider->Lock);
}

/*
 * Must hold pProvider->Lock.  Function may release and re-acquire.
 * See comment above WmProviderRemoveHandler.
 */
void WmProviderDisableRemove(WM_PROVIDER *pProvider)
{
	while (pProvider->Exclusive > 0) {
		pProvider->Pending++;
		KeReleaseGuardedMutex(&pProvider->Lock);
		KeWaitForSingleObject(&pProvider->SharedEvent, Executive, KernelMode,
							  FALSE, NULL);
		KeAcquireGuardedMutex(&pProvider->Lock);
		pProvider->Pending--;
	}
	InterlockedIncrement(&pProvider->Active);
}

/*
 * No need to hold pProvider->Lock when releasing.
 * See comment above WmProviderRemoveHandler.
 */
void WmProviderEnableRemove(WM_PROVIDER *pProvider)
{
	InterlockedDecrement(&pProvider->Active);
	if (pProvider->Exclusive > 0) {
		KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE);
	}
}

/*
 * The remove handler blocks all other threads executing through this
 * provider until the remove has been processed.  Because device removal is
 * rare, we want a simple, optimized code path for all calls that access
 * the underlying hardware device, making use of any locks that we would
 * have to acquire anyway.  The locking for exclusive access can be
 * as ugly and slow as needed.
 */
void WmProviderRemoveHandler(WM_PROVIDER *pProvider, WM_IB_DEVICE *pDevice)
{
	WM_REGISTRATION *reg;
	SIZE_T i;

	WmProviderLockRemove(pProvider);
	IndexListForEach(&pProvider->RegIndex, i) {
		reg = IndexListAt(&pProvider->RegIndex, i);
		if (reg->pDevice == pDevice) {
			WmRegRemoveHandler(reg);
		}
	}
	WmProviderUnlockRemove(pProvider);
}

static NTSTATUS WmCopyRead(WM_PROVIDER *pProvider, WM_IO_MAD *pIoMad,
						   ib_mad_element_t *pMad, size_t *pLen)
{
	WM_REGISTRATION		*reg;

	reg = (WM_REGISTRATION *) pMad->context1;
	pIoMad->Id = reg->Id;

	pIoMad->Status = pMad->status;
	pIoMad->Timeout = pMad->timeout_ms;
	pIoMad->Retries = pMad->retry_cnt;
	pIoMad->Length = pMad->size;

	pIoMad->Address.Qpn = pMad->remote_qp;
	pIoMad->Address.Qkey = pMad->remote_qkey;
	pIoMad->Address.PkeyIndex = pMad->pkey_index;

	if ((pIoMad->Address.GrhValid = (UINT16) pMad->grh_valid)) {
		pIoMad->Address.VersionClassFlow = pMad->p_grh->ver_class_flow;
		pIoMad->Address.HopLimit = pMad->p_grh->hop_limit;
		pIoMad->Address.GidIndex = 0;	// TODO: update IBAL to use SGID index
		RtlCopyMemory(pIoMad->Address.Gid, pMad->p_grh->dest_gid.raw, 16);
	}

	pIoMad->Address.Lid = pMad->remote_lid;
	pIoMad->Address.ServiceLevel = pMad->remote_sl;
	pIoMad->Address.PathBits = pMad->path_bits;
	pIoMad->Address.StaticRate = 0;
	pIoMad->Address.Reserved = 0;

	if (*pLen >= sizeof(WM_IO_MAD) + pMad->size) {
		RtlCopyMemory(pIoMad + 1, pMad->p_mad_buf, pMad->size);
		*pLen = sizeof(WM_IO_MAD) + pMad->size;
		return STATUS_SUCCESS;
	} else {
		*pLen = sizeof(WM_IO_MAD);
		return STATUS_MORE_ENTRIES;
	}
}

void WmProviderRead(WM_PROVIDER *pProvider, WDFREQUEST Request)
{
	WM_REGISTRATION		*reg;
	NTSTATUS			status;
	WM_IO_MAD			*wmad;
	size_t				outlen, len = 0;

	status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WM_IO_MAD), &wmad, &outlen);
	if (!NT_SUCCESS(status)) {
		goto out;
	}

	WdfObjectAcquireLock(pProvider->ReadQueue);
	if (pProvider->MadHead == NULL) {
		status = WdfRequestForwardToIoQueue(Request, pProvider->ReadQueue);
		WdfObjectReleaseLock(pProvider->ReadQueue);
		if (NT_SUCCESS(status)) {
			return;
		}
		goto out;
	}

	len = outlen;
	status = WmCopyRead(pProvider, wmad, pProvider->MadHead, &len);
	if (NT_SUCCESS(status)) {
		reg = (WM_REGISTRATION *) pProvider->MadHead->context1;
		reg->pDevice->IbInterface.put_mad(WmRemoveMad(pProvider));
	}
	WdfObjectReleaseLock(pProvider->ReadQueue);

out:
	WdfRequestCompleteWithInformation(Request, status, len);
}

static NTSTATUS WmSendMad(WM_REGISTRATION *pRegistration, WM_IO_MAD *pIoMad, UINT32 size)
{
	ib_al_ifc_t			*pifc;
	NTSTATUS			status;
	ib_mad_element_t	*mad;
	ib_api_status_t		ib_status;

	pifc = &pRegistration->pDevice->IbInterface;
	ib_status = pifc->get_mad(pRegistration->hMadPool, size, &mad);
	if (ib_status != IB_SUCCESS) {
		return STATUS_NO_MEMORY;
	}

	mad->context1 = pRegistration;
	RtlCopyMemory(mad->p_mad_buf, pIoMad + 1, size);
	mad->size = size;
	mad->remote_qp = pIoMad->Address.Qpn;
	mad->remote_qkey = pIoMad->Address.Qkey;
	mad->resp_expected = (pIoMad->Timeout > 0);
	mad->timeout_ms = pIoMad->Timeout;
	mad->retry_cnt = pIoMad->Retries;

	if ((mad->grh_valid = pIoMad->Address.GrhValid)) {
		mad->p_grh->ver_class_flow = pIoMad->Address.VersionClassFlow;
		mad->p_grh->hop_limit = pIoMad->Address.HopLimit;
		// TODO: update IBAL to use SGID index
		// mad->p_grh->src_gid_index = pIoMad->Address.GidIndex;
		RtlCopyMemory(mad->p_grh->dest_gid.raw, pIoMad->Address.Gid, 16);
	}

	mad->remote_lid = pIoMad->Address.Lid;
	mad->remote_sl = pIoMad->Address.ServiceLevel;
	mad->pkey_index = pIoMad->Address.PkeyIndex;
	mad->path_bits = pIoMad->Address.PathBits;

	ib_status = pifc->send_mad(pRegistration->hService, mad, NULL);
	if (ib_status != IB_SUCCESS) {
		status = STATUS_UNSUCCESSFUL;
		goto err;
	}

	return STATUS_SUCCESS;

err:
	pRegistration->pDevice->IbInterface.put_mad(mad);
	return status;
}

void WmProviderWrite(WM_PROVIDER *pProvider, WDFREQUEST Request)
{
	WM_REGISTRATION		*reg;
	NTSTATUS			status;
	WM_IO_MAD			*wmad;
	size_t				inlen;

	status = WdfRequestRetrieveInputBuffer(Request, sizeof(WM_IO_MAD) + 256,
										   &wmad, &inlen);
	if (!NT_SUCCESS(status)) {
		goto out;
	}

	reg = WmRegAcquire(pProvider, wmad->Id);
	if (reg == NULL) {
		status = STATUS_NOT_FOUND;
		goto out;
	}

	status = WmSendMad(reg, wmad, (UINT32) (inlen - sizeof(WM_IO_MAD)));
	WmRegRelease(reg);

out:
	WdfRequestComplete(Request, status);
}

void WmReceiveHandler(ib_mad_svc_handle_t hService, void *Context,
					  ib_mad_element_t *pMad)
{
	WM_REGISTRATION	*reg;
	WM_PROVIDER		*prov = Context;
	WDFREQUEST		request;
	NTSTATUS		status;
	WM_IO_MAD		*wmad;
	size_t			len = 0;

	UNREFERENCED_PARAMETER(hService);

	WdfObjectAcquireLock(prov->ReadQueue);
	status = WdfIoQueueRetrieveNextRequest(prov->ReadQueue, &request);
	if (!NT_SUCCESS(status)) {
		WmInsertMad(prov, pMad);
		WdfObjectReleaseLock(prov->ReadQueue);
		return;
	}

	status = WdfRequestRetrieveOutputBuffer(request, sizeof(WM_IO_MAD), &wmad, &len);
	if (!NT_SUCCESS(status)) {
		reg = (WM_REGISTRATION *) pMad->context1;
		reg->pDevice->IbInterface.put_mad(pMad);
		goto out;
	}

	status = WmCopyRead(prov, wmad, pMad, &len);
	if (NT_SUCCESS(status)) {
		reg = (WM_REGISTRATION *) pMad->context1;
		reg->pDevice->IbInterface.put_mad(pMad);
	} else {
		WmInsertMad(prov, pMad);
	}
	WdfObjectReleaseLock(prov->ReadQueue);

out:
	WdfRequestCompleteWithInformation(request, status, len);	
}

void WmSendHandler(ib_mad_svc_handle_t hService, void *Context,
				   ib_mad_element_t *pMad)
{
	WM_PROVIDER *prov = Context;
	UNREFERENCED_PARAMETER(hService);
	pMad;
}

void WmProviderCancel(WM_PROVIDER *pProvider, WDFREQUEST Request)
{
	WDFREQUEST	request;
	NTSTATUS	status;

	WdfObjectAcquireLock(pProvider->ReadQueue);
	status = WdfIoQueueRetrieveNextRequest(pProvider->ReadQueue, &request);

	while (NT_SUCCESS(status)) {
		WdfRequestComplete(request, STATUS_CANCELLED);
		status = WdfIoQueueRetrieveNextRequest(pProvider->ReadQueue, &request);
	}
	WdfObjectReleaseLock(pProvider->ReadQueue);

	WdfRequestComplete(Request, status);
}
/*
 * Copyright (c) 2008 Intel Corporation. All rights reserved.
 *
 * This software is available to you under the OpenIB.org BSD license
 * below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
 * 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.
 */

#pragma once

#ifndef _WM_PROVIDER_H_
#define _WM_PROVIDER_H_

#include <ntddk.h>
#include <wdf.h>
#include <wdm.h>

#include <iba\ib_al.h>
#include "wm_driver.h"
#include "index_list.h"

typedef struct _WM_PROVIDER
{
	LIST_ENTRY			Entry;
	INDEX_LIST			RegIndex;
	WDFQUEUE			ReadQueue;

	ib_mad_element_t	*MadHead;
	ib_mad_element_t	*MadTail;

	KGUARDED_MUTEX		Lock;
	LONG				Ref;
	KEVENT				Event;
	LONG				Pending;
	LONG				Active;
	KEVENT				SharedEvent;
	LONG				Exclusive;
	KEVENT				ExclusiveEvent;

}	WM_PROVIDER;

void WmProviderGet(WM_PROVIDER *pProvider);
void WmProviderPut(WM_PROVIDER *pProvider);
NTSTATUS WmProviderInit(WM_PROVIDER *pProvider);
void WmProviderCleanup(WM_PROVIDER *pProvider);

void WmProviderRemoveHandler(WM_PROVIDER *pProvider, WM_IB_DEVICE *pDevice);
void WmProviderDisableRemove(WM_PROVIDER *pProvider);
void WmProviderEnableRemove(WM_PROVIDER *pProvider);

void WmProviderRead(WM_PROVIDER *pProvider, WDFREQUEST Request);
void WmProviderWrite(WM_PROVIDER *pProvider, WDFREQUEST Request);
void WmReceiveHandler(ib_mad_svc_handle_t hService, void *Context,
					  ib_mad_element_t *pMad);
void WmSendHandler(ib_mad_svc_handle_t hService, void *Context,
				   ib_mad_element_t *pMad);
void WmProviderFlushReceives(WM_PROVIDER *pProvider,
							 struct _WM_REGISTRATION *pRegistration);

#endif // _WM_PROVIDER_H_
/*
 * Copyright (c) 2008 Intel Corporation. All rights reserved.
 *
 * This software is available to you under the OpenIB.org BSD license
 * below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
 * 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.
 */

#include <iba\ib_al.h>
#include "wm_driver.h"
#include "wm_reg.h"
#include "wm_ioctl.h"

WM_REGISTRATION *WmRegAcquire(WM_PROVIDER *pProvider, UINT64 Id)
{
	WM_REGISTRATION *reg;

	KeAcquireGuardedMutex(&pProvider->Lock);
	WmProviderDisableRemove(pProvider);
	reg = IndexListAt(&pProvider->RegIndex, (SIZE_T) Id);
	if (reg != NULL && reg->pDevice != NULL) {
		InterlockedIncrement(&reg->Ref);
	} else {
		reg = NULL;
		WmProviderEnableRemove(pProvider);
	}
	KeReleaseGuardedMutex(&pProvider->Lock);

	return reg;
}

void WmRegRelease(WM_REGISTRATION *pRegistration)
{
	WmProviderEnableRemove(pRegistration->pProvider);
	InterlockedDecrement(&pRegistration->Ref);
}

static WM_REGISTRATION *WmRegAlloc(WM_PROVIDER *pProvider)
{
	WM_REGISTRATION *reg;

	reg = ExAllocatePoolWithTag(PagedPool, sizeof(WM_REGISTRATION), 'grmw');
	if (reg == NULL) {
		return NULL;
	}

	RtlZeroMemory(reg, sizeof(WM_REGISTRATION));
	reg->Ref = 1;

	reg->pProvider = pProvider;
	WmProviderGet(pProvider);
	return reg;
}

static int WmConvertMethods(ib_mad_svc_t *svc, WM_IO_REGISTER *pAttributes)
{
	int i, j, unsolicited = 0;

	for (i = 0; i < 16; i++) {
		for (j = 0; j < 8; j++) {
			if (((pAttributes->Methods[i] >> j) & 0x01) != 0) {
				svc->method_array[i * 8 + j] = 1;
				unsolicited = 1;
			}
		}
	}

	return unsolicited;
}

static NTSTATUS WmRegInit(WM_REGISTRATION *pRegistration, WM_IO_REGISTER *pAttributes)
{
	WM_IB_DEVICE	*dev;
	ib_qp_create_t	attr;
	ib_mad_svc_t	svc;
	ib_api_status_t ib_status;
	NTSTATUS		status;

	if (pAttributes->Qpn == 0) {
		attr.qp_type = IB_QPT_QP0_ALIAS;
	} else if (pAttributes->Qpn == IB_QP1) {
		attr.qp_type = IB_QPT_QP1_ALIAS;
	} else {
		return STATUS_BAD_NETWORK_PATH;
	}

	dev = WmIbDeviceGet(pAttributes->Guid);
	if (dev == NULL) {
		return STATUS_NO_SUCH_DEVICE;
	}

	if (--pAttributes->Port > dev->PortCount) {
		status = STATUS_INVALID_PORT_HANDLE;
		goto err1;
	}

	RtlZeroMemory(&attr, sizeof attr);
	attr.sq_depth = attr.rq_depth = 1;
	attr.sq_sge = attr.rq_sge = 1;
	attr.sq_signaled = 1;

	ib_status = dev->IbInterface.get_spl_qp(dev->hPd,
	
dev->pPortArray[pAttributes->Port].Guid,
											&attr, pRegistration, NULL,
											&pRegistration->hMadPool,
											&pRegistration->hQp);
	if (ib_status != IB_SUCCESS) {
		status = STATUS_UNSUCCESSFUL;
		goto err1;
	}

	svc.mad_svc_context = pRegistration->pProvider;
	svc.pfn_mad_send_cb = WmSendHandler;
	svc.pfn_mad_recv_cb = WmReceiveHandler;
	svc.support_unsol = WmConvertMethods(&svc, pAttributes);
	svc.mgmt_class = pAttributes->Class;
	svc.mgmt_version = pAttributes->Version;
    svc.svc_type = IB_MAD_SVC_DEFAULT;

	ib_status = dev->IbInterface.reg_mad_svc(pRegistration->hQp, &svc,
											 &pRegistration->hService);
	if (ib_status != IB_SUCCESS) {
		status = STATUS_UNSUCCESSFUL;
		goto err2;
	}

	pRegistration->pDevice = dev;
	return STATUS_SUCCESS;

err2:
	dev->IbInterface.destroy_qp(pRegistration->hQp, NULL);
err1:
	WmIbDevicePut(dev);
	pRegistration->pDevice = NULL;
	return status;
}

void WmRegister(WM_PROVIDER *pProvider, WDFREQUEST Request)
{
	WM_REGISTRATION	*reg;
	WM_IO_REGISTER	*attr;
	UINT64			*id;
	NTSTATUS		status;

	status = WdfRequestRetrieveInputBuffer(Request, sizeof(WM_IO_REGISTER), &attr, NULL);
	if (!NT_SUCCESS(status)) {
		goto err1;
	}
	status = WdfRequestRetrieveOutputBuffer(Request, sizeof(UINT64), &id, NULL);
	if (!NT_SUCCESS(status)) {
		goto err1;
	}

	reg = WmRegAlloc(pProvider);
	if (reg == NULL) {
		status = STATUS_NO_MEMORY;
		goto err1;
	}

	KeAcquireGuardedMutex(&pProvider->Lock);
	WmProviderDisableRemove(pProvider);
	KeReleaseGuardedMutex(&pProvider->Lock);

	status = WmRegInit(reg, attr);
	if (!NT_SUCCESS(status)) {
		goto err2;
	}

	KeAcquireGuardedMutex(&pProvider->Lock);
	reg->Id = IndexListInsertHead(&pProvider->RegIndex, reg);
	if (reg->Id == 0) {
		status = STATUS_NO_MEMORY;
		goto err2;
	}
	KeReleaseGuardedMutex(&pProvider->Lock);

	WmProviderEnableRemove(pProvider);
	*id = reg->Id;
	WdfRequestCompleteWithInformation(Request, status, sizeof(UINT64));
	return;

err2:
	WmRegFree(reg);
	WmProviderEnableRemove(pProvider);
err1:
	WdfRequestComplete(Request, status);
}

void WmDeregister(WM_PROVIDER *pProvider, WDFREQUEST Request)
{
	WM_REGISTRATION *reg;
	UINT64			*id;
	NTSTATUS		status;

	status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);
	if (!NT_SUCCESS(status)) {
		goto out;
	}

	KeAcquireGuardedMutex(&pProvider->Lock);
	WmProviderDisableRemove(pProvider);
	reg = IndexListAt(&pProvider->RegIndex, (SIZE_T) *id);
	if (reg == NULL) {
		status = STATUS_NO_SUCH_DEVICE;
	} else if (reg->Ref > 1) {
		status = STATUS_ACCESS_DENIED;
	} else {
		IndexListRemove(&pProvider->RegIndex, (SIZE_T) *id);
		status = STATUS_SUCCESS;
	}
	KeReleaseGuardedMutex(&pProvider->Lock);

	if (NT_SUCCESS(status)) {
		WmRegFree(reg);
	}
	WmProviderEnableRemove(pProvider);
out:
	WdfRequestComplete(Request, status);
}

void WmRegFree(WM_REGISTRATION *pRegistatration)
{
	WmRegRemoveHandler(pRegistatration);
	WmProviderPut(pRegistatration->pProvider);
	ExFreePool(pRegistatration);
}

void WmRegRemoveHandler(WM_REGISTRATION *pRegistration)
{
	if (pRegistration->pDevice == NULL) {
		return;
	}

	pRegistration->pDevice->IbInterface.destroy_qp(pRegistration->hQp, NULL);
	WmProviderFlushReceives(pRegistration->pProvider, pRegistration);
	WmIbDevicePut(pRegistration->pDevice);
	pRegistration->pDevice = NULL;
}
/*
 * Copyright (c) 2008 Intel Corporation. All rights reserved.
 *
 * This software is available to you under the OpenIB.org BSD license
 * below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
 * 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.
 */

#pragma once

#ifndef _WM_REG_H_
#define _WM_REG_H_

#include <ntddk.h>
#include <wdm.h>
#include <iba\ib_types.h>

#include "wm_driver.h"
#include "wm_provider.h"

typedef struct _WM_REGISTRATION
{
	WM_PROVIDER				*pProvider;
	WM_IB_DEVICE			*pDevice;
	LIST_ENTRY				Entry;

	ib_qp_handle_t			hQp;
	ib_pool_key_t			hMadPool;
	ib_mad_svc_handle_t		hService;
	//UINT8					Port;

	SIZE_T					Id;
	LONG					Ref;

}	WM_REGISTRATION;

void WmRegister(WM_PROVIDER *pProvider, WDFREQUEST Request);
void WmDeregister(WM_PROVIDER *pProvider, WDFREQUEST Request);
void WmRegFree(WM_REGISTRATION *pRegistration);
void WmRegRemoveHandler(WM_REGISTRATION *pRegistration);

WM_REGISTRATION *WmRegAcquire(WM_PROVIDER *pProvider, UINT64 Id);
void WmRegRelease(WM_REGISTRATION *pRegistration);

#endif // __WM_REG_H_





More information about the ofw mailing list