[ofw] [RFC] [PATCH 4/4 v2] winverbs.sys: partial driver implementation

Sean Hefty sean.hefty at intel.com
Thu Apr 24 14:00:34 PDT 2008


The driver implements opening/closing/query a device, allocating PDs,
registering memory, allocating memory windows, and creating address handles.
It also handles device removal with active userspace users.

Major missing verbs functionality includes: CQ, SRQ, and QP.

Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
Changes from V1:
Added MW and AH calls.

Reworked synchronization with device removal.  *Acquire() routines only
return success if the RDMA device has not been removed.  Locking was reworked
to avoid race conditions.

Cleanup routines only remove kernel widgets from index lists if the widget
is successfully destroyed.

Minor fixes and code restructuring based on review feedback.

Index: index_list.c
===================================================================
--- index_list.c	(revision 0)
+++ index_list.c	(revision 0)
@@ -0,0 +1,108 @@
+/*
+ * 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.h"
+
+static BOOLEAN IndexListGrow(INDEX_LIST *pIndexList)
+{
+	INDEX_ENTRY	*array;
+	SIZE_T		size, i;
+
+	size = pIndexList->Size + (PAGE_SIZE / sizeof(INDEX_ENTRY));
+	array = ExAllocatePoolWithTag(PagedPool, size * sizeof(INDEX_ENTRY), 'xdni');
+	if (array == NULL) {
+		return FALSE;
+	}
+
+	i = size;
+	while (i-- > pIndexList->Size) {
+		array[i].pItem = NULL;
+		array[i].Next = pIndexList->FreeList;
+		pIndexList->FreeList = i;
+	}
+
+	if (pIndexList->pArray != NULL) {
+		RtlCopyMemory(array, pIndexList->pArray, pIndexList->Size * sizeof(INDEX_ENTRY));
+		ExFreePool(pIndexList->pArray);
+	} else {
+		array[0].Next = 0;
+		array[0].Prev = 0;
+		pIndexList->FreeList = 1;
+	}
+
+	pIndexList->Size = size;
+	pIndexList->pArray = array;
+	return TRUE;
+}
+
+SIZE_T IndexListInsertHead(INDEX_LIST *pIndexList, void *pItem)
+{
+	INDEX_ENTRY	*entry;
+	SIZE_T		index;
+
+	if (pIndexList->FreeList == 0 && !IndexListGrow(pIndexList)) {
+		return 0;
+	}
+
+	index = pIndexList->FreeList;
+	entry = &pIndexList->pArray[index];
+	pIndexList->FreeList = entry->Next;
+
+	entry->pItem = pItem;
+	entry->Next = pIndexList->pArray[0].Next;
+	pIndexList->pArray[0].Next = index;
+	entry->Prev = 0;
+	pIndexList->pArray[entry->Next].Prev = index;
+
+	return index;
+}
+
+void *IndexListRemove(INDEX_LIST *pIndexList, SIZE_T Index)
+{
+	INDEX_ENTRY	*entry;
+	void		*item;
+
+	if (Index >= pIndexList->Size) {
+		return NULL;
+	}
+
+	entry = &pIndexList->pArray[Index];
+	if (entry->pItem == NULL) {
+		return NULL;
+	}
+
+	pIndexList->pArray[entry->Next].Prev = entry->Prev;
+	pIndexList->pArray[entry->Prev].Next = entry->Next;
+
+	item = entry->pItem;
+	entry->pItem = NULL;
+	entry->Next = pIndexList->FreeList;
+	pIndexList->FreeList = Index;
+	return item;
+}
Index: index_list.h
===================================================================
--- index_list.h	(revision 0)
+++ index_list.h	(revision 0)
@@ -0,0 +1,84 @@
+/*
+ * 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 _INDEX_LIST_H_
+#define _INDEX_LIST_H_
+
+#include <ntddk.h>
+
+typedef struct _INDEX_ENTRY
+{
+	SIZE_T				Next;
+	SIZE_T				Prev;
+	void				*pItem;
+
+}	INDEX_ENTRY;
+
+// Synchronization must be provided by the caller.
+typedef struct _INDEX_LIST
+{
+	INDEX_ENTRY			*pArray;  // pArray[0] is list head of used entries
+	SIZE_T				FreeList; // singly-linked list of free INDEX_ENTRY's
+	SIZE_T				Size;
+
+}	INDEX_LIST;
+
+static void IndexListInit(INDEX_LIST *pIndexList)
+{
+	RtlZeroMemory(pIndexList, sizeof(INDEX_LIST));
+}
+
+static void IndexListDestroy(INDEX_LIST *pIndexList)
+{
+	if (pIndexList->pArray != NULL) {
+		ExFreePool(pIndexList->pArray);
+	}
+}
+
+SIZE_T IndexListInsertHead(INDEX_LIST *pIndexList, void *pItem);
+
+static void *IndexListAt(INDEX_LIST *pIndexList, SIZE_T Index)
+{
+	return (Index < pIndexList->Size) ? pIndexList->pArray[Index].pItem : NULL;
+}
+
+void *IndexListRemove(INDEX_LIST *pIndexList, SIZE_T Index);
+
+static void *IndexListRemoveHead(INDEX_LIST *pIndexList)
+{
+	return IndexListRemove(pIndexList, pIndexList->pArray[0].Next);
+}
+
+#define IndexListForEach(pIndexList, Index)						\
+	for (Index = (pIndexList)->pArray[0].Next; Index != 0;	\
+		 Index = (pIndexList)->pArray[Index].Next)
+
+#endif // _INDEX_LIST_H_
Index: wv_device.c
===================================================================
--- wv_device.c	(revision 0)
+++ wv_device.c	(revision 0)
@@ -0,0 +1,587 @@
+/*
+ * 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 "wv_device.h"
+#include "wv_pd.h"
+#include "wv_ioctl.h"
+
+void WvDeviceGet(WV_DEVICE *pDevice)
+{
+	InterlockedIncrement(&pDevice->Ref);
+}
+
+void WvDevicePut(WV_DEVICE *pDevice)
+{
+	if (InterlockedDecrement(&pDevice->Ref) == 0) {
+		KeSetEvent(&pDevice->Event, 0, FALSE);
+	}
+}
+
+WV_DEVICE *WvDeviceAcquire(WV_PROVIDER *pProvider, UINT64 Id)
+{
+	WV_DEVICE *dev;
+
+	KeAcquireGuardedMutex(&pProvider->Lock);
+	WvProviderDisableRemove(pProvider);
+	dev = IndexListAt(&pProvider->DevIndex, (SIZE_T) Id);
+	if (dev != NULL && dev->hVerbsDevice != NULL) {
+		WvDeviceGet(dev);
+	} else {
+		dev = NULL;
+		WvProviderEnableRemove(pProvider);
+	}
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	return dev;
+}
+
+void WvDeviceRelease(WV_DEVICE *pDevice)
+{
+	WvProviderEnableRemove(pDevice->pProvider);
+	WvDevicePut(pDevice);
+}
+
+WV_DEVICE *WvDeviceAlloc(WV_PROVIDER *pProvider)
+{
+	WV_DEVICE *dev;
+
+	dev = ExAllocatePoolWithTag(PagedPool, sizeof(WV_DEVICE), 'cdvw');
+	if (dev == NULL) {
+		return NULL;
+	}
+
+	dev->pDevice = NULL;
+	dev->pVerbs = NULL;
+	dev->hVerbsDevice = NULL;
+	dev->Ref = 1;
+	InitializeListHead(&dev->PdList);
+	KeInitializeEvent(&dev->Event, NotificationEvent, FALSE);
+
+	dev->pProvider = pProvider;
+	WvProviderGet(pProvider);
+	return dev;
+}
+
+NTSTATUS WvDeviceInit(WV_DEVICE *pDevice, UINT64 Guid, ci_umv_buf_t *pVerbsData)
+{
+	WV_RDMA_DEVICE *dev;
+	ib_api_status_t ib_status;
+
+	dev = WvRdmaDeviceGet(Guid);
+	if (dev == NULL) {
+		return STATUS_NO_SUCH_DEVICE;
+	}
+
+	ib_status = pDevice->pVerbs->um_open_ca(dev->hDevice, pVerbsData,
+											&pDevice->hVerbsDevice);
+	if (ib_status != IB_SUCCESS) {
+		goto err;
+	}
+
+	pDevice->pDevice = dev;
+	pDevice->pVerbs = &dev->Interface.Verbs;
+	return STATUS_SUCCESS;
+
+err:
+	WvRdmaDevicePut(pDevice->pDevice);
+	pDevice->hVerbsDevice = NULL;
+	return STATUS_UNSUCCESSFUL;
+}
+
+void WvDeviceFree(WV_DEVICE *pDevice)
+{
+	if (InterlockedDecrement(&pDevice->Ref) > 0) {
+		KeWaitForSingleObject(&pDevice->Event, Executive, KernelMode, FALSE, NULL);
+	}
+
+	if (pDevice->hVerbsDevice != NULL) {
+		pDevice->pVerbs->um_close_ca(pDevice->pDevice->hDevice,
+									 pDevice->hVerbsDevice);
+		WvRdmaDevicePut(pDevice->pDevice);
+	}
+
+	WvProviderPut(pDevice->pProvider);
+	ExFreePool(pDevice);
+}
+
+void WvDeviceRemoveHandler(WV_DEVICE *pDevice)
+{
+	LIST_ENTRY				*entry;
+	WV_PROTECTION_DOMAIN	*pd;
+
+	for (entry = pDevice->PdList.Flink; entry != &pDevice->PdList;
+		 entry = entry->Flink) {
+		pd = CONTAINING_RECORD(entry, WV_PROTECTION_DOMAIN, Entry);
+		WvPdRemoveHandler(pd);
+	}
+
+	pDevice->pVerbs->um_close_ca(pDevice->pDevice->hDevice,
+								 pDevice->hVerbsDevice);
+	WvRdmaDevicePut(pDevice->pDevice);
+	pDevice->pDevice = NULL;
+	pDevice->pVerbs = NULL;
+	pDevice->hVerbsDevice = NULL;
+}
+
+static void WvSetDeviceCap(UINT32 *pFlags, ib_ca_attr_t *pCaAttr)
+{
+	*pFlags = 0;
+
+	*pFlags |= pCaAttr->bad_pkey_ctr_support ? WV_IO_BAD_PKEY_COUNTER : 0;
+	*pFlags |= pCaAttr->bad_qkey_ctr_support ? WV_IO_BAD_QKEY_COUNTER : 0;
+	*pFlags |= pCaAttr->apm_support ? WV_IO_PATH_MIGRATION : 0;
+	*pFlags |= pCaAttr->av_port_check ? WV_IO_AH_PORT_CHECKING : 0;
+	*pFlags |= pCaAttr->change_primary_port ? WV_IO_CHANGE_PHYSICAL_PORT : 0;
+	*pFlags |= pCaAttr->modify_wr_depth ? WV_IO_RESIZE_MAX_WR : 0;
+	*pFlags |= pCaAttr->modify_srq_depth ? WV_IO_SRQ_RESIZE : 0;
+	*pFlags |= pCaAttr->current_qp_state_support ? WV_IO_QP_STATE_MODIFIER : 0;
+	*pFlags |= pCaAttr->shutdown_port_capability ? WV_IO_SHUTDOWN_PORT : 0;
+	*pFlags |= pCaAttr->init_type_support ? WV_IO_INIT_TYPE : 0;
+	*pFlags |= pCaAttr->port_active_event_support ? WV_IO_PORT_ACTIVE_EVENT : 0;
+	*pFlags |= pCaAttr->system_image_guid_support ? WV_IO_SYSTEM_IMAGE_GUID : 0;
+	*pFlags |= WV_IO_RC_RNR_NAK_GENERATION;
+	*pFlags |= WV_IO_BATCH_NOTIFY_CQ;
+}
+
+static void WvSetDevicePages(UINT32 *pFlags, ib_ca_attr_t *pCaAttr)
+{
+	unsigned int i;
+	UINT32 size;
+
+	*pFlags = 0;
+
+	for (i = 0; i < pCaAttr->num_page_sizes; i++) {
+		size = pCaAttr->p_page_size[i];
+		*pFlags |= (size & (size - 1)) ? 0 : size;
+	}
+}
+
+static void WvConvertDevAttr(WV_IO_DEVICE_ATTRIBUTES* pAttributes,
+							 ib_ca_attr_t *pCaAttr)
+{
+	pAttributes->FwVersion			= pCaAttr->fw_ver;
+	pAttributes->NodeGuid			= pCaAttr->ca_guid;
+	pAttributes->SystemImageGuid	= pCaAttr->system_image_guid;
+	pAttributes->VendorId			= pCaAttr->vend_id;
+	pAttributes->VendorPartId		= pCaAttr->dev_id;
+	pAttributes->HwVersion			= pCaAttr->revision;
+
+	WvSetDeviceCap(&pAttributes->CapabilityFlags, pCaAttr);
+	pAttributes->AtomicCapability	= (UINT32) pCaAttr->atomicity;
+	WvSetDevicePages(&pAttributes->PageSizeCapabilityFlags, pCaAttr);
+
+	pAttributes->MaxMrSize			= pCaAttr->init_region_size;
+	pAttributes->MaxQp				= pCaAttr->max_qps;
+	pAttributes->MaxQpWr			= pCaAttr->max_wrs;
+	pAttributes->MaxSge				= pCaAttr->max_sges;
+	pAttributes->MaxCq				= pCaAttr->max_cqs;
+	pAttributes->MaxCqEntries		= pCaAttr->max_cqes;
+	pAttributes->MaxMr				= pCaAttr->init_regions;
+	pAttributes->MaxPd				= pCaAttr->max_pds;
+	pAttributes->MaxQpResponderResources	= pCaAttr->max_qp_resp_res;
+	pAttributes->MaxResponderResources		= pCaAttr->max_resp_res;
+	pAttributes->MaxQpInitiatorDepth		= pCaAttr->max_qp_init_depth;
+	pAttributes->MaxMw				= pCaAttr->init_windows;
+	pAttributes->MaxMulticast		= pCaAttr->max_mcast_grps;
+	pAttributes->MaxQpAttach		= pCaAttr->max_qps_per_mcast_grp;
+	pAttributes->MaxMulticastQp		= pCaAttr->max_mcast_qps;
+	pAttributes->MaxAh				= pCaAttr->max_addr_handles;
+	pAttributes->MaxFmr				= pCaAttr->max_fmr;
+	pAttributes->MaxMapPerFmr		= pCaAttr->max_map_per_fmr;
+	pAttributes->MaxSrq				= pCaAttr->max_srq;
+	pAttributes->MaxSrqWr			= pCaAttr->max_srq_wrs;
+	pAttributes->MaxSrqSge			= pCaAttr->max_srq_sges;
+	pAttributes->MaxPkeys			= pCaAttr->max_partitions;
+	pAttributes->LocalAckDelay		= pCaAttr->local_ack_delay;
+	pAttributes->PhysPortCount		= pCaAttr->num_ports;
+}
+
+static void WvConvertPortCap(UINT32 *pFlags, ib_port_cap_t *pCap)
+{
+	*pFlags = 0;
+
+	*pFlags |= pCap->qkey_ctr ? WV_IO_BAD_QKEY_COUNTER : 0;
+	*pFlags |= pCap->pkey_ctr ? WV_IO_BAD_PKEY_COUNTER : 0;
+	*pFlags |= pCap->apm ? WV_IO_PATH_MIGRATION : 0;
+	*pFlags |= pCap->sysguid ? WV_IO_SYSTEM_IMAGE_GUID : 0;
+	*pFlags |= pCap->port_active ? WV_IO_PORT_ACTIVE_EVENT : 0;
+
+	// cannot determine from ib_port_attr_t:
+	// WV_IO_RESIZE_MAX_WR
+	// WV_IO_CHANGE_PHYSICAL_PORT
+	// WV_IO_AH_PORT_CHECKING
+	*pFlags |= WV_IO_QP_STATE_MODIFIER;
+	// WV_IO_SHUTDOWN_PORT
+	// WV_IO_INIT_TYPE
+	*pFlags |= WV_IO_RC_RNR_NAK_GENERATION;
+	// WV_IO_SRQ_RESIZE
+	*pFlags |= WV_IO_BATCH_NOTIFY_CQ;
+}
+
+static void WvConvertPortAttr(WV_IO_PORT_ATTRIBUTES *pAttributes,
+							  ib_port_attr_t *pPortAttr)
+{
+	WvConvertPortCap(&pAttributes->PortCabilityFlags, &pPortAttr->cap);
+	pAttributes->State			= pPortAttr->link_state;
+	pAttributes->MaxMtu			= 0;	// cannot determine from ib_port_attr_t
+	pAttributes->ActiveMtu		= pPortAttr->mtu;
+	pAttributes->GidTableLength	= pPortAttr->num_gids;
+	pAttributes->MaxMessageSize	= (UINT32) pPortAttr->max_msg_size;
+	pAttributes->BadPkeyCounter	= pPortAttr->pkey_ctr;
+	pAttributes->QkeyViolationCounter	= pPortAttr->qkey_ctr;
+	pAttributes->PkeyTableLength		= pPortAttr->num_pkeys;
+	pAttributes->Lid			= pPortAttr->lid;
+	pAttributes->SmLid			= pPortAttr->sm_lid;
+	pAttributes->Lmc			= pPortAttr->lmc;
+	pAttributes->MaxVls			= (UINT8) pPortAttr->max_vls;
+	pAttributes->SmSl			= pPortAttr->sm_sl;
+	pAttributes->SubneTimeout	= pPortAttr->subnet_timeout;
+	pAttributes->InitTypeReply	= pPortAttr->init_type_reply;
+	pAttributes->ActiveWidth	= pPortAttr->link_width_supported;
+	pAttributes->ActiveSpeed	= 0;	// cannot determine from ib_port_attr_t
+	pAttributes->PhysicalState	= 0;	// cannot determine from ib_port_attr_t
+	pAttributes->Reserved[0]	= 0;
+	pAttributes->Reserved[1]	= 0;
+}
+
+static ib_ca_attr_t *WvQueryCaAttributes(WV_DEVICE *pDevice)
+{
+	ib_ca_attr_t	*attr;
+	UINT32			size;
+	ib_api_status_t	ib_status;
+
+	size = 0;
+	ib_status = pDevice->pVerbs->query_ca(pDevice->hVerbsDevice, NULL, &size, NULL);
+	if (ib_status != IB_INSUFFICIENT_MEMORY) {
+		attr = NULL;
+		goto out;
+	}
+
+	attr = ExAllocatePoolWithTag(PagedPool, size, 'acvw');
+	if (attr == NULL) {
+		goto out;
+	}
+
+	ib_status = pDevice->pVerbs->query_ca(pDevice->hVerbsDevice, NULL, &size, NULL);
+	if (ib_status != IB_SUCCESS) {
+		ExFreePool(attr);
+		attr = NULL;
+	}
+
+out:
+	return attr;
+}
+
+void WvDeviceQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	UINT64					*id;
+	WV_IO_DEVICE_ATTRIBUTES	*attr;
+	WV_DEVICE				*dev;
+	ib_ca_attr_t			*ca_attr;
+	NTSTATUS				status;
+	UINT32					outlen = 0;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto complete;
+	}
+	status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_DEVICE_ATTRIBUTES),
+											&attr, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto complete;
+	}
+
+	dev = WvDeviceAcquire(pProvider, *id);
+	if (dev == NULL) {
+		status = STATUS_NO_SUCH_DEVICE;
+		goto complete;
+	}
+
+	ca_attr = WvQueryCaAttributes(dev);
+	WvDeviceRelease(dev);
+
+	if (ca_attr == NULL) {
+		status = STATUS_NO_MEMORY;
+		goto complete;
+	}
+
+	WvConvertDevAttr(attr, ca_attr);
+	outlen = sizeof(WV_IO_DEVICE_ATTRIBUTES);
+	ExFreePool(ca_attr);
+
+complete:
+	WdfRequestCompleteWithInformation(Request, status, outlen);
+}
+
+void WvDevicePortQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	WV_IO_DEVICE_PORT_QUERY	*query;
+	WV_IO_PORT_ATTRIBUTES	*attr;
+	WV_DEVICE				*dev;
+	ib_ca_attr_t			*ca_attr;
+	NTSTATUS				status;
+	UINT32					outlen = 0;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY),
+										   &query, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto complete;
+	}
+	status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_PORT_ATTRIBUTES),
+											&attr, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto complete;
+	}
+
+	dev = WvDeviceAcquire(pProvider, query->Id);
+	if (dev == NULL) {
+		status = STATUS_NO_SUCH_DEVICE;
+		goto complete;
+	}
+
+	ca_attr = WvQueryCaAttributes(dev);
+	WvDeviceRelease(dev);
+
+	if (ca_attr == NULL) {
+		status = STATUS_NO_MEMORY;
+		goto complete;
+	}
+
+	if (query->PortNumber >= ca_attr->num_ports) {
+		status = STATUS_INVALID_PORT_HANDLE;
+		goto free;
+	}
+
+	WvConvertPortAttr(attr, &ca_attr->p_port_attr[query->PortNumber]);
+	outlen = sizeof(WV_IO_PORT_ATTRIBUTES);
+
+free:
+	ExFreePool(ca_attr);
+complete:
+	WdfRequestCompleteWithInformation(Request, status, outlen);
+}
+
+void WvDeviceGidQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	WV_IO_DEVICE_PORT_QUERY	*query;
+	WV_IO_GID				*gid;
+	WV_DEVICE				*dev;
+	ib_ca_attr_t			*ca_attr;
+	ib_port_attr_t			*port_attr;
+	NTSTATUS				status;
+	UINT32					i, size, outlen = 0;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY),
+										   &query, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto complete;
+	}
+	status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_GID), &gid, &size);
+	if (!NT_SUCCESS(status)) {
+		goto complete;
+	}
+
+	dev = WvDeviceAcquire(pProvider, query->Id);
+	if (dev == NULL) {
+		status = STATUS_NO_SUCH_DEVICE;
+		goto complete;
+	}
+
+	ca_attr = WvQueryCaAttributes(dev);
+	WvDeviceRelease(dev);
+
+	if (ca_attr == NULL) {
+		status = STATUS_NO_MEMORY;
+		goto complete;
+	}
+
+	if (query->PortNumber >= ca_attr->num_ports) {
+		status = STATUS_INVALID_PORT_HANDLE;
+		goto free;
+	}
+
+	size /= sizeof(WV_IO_GID);
+	port_attr = &ca_attr->p_port_attr[query->PortNumber];
+	for (i = 0; i < size && i < port_attr->num_gids; i++) {
+		RtlCopyMemory(&gid[i], &port_attr->p_gid_table[i], sizeof(WV_IO_GID));
+	}
+
+	outlen = i * sizeof(WV_IO_GID);
+	if (i < port_attr->num_gids) {
+		status = STATUS_MORE_ENTRIES;
+	}
+
+free:
+	ExFreePool(ca_attr);
+complete:
+	WdfRequestCompleteWithInformation(Request, status, outlen);
+}
+
+void WvDevicePkeyQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	WV_IO_DEVICE_PORT_QUERY	*query;
+	UINT16					*pkey;
+	WV_DEVICE				*dev;
+	ib_ca_attr_t			*ca_attr;
+	ib_port_attr_t			*port_attr;
+	NTSTATUS				status;
+	UINT32					i, size, outlen = 0;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY),
+										   &query, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto complete;
+	}
+	status = WdfRequestRetrieveOutputBuffer(Request, sizeof(UINT16), &pkey, &size);
+	if (!NT_SUCCESS(status)) {
+		goto complete;
+	}
+
+	dev = WvDeviceAcquire(pProvider, query->Id);
+	if (dev == NULL) {
+		status = STATUS_NO_SUCH_DEVICE;
+		goto complete;
+	}
+
+	ca_attr = WvQueryCaAttributes(dev);
+	WvDeviceRelease(dev);
+
+	if (ca_attr == NULL) {
+		status = STATUS_NO_MEMORY;
+		goto complete;
+	}
+
+	if (query->PortNumber >= ca_attr->num_ports) {
+		status = STATUS_INVALID_PORT_HANDLE;
+		goto free;
+	}
+
+	size /= sizeof(UINT16);
+	port_attr = &ca_attr->p_port_attr[query->PortNumber];
+	for (i = 0; i < size && i < port_attr->num_pkeys; i++) {
+		pkey[i] = port_attr->p_pkey_table[i];
+	}
+
+	outlen = i * sizeof(UINT16);
+	if (i < port_attr->num_pkeys) {
+		status = STATUS_MORE_ENTRIES;
+	}
+
+free:
+	ExFreePool(ca_attr);
+complete:
+	WdfRequestCompleteWithInformation(Request, status, outlen);
+}
+
+void WvPdAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	WV_IO_ID				*inid, *outid;
+	size_t					inlen, outlen;
+	WV_DEVICE				*dev;
+	WV_PROTECTION_DOMAIN	*pd;
+	NTSTATUS				status;
+	ci_umv_buf_t			verbsData;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen);
+	if (!NT_SUCCESS(status)) {
+		goto err1;
+	}
+	status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);
+	if (!NT_SUCCESS(status)) {
+		goto err1;
+	}
+
+	dev = WvDeviceAcquire(pProvider, inid->Id);
+	if (dev == NULL) {
+		status = STATUS_NO_SUCH_DEVICE;
+		goto err1;
+	}
+
+	WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID),
+					outlen - sizeof(WV_IO_ID), inid + 1);
+	status = WvPdAlloc(dev, &pd, &verbsData);
+	if (!NT_SUCCESS(status)) {
+		goto err2;
+	}
+
+	KeAcquireGuardedMutex(&pProvider->Lock);
+	outid->Id= IndexListInsertHead(&pProvider->PdIndex, pd);
+	if (outid->Id == 0) {
+		status = STATUS_NO_MEMORY;
+		goto err3;
+	}
+	InsertHeadList(&dev->PdList, &pd->Entry);
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	WvDeviceRelease(dev);
+	outid->VerbInfo = verbsData.status;
+	WdfRequestCompleteWithInformation(Request, status, outlen);
+	return;
+
+err3:
+	KeReleaseGuardedMutex(&pProvider->Lock);
+	WvPdFree(pd);
+err2:
+	WvDeviceRelease(dev);
+err1:
+	WdfRequestComplete(Request, status);
+}
+
+void WvPdDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	WV_PROTECTION_DOMAIN	*pd;
+	UINT64					*id;
+	NTSTATUS				status;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto out;
+	}
+
+	KeAcquireGuardedMutex(&pProvider->Lock);
+	WvProviderDisableRemove(pProvider);
+	pd = IndexListAt(&pProvider->PdIndex, (SIZE_T) id);
+	if (pd == NULL) {
+		status = STATUS_NOT_FOUND;
+	} else if (pd->Ref > 1) {
+		status = STATUS_ACCESS_DENIED;
+	} else {
+		IndexListRemove(&pProvider->PdIndex, (SIZE_T) id);
+		RemoveEntryList(&pd->Entry);
+		status = STATUS_SUCCESS;
+	}
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	if (NT_SUCCESS(status)) {
+		WvPdFree(pd);
+	}
+	WvProviderEnableRemove(pProvider);
+out:
+	WdfRequestComplete(Request, status);
+}
Index: wv_device.h
===================================================================
--- wv_device.h	(revision 1035)
+++ wv_device.h	(working copy)
@@ -36,18 +36,40 @@
 #include <wdm.h>
 #include <iba\ib_types.h>
 #include <iba\ib_ci.h>
+
+#include "wv_driver.h"
 #include "wv_provider.h"
 
 typedef struct _WV_DEVICE
 {
 	WV_PROVIDER			*pProvider;
+	WV_RDMA_DEVICE		*pDevice;
+	ci_interface_t		*pVerbs;
 	LIST_ENTRY			Entry;
-	ci_interface_t		Verbs;
 	ib_ca_handle_t		hVerbsDevice;
+	LIST_ENTRY			PdList;
 	SIZE_T				Id;
-	UINT64				Guid;
-	LONG				nRef;
+	KEVENT				Event;
+	LONG				Ref;
 
 }	WV_DEVICE;
 
+struct _WV_DEVICE *WvDeviceAcquire(WV_PROVIDER *pProvider, UINT64 Id);
+void WvDeviceRelease(WV_DEVICE *pDevice);
+void WvDeviceGet(WV_DEVICE *pDevice);
+void WvDevicePut(WV_DEVICE *pDevice);
+
+WV_DEVICE *WvDeviceAlloc(WV_PROVIDER *pProvider);
+NTSTATUS WvDeviceInit(WV_DEVICE *pDevice, UINT64 Guid, ci_umv_buf_t *pVerbsData);
+void WvDeviceFree(WV_DEVICE *pDevice);
+void WvDeviceRemoveHandler(WV_DEVICE *pDevice);
+
+void WvDeviceQuery(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvDevicePortQuery(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvDeviceGidQuery(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvDevicePkeyQuery(WV_PROVIDER *pProvider, WDFREQUEST Request);
+
+void WvPdAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvPdDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request);
+
 #endif // __WV_DEVICE_H_
Index: wv_driver.c
===================================================================
--- wv_driver.c	(revision 1035)
+++ wv_driver.c	(working copy)
@@ -30,9 +30,10 @@
 #include <ntddk.h>
 #include <wdf.h>
 #include <wdmsec.h>
-#include <winerror.h>
+#include <ntstatus.h>
 #include <initguid.h>
 
+#include <rdma/verbs.h>
 #include "wv_driver.h"
 #include "wv_ioctl.h"
 #include "wv_provider.h"
@@ -44,20 +45,113 @@
 #include "wv_listen.h"
 #include "wv_ep.h"
 
-WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WV_RDMA_DEVICE, WvGetRdmaDevice)
-WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WV_PROVIDER, WvGetProvider)
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WV_RDMA_DEVICE, WvRdmaDeviceGetContext)
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WV_PROVIDER, WvProviderGetContext)
 
-static WDFDEVICE	ControlDevice;
-KGUARDED_MUTEX		DevLock;
-LIST_ENTRY			DevList;
+static WDFDEVICE		ControlDevice;
+static LIST_ENTRY		DevList;
+static LIST_ENTRY		ProvList;
+static KGUARDED_MUTEX	Lock;
 
-static EVT_WDF_DRIVER_DEVICE_ADD			WvDeviceAdd;
-static EVT_WDF_OBJECT_CONTEXT_CLEANUP		WvDeviceCleanup;
+static EVT_WDF_DRIVER_DEVICE_ADD			WvRdmaDeviceAdd;
+static EVT_WDF_OBJECT_CONTEXT_CLEANUP		WvRdmaDeviceCleanup;
 static EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL	WvIoDeviceControl;
 static EVT_WDF_DEVICE_FILE_CREATE			WvFileCreate;
 static EVT_WDF_FILE_CLEANUP					WvFileCleanup;
 static EVT_WDF_FILE_CLOSE					WvFileClose;
 
+WV_RDMA_DEVICE *WvRdmaDeviceGet(UINT64 Guid)
+{
+	WV_RDMA_DEVICE	*cur_dev, *dev = NULL;
+	LIST_ENTRY		*entry;
+
+	KeAcquireGuardedMutex(&Lock);
+	for (entry = DevList.Flink; entry != &DevList; entry = entry->Flink) {
+		cur_dev = CONTAINING_RECORD(entry, WV_RDMA_DEVICE, Entry);
+		if (cur_dev->Interface.Verbs.guid == Guid) {
+			InterlockedIncrement(&cur_dev->Ref);
+			dev = cur_dev;
+			break;
+		}
+	}
+	KeReleaseGuardedMutex(&Lock);
+	return dev;
+}
+
+void WvRdmaDevicePut(WV_RDMA_DEVICE *pDevice)
+{
+	if (InterlockedDecrement(&pDevice->Ref) == 0) {
+		KeSetEvent(&pDevice->Event, 0, FALSE);
+	}
+}
+
+static void WvGuidQuery(WDFREQUEST Request)
+{
+	WV_IO_GUID_LIST	*list;
+	size_t			len = 0;
+	WV_RDMA_DEVICE	*dev;
+	ULONG			count, i;
+	LIST_ENTRY		*entry;
+	NTSTATUS		status;
+
+	status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_GUID_LIST),
+											&list, &len);
+	if (!NT_SUCCESS(status)) {
+		goto out;
+	}
+
+	count = (len - sizeof(UINT64)) / sizeof(UINT64);
+	i = 0;
+	len = sizeof(UINT64);
+	KeAcquireGuardedMutex(&Lock);
+	for (entry = DevList.Flink; entry != &DevList; entry = entry->Flink) {
+		dev = CONTAINING_RECORD(entry, WV_RDMA_DEVICE, Entry);
+		if (i < count) {
+			list->Guid[i] = dev->Interface.Verbs.guid;
+			len += sizeof(UINT64);
+		}
+		i++;
+	}
+	list->Count = i;
+	KeReleaseGuardedMutex(&Lock);
+
+out:
+	WdfRequestCompleteWithInformation(Request, status, len);
+}
+
+static void WvLibraryQuery(WDFREQUEST Request)
+{
+	UINT64			*guid;
+	char			*name;
+	size_t			len = 0;
+	WV_RDMA_DEVICE	*dev;
+	NTSTATUS		status;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &guid, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto out;
+	}
+	status = WdfRequestRetrieveOutputBuffer(Request,
+
sizeof(dev->Interface.Verbs.libname),
+											&name, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto out;
+	}
+
+	dev = WvRdmaDeviceGet(*guid);
+	if (dev == NULL) {
+		status = STATUS_NO_SUCH_DEVICE;
+		goto out;
+	}
+
+	len = sizeof(dev->Interface.Verbs.libname);
+	RtlCopyMemory(name, dev->Interface.Verbs.libname, len);
+	WvRdmaDevicePut(dev);
+
+out:
+	WdfRequestCompleteWithInformation(Request, status, len);
+}
+
 static VOID WvIoDeviceControl(WDFQUEUE Queue, WDFREQUEST Request,
 							  size_t OutLen, size_t InLen, ULONG IoControlCode)
 {
@@ -68,41 +162,73 @@
 	UNREFERENCED_PARAMETER(Queue);
 
 	file = WdfRequestGetFileObject(Request);
-	prov = WvGetProvider(file);
+	prov = WvProviderGetContext(file);
 
 	switch (IoControlCode) {
 	case WV_IOCTL_GUID_QUERY:
 		WvGuidQuery(Request);
 		break;
-	//case WV_IOCTL_LIBRARY_QUERY:WvLibraryQuery;break;
-	//case WV_IOCTL_DEVICE_OPEN:WvDeviceOpen;break;
-	//case WV_IOCTL_DEVICE_CLOSE:WvDeviceClose;break;
-	//case WV_IOCTL_DEVICE_QUERY:WvDevideQuery;break;
-	//case WV_IOCTL_DEVICE_PORT_QUERY:WvDevicePortQuery;break;
-	//case WV_IOCTL_DEVICE_GID_QUERY:WvDeviceGidQuery;break;
-	//case WV_IOCTL_DEVICE_PKEY_QUERY:WvDevicePkeyQuery;break;
+	case WV_IOCTL_LIBRARY_QUERY:
+		WvLibraryQuery(Request);
+		break;
+	case WV_IOCTL_DEVICE_OPEN:
+		WvDeviceOpen(prov, Request);
+		break;
+	case WV_IOCTL_DEVICE_CLOSE:
+		WvDeviceClose(prov, Request);
+		break;
+	case WV_IOCTL_DEVICE_QUERY:
+		WvDeviceQuery(prov, Request);
+		break;
+	case WV_IOCTL_DEVICE_PORT_QUERY:
+		WvDevicePortQuery(prov, Request);
+		break;
+	case WV_IOCTL_DEVICE_GID_QUERY:
+		WvDeviceGidQuery(prov, Request);
+		break;
+	case WV_IOCTL_DEVICE_PKEY_QUERY:
+		WvDevicePkeyQuery(prov, Request);
+		break;
 	//case WV_IOCTL_DEVICE_NOTIFY:WvDeviceNotify;break;
 	//case WV_IOCTL_DEVICE_CANCEL:WvDeviceCancel;break;
-	//case WV_IOCTL_PD_ALLOCATE:WvPdAllocate;break;
-	//case WV_IOCTL_PD_DEALLOCATE:WvPdDeallocate;break;
-	//case WV_IOCTL_MEMORY_REGISTER:WvMemoryRegister;break;
-	//case WV_IOCTL_MEMORY_DEREGISTER:WvmemoryDeregister;break;
-	//case WV_IOCTL_MW_ALLOCATE:WvMwAllocate;break;
-	//case WV_IOCTL_MW_DEALLOCATE:WvMwDeallocate;break;
-	//case WV_IOCTL_AH_CREATE:WvAhCreate;break;
-	//case WV_IOCTL_AH_DESTROY:WvAhDestroy;break;
+	case WV_IOCTL_PD_ALLOCATE:
+		WvPdAllocate(prov, Request);
+		break;
+	case WV_IOCTL_PD_DEALLOCATE:
+		WvPdDeallocate(prov, Request);
+		break;
+	case WV_IOCTL_MEMORY_REGISTER:
+		WvMrRegister(prov, Request);
+		break;
+	case WV_IOCTL_MEMORY_DEREGISTER:
+		WvMrDeregister(prov, Request);
+		break;
+	case WV_IOCTL_MW_ALLOCATE:
+		WvMwAllocate(prov, Request);
+		break;
+	case WV_IOCTL_MW_DEALLOCATE:
+		WvMwDeallocate(prov, Request);
+		break;
+	case WV_IOCTL_AH_CREATE:
+		WvAhCreate(prov, Request);
+		break;
+	case WV_IOCTL_AH_DESTROY:
+		WvAhDestroy(prov, Request);
+		break;
 	//case WV_IOCTL_CQ_CREATE:WvCqCreate;break;
 	//case WV_IOCTL_CQ_DESTROY:WvCqDestroy;break;
 	//case WV_IOCTL_CQ_RESIZE:WvCqResize;break;
 	//case WV_IOCTL_CQ_NOTIFY:WvCqNotify;break;
 	//case WV_IOCTL_CQ_BATCH_NOTIFY:WvCqBatchNotify;break;
 	//case WV_IOCTL_CQ_CANCEL:WvCqCancel;break;
+
 	//case WV_IOCTL_SRQ_CREATE :WvSrqCreate;break;
 	//case WV_IOCTL_SRQ_DESTROY:WvSrqDestroy;break;
 	//case WV_IOCTL_SRQ_QUERY:WvSrqQuery;break;
 	//case WV_IOCTL_SRQ_MODIFY:WvSrqModify;break;
 	//case WV_IOCTL_SRQ_NOTIFY:WvSrqNotify;break;
 	//case WV_IOCTL_SRQ_CANCEL:WvSrqCancel;break;
+
 	//case WV_IOCTL_QP_CREATE:WvQpCreate;break;
 	//case WV_IOCTL_QP_DESTROY:WvQpDestroy;break;
 	//case WV_IOCTL_QP_QUERY:WvQpQuery;break;
@@ -110,6 +236,7 @@
 	//case WV_IOCTL_QP_ATTACH:WvQpAttach;break;
 	//case WV_IOCTL_QP_DETACH:WvQpDetach;break;
 	//case WV_IOCTL_QP_CANCEL:WvQpCancel;break;
+
 	//case WV_IOCTL_ADDRESS_QUERY:WvAddressQuery;break;
 	//case WV_IOCTL_EP_CREATE:WvEpCreate;break;
 	//case WV_IOCTL_EP_DESTROY:WvEpDestroy;break;
@@ -129,7 +256,7 @@
 	//case WV_IOCTL_LISTEN_GET_REQUEST:WvListenGetRequest;break;
 	//case WV_IOCTL_LISTEN_CANCEL:WvListenCancel;break;
 	default:
-		WdfRequestComplete(Request, E_NOINTERFACE);
+		WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);
 		break;
 	}
 }
@@ -137,26 +264,29 @@
 static VOID WvFileCreate(WDFDEVICE Device, WDFREQUEST Request,
 						 WDFFILEOBJECT FileObject)
 {
-	WV_PROVIDER	*prov;
-
+	WV_PROVIDER	*prov = WvProviderGetContext(FileObject);
 	UNREFERENCED_PARAMETER(Device);
 
-	prov = WvGetProvider(FileObject);
 	WvProviderInit(prov);
+	KeAcquireGuardedMutex(&Lock);
+	InsertHeadList(&ProvList, &prov->Entry);
+	KeReleaseGuardedMutex(&Lock);
 	WdfRequestComplete(Request, STATUS_SUCCESS);
 }
 
 static VOID WvFileCleanup(WDFFILEOBJECT FileObject)
 {
-	UNREFERENCED_PARAMETER(FileObject);
+	WV_PROVIDER *prov = WvProviderGetContext(FileObject);
+
+	KeAcquireGuardedMutex(&Lock);
+	RemoveEntryList(&prov->Entry);
+	KeReleaseGuardedMutex(&Lock);
+	WvProviderCleanup(prov);
 }
 
 static VOID WvFileClose(WDFFILEOBJECT FileObject)
 {
-	WV_PROVIDER *prov;
-
-	prov = WvGetProvider(FileObject);
-	WvProviderDestroy(prov);
+	UNREFERENCED_PARAMETER(FileObject);
 }
 
 static VOID WvCreateControlDevice(WDFDRIVER Driver)
@@ -215,7 +345,7 @@
 	WdfDeviceInitFree(pinit);
 }
 
-static NTSTATUS WvDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
+static NTSTATUS WvRdmaDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
 {
 	WDF_OBJECT_ATTRIBUTES	attr;
 	WDFDEVICE				dev;
@@ -226,19 +356,30 @@
 	WdfFdoInitSetFilter(DeviceInit);
 
 	WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WV_RDMA_DEVICE);
-	attr.EvtCleanupCallback = WvDeviceCleanup;
+	attr.EvtCleanupCallback = WvRdmaDeviceCleanup;
 	status = WdfDeviceCreate(&DeviceInit, &attr, &dev);
 	if (!NT_SUCCESS(status)) {
 		return status;
 	}
 
-	pdev = WvGetRdmaDevice(dev);
-	pdev->Guid = 0x1234567890ABCDEF;
+	pdev = WvRdmaDeviceGetContext(dev);
+	RtlZeroMemory(pdev, sizeof *pdev);
+	pdev->Ref = 1;
+	KeInitializeEvent(&pdev->Event, NotificationEvent, FALSE);
 
-	KeAcquireGuardedMutex(&DevLock);
+	status = WdfFdoQueryForInterface(dev, &GUID_RDMA_INTERFACE_VERBS,
+									 (PINTERFACE) &pdev->Interface,
+									 sizeof(pdev->Interface), VerbsVersion(2, 0),
+									 NULL);
+	if (!NT_SUCCESS(status)) {
+		return status;
+	}
+	pdev->hDevice = pdev->Interface.Verbs.p_hca_dev;
+
+	KeAcquireGuardedMutex(&Lock);
 	create = IsListEmpty(&DevList);
 	InsertHeadList(&DevList, &pdev->Entry);
-	KeReleaseGuardedMutex(&DevLock);
+	KeReleaseGuardedMutex(&Lock);
 
 	if (create) {
 		WvCreateControlDevice(Driver);
@@ -247,19 +388,38 @@
 	return status;
 }
 
-static VOID WvDeviceCleanup(WDFDEVICE Device)
+static VOID WvRdmaDeviceCleanup(WDFDEVICE Device)
 {
 	WV_RDMA_DEVICE			*pdev;
+	WV_PROVIDER				*prov;
+	LIST_ENTRY				*entry;
 	BOOLEAN					destroy;
 	WDFDEVICE				ctrldev;
 
-	pdev = WvGetRdmaDevice(Device);
-	KeAcquireGuardedMutex(&DevLock);
+	pdev = WvRdmaDeviceGetContext(Device);
+	if (pdev->hDevice == NULL) {
+		return;
+	}
+
+	KeAcquireGuardedMutex(&Lock);
 	RemoveEntryList(&pdev->Entry);
 	destroy = IsListEmpty(&DevList);
 	ctrldev = ControlDevice;
-	KeReleaseGuardedMutex(&DevLock);
 
+	for (entry = ProvList.Flink; entry != &ProvList; entry = entry->Flink) {
+		prov = CONTAINING_RECORD(entry, WV_PROVIDER, Entry);
+		WvProviderRemoveHandler(prov, pdev);
+	}
+
+	KeReleaseGuardedMutex(&Lock);
+
+	if (InterlockedDecrement(&pdev->Ref) > 0) {
+		KeWaitForSingleObject(&pdev->Event, Executive, KernelMode, FALSE, NULL);
+	}
+
+	pdev->Interface.InterfaceHeader.
+		InterfaceDereference(pdev->Interface.InterfaceHeader.Context);
+
 	if (destroy) {
 		WdfObjectDelete(ctrldev);
 	}
@@ -272,9 +432,10 @@
 	WDFDRIVER				driv;
 
 	InitializeListHead(&DevList);
-	KeInitializeGuardedMutex(&DevLock);
+	InitializeListHead(&ProvList);
+	KeInitializeGuardedMutex(&Lock);
 
-	WDF_DRIVER_CONFIG_INIT(&config, WvDeviceAdd);
+	WDF_DRIVER_CONFIG_INIT(&config, WvRdmaDeviceAdd);
 	status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
 							 &config, &driv);
 	if (!NT_SUCCESS(status)) {
Index: wv_driver.h
===================================================================
--- wv_driver.h	(revision 1035)
+++ wv_driver.h	(working copy)
@@ -34,19 +34,33 @@
 
 #include <ntddk.h>
 #include <wdm.h>
+
 #include <iba\ib_types.h>
 #include <iba\ib_ci.h>
+#include <rdma\verbs.h>
 
 typedef struct _WV_RDMA_DEVICE
 {
-	UINT64			Guid;
-	LIST_ENTRY		Entry;
-	ci_interface_t	Verbs;
-	ib_ca_handle_t	hVerbsDevice;
+	LIST_ENTRY				Entry;
+	LONG					Ref;
+	KEVENT					Event;
+	ib_ca_handle_t			hDevice;
+	RDMA_INTERFACE_VERBS	Interface;
 
 }	WV_RDMA_DEVICE;
 
-extern KGUARDED_MUTEX	DevLock;
-extern LIST_ENTRY		DevList;
+WV_RDMA_DEVICE *WvRdmaDeviceGet(UINT64 Guid);
+void WvRdmaDevicePut(WV_RDMA_DEVICE *pDevice);
 
+static inline void WvInitVerbsData(ci_umv_buf_t *pVerbsData, UINT32 Command,
+								   UINT32 InputLength, UINT32 OutputLength,
+								   void *pBuffer)
+{
+	pVerbsData->command = Command;
+	pVerbsData->input_size = InputLength;
+	pVerbsData->output_size = OutputLength;
+	pVerbsData->p_inout_buf = pBuffer;
+	pVerbsData->status = 0;
+}
+
 #endif // _WV_DRIVER_H_
Index: wv_pd.c
===================================================================
--- wv_pd.c	(revision 0)
+++ wv_pd.c	(revision 0)
@@ -0,0 +1,486 @@
+/*
+ * 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 "wv_pd.h"
+#include "wv_ioctl.h"
+
+void WvPdGet(WV_PROTECTION_DOMAIN *pPd)
+{
+	InterlockedIncrement(&pPd->Ref);
+}
+
+void WvPdPut(WV_PROTECTION_DOMAIN *pPd)
+{
+	if (InterlockedDecrement(&pPd->Ref) == 0) {
+		KeSetEvent(&pPd->Event, 0, FALSE);
+	}
+}
+
+WV_PROTECTION_DOMAIN *WvPdAcquire(WV_PROVIDER *pProvider, UINT64 Id)
+{
+	WV_PROTECTION_DOMAIN *pd;
+
+	KeAcquireGuardedMutex(&pProvider->Lock);
+	WvProviderDisableRemove(pProvider);
+	pd = IndexListAt(&pProvider->PdIndex, (SIZE_T) Id);
+	if (pd != NULL && pd->hVerbsPd != NULL) {
+		WvPdGet(pd);
+	} else {
+		pd = NULL;
+		WvProviderEnableRemove(pProvider);
+	}
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	return pd;
+}
+
+void WvPdRelease(WV_PROTECTION_DOMAIN *pPd)
+{
+	WvProviderEnableRemove(pPd->pDevice->pProvider);
+	WvPdPut(pPd);
+}
+
+NTSTATUS WvPdAlloc(WV_DEVICE *pDevice, WV_PROTECTION_DOMAIN **ppPd,
+				   ci_umv_buf_t *pVerbsData)
+{
+	ib_api_status_t			ib_status;
+	WV_PROTECTION_DOMAIN	*pd;
+
+	pd = ExAllocatePoolWithTag(PagedPool, sizeof(WV_PROTECTION_DOMAIN), 'apvw');
+	if (pd == NULL) {
+		return STATUS_NO_MEMORY;
+	}
+
+	pd->Ref = 1;
+	KeInitializeEvent(&pd->Event, NotificationEvent, FALSE);
+	InitializeListHead(&pd->MwList);
+	InitializeListHead(&pd->AhList);
+	cl_qmap_init(&pd->MrMap);
+	KeInitializeGuardedMutex(&pd->Lock);
+
+	ib_status = pDevice->pVerbs->allocate_pd(pDevice->hVerbsDevice, IB_PDT_NORMAL,
+											 &pd->hVerbsPd, pVerbsData);
+	if (ib_status != IB_SUCCESS) {
+		goto err;
+	}
+
+	pd->pDevice = pDevice;
+	pd->pVerbs = pDevice->pVerbs;
+	WvDeviceGet(pDevice);
+	*ppPd = pd;
+	return STATUS_SUCCESS;
+
+err:
+	ExFreePool(pd);
+	return STATUS_UNSUCCESSFUL;
+}
+
+void WvPdFree(WV_PROTECTION_DOMAIN *pPd)
+{
+	WV_MEMORY_REGION	*mr;
+	cl_map_item_t		*item;
+
+	if (InterlockedDecrement(&pPd->Ref) > 0) {
+		KeWaitForSingleObject(&pPd->Event, Executive, KernelMode, FALSE, NULL);
+	}
+
+	for (item = cl_qmap_head(&pPd->MrMap); item != cl_qmap_end(&pPd->MrMap);
+		 item = cl_qmap_next(item)) {
+		mr = CONTAINING_RECORD(item, WV_MEMORY_REGION, Item);
+		if (mr->hVerbsMr != NULL) {
+			pPd->pVerbs->deregister_mr(mr->hVerbsMr);
+		}
+
+		cl_qmap_remove_item(&pPd->MrMap, &mr->Item);
+		ExFreePool(mr);
+	}
+
+	if (pPd->hVerbsPd != NULL) {
+		pPd->pVerbs->deallocate_pd(pPd->hVerbsPd);
+	}
+
+	WvDevicePut(pPd->pDevice);
+	ExFreePool(pPd);
+}
+
+void WvPdRemoveHandler(WV_PROTECTION_DOMAIN *pPd)
+{
+	WV_MEMORY_REGION	*mr;
+	cl_map_item_t		*item;
+
+	for (item = cl_qmap_head(&pPd->MrMap); item != cl_qmap_end(&pPd->MrMap);
+		 item = cl_qmap_next(item)) {
+		mr = CONTAINING_RECORD(item, WV_MEMORY_REGION, Item);
+		pPd->pVerbs->deregister_mr(mr->hVerbsMr);
+		mr->hVerbsMr = NULL;
+	}
+
+	pPd->pVerbs->deallocate_pd(pPd->hVerbsPd);
+	pPd->pVerbs = NULL;
+	pPd->hVerbsPd = NULL;
+}
+
+void WvMrRegister(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	WV_IO_MEMORY_REGISTER	*reg;
+	WV_IO_MEMORY_KEYS		*keys;
+	WV_PROTECTION_DOMAIN	*pd;
+	WV_MEMORY_REGION		*mr;
+	ib_mr_create_t			attr;
+	NTSTATUS				status;
+	ib_api_status_t			ib_status;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_MEMORY_REGISTER),
+										   &reg, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto err1;
+	}
+	status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_MEMORY_KEYS),
+											&keys, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto err1;
+	}
+
+	pd = WvPdAcquire(pProvider, reg->Id);
+	if (pd == NULL) {
+		status = STATUS_NOT_FOUND;
+		goto err1;
+	}
+
+	mr = ExAllocatePoolWithTag(PagedPool, sizeof(WV_MEMORY_REGION), 'rmvw');
+	if (mr == NULL) {
+		status = STATUS_NO_MEMORY;
+		goto err2;
+	}
+
+	attr.access_ctrl = reg->AccessFlags;
+	attr.length = reg->BufferLength;
+	attr.vaddr = (void *) (ULONG_PTR) reg->Address;
+	ib_status = pd->pVerbs->register_mr(pd->hVerbsPd, &attr, &keys->Lkey,
+										&keys->Rkey, &mr->hVerbsMr, TRUE);
+	if (ib_status != IB_SUCCESS) {
+		status = STATUS_UNSUCCESSFUL;
+		goto err3;
+	}
+
+	KeAcquireGuardedMutex(&pd->Lock);
+	cl_qmap_insert(&pd->MrMap, keys->Lkey, &mr->Item);
+	KeReleaseGuardedMutex(&pd->Lock);
+
+	WvPdRelease(pd);
+	WdfRequestCompleteWithInformation(Request, status, sizeof(WV_IO_MEMORY_KEYS));
+	return;
+
+err3:
+	ExFreePool(mr);
+err2:
+	WvPdRelease(pd);
+err1:
+	WdfRequestComplete(Request, status);
+}
+
+void WvMrDeregister(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	WV_IO_ID				*id;
+	WV_PROTECTION_DOMAIN	*pd;
+	WV_MEMORY_REGION		*mr;
+	cl_map_item_t			*item;
+	NTSTATUS				status;
+	ib_api_status_t			ib_status;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto complete;
+	}
+
+	pd = WvPdAcquire(pProvider, id->Id);
+	if (pd == NULL) {
+		status = STATUS_NOT_FOUND;
+		goto complete;
+	}
+
+	KeAcquireGuardedMutex(&pd->Lock);
+	item = cl_qmap_remove(&pd->MrMap, id->Data);
+	KeReleaseGuardedMutex(&pd->Lock);
+
+	if (item == cl_qmap_end(&pd->MrMap)) {
+		status = STATUS_NOT_FOUND;
+		goto release;
+	}
+
+	mr = CONTAINING_RECORD(item, WV_MEMORY_REGION, Item);
+
+	ib_status = pd->pVerbs->deregister_mr(mr->hVerbsMr);
+	if (ib_status != IB_SUCCESS) {
+		status = STATUS_UNSUCCESSFUL;
+		KeAcquireGuardedMutex(&pd->Lock);
+		cl_qmap_insert(&pd->MrMap, id->Data, &mr->Item);
+		KeReleaseGuardedMutex(&pd->Lock);
+		goto release;
+	}
+
+	ExFreePool(mr);
+release:
+	WvPdRelease(pd);
+complete:
+	WdfRequestComplete(Request, status);
+}
+
+void WvMwAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	WV_IO_ID				*inid, *outid;
+	size_t					inlen, outlen;
+	WV_PROTECTION_DOMAIN	*pd;
+	WV_MEMORY_WINDOW		*mw;
+	NTSTATUS				status;
+	ib_api_status_t			ib_status;
+	ci_umv_buf_t			verbsData;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen);
+	if (!NT_SUCCESS(status)) {
+		goto err1;
+	}
+	status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);
+	if (!NT_SUCCESS(status)) {
+		goto err1;
+	}
+
+	pd = WvPdAcquire(pProvider, inid->Id);
+	if (pd == NULL) {
+		status = STATUS_NOT_FOUND;
+		goto err1;
+	}
+
+	mw = ExAllocatePoolWithTag(PagedPool, sizeof(WV_MEMORY_WINDOW), 'wmvw');
+	if (mw == NULL) {
+		status = STATUS_NO_MEMORY;
+		goto err2;
+	}
+
+	WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID),
+					outlen - sizeof(WV_IO_ID), inid + 1);
+	ib_status = pd->pVerbs->create_mw(pd->hVerbsPd, &outid->Data, &mw->hVerbsMw,
+									  &verbsData);
+	if (ib_status != IB_SUCCESS) {
+		status = STATUS_UNSUCCESSFUL;
+		goto err3;
+	}
+
+	KeAcquireGuardedMutex(&pProvider->Lock);
+	outid->Id = IndexListInsertHead(&pProvider->MwIndex, mw);
+	if (outid->Id == 0) {
+		status = STATUS_NO_MEMORY;
+		goto err3;
+	}
+	InsertHeadList(&pd->MwList, &mw->Entry);
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	mw->pPd = pd;
+	WvPdGet(pd);
+
+	WvPdRelease(pd);
+	outid->VerbInfo = verbsData.status;
+	WdfRequestCompleteWithInformation(Request, status, outlen);
+	return;
+
+err3:
+	KeReleaseGuardedMutex(&pProvider->Lock);
+	WvMwFree(mw);
+err2:
+	WvPdRelease(pd);
+err1:
+	WdfRequestComplete(Request, status);
+}
+
+void WvMwDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	WV_MEMORY_WINDOW	*mw;
+	UINT64				*id;
+	NTSTATUS			status;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto out;
+	}
+
+	KeAcquireGuardedMutex(&pProvider->Lock);
+	WvProviderDisableRemove(pProvider);
+	mw = IndexListAt(&pProvider->MwIndex, (SIZE_T) id);
+	if (mw == NULL) {
+		status = STATUS_NOT_FOUND;
+	} else {
+		IndexListRemove(&pProvider->MwIndex, (SIZE_T) id);
+		RemoveEntryList(&mw->Entry);
+		status = STATUS_SUCCESS;
+	}
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	if (NT_SUCCESS(status)) {
+		WvMwFree(mw);
+	}
+	WvProviderEnableRemove(pProvider);
+out:
+	WdfRequestComplete(Request, status);
+}
+
+void WvMwFree(WV_MEMORY_WINDOW *pMw)
+{
+	if (pMw->hVerbsMw != NULL) {
+		pMw->pPd->pVerbs->destroy_mw(pMw->hVerbsMw);
+	}
+
+	WvPdPut(pMw->pPd);
+	ExFreePool(pMw);
+}
+
+static void WvVerbsConvertAv(ib_av_attr_t *pVerbsAv, WV_IO_AV *pAv)
+{
+	if (pAv->GrhValid) {
+		RtlCopyMemory(&pVerbsAv->grh, &pAv, sizeof pVerbsAv->grh);
+		pVerbsAv->grh_valid = 1;
+	} else {
+		pVerbsAv->grh_valid = 0;
+	}
+
+	pVerbsAv->port_num = pAv->PortNumber;
+	pVerbsAv->sl = pAv->ServiceLevel;
+	pVerbsAv->dlid = pAv->DLid;
+	pVerbsAv->static_rate = pAv->StaticRate;
+	pVerbsAv->path_bits = pAv->SourcePathBits;
+}
+
+void WvAhCreate(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	WV_IO_ID				*outid;
+	size_t					inlen, outlen;
+	WV_PROTECTION_DOMAIN	*pd;
+	WV_ADDRESS_HANDLE		*ah;
+	WV_IO_AH_CREATE			*pav;
+	ib_av_attr_t			av;
+	NTSTATUS				status;
+	ib_api_status_t			ib_status;
+	ci_umv_buf_t			verbsData;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_AH_CREATE),
+										   &pav, &inlen);
+	if (!NT_SUCCESS(status)) {
+		goto err1;
+	}
+	status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);
+	if (!NT_SUCCESS(status)) {
+		goto err1;
+	}
+
+	pd = WvPdAcquire(pProvider, pav->Id.Id);
+	if (pd == NULL) {
+		status = STATUS_NOT_FOUND;
+		goto err1;
+	}
+
+	ah = ExAllocatePoolWithTag(PagedPool, sizeof(WV_ADDRESS_HANDLE), 'havw');
+	if (ah == NULL) {
+		status = STATUS_NO_MEMORY;
+		goto err2;
+	}
+
+	WvVerbsConvertAv(&av, &pav->AddressVector);
+	WvInitVerbsData(&verbsData, pav->Id.VerbInfo, inlen - sizeof(WV_IO_AH_CREATE),
+					outlen - sizeof(WV_IO_ID), pav + 1);
+	ib_status = pd->pVerbs->create_av(pd->hVerbsPd, &av, &ah->hVerbsAh, &verbsData);
+	if (ib_status != IB_SUCCESS) {
+		status = STATUS_UNSUCCESSFUL;
+		goto err3;
+	}
+
+	KeAcquireGuardedMutex(&pProvider->Lock);
+	outid->Id = IndexListInsertHead(&pProvider->AhIndex, ah);
+	if (outid->Id == 0) {
+		status = STATUS_NO_MEMORY;
+		goto err3;
+	}
+	InsertHeadList(&pd->AhList, &ah->Entry);
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	ah->pPd = pd;
+	WvPdGet(pd);
+
+	WvPdRelease(pd);
+	outid->VerbInfo = verbsData.status;
+	WdfRequestCompleteWithInformation(Request, status, outlen);
+	return;
+
+err3:
+	KeReleaseGuardedMutex(&pProvider->Lock);
+	WvAhFree(ah);
+err2:
+	WvPdRelease(pd);
+err1:
+	WdfRequestComplete(Request, status);
+}
+
+void WvAhDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	WV_ADDRESS_HANDLE	*ah;
+	UINT64				*id;
+	NTSTATUS			status;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto out;
+	}
+
+	KeAcquireGuardedMutex(&pProvider->Lock);
+	WvProviderDisableRemove(pProvider);
+	ah = IndexListAt(&pProvider->AhIndex, (SIZE_T) id);
+	if (ah == NULL) {
+		status = STATUS_NOT_FOUND;
+	} else {
+		IndexListRemove(&pProvider->AhIndex, (SIZE_T) id);
+		RemoveEntryList(&ah->Entry);
+		status = STATUS_SUCCESS;
+	}
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	if (NT_SUCCESS(status)) {
+		WvAhFree(ah);
+	}
+	WvProviderEnableRemove(pProvider);
+out:
+	WdfRequestComplete(Request, status);
+}
+
+void WvAhFree(WV_ADDRESS_HANDLE *pAh)
+{
+	if (pAh->hVerbsAh != NULL) {
+		pAh->pPd->pVerbs->destroy_av(pAh->hVerbsAh);
+	}
+
+	WvPdPut(pAh->pPd);
+	ExFreePool(pAh);
+}
Index: wv_pd.h
===================================================================
--- wv_pd.h	(revision 1035)
+++ wv_pd.h	(working copy)
@@ -32,44 +32,78 @@
 #ifndef _WV_PD_H_
 #define _WV_PD_H_
 
+#include <ntddk.h>
 #include <wdm.h>
 #include <iba\ib_types.h>
 #include <iba\ib_ci.h>
+
 #include "wv_device.h"
+#include "wv_provider.h"
 
 typedef struct _WV_PROTECTION_DOMAIN
 {
-	WV_DEVICE				*pDevice;
-	ci_interface_t			*pVerbs;
-	ib_pd_handle_t			hVerbsPd;
-	UINT64					Id;
-	volatile LONG			m_nRef;
+	WV_DEVICE			*pDevice;
+	ci_interface_t		*pVerbs;
+	ib_pd_handle_t		hVerbsPd;
+	LIST_ENTRY			Entry;
 
+	LIST_ENTRY			MwList;
+	LIST_ENTRY			AhList;
+	KGUARDED_MUTEX		Lock;
+	cl_qmap_t			MrMap;
+
+	KEVENT				Event;
+	LONG				Ref;
+
 }	WV_PROTECTION_DOMAIN;
 
+struct _WV_PROTECTION_DOMAIN *WvPdAcquire(WV_PROVIDER *pProvider, UINT64 Id);
+void WvPdRelease(WV_PROTECTION_DOMAIN *pPd);
+void WvPdGet(WV_PROTECTION_DOMAIN *pPd);
+void WvPdPut(WV_PROTECTION_DOMAIN *pPd);
 
+NTSTATUS WvPdAlloc(WV_DEVICE *pDevice, WV_PROTECTION_DOMAIN **ppPd,
+				   ci_umv_buf_t *pVerbsData);
+void WvPdFree(WV_PROTECTION_DOMAIN *pPd);
+void WvPdRemoveHandler(WV_PROTECTION_DOMAIN *pPd);
+
+
+typedef struct _WV_MEMORY_REGION
+{
+	ib_mr_handle_t			hVerbsMr;
+	cl_map_item_t			Item;
+
+}	WV_MEMORY_REGION;
+
+void WvMrRegister(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvMrDeregister(WV_PROVIDER *pProvider, WDFREQUEST Request);
+
+
 typedef struct _WV_MEMORY_WINDOW
 {
 	WV_PROTECTION_DOMAIN	*pPd;
-	ci_interface_t			*pVerbs;
 	ib_mw_handle_t			hVerbsMw;
-	UINT64					Id;
-	UINT32					Rkey;
-	volatile LONG			nRef;
+	LIST_ENTRY				Entry;
 
 }	WV_MEMORY_WINDOW;
 
+void WvMwAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvMwDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvMwFree(WV_MEMORY_WINDOW *pMw);
 
+
 typedef struct _WV_ADDRESS_HANDLE
 {
 	WV_PROTECTION_DOMAIN	*pPd;
-	ci_interface_t			*pVerbs;
 	ib_av_handle_t			hVerbsAh;
-	UINT64					Id;
-	volatile LONG			m_nRef;
+	LIST_ENTRY				Entry;
 
 }	WV_ADDRESS_HANDLE;
 
+void WvAhCreate(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvAhDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvAhFree(WV_ADDRESS_HANDLE *pAh);
+
 //void WvVerbsConvertAv(ib_av_attr_t *pVerbsAv, WV_ADDRESS_VECTOR *pAv,
 //					  UINT8 PathMtu, UINT8 LocalAckTimeout,
 //					  UINT8 SequenceErrorRetryCount, UINT8 RnrRetryCount);
Index: wv_provider.c
===================================================================
--- wv_provider.c	(revision 1035)
+++ wv_provider.c	(working copy)
@@ -27,62 +27,243 @@
  * SOFTWARE.
  */
 
