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

Sean Hefty sean.hefty at intel.com
Tue Apr 22 16:48:48 PDT 2008


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

Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
I had a hard time coming up with the implementation to handle device
removal with active userspace users in a way that had the least impact
on performance.  I'd appreciate it if someone could review at least
that relevant code portions.  Please see the WvProviderRemoveHandler(),
and the 4 functions immediately above it.

Index: wv_device.c
===================================================================
--- wv_device.c	(revision 0)
+++ wv_device.c	(revision 0)
@@ -0,0 +1,580 @@
+/*
+ * 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);
+	dev = IndexListAt(&pProvider->DevIndex, (SIZE_T) Id);
+	if (dev != NULL) {
+		WvProviderRemoveDisable(pProvider);
+		WvDeviceGet(dev);
+	}
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	return dev;
+}
+
+void WvDeviceRelease(WV_DEVICE *pDevice)
+{
+	WvProviderRemoveEnable(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->hVerbsDevice = NULL;
+	dev->pDevice = 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;
+	}
+
+	pDevice->pDevice = dev;
+	pDevice->pVerbs = &dev->Interface.Verbs;
+	ib_status = pDevice->pVerbs->um_open_ca(dev->hDevice, pVerbsData,
+											&pDevice->hVerbsDevice);
+	if (ib_status != IB_SUCCESS) {
+		goto err;
+	}
+	return STATUS_SUCCESS;
+
+err:
+	WvRdmaDevicePut(pDevice->pDevice);
+	pDevice->pDevice = NULL;
+	return STATUS_UNSUCCESSFUL;
+}
+
+void WvDeviceDestroy(WV_DEVICE *pDevice)
+{
+	if (InterlockedDecrement(&pDevice->Ref) > 0) {
+		KeWaitForSingleObject(&pDevice->Event, Executive, KernelMode, FALSE, NULL);
+	}
+
+	if (pDevice->pDevice != 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;
+}
+
+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);
+	if (ca_attr == NULL) {
+		status = STATUS_NO_MEMORY;
+		goto release;
+	}
+
+	WvConvertDevAttr(attr, ca_attr);
+	outlen = sizeof(WV_IO_DEVICE_ATTRIBUTES);
+	ExFreePool(ca_attr);
+
+release:
+	WvDeviceRelease(dev);
+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);
+	if (ca_attr == NULL) {
+		status = STATUS_NO_MEMORY;
+		goto release;
+	}
+
+	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);
+release:
+	WvDeviceRelease(dev);
+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);
+	if (ca_attr == NULL) {
+		status = STATUS_NO_MEMORY;
+		goto release;
+	}
+
+	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);
+release:
+	WvDeviceRelease(dev);
+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);
+	if (ca_attr == NULL) {
+		status = STATUS_NO_MEMORY;
+		goto release;
+	}
+
+	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);
+release:
+	WvDeviceRelease(dev);
+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);
+	pd->Id = IndexListInsert(&pProvider->PdIndex, pd);
+	if (pd->Id == 0) {
+		status = STATUS_NO_MEMORY;
+		goto err3;
+	}
+	InsertHeadList(&dev->PdList, &pd->Entry);
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	WvDeviceRelease(dev);
+	outid->Id = pd->Id;
+	outid->VerbInfo = verbsData.status;
+	WdfRequestCompleteWithInformation(Request, status, outlen);
+	return;
+
+err3:
+	KeReleaseGuardedMutex(&pProvider->Lock);
+	WvPdDestroy(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);
+	WvProviderRemoveDisable(pProvider);
+	pd = IndexListRemove(&pProvider->PdIndex, (SIZE_T) id);
+	if (pd == NULL) {
+		status = STATUS_NOT_FOUND;
+	} else if (pd->Ref > 1) {
+		status = STATUS_ACCESS_DENIED;
+	} else {
+		RemoveEntryList(&pd->Entry);
+		status = STATUS_SUCCESS;
+	}
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	if (NT_SUCCESS(status)) {
+		WvPdDestroy(pd);
+	}
+	WvProviderRemoveEnable(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 WvDeviceDestroy(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,122 @@
 #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;
 
+static WV_RDMA_DEVICE *WvRdmaDeviceFind(UINT64 Guid)
+{
+	WV_RDMA_DEVICE	*dev;
+	LIST_ENTRY		*entry;
+
+	for (entry = DevList.Flink; entry != &DevList; entry = entry->Flink) {
+		dev = CONTAINING_RECORD(entry, WV_RDMA_DEVICE, Entry);
+		if (dev->Interface.Verbs.guid == Guid) {
+			return dev;
+		}
+	}
+	return NULL;
+}
+
+WV_RDMA_DEVICE *WvRdmaDeviceGet(UINT64 Guid)
+{
+	WV_RDMA_DEVICE	*dev;
+
+	KeAcquireGuardedMutex(&Lock);
+	dev = WvRdmaDeviceFind(Guid);
+	if (dev != NULL) {
+		InterlockedIncrement(&dev->Ref);
+	}
+	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,25 +171,47 @@
 	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_PD_ALLOCATE:
+		WvPdAllocate(prov, Request);
+		break;
+	case WV_IOCTL_PD_DEALLOCATE:
+		WvPdDeallocate(prov, Request);
+		break;
+	case WV_IOCTL_MEMORY_REGISTER:
+		WvMemoryRegister(prov, Request);
+		break;
+	case WV_IOCTL_MEMORY_DEREGISTER:
+		WvMemoryDeregister(prov, Request);
+		break;
 	//case WV_IOCTL_MW_ALLOCATE:WvMwAllocate;break;
 	//case WV_IOCTL_MW_DEALLOCATE:WvMwDeallocate;break;
 	//case WV_IOCTL_AH_CREATE:WvAhCreate;break;
@@ -129,7 +254,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,12 +262,13 @@
 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);
 }
 
@@ -153,10 +279,12 @@
 
 static VOID WvFileClose(WDFFILEOBJECT FileObject)
 {
-	WV_PROVIDER *prov;
+	WV_PROVIDER *prov = WvProviderGetContext(FileObject);
 
-	prov = WvGetProvider(FileObject);
-	WvProviderDestroy(prov);
+	KeAcquireGuardedMutex(&Lock);
+	RemoveEntryList(&prov->Entry);
+	KeReleaseGuardedMutex(&Lock);
+	WvProviderCleanup(prov);
 }
 
 static VOID WvCreateControlDevice(WDFDRIVER Driver)
@@ -215,7 +343,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 +354,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 +386,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 +430,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,249 @@
+/*
+ * 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);
+	pd = IndexListAt(&pProvider->PdIndex, (SIZE_T) Id);
+	if (pd != NULL) {
+		WvProviderRemoveDisable(pProvider);
+		WvPdGet(pd);
+	}
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	return pd;
+}
+
+void WvPdRelease(WV_PROTECTION_DOMAIN *pPd)
+{
+	WvProviderRemoveEnable(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);
+	pd->pDevice = pDevice;
+	pd->pVerbs = pDevice->pVerbs;
+	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;
+	}
+
+	WvDeviceGet(pDevice);
+	*ppPd = pd;
+	return STATUS_SUCCESS;
+
+err:
+	ExFreePool(pd);
+	return STATUS_UNSUCCESSFUL;
+}
+
+void WvPdDestroy(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;
+	}
+
+	if (InterlockedDecrement(&pPd->Ref) > 0) {
+		KeWaitForSingleObject(&pPd->Event, Executive, KernelMode, FALSE, NULL);
+	}
+
+	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->hVerbsPd = NULL;
+}
+
+void WvMemoryRegister(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), 'mrvw');
+	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;
+	}
+
+	WvPdGet(pd);
+	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 WvMemoryDeregister(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);
+	if (mr->hVerbsMr == NULL) {
+		goto free;
+	}
+
+	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;
+	}
+
+free:
+	WvPdPut(pd);
+	ExFreePool(mr);
+release:
+	WvPdRelease(pd);
+complete:
+	WdfRequestComplete(Request, status);
+}
Index: wv_pd.h
===================================================================
--- wv_pd.h	(revision 1035)
+++ wv_pd.h	(working copy)
@@ -32,22 +32,52 @@
 #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;
 
+	KGUARDED_MUTEX		Lock;
+	cl_qmap_t			MrMap;
+
+	SIZE_T				Id;
+	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 WvPdDestroy(WV_PROTECTION_DOMAIN *pPd);
+void WvPdRemoveHandler(WV_PROTECTION_DOMAIN *pPd);
+
+void WvMemoryRegister(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvMemoryDeregister(WV_PROVIDER *pProvider, WDFREQUEST Request);
+
+
+typedef struct _WV_MEMORY_REGION
+{
+	WV_PROTECTION_DOMAIN	*pPd;
+	ib_mr_handle_t			hVerbsMr;
+	cl_map_item_t			Item;
+
+}	WV_MEMORY_REGION;
+
 typedef struct _WV_MEMORY_WINDOW
 {
 	WV_PROTECTION_DOMAIN	*pPd;
Index: wv_provider.c
===================================================================
--- wv_provider.c	(revision 1035)
+++ wv_provider.c	(working copy)
@@ -27,62 +27,229 @@
  * 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);
+
+	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;
+
+	while ((pd = IndexListRemoveFirst(&pProvider->PdIndex)) != NULL) {
+		WvPdDestroy(pd);
 	}
-	pioGuids->Count = i;
-	KeReleaseGuardedMutex(&DevLock);
 
-out:
-	WdfRequestCompleteWithInformation(Request, status, len);
+	while ((dev = IndexListRemoveFirst(&pProvider->DevIndex)) != NULL) {
+		WvDeviceDestroy(dev);
+	}
+
+	if (InterlockedDecrement(&pProvider->Ref) > 0) {
+		KeWaitForSingleObject(&pProvider->Event, Executive, KernelMode, FALSE, NULL);
+	}
+
+	IndexListDestroy(&pProvider->PdIndex);
+	IndexListDestroy(&pProvider->DevIndex);
 }
 
-void WvProviderInit(WV_PROVIDER *pProvider)
+// See comment above WvProviderRemoveHandler.
+static void WvProviderRemoveLock(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 WvProviderRemoveUnlock(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 WvProviderRemoveDisable(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 WvProviderRemoveEnable(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);
+	WvProviderRemoveLock(pProvider);
+	IndexListForEach(&pProvider->DevIndex, i) {
+		dev = IndexListAt(&pProvider->DevIndex, i);
+		if (dev->pDevice == pDevice) {
+			WvDeviceRemoveHandler(dev);
+		}
 	}
+	WvProviderRemoveUnlock(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);
+	WvProviderRemoveDisable(pProvider);
+	dev->Id = IndexListInsert(&pProvider->DevIndex, dev);
+	if (dev->Id == 0) {
+		status = STATUS_NO_MEMORY;
+		goto err2;
+	}
+	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 err3;
+	}
+
+	WvProviderRemoveEnable(pProvider);
+	outid->Id = dev->Id;
+	outid->VerbInfo = verbsData.status;
+	WdfRequestCompleteWithInformation(Request, status, outlen);
+	return;
+
+err3:
+	KeAcquireGuardedMutex(&pProvider->Lock);
+	IndexListRemove(&pProvider->DevIndex, dev->Id);
+err2:
+	KeReleaseGuardedMutex(&pProvider->Lock);
+	WvProviderRemoveEnable(pProvider);
+	WvDeviceDestroy(dev);
+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);
+	WvProviderRemoveDisable(pProvider);
+	dev = IndexListRemove(&pProvider->DevIndex, (SIZE_T) id);
+	if (dev == NULL) {
+		status = STATUS_NO_SUCH_DEVICE;
+	} else if (dev->Ref > 1) {
+		status = STATUS_ACCESS_DENIED;
+	} else {
+		status = STATUS_SUCCESS;
+	}
+	KeReleaseGuardedMutex(&pProvider->Lock);
+
+	if (NT_SUCCESS(status)) {
+		WvDeviceDestroy(dev);
+	}
+	WvProviderRemoveEnable(pProvider);
+out:
+	WdfRequestComplete(Request, status);
+}
Index: wv_provider.h
===================================================================
--- wv_provider.h	(revision 1035)
+++ wv_provider.h	(working copy)
@@ -36,16 +36,40 @@
 #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;
+
 	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 WvProviderRemoveDisable(WV_PROVIDER *pProvider);
+void WvProviderRemoveEnable(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