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 <[EMAIL PROTECTED]>
---
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_


_______________________________________________
ofw mailing list
[email protected]
http://lists.openfabrics.org/cgi-bin/mailman/listinfo/ofw

Reply via email to