-#include <winerror.h>
+#include <ntstatus.h>
 
 #include <rdma\wvstatus.h>
 #include "wv_driver.h"
 #include "wv_ioctl.h"
 #include "wv_provider.h"
 #include "wv_device.h"
+#include "wv_pd.h"
 
-void WvGuidQuery(WDFREQUEST Request)
+void WvProviderGet(WV_PROVIDER *pProvider)
 {
-	WV_IO_GUID_LIST	*pioGuids;
-	size_t			len = 0;
-	WV_RDMA_DEVICE	*pdev;
-	ULONG			count, i;
-	LIST_ENTRY		*pentry;
-	NTSTATUS		status;
+	InterlockedIncrement(&pProvider->Ref);
+}
 
-	status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_GUID_LIST),
-											&pioGuids, &len);
-	if (!NT_SUCCESS(status)) {
-		goto out;
+void WvProviderPut(WV_PROVIDER *pProvider)
+{
+	if (InterlockedDecrement(&pProvider->Ref) == 0) {
+		KeSetEvent(&pProvider->Event, 0, FALSE);
 	}
+}
 
-	count = (len - sizeof(UINT64)) / sizeof(UINT64);
-	i = 0;
-	len = sizeof(UINT64);
-	KeAcquireGuardedMutex(&DevLock);
-	for (pentry = DevList.Flink; pentry != &DevList; pentry = pentry->Flink) {
-		pdev = CONTAINING_RECORD(pentry, WV_RDMA_DEVICE, Entry);
-		if (i < count) {
-			pioGuids->Guid[i] = pdev->Guid;
-			len += sizeof(UINT64);
-		}
-		i++;
+void WvProviderInit(WV_PROVIDER *pProvider)
+{
+	IndexListInit(&pProvider->DevIndex);
+	IndexListInit(&pProvider->PdIndex);
+	IndexListInit(&pProvider->MwIndex);
+	IndexListInit(&pProvider->AhIndex);
+
+	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);
+}
+
+void WvProviderCleanup(WV_PROVIDER *pProvider)
+{
+	WV_DEVICE				*dev;
+	WV_PROTECTION_DOMAIN	*pd;
+	WV_MEMORY_WINDOW		*mw;
+	WV_ADDRESS_HANDLE		*ah;
+
+	while ((ah = IndexListRemoveHead(&pProvider->AhIndex)) != NULL) {
+		RemoveEntryList(&ah->Entry);
+		WvAhFree(ah);
 	}
-	pioGuids->Count = i;
-	KeReleaseGuardedMutex(&DevLock);
+	while ((mw = IndexListRemoveHead(&pProvider->MwIndex)) != NULL) {
+		RemoveEntryList(&mw->Entry);
+		WvMwFree(mw);
+	}
+	while ((pd = IndexListRemoveHead(&pProvider->PdIndex)) != NULL) {
+		RemoveEntryList(&pd->Entry);
+		WvPdFree(pd);
+	}
+	while ((dev = IndexListRemoveHead(&pProvider->DevIndex)) != NULL) {
+		WvDeviceFree(dev);
+	}
 
-out:
-	WdfRequestCompleteWithInformation(Request, status, len);
+	if (InterlockedDecrement(&pProvider->Ref) > 0) {
+		KeWaitForSingleObject(&pProvider->Event, Executive, KernelMode, FALSE, NULL);
+	}
+
+	IndexListDestroy(&pProvider->AhIndex);
+	IndexListDestroy(&pProvider->MwIndex);
+	IndexListDestroy(&pProvider->PdIndex);
+	IndexListDestroy(&pProvider->DevIndex);
 }
 
-void WvProviderInit(WV_PROVIDER *pProvider)
+// See comment above WvProviderRemoveHandler.
+static void WvProviderLockRemove(WV_PROVIDER *pProvider)
 {
-	InitializeListHead(&pProvider->DevList);
-	KeInitializeGuardedMutex(&pProvider->Lock);
+	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);
 }
 
-void WvProviderDestroy(WV_PROVIDER *pProvider)
+// See comment above WvProviderRemoveHandler.
+static void WvProviderUnlockRemove(WV_PROVIDER *pProvider)
 {
-	LIST_ENTRY *entry;
+	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 WvProviderRemoveHandler.
+ */
+void WvProviderDisableRemove(WV_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 WvProviderRemoveHandler.
+ */
+void WvProviderEnableRemove(WV_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 WvProviderRemoveHandler(WV_PROVIDER *pProvider, WV_RDMA_DEVICE *pDevice)
+{
 	WV_DEVICE *dev;
+	SIZE_T i;
 
-	while (!IsListEmpty(&pProvider->DevList)) {
-		entry = RemoveHeadList(&pProvider->DevList);
-		dev = CONTAINING_RECORD(entry, WV_DEVICE, Entry);
-		//WvDeviceDestroy(dev);
+	WvProviderLockRemove(pProvider);
+	IndexListForEach(&pProvider->DevIndex, i) {
+		dev = IndexListAt(&pProvider->DevIndex, i);
+		if (dev->pDevice == pDevice) {
+			WvDeviceRemoveHandler(dev);
+		}
 	}
+	WvProviderUnlockRemove(pProvider);
 }
+
+void WvDeviceOpen(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	WV_IO_ID		*inid, *outid;
+	size_t			inlen, outlen;
+	WV_DEVICE		*dev;
+	NTSTATUS		status;
+	ci_umv_buf_t	verbsData;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen);
+	if (!NT_SUCCESS(status)) {
+		goto err1;
+	}
+	status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);
+	if (!NT_SUCCESS(status)) {
+		goto err1;
+	}
+
+	dev = WvDeviceAlloc(pProvider);
+	if (dev == NULL) {
+		status = STATUS_NO_MEMORY;
+		goto err1;
+	}
+
+	KeAcquireGuardedMutex(&pProvider->Lock);
+	WvProviderDisableRemove(pProvider);
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID),
+					outlen - sizeof(WV_IO_ID), inid + 1);
+	status = WvDeviceInit(dev, inid->Id, &verbsData);
+	if (!NT_SUCCESS(status)) {
+		goto err2;
+	}
+
+	KeAcquireGuardedMutex(&pProvider->Lock);
+	dev->Id = IndexListInsertHead(&pProvider->DevIndex, dev);
+	if (dev->Id == 0) {
+		status = STATUS_NO_MEMORY;
+		goto err2;
+	}
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	WvProviderEnableRemove(pProvider);
+	outid->Id = dev->Id;
+	outid->VerbInfo = verbsData.status;
+	WdfRequestCompleteWithInformation(Request, status, outlen);
+	return;
+
+err2:
+	WvDeviceFree(dev);
+	WvProviderEnableRemove(pProvider);
+err1:
+	WdfRequestComplete(Request, status);
+}
+
+void WvDeviceClose(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+	WV_DEVICE	*dev;
+	UINT64		*id;
+	NTSTATUS	status;
+
+	status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);
+	if (!NT_SUCCESS(status)) {
+		goto out;
+	}
+
+	KeAcquireGuardedMutex(&pProvider->Lock);
+	WvProviderDisableRemove(pProvider);
+	dev = IndexListAt(&pProvider->DevIndex, (SIZE_T) id);
+	if (dev == NULL) {
+		status = STATUS_NO_SUCH_DEVICE;
+	} else if (dev->Ref > 1) {
+		status = STATUS_ACCESS_DENIED;
+	} else {
+		IndexListRemove(&pProvider->DevIndex, (SIZE_T) id);
+		status = STATUS_SUCCESS;
+	}
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	if (NT_SUCCESS(status)) {
+		WvDeviceFree(dev);
+	}
+	WvProviderEnableRemove(pProvider);
+out:
+	WdfRequestComplete(Request, status);
+}
Index: wv_provider.h
===================================================================
--- wv_provider.h	(revision 1035)
+++ wv_provider.h	(working copy)
@@ -36,16 +36,42 @@
 #include <wdf.h>
 #include <wdm.h>
 
+#include <complib\cl_qmap.h>
+#include "wv_driver.h"
+#include "index_list.h"
+
+struct _WV_DEVICE;
+struct _WV_PROTECTION_DOMAIN;
+
 typedef struct _WV_PROVIDER
 {
+	LIST_ENTRY		Entry;
+	INDEX_LIST		DevIndex;
+	INDEX_LIST		PdIndex;
+	INDEX_LIST		MwIndex;
+	INDEX_LIST		AhIndex;
+
 	KGUARDED_MUTEX	Lock;
-	LIST_ENTRY		DevList;
+	LONG			Ref;
+	KEVENT			Event;
+	LONG			Pending;
+	LONG			Active;
+	KEVENT			SharedEvent;
+	LONG			Exclusive;
+	KEVENT			ExclusiveEvent;
 
 }	WV_PROVIDER;
 
+void WvProviderGet(WV_PROVIDER *pProvider);
+void WvProviderPut(WV_PROVIDER *pProvider);
 void WvProviderInit(WV_PROVIDER *pProvider);
-void WvProviderDestroy(WV_PROVIDER *pProvider);
+void WvProviderCleanup(WV_PROVIDER *pProvider);
 
-void WvGuidQuery(WDFREQUEST Request);
+void WvProviderRemoveHandler(WV_PROVIDER *pProvider, WV_RDMA_DEVICE *pDevice);
+void WvProviderDisableRemove(WV_PROVIDER *pProvider);
+void WvProviderEnableRemove(WV_PROVIDER *pProvider);
 
+void WvDeviceOpen(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvDeviceClose(WV_PROVIDER *pProvider, WDFREQUEST Request);
+
 #endif // _WV_PROVIDER_H_





More information about the ofw mailing list