[ofw] [Patch 47/62] Reference implementation of NDv2

Fab Tillier ftillier at microsoft.com
Wed Feb 20 20:48:53 PST 2013


New ND filter and provider.

Note that ndinstall was extended to support installing/removing the NDv1 and NDv2 providers independently, using the name mlx4nd and mlx4nd2.  Both are implemented by the same DLL, mlx4nd.dll

Signed-off-by: Fab Tillier <ftillier at microsoft.com>

diff -dwup3 -X excl.txt -r \dev\openib\ofw\gen1\branches\mlx4_30\trunk\core\dirs .\core\dirs
--- \dev\openib\ofw\gen1\branches\mlx4_30\trunk\core\dirs	Tue Aug 07 16:41:02 2012
+++ .\core\dirs	Thu Jul 26 16:01:17 2012
@@ -5,4 +5,5 @@ DIRS=\
 	ibat		\
 	winverbs	\
 	winmad		\
+        ndfltr \
 	fip
diff -dwup3 -X excl.txt -r \dev\openib\ofw\gen1\branches\mlx4_30\trunk\hw\mlx4\user\dirs .\hw\mlx4\user\dirs
--- \dev\openib\ofw\gen1\branches\mlx4_30\trunk\hw\mlx4\user\dirs	Thu Mar 29 00:15:30 2012
+++ .\hw\mlx4\user\dirs	Mon Apr 16 11:51:54 2012
@@ -1,2 +1,3 @@
 DIRS=\
-	hca
+    hca \
+    nd \
diff -dwup3 -X excl.txt -r \dev\openib\ofw\gen1\branches\mlx4_30\trunk\tools\ndinstall\user\installsp.c .\tools\ndinstall\user\installsp.c
--- \dev\openib\ofw\gen1\branches\mlx4_30\trunk\tools\ndinstall\user\installsp.c	Thu May 31 11:22:11 2012
+++ .\tools\ndinstall\user\installsp.c	Tue Aug 07 10:24:43 2012
@@ -55,28 +55,34 @@
 #define IBAL_DEBUG_INDEX	1
 #define WV_INDEX			2
 #define WV_DEBUG_INDEX		3
-#define MAX_INDEX			4
+#define MLX4_INDEX          4
+#define MLX4v2_INDEX        5
+#define MAX_INDEX			6
 
 #define DEFAULT_PROVIDER_INDEX IBAL_INDEX
 
 static int g_index=DEFAULT_PROVIDER_INDEX;
 
 static const char * const provider_name[MAX_INDEX] = {
-	"IBAL", "IBAL (debug)", "WinVerbs", "WinVerbs (debug)"
+	"IBAL", "IBAL (debug)", "WinVerbs", "WinVerbs (debug)", "mlx4nd", "mlx4nd2"
 };
 
 static const WCHAR * const provider_path[MAX_INDEX] = {
 	L"%SYSTEMROOT%\\system32\\ibndprov.dll",
 	L"%SYSTEMROOT%\\system32\\ibndprov.dll",
 	L"%SYSTEMROOT%\\system32\\wvndprov.dll",
-	L"%SYSTEMROOT%\\system32\\wvndprovd.dll"
+	L"%SYSTEMROOT%\\system32\\wvndprovd.dll",
+    L"%SYSTEMROOT%\\system32\\mlx4nd.dll",
+    L"%SYSTEMROOT%\\system32\\mlx4nd.dll"
 };
 
 static const WCHAR * const provider_desc[MAX_INDEX] = {
 	L"OpenFabrics Network Direct Provider",
 	L"OpenFabrics Network Direct Provider (Debug)",
 	L"OpenFabrics Winverbs Network Direct Provider",
-	L"OpenFabrics Winverbs Network Direct Provider (Debug)"
+	L"OpenFabrics Winverbs NetworkDirect Provider (Debug)",
+    L"OpenFabrics NDv1 Provider for Mellanox ConnectX",
+    L"OpenFabrics NDv2 Provider for Mellanox ConnectX"
 };
 
 static GUID provider_guid[MAX_INDEX] = {
@@ -87,7 +93,9 @@ static GUID provider_guid[MAX_INDEX] = {
 	// {854DCE83-C872-4462-A3EB-C961C40E59D0}
 	{ 0x854dce83, 0xc872, 0x4462, { 0xa3, 0xeb, 0xc9, 0x61, 0xc4, 0x0e, 0x59, 0xd0 } },
 	// {1B8F1692-EDD9-4153-A159-605A73BCFFCF}
-	{ 0x1b8f1692, 0xedd9, 0x4153, { 0xa1, 0x59, 0x60, 0x5a, 0x73, 0xbc, 0xff, 0xcf } }
+	{ 0x1b8f1692, 0xedd9, 0x4153, { 0xa1, 0x59, 0x60, 0x5a, 0x73, 0xbc, 0xff, 0xcf } },
+    { 0xc42da8c6, 0xd1a1, 0x4f78, { 0x9f, 0x52, 0x27, 0x6c, 0x74, 0x93, 0x55, 0x96 } },
+    { 0xb324ac22, 0x3a56, 0x4e6f, { 0xa9, 0xc4, 0x36, 0xdc, 0xc4, 0x28, 0xef, 0x65 } }
 };
 
 #ifdef _WIN64
@@ -115,6 +123,8 @@ show_usage (char *progname)
 	printf("\tprovider must be one of the following names:\n");
 	printf("\t\tibal\n");
 	printf("\t\twinverbs\n");
+    printf("\t\tmlx4nd\n");
+    printf("\t\tmlx4nd2\n");
 	printf("\t\t<blank> use the default ND provider '%s'\n",
 		provider_name[DEFAULT_PROVIDER_INDEX]);
 }
@@ -194,7 +204,11 @@ static int install_provider(void)
 	provider.ProviderId = provider_guid[g_index];
 	provider.dwCatalogEntryId = 0;
 	provider.ProtocolChain.ChainLen = 1;	/* Base Protocol Service Provider */
+    if(g_index == MLX4v2_INDEX) {
+        provider.iVersion = 0x20000/*ND_VERSION_2*/;
+    } else {
 	provider.iVersion = 1;
+    }
 	if (g_index == IBAL_INDEX || g_index == IBAL_DEBUG_INDEX) {
 		provider.iAddressFamily = AF_INET;
 		provider.iMaxSockAddr = sizeof(SOCKADDR_IN);
Index: hw/mlx4/user/nd/connector.h
===================================================================
--- hw/mlx4/user/nd/connector.h	(revision 0)
+++ hw/mlx4/user/nd/connector.h	(revision 0)
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+namespace NDv2
+{
+
+bool CopyAddress(
+    __in_bcount(cbAddress) const struct sockaddr* pAddress,
+    ULONG cbAddress,
+    __out SOCKADDR_INET* pInetAddress
+    );
+
+HRESULT CopyAddress(
+    __in SOCKADDR_INET& inetAddress,
+    __out_bcount_part_opt(*pcbAddress, *pcbAddress) struct sockaddr* pAddress,
+    __inout ULONG* pcbAddress
+    );
+
+class Connector
+    : public Overlapped<Connector, IND2Connector>
+{
+    typedef Overlapped<Connector, IND2Connector> _Base;
+
+    Adapter& m_Adapter;
+
+    UINT64 m_hConnector;
+    Qp* m_pQp;
+
+    static const UINT8 _MaxRetryCount = 6;
+
+public:
+    static const GUID _Guid;
+
+private:
+    operator =(Connector&) {}
+
+public:
+    Connector(Adapter& adapter);
+    ~Connector();
+
+    HRESULT Initialize(HANDLE hFile, BOOLEAN v1);
+
+    void* GetInterface(REFIID riid);
+
+    UINT64 GetHandle() const { return m_hConnector; }
+    static ULONG GetCancelIoctlCode() { return IOCTL_ND_CONNECTOR_CANCEL_IO; }
+
+public:
+    // *** IND2Connector methods ***
+    STDMETHODIMP Bind(
+        __in_bcount(cbAddress) const struct sockaddr* pAddress,
+        ULONG cbAddress
+        );
+
+    STDMETHODIMP Connect(
+        __in IUnknown* pQueuePair,
+        __in_bcount(cbDestAddress) const struct sockaddr* pDestAddress,
+        ULONG cbDestAddress,
+        ULONG inboundReadLimit,
+        ULONG outboundReadLimit,
+        __in_bcount_opt(cbPrivateData) const VOID* pPrivateData,
+        ULONG cbPrivateData,
+        __inout OVERLAPPED* pOverlapped
+        );
+
+    STDMETHODIMP CompleteConnect(
+        __inout OVERLAPPED* pOverlapped
+        );
+
+    STDMETHODIMP Accept(
+        __in IUnknown* pQueuePair,
+        ULONG inboundReadLimit,
+        ULONG outboundReadLimit,
+        __in_bcount_opt(cbPrivateData) const VOID* pPrivateData,
+        ULONG cbPrivateData,
+        __inout OVERLAPPED* pOverlapped
+        );
+
+    STDMETHODIMP Reject(
+        __in_bcount_opt(cbPrivateData) const VOID* pPrivateData,
+        ULONG cbPrivateData
+        );
+
+    STDMETHODIMP GetReadLimits(
+        __out_opt ULONG* pInboundReadLimit,
+        __out_opt ULONG* pOutboundReadLimit
+        );
+
+    STDMETHODIMP GetPrivateData(
+        __out_bcount_opt(*pcbPrivateData) VOID* pPrivateData,
+        __inout ULONG* pcbPrivateData
+        );
+
+    STDMETHODIMP GetLocalAddress(
+        __out_bcount_part_opt(*pcbAddress, *pcbAddress) struct sockaddr* pAddress,
+        __inout ULONG* pcbAddress
+        );
+
+    STDMETHODIMP GetPeerAddress(
+        __out_bcount_part_opt(*pcbAddress, *pcbAddress) struct sockaddr* pAddress,
+        __inout ULONG* pcbAddress
+        );
+
+    STDMETHODIMP NotifyDisconnect(
+        __inout OVERLAPPED* pOverlapped
+        );
+
+    STDMETHODIMP Disconnect(
+        __inout OVERLAPPED* pOverlapped
+        );
+};
+
+} // namespace NDv2
+
+namespace NDv1
+{
+
+class Connector
+    : public Unknown<Connector, INDConnector>
+{
+    typedef Unknown<Connector, INDConnector> _Base;
+
+    Adapter& m_Adapter;
+    IND2Connector& m_Connector;
+
+    ULONG m_InboundReadLimit;
+    ULONG m_OutboundReadLimit;
+
+private:
+    operator =(Connector&) {}
+
+public:
+    Connector(Adapter& adapter, IND2Connector& connector);
+    ~Connector(void);
+
+    void* GetInterface(REFIID riid);
+
+    IND2Connector* GetConnector() const { return &m_Connector; }
+
+public:
+    static HRESULT Create(
+        __in Adapter& adapter,
+        __in IND2Connector& connector,
+        __deref_out INDConnector** ppConnector
+        );
+
+public:
+    // *** INDOverlapped methods ***
+    HRESULT STDMETHODCALLTYPE CancelOverlappedRequests(void)
+    {
+        return m_Connector.CancelOverlappedRequests();
+    }
+
+    HRESULT STDMETHODCALLTYPE GetOverlappedResult(
+        __inout_opt OVERLAPPED *pOverlapped,
+        __out SIZE_T *pNumberOfBytesTransferred,
+        __in BOOL bWait
+        )
+    {
+        *pNumberOfBytesTransferred = 0;
+        return m_Connector.GetOverlappedResult(pOverlapped, bWait);
+    }
+
+    // *** INDConnector methods ***
+    HRESULT STDMETHODCALLTYPE CreateEndpoint(
+        __in INDCompletionQueue* pInboundCq,
+        __in INDCompletionQueue* pOutboundCq,
+        __in SIZE_T nInboundEntries,
+        __in SIZE_T nOutboundEntries,
+        __in SIZE_T nInboundSge,
+        __in SIZE_T nOutboundSge,
+        __in SIZE_T InboundReadLimit,
+        __in SIZE_T OutboundReadLimit,
+        __out_opt SIZE_T* pMaxInlineData,
+        __deref_out INDEndpoint** ppEndpoint
+        );
+
+    HRESULT STDMETHODCALLTYPE Connect(
+        __in INDEndpoint* pEndpoint,
+        __in_bcount(AddressLength) const struct sockaddr* pAddress,
+        __in SIZE_T AddressLength,
+        __in INT Protocol,
+        __in_opt USHORT LocalPort,
+        __in_bcount_opt(PrivateDataLength) const void* pPrivateData,
+        __in SIZE_T PrivateDataLength,
+        __inout OVERLAPPED* pOverlapped
+        );
+
+    HRESULT STDMETHODCALLTYPE CompleteConnect(
+        __inout OVERLAPPED* pOverlapped
+        );
+
+    HRESULT STDMETHODCALLTYPE Accept(
+        __in INDEndpoint* pEndpoint,
+        __in_bcount_opt(PrivateDataLength) const void* pPrivateData,
+        __in SIZE_T PrivateDataLength,
+        __inout OVERLAPPED* pOverlapped
+        );
+
+    HRESULT STDMETHODCALLTYPE Reject(
+        __in_bcount_opt(PrivateDataLength) const void* pPrivateData,
+        __in SIZE_T PrivateDataLength
+        );
+
+    HRESULT STDMETHODCALLTYPE GetConnectionData(
+        __out_opt SIZE_T* pInboundReadLimit,
+        __out_opt SIZE_T* pOutboundReadLimit,
+        __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData,
+        __inout SIZE_T* pPrivateDataLength
+        );
+
+    HRESULT STDMETHODCALLTYPE GetLocalAddress(
+        __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress,
+        __inout SIZE_T* pAddressLength
+        );
+
+    HRESULT STDMETHODCALLTYPE GetPeerAddress(
+        __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress,
+        __inout SIZE_T* pAddressLength
+        );
+
+    HRESULT STDMETHODCALLTYPE NotifyDisconnect(
+        __inout_opt OVERLAPPED* pOverlapped
+        );
+
+    HRESULT STDMETHODCALLTYPE Disconnect(
+        __inout OVERLAPPED* pOverlapped
+        );
+};
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/provider.h
===================================================================
--- hw/mlx4/user/nd/provider.h	(revision 0)
+++ hw/mlx4/user/nd/provider.h	(revision 0)
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+
+namespace NDv2
+{
+
+class Provider
+    : public Unknown<Provider,IND2Provider>
+{
+    typedef Unknown<Provider,IND2Provider> _Base;
+
+    HANDLE  m_hProvider;
+
+private:
+    Provider(void);
+
+public:
+    static HRESULT Create(__in REFIID riid, __out void** ppProvider);
+    ~Provider(void);
+
+public:
+    // IND2Provider Methods
+    HRESULT STDMETHODCALLTYPE QueryAddressList(
+        __out_bcount_part_opt(*pcbAddressList, *pcbAddressList) SOCKET_ADDRESS_LIST* pAddressList,
+        __inout ULONG* pcbAddressList
+        );
+
+    HRESULT STDMETHODCALLTYPE ResolveAddress(
+        __in_bcount(cbAddress) const struct sockaddr* pAddress,
+        ULONG cbAddress,
+        __out UINT64* pAdapterId
+        );
+
+    HRESULT STDMETHODCALLTYPE OpenAdapter(
+        __in REFIID iid,
+        UINT64 adapterId,
+        __deref_out VOID** ppAdapter
+        );
+
+public:
+    void* GetInterface(REFIID riid);
+
+    HRESULT Ioctl(
+        __in ULONG IoControlCode,
+        __in_bcount(cbInput) void* pInput,
+        __in ULONG cbInput,
+        __out_bcount_part_opt(*pcbOutput,*pcbOutput) void* pOutput,
+        __inout ULONG* pcbOutput
+        );
+
+    HRESULT Ioctl(
+        __in ULONG IoControlCode,
+        __in_bcount(cbInput) void* pInput,
+        __in ULONG cbInput
+        );
+
+    HANDLE GetFileHandle() const { return m_hProvider; }
+
+    void FreeHandle( UINT64 handle, ULONG ctlCode );
+};
+
+} // namespace NDv2
+
+namespace NDv1
+{
+
+class Provider
+    : public Unknown<Provider,INDProvider>
+{
+    typedef Unknown<Provider,INDProvider> _Base;
+
+    IND2Provider* m_pProvider;
+
+private:
+    Provider(void);
+
+public:
+    static HRESULT Create(__out void** ppProvider);
+    ~Provider(void);
+
+public:
+    // INDProvider Methods
+    HRESULT STDMETHODCALLTYPE QueryAddressList(
+        __out_bcount_part_opt(*pBufferSize, *pBufferSize) SOCKET_ADDRESS_LIST* pAddressList,
+        __inout SIZE_T* pBufferSize
+        );
+
+    HRESULT STDMETHODCALLTYPE OpenAdapter(
+        __in_bcount(AddressLength) const struct sockaddr* pAddress,
+        __in SIZE_T AddressLength,
+        __deref_out INDAdapter** ppAdapter
+        );
+
+public:
+    void* GetInterface(REFIID iid);
+};
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/SOURCES
===================================================================
--- hw/mlx4/user/nd/SOURCES	(revision 0)
+++ hw/mlx4/user/nd/SOURCES	(revision 0)
@@ -0,0 +1,51 @@
+BASETARGETNAME=mlx4nd
+TARGETNAME = $(BASETARGETNAME)
+
+TARGETPATH=..\..\..\..\bin\user\obj$(BUILD_ALT_DIR)
+TARGETTYPE=DYNLINK
+DLLDEF = $(OBJ_PATH)\$O\mlx4nd.def
+DLLENTRY=DllMain
+
+USE_NTDLL=1
+
+PRECOMPILED_INCLUDE=precomp.h
+PRECOMPILED_CXX=1
+USECXX_FLAG=1
+
+SOURCES= \
+    mlx4nd.rc \
+    main.cpp \
+    factory.cpp \
+    provider.cpp \
+    adapter.cpp \
+    connector.cpp \
+    cq.cpp \
+    listener.cpp \
+    mr.cpp \
+    mw.cpp \
+    qp.cpp \
+    srq.cpp \
+
+INCLUDES= \
+    $(SDK_INC_PATH); \
+    $(PLATFORM_SDK_PATH)\include; \
+    $(ND_SDK_PATH)\include; \
+    ..\..\inc; \
+    ..\..\..\..\inc; \
+    ..\..\..\..\inc\user; \
+    ..\..\..\..\core\ndfltr\kernel; \
+    ..\hca; \
+
+#/GL
+#LINKER_FLAGS=$(LINKER_FLAGS) /LTCG
+
+TARGETLIBS= \
+    $(SDK_LIB_PATH)\Kernel32.lib\
+    $(SDK_LIB_PATH)\Advapi32.lib\
+    $(SDK_LIB_PATH)\ws2_32.lib \
+    $(SDK_LIB_PATH)\uuid.lib \
+    $(TARGETPATH)\*\mlx4u.lib \
+
+BUILD_PRODUCES=mlx4nd
+
+MSC_WARNING_LEVEL= /W4
Index: hw/mlx4/user/nd/cq.cpp
===================================================================
--- hw/mlx4/user/nd/cq.cpp	(revision 0)
+++ hw/mlx4/user/nd/cq.cpp	(revision 0)
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+namespace NDv2
+{
+// {3186027E-65EB-4EA4-B469-D6B50D7F5AE6}
+const GUID Cq::_Guid = 
+{ 0x3186027e, 0x65eb, 0x4ea4, { 0xb4, 0x69, 0xd6, 0xb5, 0xd, 0x7f, 0x5a, 0xe6 } };
+
+Cq::Cq(Adapter& adapter)
+    : m_Adapter(adapter),
+    m_hCq(0)
+{
+    adapter.AddRef();
+#if DBG
+    InterlockedIncrement(&g_nRef[NdCq]);
+#endif
+}
+
+
+Cq::~Cq(void)
+{
+    if( m_hCq != 0 )
+    {
+        FreeCq(IB_SUCCESS);
+    }
+    m_Adapter.Release();
+#if DBG
+    InterlockedDecrement(&g_nRef[NdCq]);
+#endif
+}
+
+
+HRESULT
+Cq::Initialize(
+    HANDLE hFile,
+    ULONG queueDepth,
+    USHORT group,
+    KAFFINITY affinity
+    )
+{
+    HRESULT hr = _Base::Initialize(hFile);
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    struct _createCq
+    {
+        union _ioctl
+        {
+            ND_CREATE_CQ in;
+            ND_RESOURCE_DESCRIPTOR out;
+        } ioctl;
+        union _dev
+        {
+            struct ibv_create_cq req;
+            struct ibv_create_cq_resp resp;
+        } dev;
+    } createCq;
+
+    createCq.ioctl.in.Version = ND_IOCTL_VERSION;
+    createCq.ioctl.in.QueueDepth = queueDepth;
+    createCq.ioctl.in.CeMappingCount = RTL_NUMBER_OF_V2(createCq.dev.req.mappings);
+    createCq.ioctl.in.CbMappingsOffset = FIELD_OFFSET(struct _createCq, dev.req.mappings);
+    createCq.ioctl.in.AdapterHandle = m_Adapter.GetHandle();
+    createCq.ioctl.in.Affinity.Group = group;
+    createCq.ioctl.in.Affinity.Mask = affinity;
+
+    ci_umv_buf_t umvBuf;
+    uint32_t size = queueDepth;
+    ib_api_status_t ibStatus = mlx4_pre_create_cq(
+        m_Adapter.GetUvpCa(),
+        &size,
+        &umvBuf,
+        &m_uCq
+        );
+    if( ibStatus != IB_SUCCESS )
+    {
+        return ConvertIbStatus( ibStatus );
+    }
+
+    createCq.ioctl.in.QueueDepth = size;
+
+    if( umvBuf.input_size != sizeof(createCq.dev.req) ||
+        umvBuf.output_size != sizeof(createCq.dev.resp) )
+    {
+        mlx4_post_create_cq(
+            m_Adapter.GetUvpCa(),
+            IB_INSUFFICIENT_RESOURCES,
+            queueDepth,
+            &m_uCq,
+            &umvBuf
+            );
+        return E_UNEXPECTED;
+    }
+
+    RtlCopyMemory(
+        &createCq.dev.req,
+        reinterpret_cast<void*>(umvBuf.p_inout_buf),
+        sizeof(createCq.dev.req)
+        );
+
+    ULONG cbOut = sizeof(createCq.ioctl) + sizeof(createCq.dev.resp);
+    hr = m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_CQ_CREATE,
+        &createCq,
+        sizeof(createCq.ioctl) + sizeof(createCq.dev.req),
+        &createCq,
+        &cbOut
+        );
+    if( FAILED(hr) )
+    {
+        mlx4_post_create_cq(
+            m_Adapter.GetUvpCa(),
+            IB_INSUFFICIENT_RESOURCES,
+            queueDepth,
+            &m_uCq,
+            &umvBuf
+            );
+        return hr;
+    }
+
+    m_hCq = createCq.ioctl.out.Handle;
+
+    if( cbOut != sizeof(createCq.ioctl) + sizeof(createCq.dev.resp) )
+    {
+        FreeCq(IB_INSUFFICIENT_RESOURCES);
+        mlx4_post_create_cq(
+            m_Adapter.GetUvpCa(),
+            IB_INSUFFICIENT_RESOURCES,
+            queueDepth,
+            &m_uCq,
+            &umvBuf
+            );
+        return E_UNEXPECTED;
+    }
+
+    RtlCopyMemory(
+        reinterpret_cast<void*>(umvBuf.p_inout_buf),
+        &createCq.dev.resp,
+        sizeof(createCq.dev.resp)
+        );
+    mlx4_post_create_cq(
+        m_Adapter.GetUvpCa(),
+        IB_SUCCESS,
+        queueDepth,
+        &m_uCq,
+        &umvBuf
+        );
+
+    return hr;
+}
+
+
+void* Cq::GetInterface(REFIID riid)
+{
+    if( riid == IID_IND2CompletionQueue )
+    {
+        return static_cast<IND2CompletionQueue*>(this);
+    }
+
+    if( riid == _Guid )
+    {
+        return this;
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+// *** IND2CompletionQueue methods ***
+STDMETHODIMP Cq::GetNotifyAffinity(
+    __out USHORT* pGroup,
+    __out KAFFINITY* pAffinity
+    )
+{
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = m_hCq;
+
+    GROUP_AFFINITY affinity;
+    ULONG cbAffinity = sizeof(affinity);
+    HRESULT hr = m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_CQ_GET_AFFINITY,
+        &in,
+        sizeof(in),
+        &affinity,
+        &cbAffinity
+        );
+    if( SUCCEEDED(hr) )
+    {
+        *pGroup = affinity.Group;
+        *pAffinity = affinity.Mask;
+    }
+    return hr;
+}
+
+
+STDMETHODIMP Cq::Resize(
+    ULONG /*queueDepth*/
+    )
+{
+    return E_NOTIMPL;
+}
+
+
+STDMETHODIMP Cq::Notify(
+    ULONG type,
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    ND_CQ_NOTIFY in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Type = type;
+    in.CqHandle = m_hCq;
+
+    HRESULT hr = ::IoctlAsync(
+        m_hFile,
+        IOCTL_ND_CQ_NOTIFY,
+        &in,
+        sizeof(in),
+        NULL,
+        0,
+        pOverlapped
+        );
+    if( hr == STATUS_PENDING )
+    {
+        mlx4_arm_cq(
+            m_uCq,
+            type == ND_CQ_NOTIFY_SOLICITED? TRUE : FALSE
+            );
+    }
+    return hr;
+}
+
+
+STDMETHODIMP_(ULONG) Cq::GetResults(
+    THIS_
+    __out_ecount_part(nResults,return) ND2_RESULT results[],
+    ULONG nResults
+    )
+{
+    uvp_wc_t wc;
+
+    ULONG i;
+    for( i = 0; i < nResults; i++ )
+    {
+        if( mlx4_poll_cq_array(m_uCq, 1, &wc) != 1 )
+        {
+            break;
+        }
+
+        results[i].Status = DecodeCompletionStatus(wc.status);
+        results[i].BytesTransferred = wc.length;
+        results[i].QueuePairContext = wc.qp_context;
+        if( wc.wc_type == IB_WC_NOP )
+        {
+            MwOpContext* opContext = reinterpret_cast<MwOpContext*>(wc.wr_id);
+            results[i].RequestType = opContext->GetRequestType();
+            results[i].RequestContext = opContext->GetRequestContext();
+            if( SUCCEEDED(results[i].Status) )
+            {
+                results[i].Status = opContext->Complete();
+            }
+            delete opContext;
+        }
+        else
+        {
+            results[i].RequestContext = reinterpret_cast<void*>(wc.wr_id);
+            results[i].RequestType = DecodeCompletionType(wc.wc_type);
+        }
+    }
+    return i;
+}
+
+
+void Cq::FreeCq(ib_api_status_t ibStatus)
+{
+    m_Adapter.GetProvider().FreeHandle(m_hCq, IOCTL_ND_CQ_FREE);
+
+    mlx4_post_destroy_cq(m_uCq, ibStatus);
+
+    m_hCq = 0;
+}
+
+} // namespace NDv2
+
+namespace NDv1
+{
+
+Cq::Cq(IND2CompletionQueue& cq)
+    : _Base(),
+    m_Cq(cq)
+{
+    cq.AddRef();
+}
+
+
+/*static*/
+HRESULT Cq::Create(IND2CompletionQueue& cq, INDCompletionQueue** ppCq)
+{
+    Cq* pCq = new Cq(cq);
+    if( pCq == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    *ppCq = pCq;
+    return S_OK;
+}
+
+
+void* Cq::GetInterface(REFIID riid)
+{
+    if( riid == IID_INDOverlapped )
+    {
+        return static_cast<INDOverlapped*>(this);
+    }
+
+    if( riid == IID_INDCompletionQueue )
+    {
+        return static_cast<INDCompletionQueue*>(this);
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+SIZE_T Cq::GetResults(
+    __out_ecount(nResults) ND_RESULT* pResults[],
+    __in SIZE_T nResults
+    )
+{
+    ND2_RESULT result;
+
+    ULONG i;
+    for( i = 0; i < nResults; i++ )
+    {
+        if( m_Cq.GetResults(&result, 1) != 1 )
+        {
+            break;
+        }
+
+        pResults[i] = reinterpret_cast<ND_RESULT*>(result.RequestContext);
+        pResults[i]->Status = result.Status;
+        if( result.RequestType == Nd2RequestTypeReceive )
+        {
+            pResults[i]->BytesTransferred = result.BytesTransferred;
+        }
+    }
+    return i;
+}
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/unknown.h
===================================================================
--- hw/mlx4/user/nd/unknown.h	(revision 0)
+++ hw/mlx4/user/nd/unknown.h	(revision 0)
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+template<
+    typename ThisT,
+    typename InterfaceT
+    >
+class __declspec(novtable) Unknown
+    : public InterfaceT
+{
+    friend typename ThisT;
+protected:
+    volatile LONG   m_references;
+
+public:
+    Unknown()
+        : m_references(1)
+    {
+    }
+
+    STDMETHOD(QueryInterface)(
+        REFIID riid,
+        LPVOID FAR* ppvObj
+        )
+    {
+        ThisT* pThis = static_cast<ThisT*>( this );
+        if( ppvObj == NULL )
+        {
+            return E_POINTER;
+        }
+        *ppvObj = pThis->GetInterface(riid);
+        if( *ppvObj == NULL )
+        {
+            return E_NOINTERFACE;
+        }
+        InterlockedIncrement(&pThis->m_references);
+        return S_OK;
+    }
+
+    STDMETHOD_(ULONG,AddRef)()
+    {
+        ThisT* pThis = static_cast<ThisT*>( this );
+        return InterlockedIncrement(&pThis->m_references);
+    }
+
+    STDMETHOD_(ULONG,Release)()
+    {
+        ThisT* pThis = static_cast<ThisT*>( this );
+        ULONG refs = InterlockedDecrement(&pThis->m_references);
+        if( 0 == refs )
+        {
+            pThis->FinalRelease();
+        }
+        return refs;
+    }
+
+public:
+    void* GetInterface(REFIID riid)
+    {
+        ThisT* pThis = static_cast<ThisT*>( this );
+        if( IID_IUnknown == riid )
+        {
+            return static_cast<IUnknown*>( pThis );
+        }
+        return NULL;
+    }
+
+    void FinalRelease()
+    {
+        ThisT* pThis = static_cast<ThisT*>( this );
+        delete pThis;
+    }
+};
Index: hw/mlx4/user/nd/srq.cpp
===================================================================
--- hw/mlx4/user/nd/srq.cpp	(revision 0)
+++ hw/mlx4/user/nd/srq.cpp	(revision 0)
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+namespace NDv2
+{
+// {3186027E-65EB-4EA4-B469-D6B50D7F5AE6}
+const GUID Srq::_Guid = 
+{ 0x3186027e, 0x65eb, 0x4ea4, { 0xb4, 0x69, 0xd6, 0xb5, 0xd, 0x7f, 0x5a, 0xe6 } };
+
+Srq::Srq(Adapter& adapter)
+    : m_Adapter(adapter),
+    m_hSrq(0)
+{
+    adapter.AddRef();
+#if DBG
+    InterlockedIncrement(&g_nRef[NdSrq]);
+#endif
+}
+
+
+Srq::~Srq(void)
+{
+    if( m_hSrq != 0 )
+    {
+        FreeSrq(IB_SUCCESS);
+    }
+    m_Adapter.Release();
+#if DBG
+    InterlockedIncrement(&g_nRef[NdSrq]);
+#endif
+}
+
+
+HRESULT
+Srq::Initialize(
+    HANDLE hFile,
+    ULONG queueDepth,
+    ULONG maxRequestSge,
+    ULONG notifyThreshold,
+    USHORT group,
+    KAFFINITY affinity
+    )
+{
+    HRESULT hr = _Base::Initialize(hFile);
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    struct _createSrq
+    {
+        union _ioctl
+        {
+            ND_CREATE_SRQ in;
+            ND_RESOURCE_DESCRIPTOR out;
+        } ioctl;
+        union _dev
+        {
+            struct ibv_create_srq req;
+            struct ibv_create_srq_resp resp;
+        } dev;
+    } createSrq;
+
+    createSrq.ioctl.in.Version = ND_IOCTL_VERSION;
+    createSrq.ioctl.in.QueueDepth = queueDepth;
+    createSrq.ioctl.in.CeMappingCount = RTL_NUMBER_OF_V2(createSrq.dev.req.mappings);
+    createSrq.ioctl.in.CbMappingsOffset = FIELD_OFFSET(struct _createSrq, dev.req.mappings);
+    createSrq.ioctl.in.MaxRequestSge = maxRequestSge;
+    createSrq.ioctl.in.NotifyThreshold = notifyThreshold;
+    createSrq.ioctl.in.PdHandle = m_Adapter.GetPdHandle();
+    createSrq.ioctl.in.Affinity.Group = group;
+    createSrq.ioctl.in.Affinity.Mask = affinity;
+
+    ib_srq_attr_t attr;
+    attr.max_wr = queueDepth;
+    attr.max_sge = maxRequestSge;
+    attr.srq_limit = notifyThreshold;
+
+    ci_umv_buf_t umvBuf;
+    ib_api_status_t ibStatus = mlx4_pre_create_srq(
+        m_Adapter.GetUvpPd(),
+        &attr,
+        &umvBuf,
+        &m_uSrq
+        );
+    if( ibStatus != IB_SUCCESS )
+    {
+        return ConvertIbStatus( ibStatus );
+    }
+
+    if( umvBuf.input_size != sizeof(createSrq.dev.req) ||
+        umvBuf.output_size != sizeof(createSrq.dev.resp) )
+    {
+        mlx4_post_create_srq(
+            m_Adapter.GetUvpPd(),
+            IB_INSUFFICIENT_RESOURCES,
+            &m_uSrq,
+            &umvBuf
+            );
+        return E_UNEXPECTED;
+    }
+
+    RtlCopyMemory(
+        &createSrq.dev.req,
+        reinterpret_cast<void*>(umvBuf.p_inout_buf),
+        sizeof(createSrq.dev.req)
+        );
+
+    ULONG cbOut = sizeof(createSrq.ioctl) + sizeof(createSrq.dev.resp);
+    hr = m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_SRQ_CREATE,
+        &createSrq,
+        sizeof(createSrq.ioctl) + sizeof(createSrq.dev.req),
+        &createSrq,
+        &cbOut
+        );
+    if( FAILED(hr) )
+    {
+        mlx4_post_create_srq(
+            m_Adapter.GetUvpPd(),
+            IB_INSUFFICIENT_RESOURCES,
+            &m_uSrq,
+            &umvBuf
+            );
+        return hr;
+    }
+
+    m_hSrq = createSrq.ioctl.out.Handle;
+
+    if( cbOut != sizeof(createSrq.ioctl) + sizeof(createSrq.dev.resp) )
+    {
+        FreeSrq(IB_INSUFFICIENT_RESOURCES);
+        mlx4_post_create_srq(
+            m_Adapter.GetUvpPd(),
+            IB_INSUFFICIENT_RESOURCES,
+            &m_uSrq,
+            &umvBuf
+            );
+        return E_UNEXPECTED;
+    }
+
+    RtlCopyMemory(
+        reinterpret_cast<void*>(umvBuf.p_inout_buf),
+        &createSrq.dev.resp,
+        sizeof(createSrq.dev.resp)
+        );
+    mlx4_post_create_srq(
+        m_Adapter.GetUvpPd(),
+        IB_SUCCESS,
+        &m_uSrq,
+        &umvBuf
+        );
+
+    return hr;
+}
+
+
+void* Srq::GetInterface(REFIID riid)
+{
+    if( riid == IID_IND2SharedReceiveQueue )
+    {
+        return static_cast<IND2SharedReceiveQueue*>(this);
+    }
+
+    if( riid == _Guid )
+    {
+        return this;
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+// *** IND2CompletionQueue methods ***
+STDMETHODIMP Srq::GetNotifyAffinity(
+    __out USHORT* pGroup,
+    __out KAFFINITY* pAffinity
+    )
+{
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = m_hSrq;
+
+    GROUP_AFFINITY affinity;
+    ULONG cbAffinity = sizeof(affinity);
+    HRESULT hr = m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_SRQ_GET_AFFINITY,
+        &in,
+        sizeof(in),
+        &affinity,
+        &cbAffinity
+        );
+    if( SUCCEEDED(hr) )
+    {
+        *pGroup = affinity.Group;
+        *pAffinity = affinity.Mask;
+    }
+    return hr;
+}
+
+
+STDMETHODIMP Srq::Modify(
+    ULONG /*queueDepth*/,
+    ULONG /*notifyThreshold*/
+    )
+{
+    return E_NOTIMPL;
+}
+
+
+STDMETHODIMP Srq::Notify(
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = m_hSrq;
+
+    return ::IoctlAsync(m_hFile, IOCTL_ND_SRQ_NOTIFY, &in, sizeof(in), NULL, 0, pOverlapped);
+}
+
+
+STDMETHODIMP Srq::Receive(
+    __in_opt VOID* requestContext,
+    __in_ecount_opt(nSge) const ND2_SGE sge[],
+    ULONG nSge
+    )
+{
+#ifdef _WIN64
+    ib_recv_wr_t wr;
+    wr.p_next = NULL;
+    wr.wr_id = reinterpret_cast<ULONG_PTR>(requestContext);
+    wr.num_ds = nSge;
+    wr.ds_array = reinterpret_cast<ib_local_ds_t*>(const_cast<ND2_SGE*>(sge));
+
+    ib_api_status_t ibStatus = mlx4_post_srq_recv( m_uSrq, &wr, NULL );
+    switch( ibStatus )
+    {
+    case IB_SUCCESS:
+        return S_OK;
+    case IB_INSUFFICIENT_RESOURCES:
+        return ND_NO_MORE_ENTRIES;
+    case IB_INVALID_MAX_SGE:
+        return ND_DATA_OVERRUN;
+    case IB_INVALID_QP_STATE:
+        return ND_CONNECTION_INVALID;
+    default:
+        return ND_UNSUCCESSFUL;
+    }
+#else
+    UNREFERENCED_PARAMETER(requestContext);
+    UNREFERENCED_PARAMETER(sge);
+    UNREFERENCED_PARAMETER(nSge);
+    return E_NOTIMPL;
+#endif
+}
+
+
+void Srq::FreeSrq(ib_api_status_t ibStatus)
+{
+    m_Adapter.GetProvider().FreeHandle(m_hSrq, IOCTL_ND_SRQ_FREE);
+    mlx4_post_destroy_srq(m_uSrq, ibStatus);
+    m_hSrq = 0;
+}
+
+} // namespace NDv2
Index: hw/mlx4/user/nd/overlapped.h
===================================================================
--- hw/mlx4/user/nd/overlapped.h	(revision 0)
+++ hw/mlx4/user/nd/overlapped.h	(revision 0)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+namespace NDv2
+{
+
+template<
+    typename ThisT,
+    typename InterfaceT
+    >
+class __declspec(novtable) Overlapped
+    : public Unknown<ThisT, InterfaceT>
+{
+    friend typename ThisT;
+    typedef Unknown<ThisT, InterfaceT> _Base;
+
+protected:
+    HANDLE m_hFile;
+
+public:
+    Overlapped()
+        : m_hFile(INVALID_HANDLE_VALUE)
+    {
+    }
+
+    ~Overlapped()
+    {
+        if( m_hFile != INVALID_HANDLE_VALUE )
+        {
+            CloseHandle(m_hFile);
+        }
+    }
+
+    HRESULT Initialize(HANDLE hFile)
+    {
+        BOOL ret = DuplicateHandle(
+            GetCurrentProcess(),
+            hFile,
+            GetCurrentProcess(),
+            &m_hFile,
+            0,
+            FALSE,
+            DUPLICATE_SAME_ACCESS
+            );
+        if( ret == FALSE )
+        {
+            return HRESULT_FROM_WIN32(GetLastError());
+        }
+        return S_OK;
+    }
+
+    void* GetInterface(REFIID riid)
+    {
+        ThisT* pThis = static_cast<ThisT*>( this );
+        if( riid == IID_IND2Overlapped )
+        {
+            return static_cast<IND2Overlapped*>( pThis );
+        }
+
+        return _Base::GetInterface(riid);
+    }
+
+public:
+    STDMETHODIMP CancelOverlappedRequests()
+    {
+        ND_HANDLE in;
+        in.Version = ND_IOCTL_VERSION;
+        in.Reserved = 0;
+        in.Handle = static_cast<ThisT*>(this)->GetHandle();
+
+        ULONG cbOut = 0;
+        return ::Ioctl(m_hFile, ThisT::GetCancelIoctlCode(), &in, sizeof(in), NULL, &cbOut);
+    }
+
+    STDMETHODIMP GetOverlappedResult(
+        __in OVERLAPPED* pOverlapped,
+        BOOL wait
+        )
+    {
+        ULONG cbOut;
+        ::GetOverlappedResult(m_hFile, pOverlapped, &cbOut, wait);
+        return static_cast<HRESULT>(pOverlapped->Internal);
+    }
+};
+
+} // namespace NDv2
Index: hw/mlx4/user/nd/factory.cpp
===================================================================
--- hw/mlx4/user/nd/factory.cpp	(revision 0)
+++ hw/mlx4/user/nd/factory.cpp	(revision 0)
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+
+ClassFactory::ClassFactory(void)
+    : _Base()
+{
+    //
+    // We need DllCanUnloadNow to report whether there are any objects left.  We normally
+    // only count top level provider objects, as all children hold a reference on their parent.
+    // For NDv1, however, the provider object is created via a class factory object.
+    // For simplicity, reuse the provider counter for the class factory.
+    //
+    InterlockedIncrement(&g_nRef[NdProvider]);
+}
+
+
+ClassFactory::~ClassFactory(void)
+{
+    InterlockedDecrement(&g_nRef[NdProvider]);
+}
+
+
+void* ClassFactory::GetInterface(
+    REFIID riid
+    )
+{
+    if( IsEqualIID( riid, IID_IClassFactory ) )
+    {
+        return static_cast<IClassFactory*>(this);
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+HRESULT ClassFactory::CreateInstance(
+    IUnknown* pUnkOuter,
+    REFIID riid,
+    void** ppObject )
+{
+    if( pUnkOuter != NULL )
+        return CLASS_E_NOAGGREGATION;
+
+    if( IsEqualIID( riid, IID_INDProvider ) )
+    {
+        return NDv1::Provider::Create(ppObject);
+    }
+
+    return NDv2::Provider::Create(riid, ppObject);
+}
+
+
+HRESULT ClassFactory::LockServer( BOOL )
+{
+    return S_OK;
+}
Index: hw/mlx4/user/nd/cq.h
===================================================================
--- hw/mlx4/user/nd/cq.h	(revision 0)
+++ hw/mlx4/user/nd/cq.h	(revision 0)
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+namespace NDv2
+{
+
+class Cq
+    : public Overlapped<Cq, IND2CompletionQueue>
+{
+    typedef Overlapped<Cq, IND2CompletionQueue> _Base;
+
+public:
+    static const GUID _Guid;
+
+private:
+    Adapter& m_Adapter;
+
+    UINT64 m_hCq;
+    ib_cq_handle_t m_uCq;
+
+private:
+    operator =(Cq&){}
+
+public:
+    Cq(Adapter& adapter);
+    ~Cq(void);
+
+    HRESULT Initialize(
+        HANDLE hFile,
+        ULONG queueDepth,
+        USHORT group,
+        KAFFINITY affinity
+        );
+
+    void* GetInterface(REFIID riid);
+
+    UINT64 GetHandle() const { return m_hCq; }
+    ib_cq_handle_t GetUvpCq() const { return m_uCq; }
+
+    static ULONG GetCancelIoctlCode() { return IOCTL_ND_CQ_CANCEL_IO; }
+
+public:
+    // *** IND2CompletionQueue methods ***
+    STDMETHODIMP GetNotifyAffinity(
+        __out USHORT* pGroup,
+        __out KAFFINITY* pAffinity
+        );
+
+    STDMETHODIMP Resize(
+        ULONG queueDepth
+        );
+
+    STDMETHODIMP Notify(
+        ULONG type,
+        __inout OVERLAPPED* pOverlapped
+        );
+
+    STDMETHODIMP_(ULONG) GetResults(
+        THIS_
+        __out_ecount_part(nResults,return) ND2_RESULT results[],
+        ULONG nResults
+        );
+
+private:
+    void FreeCq(ib_api_status_t ibStatus);
+
+    static __forceinline ND2_REQUEST_TYPE DecodeCompletionType(ib_wc_type_t type)
+    {
+        switch( type )
+        {
+        case IB_WC_SEND:
+            return Nd2RequestTypeSend;
+        case IB_WC_RDMA_WRITE:
+            return Nd2RequestTypeWrite;
+        case IB_WC_RDMA_READ:
+            return Nd2RequestTypeRead;
+        //case IB_WC_COMPARE_SWAP:
+        //case IB_WC_FETCH_ADD:
+        case IB_WC_MW_BIND:
+            return Nd2RequestTypeBind;
+        case IB_WC_RECV:
+            return Nd2RequestTypeReceive;
+        //case IB_WC_RECV_RDMA_WRITE:
+        //case IB_WC_LSO:
+        case IB_WC_LOCAL_INV:
+            return Nd2RequestTypeInvalidate;
+        //case IB_WC_FAST_REG_MR:
+        default:
+            __assume(0);
+        }
+    }
+
+    static __forceinline HRESULT DecodeCompletionStatus(ib_wc_status_t status)
+    {
+        switch( status )
+        {
+        case IB_WCS_SUCCESS:
+            return STATUS_SUCCESS;
+        case IB_WCS_LOCAL_LEN_ERR:
+            return STATUS_DATA_OVERRUN;
+        case IB_WCS_LOCAL_OP_ERR:
+            return STATUS_INTERNAL_ERROR;
+        case IB_WCS_LOCAL_PROTECTION_ERR:
+            return STATUS_ACCESS_VIOLATION;
+        case IB_WCS_WR_FLUSHED_ERR:
+            return STATUS_CANCELLED;
+        case IB_WCS_MEM_WINDOW_BIND_ERR:
+            return STATUS_ACCESS_VIOLATION;
+        case IB_WCS_REM_ACCESS_ERR:
+            return STATUS_ACCESS_VIOLATION;
+        case IB_WCS_REM_OP_ERR:
+            return STATUS_DATA_ERROR;
+        case IB_WCS_RNR_RETRY_ERR:
+            return STATUS_IO_TIMEOUT;
+        case IB_WCS_TIMEOUT_RETRY_ERR:
+            return STATUS_IO_TIMEOUT;
+        case IB_WCS_REM_INVALID_REQ_ERR:
+            return STATUS_DATA_ERROR;
+        case IB_WCS_BAD_RESP_ERR:
+            return STATUS_DATA_ERROR;
+        case IB_WCS_LOCAL_ACCESS_ERR:
+            return STATUS_ACCESS_VIOLATION;
+        case IB_WCS_GENERAL_ERR:
+            return STATUS_INTERNAL_ERROR;
+        case IB_WCS_REM_ABORT_ERR:
+            return STATUS_REQUEST_ABORTED;
+        default:
+            return E_UNEXPECTED;
+        }
+    }
+};
+
+} // namespace NDv2
+
+namespace NDv1
+{
+class Cq
+    : public Unknown<Cq, INDCompletionQueue>
+{
+    typedef Unknown<Cq, INDCompletionQueue> _Base;
+
+    IND2CompletionQueue& m_Cq;
+
+private:
+    operator =(Cq&){}
+
+public:
+    Cq(IND2CompletionQueue& cq);
+    ~Cq(void)
+    {
+        m_Cq.Release();
+    }
+
+    void* GetInterface(REFIID riid);
+
+    IND2CompletionQueue* GetCq() const { return &m_Cq; }
+
+public:
+    static HRESULT Create(IND2CompletionQueue& cq, INDCompletionQueue** ppCq);
+
+public:
+    // *** INDOverlapped methods ***
+    HRESULT STDMETHODCALLTYPE CancelOverlappedRequests(void)
+    {
+        return m_Cq.CancelOverlappedRequests();
+    }
+
+    HRESULT STDMETHODCALLTYPE GetOverlappedResult(
+        __inout_opt OVERLAPPED *pOverlapped,
+        __out SIZE_T *pNumberOfBytesTransferred,
+        __in BOOL bWait
+        )
+    {
+        *pNumberOfBytesTransferred = 0;
+        return m_Cq.GetOverlappedResult(pOverlapped, bWait);
+    }
+
+    // *** INDCompletionQueue methods ***
+    HRESULT STDMETHODCALLTYPE Resize(
+        __in SIZE_T nEntries
+        )
+    {
+        if( nEntries > ULONG_MAX )
+        {
+            return STATUS_INVALID_PARAMETER;
+        }
+
+        return m_Cq.Resize(static_cast<ULONG>(nEntries));
+    }
+
+    HRESULT STDMETHODCALLTYPE Notify(
+        __in DWORD Type,
+        __inout_opt OVERLAPPED* pOverlapped
+        )
+    {
+        return m_Cq.Notify(Type, pOverlapped);
+    }
+
+    SIZE_T STDMETHODCALLTYPE GetResults(
+        __out_ecount(nResults) ND_RESULT* pResults[],
+        __in SIZE_T nResults
+        );
+};
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/srq.h
===================================================================
--- hw/mlx4/user/nd/srq.h	(revision 0)
+++ hw/mlx4/user/nd/srq.h	(revision 0)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+namespace NDv2
+{
+
+class Srq
+    : public Overlapped<Srq, IND2SharedReceiveQueue>
+{
+    typedef Overlapped<Srq, IND2SharedReceiveQueue> _Base;
+
+    Adapter& m_Adapter;
+
+    UINT64 m_hSrq;
+    ib_srq_handle_t m_uSrq;
+
+public:
+    static const GUID _Guid;
+
+private:
+    operator =(Srq&){}
+
+public:
+    Srq(Adapter& adapter);
+    ~Srq();
+
+    HRESULT Initialize(
+        HANDLE hFile,
+        ULONG queueDepth,
+        ULONG maxRequestSge,
+        ULONG notifyThreshold,
+        USHORT group,
+        KAFFINITY affinity
+        );
+
+    void* GetInterface(REFIID riid);
+
+    UINT64 GetHandle() const { return m_hSrq; }
+    ib_srq_handle_t GetUvpSrq() const { return m_uSrq; }
+
+    static ULONG GetCancelIoctlCode() { return IOCTL_ND_SRQ_CANCEL_IO; }
+
+public:
+    // *** IND2SharedReceiveQueue methods ***
+    STDMETHODIMP GetNotifyAffinity(
+        __out USHORT* pGroup,
+        __out KAFFINITY* pAffinity
+        );
+
+    STDMETHODIMP Modify(
+        ULONG queueDepth,
+        ULONG notifyThreshold
+        );
+
+    STDMETHODIMP Notify(
+        __inout OVERLAPPED* pOverlapped
+        );
+
+    STDMETHODIMP Receive(
+        __in_opt VOID* requestContext,
+        __in_ecount_opt(nSge) const ND2_SGE sge[],
+        ULONG nSge
+        );
+
+private:
+    void FreeSrq(ib_api_status_t ibStatus);
+};
+
+} // namespace NDv2
Index: hw/mlx4/user/nd/precomp.h
===================================================================
--- hw/mlx4/user/nd/precomp.h	(revision 0)
+++ hw/mlx4/user/nd/precomp.h	(revision 0)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#include <ntstatus.h>
+#define WIN32_NO_STATUS
+#include <tchar.h>
+#include <limits.h>
+#include <unknwn.h>
+#include <assert.h>
+#include <winioctl.h>
+#include <winternl.h>
+#include <ws2tcpip.h>
+#include <ws2spi.h>
+#include <InitGuid.h>
+#include <ndspi.h>
+#include <ndstatus.h>
+
+#include "ndfltr.h"
+
+#include <iba\ib_types.h>
+#include <iba\ib_ci.h>
+#include "mx_abi.h"
+#include "verbs.h"
+
+#include "unknown.h"
+#include "overlapped.h"
+#include "main.h"
+#include "factory.h"
+#include "provider.h"
+#include "adapter.h"
+#include "cq.h"
+#include "mr.h"
+#include "mw.h"
+#include "srq.h"
+#include "qp.h"
+#include "connector.h"
+#include "listener.h"
Index: hw/mlx4/user/nd/factory.h
===================================================================
--- hw/mlx4/user/nd/factory.h	(revision 0)
+++ hw/mlx4/user/nd/factory.h	(revision 0)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+
+class ClassFactory : public Unknown<ClassFactory, IClassFactory>
+{
+    typedef Unknown<ClassFactory, IClassFactory> _Base;
+
+public:
+    ClassFactory(void);
+    ~ClassFactory(void);
+
+    // IClassFactory Methods.
+    HRESULT STDMETHODCALLTYPE CreateInstance( IUnknown* pUnkOuter, REFIID riid, void** ppObject );
+    HRESULT STDMETHODCALLTYPE LockServer( BOOL fLock );
+
+public:
+    void* GetInterface(REFIID riid);
+};
Index: hw/mlx4/user/nd/mr.cpp
===================================================================
--- hw/mlx4/user/nd/mr.cpp	(revision 0)
+++ hw/mlx4/user/nd/mr.cpp	(revision 0)
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+namespace NDv2
+{
+// {CD4D60B4-CEBC-49F5-A78E-C234659EC7EF}
+const GUID Mr::_Guid = 
+{ 0xcd4d60b4, 0xcebc, 0x49f5, { 0xa7, 0x8e, 0xc2, 0x34, 0x65, 0x9e, 0xc7, 0xef } };
+
+Mr::Mr(Adapter& adapter)
+    : m_Adapter(adapter),
+    m_hMr(0),
+    m_pBuffer(NULL),
+    m_cbBuffer(0),
+    m_nBoundWindows(0)
+{
+    adapter.AddRef();
+#if DBG
+    InterlockedIncrement(&g_nRef[NdMr]);
+#endif
+}
+
+
+Mr::~Mr()
+{
+    if( m_hMr != 0 )
+    {
+        m_Adapter.GetProvider().FreeHandle(m_hMr, IOCTL_ND_MR_FREE);
+    }
+
+    m_Adapter.Release();
+#if DBG
+    InterlockedDecrement(&g_nRef[NdMr]);
+#endif
+}
+
+
+HRESULT Mr::Initialize(HANDLE hFile)
+{
+    HRESULT hr = _Base::Initialize(hFile);
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    union _createMr
+    {
+        ND_HANDLE   in;
+        UINT64      out;
+    } createMr;
+
+    createMr.in.Version = ND_IOCTL_VERSION;
+    createMr.in.Reserved = 0;
+    createMr.in.Handle = m_Adapter.GetPdHandle();
+
+    //
+    // TODO: At some point, a MPT entry should be allocated here, which would give us the keys.
+    //
+    ULONG cbOut = sizeof(createMr);
+    hr = m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_MR_CREATE,
+        &createMr,
+        sizeof(createMr),
+        &createMr,
+        &cbOut);
+    if( SUCCEEDED(hr) )
+    {
+        m_hMr = createMr.out;
+    }
+    return hr;
+}
+
+
+void* Mr::GetInterface(REFIID riid)
+{
+    if( riid == IID_IND2MemoryRegion )
+    {
+        return static_cast<IND2MemoryRegion*>(this);
+    }
+
+    if( riid == _Guid )
+    {
+        return this;
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+HRESULT Mr::BindMr(
+    __in Mr* pMr,
+    __in_bcount(cbBuffer) const VOID* pBuffer,
+    SIZE_T cbBuffer,
+    ULONG flags
+    )
+{
+    if( pBuffer < m_pBuffer )
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    SIZE_T offset = reinterpret_cast<SIZE_T>(pBuffer) - reinterpret_cast<SIZE_T>(m_pBuffer);
+    if( offset + cbBuffer > m_cbBuffer )
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    ULONG mrFlags = ND_MR_FLAG_DO_NOT_SECURE_VM;
+    if( flags & ND_OP_FLAG_ALLOW_READ )
+    {
+        mrFlags |= ND_MR_FLAG_ALLOW_REMOTE_READ;
+    }
+    if( flags & ND_OP_FLAG_ALLOW_WRITE )
+    {
+        mrFlags |= ND_MR_FLAG_ALLOW_REMOTE_WRITE;
+    }
+
+    OVERLAPPED ov = {0};
+    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if( ov.hEvent == NULL )
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+    ov.hEvent = reinterpret_cast<HANDLE>(
+        reinterpret_cast<SIZE_T>(ov.hEvent) | 1
+        );
+
+    HRESULT hr = pMr->Register(pBuffer, cbBuffer, mrFlags, &ov);
+    if( hr == STATUS_PENDING )
+    {
+        WaitForSingleObject(ov.hEvent, INFINITE);
+    }
+    CloseHandle(ov.hEvent);
+    hr = static_cast<HRESULT>(ov.Internal);
+    if( SUCCEEDED(hr) )
+    {
+        InterlockedIncrement(&m_nBoundWindows);
+    }
+    return hr;
+}
+
+
+HRESULT Mr::InvalidateMr(Mr* pMr)
+{
+    OVERLAPPED ov = {0};
+    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if( ov.hEvent == NULL )
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+    ov.hEvent = reinterpret_cast<HANDLE>(
+        reinterpret_cast<SIZE_T>(ov.hEvent) | 1
+        );
+
+    HRESULT hr = pMr->Deregister(&ov);
+    if( hr == STATUS_PENDING )
+    {
+        WaitForSingleObject(ov.hEvent, INFINITE);
+    }
+    CloseHandle(ov.hEvent);
+    hr = static_cast<HRESULT>(ov.Internal);
+    if( SUCCEEDED(hr) )
+    {
+        InterlockedDecrement(&m_nBoundWindows);
+    }
+    return hr;
+}
+
+
+
+STDMETHODIMP Mr::Register(
+    __in_bcount(cbBuffer) const VOID* pBuffer,
+    SIZE_T cbBuffer,
+    ULONG flags,
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    ND_MR_REGISTER in;
+    in.Header.Version = ND_IOCTL_VERSION;
+    in.Header.Flags = flags;
+    in.Header.CbLength = cbBuffer;
+    in.Header.TargetAddress = reinterpret_cast<ULONG_PTR>(pBuffer);
+    in.Header.MrHandle = m_hMr;
+    in.Address = in.Header.TargetAddress;
+
+    HRESULT hr = ::IoctlAsync(
+        m_hFile,
+        IOCTL_ND_MR_REGISTER,
+        &in,
+        sizeof(in),
+        &m_Keys,
+        sizeof(m_Keys),
+        pOverlapped
+        );
+    if( SUCCEEDED(hr) )
+    {
+        m_pBuffer = pBuffer;
+        m_cbBuffer = cbBuffer;
+    }
+    return hr;
+}
+
+
+STDMETHODIMP Mr::Deregister(
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    if( m_nBoundWindows != 0 )
+    {
+        return STATUS_DEVICE_BUSY;
+    }
+
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = m_hMr;
+
+    HRESULT hr = ::IoctlAsync(
+        m_hFile,
+        IOCTL_ND_MR_DEREGISTER,
+        &in,
+        sizeof(in),
+        NULL,
+        0,
+        pOverlapped
+        );
+    if( SUCCEEDED(hr) )
+    {
+        m_pBuffer = NULL;
+        m_cbBuffer = 0;
+    }
+    return hr;
+}
+
+} // namespace NDv2
+
+namespace NDv1
+{
+
+Mr::Mr(INDAdapter& adapter, IND2MemoryRegion& mr)
+    : m_Adapter(adapter),
+    m_Mr(mr)
+{
+    adapter.AddRef();
+    mr.AddRef();
+}
+
+
+Mr::~Mr(void)
+{
+    m_Adapter.Release();
+    m_Mr.Release();
+}
+
+
+HRESULT Mr::Register(const void* pBuf, SIZE_T cbBuf, __in OVERLAPPED* pOverlapped)
+{
+    return m_Mr.Register(
+        pBuf,
+        cbBuf,
+        ND_MR_FLAG_ALLOW_LOCAL_WRITE,
+        pOverlapped
+        );
+}
+
+
+HRESULT Mr::Deregister(__in OVERLAPPED* pOverlapped)
+{
+    return m_Mr.Deregister(pOverlapped);
+}
+
+
+void Mr::CancelOverlappedRequests()
+{
+    m_Mr.CancelOverlappedRequests();
+}
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/qp.cpp
===================================================================
--- hw/mlx4/user/nd/qp.cpp	(revision 0)
+++ hw/mlx4/user/nd/qp.cpp	(revision 0)
@@ -0,0 +1,866 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+namespace NDv2
+{
+
+MwOpContext::~MwOpContext()
+{
+    m_pMw->Release();
+}
+
+
+HRESULT MwOpContext::Complete()
+{
+    if( m_RequestType == Nd2RequestTypeInvalidate )
+    {
+        return m_pMw->Invalidate();
+    }
+    return STATUS_SUCCESS;
+}
+
+
+// {47D27C8F-9E28-4D44-AECD-C31E13E81D7E}
+const GUID Qp::_Guid = 
+{ 0x47d27c8f, 0x9e28, 0x4d44, { 0xae, 0xcd, 0xc3, 0x1e, 0x13, 0xe8, 0x1d, 0x7e } };
+
+Qp::Qp(Adapter& adapter, Cq& receiveCq, Cq& initiatorCq, Srq* pSrq)
+    : m_Adapter(adapter),
+    m_ReceiveCq(receiveCq),
+    m_InitiatorCq(initiatorCq),
+    m_pSrq(pSrq),
+    m_hQp(0),
+    m_uQp(NULL)
+{
+    adapter.AddRef();
+    initiatorCq.AddRef();
+    receiveCq.AddRef();
+    if( pSrq != NULL )
+    {
+        pSrq->AddRef();
+    }
+#if DBG
+    InterlockedIncrement(&g_nRef[NdQp]);
+#endif
+}
+
+
+Qp::~Qp()
+{
+    if( m_hQp != 0 )
+    {
+        m_Adapter.GetProvider().FreeHandle(m_hQp, IOCTL_ND_QP_FREE);
+        mlx4_post_destroy_qp(m_uQp, IB_SUCCESS);
+    }
+
+    if( m_pSrq != NULL )
+    {
+        m_pSrq->Release();
+    }
+
+    m_ReceiveCq.Release();
+    m_InitiatorCq.Release();
+    m_Adapter.Release();
+#if DBG
+    InterlockedDecrement(&g_nRef[NdQp]);
+#endif
+}
+
+
+HRESULT Qp::Initialize(
+    __in_opt VOID* context,
+    ULONG receiveQueueDepth,
+    ULONG initiatorQueueDepth,
+    ULONG maxReceiveRequestSge,
+    ULONG maxInitiatorRequestSge,
+    ULONG inlineDataSize
+    )
+{
+    uvp_qp_create_t attr;
+    attr.context = context;
+    attr.qp_create.qp_type = IB_QPT_RELIABLE_CONN;
+    attr.qp_create.sq_max_inline = inlineDataSize;
+    attr.qp_create.sq_depth = initiatorQueueDepth;
+    attr.qp_create.rq_depth = receiveQueueDepth;
+    attr.qp_create.sq_sge = maxInitiatorRequestSge;
+    attr.qp_create.rq_sge = maxReceiveRequestSge;
+    attr.qp_create.h_sq_cq = m_InitiatorCq.GetUvpCq();
+    attr.qp_create.h_rq_cq = m_ReceiveCq.GetUvpCq();
+    attr.qp_create.sq_signaled = FALSE;
+
+    struct _createQp
+    {
+        union _ioctl
+        {
+            ND_CREATE_QP_HDR hdr;
+            ND_CREATE_QP in;
+            ND_CREATE_QP_WITH_SRQ inSrq;
+            ND_RESOURCE_DESCRIPTOR out;
+        } ioctl;
+        union _dev
+        {
+            ibv_create_qp req;
+            ibv_create_qp_resp resp;
+        } dev;
+    } createQp;
+
+    createQp.ioctl.hdr.Version = ND_IOCTL_VERSION;
+    createQp.ioctl.hdr.CbMaxInlineData = inlineDataSize;
+    createQp.ioctl.hdr.CeMappingCount = RTL_NUMBER_OF_V2(createQp.dev.req.mappings);
+    createQp.ioctl.hdr.CbMappingsOffset = FIELD_OFFSET(struct _createQp, dev.req.mappings);
+    createQp.ioctl.hdr.InitiatorQueueDepth = initiatorQueueDepth;
+    createQp.ioctl.hdr.MaxInitiatorRequestSge = maxInitiatorRequestSge;
+    createQp.ioctl.hdr.ReceiveCqHandle = m_ReceiveCq.GetHandle();
+    createQp.ioctl.hdr.InitiatorCqHandle = m_InitiatorCq.GetHandle();;
+    createQp.ioctl.hdr.PdHandle = m_Adapter.GetPdHandle();
+    if( m_pSrq != NULL )
+    {
+        attr.qp_create.h_srq = m_pSrq->GetUvpSrq();
+        createQp.ioctl.inSrq.SrqHandle = m_pSrq->GetHandle();
+    }
+    else
+    {
+        attr.qp_create.h_srq = NULL;
+        createQp.ioctl.in.ReceiveQueueDepth = receiveQueueDepth;
+        createQp.ioctl.in.MaxReceiveRequestSge = maxReceiveRequestSge;
+    }
+
+    ci_umv_buf_t umvBuf;
+    ib_api_status_t ibStatus = mlx4_wv_pre_create_qp(
+        m_Adapter.GetUvpPd(),
+        &attr,
+        &umvBuf,
+        &m_uQp
+        );
+    if( ibStatus != IB_SUCCESS )
+    {
+        return ConvertIbStatus( ibStatus );
+    }
+
+    if( umvBuf.input_size != sizeof(createQp.dev.req) ||
+        umvBuf.output_size != sizeof(createQp.dev.resp) )
+    {
+        mlx4_post_create_qp(
+            m_Adapter.GetUvpPd(),
+            IB_INSUFFICIENT_RESOURCES,
+            &m_uQp,
+            &umvBuf
+            );
+        return E_UNEXPECTED;
+    }
+
+    RtlCopyMemory(
+        &createQp.dev.req,
+        reinterpret_cast<void*>(umvBuf.p_inout_buf),
+        sizeof(createQp.dev.req)
+        );
+
+    ULONG cbOut = sizeof(createQp.ioctl) + sizeof(createQp.dev.resp);
+    HRESULT hr = m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_QP_CREATE,
+        &createQp,
+        sizeof(createQp.ioctl) + sizeof(createQp.dev.req),
+        &createQp,
+        &cbOut
+        );
+    if( FAILED(hr) )
+    {
+        mlx4_post_create_qp(
+            m_Adapter.GetUvpPd(),
+            IB_INSUFFICIENT_RESOURCES,
+            &m_uQp,
+            &umvBuf
+            );
+        return hr;
+    }
+
+    m_hQp = createQp.ioctl.out.Handle;
+
+    if( cbOut != sizeof(createQp.ioctl) + sizeof(createQp.dev.resp) )
+    {
+        m_Adapter.GetProvider().FreeHandle(m_hQp, IOCTL_ND_QP_FREE);
+        mlx4_post_create_qp(
+            m_Adapter.GetUvpPd(),
+            IB_INSUFFICIENT_RESOURCES,
+            &m_uQp,
+            &umvBuf
+            );
+        m_hQp = 0;
+        return E_UNEXPECTED;
+    }
+
+    RtlCopyMemory(
+        reinterpret_cast<void*>(umvBuf.p_inout_buf),
+        &createQp.dev.resp,
+        sizeof(createQp.dev.resp)
+        );
+    mlx4_post_create_qp(
+        m_Adapter.GetUvpPd(),
+        IB_SUCCESS,
+        &m_uQp,
+        &umvBuf
+        );
+
+    //
+    // QPs are created in the INIT state by the kernel filter, but there isn't a way
+    // to have the kernel call update the QP state automatically, so update it here.
+    //
+    enum ibv_qp_state* pState;
+    mlx4_nd_modify_qp(m_uQp, reinterpret_cast<void**>(&pState), &cbOut );
+    *pState = IBV_QPS_INIT;
+
+    return hr;
+}
+
+
+void* Qp::GetInterface(REFIID riid)
+{
+    if( riid == IID_IND2QueuePair )
+    {
+        return static_cast<IND2QueuePair*>(this);
+    }
+
+    if( riid == _Guid )
+    {
+        return this;
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+HRESULT Qp::PostSend(ib_send_wr_t* pWr)
+{
+    ib_api_status_t ibStatus = mlx4_post_send( m_uQp, pWr, NULL );
+    switch( ibStatus )
+    {
+    case IB_SUCCESS:
+        return S_OK;
+    case IB_INSUFFICIENT_RESOURCES:
+        return ND_NO_MORE_ENTRIES;
+    case IB_INVALID_MAX_SGE:
+        return ND_DATA_OVERRUN;
+    case IB_INVALID_QP_STATE:
+        return ND_CONNECTION_INVALID;
+    default:
+        return ND_UNSUCCESSFUL;
+    }
+}
+
+
+HRESULT Qp::PostNoop(__in MwOpContext* requestContext, ULONG flags)
+{
+    ib_send_wr_t wr;
+    wr.p_next = NULL;
+    wr.wr_id = reinterpret_cast<ULONG_PTR>(requestContext);
+    wr.wr_type = WR_NOP;
+    if( (flags & ND_OP_FLAG_SILENT_SUCCESS) != 0 )
+    {
+        wr.send_opt = 0;
+    }
+    else
+    {
+        wr.send_opt = IB_SEND_OPT_SIGNALED;
+    }
+    if( (flags & ND_OP_FLAG_READ_FENCE) != 0 )
+    {
+        wr.send_opt |= IB_SEND_OPT_FENCE;
+    }
+    wr.num_ds = 0;
+    wr.ds_array = NULL;
+    wr.remote_ops.vaddr = 0;
+    wr.remote_ops.rkey = 0;
+
+    return PostSend(&wr);
+}
+
+
+STDMETHODIMP Qp::Flush()
+{
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = m_hQp;
+
+    void* pOut;
+    ULONG cbOut;
+    mlx4_nd_modify_qp(m_uQp, &pOut, &cbOut );
+
+    return m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_QP_FLUSH,
+        &in,
+        sizeof(in),
+        pOut,
+        &cbOut
+        );
+}
+
+
+STDMETHODIMP Qp::Send(
+    __in_opt VOID* requestContext,
+    __in_ecount_opt(nSge) const ND2_SGE sge[],
+    ULONG nSge,
+    ULONG flags
+    )
+{
+    ib_send_wr_t wr;
+    wr.p_next = NULL;
+    wr.wr_id = reinterpret_cast<ULONG_PTR>(requestContext);
+    wr.wr_type = WR_SEND;
+    if( (flags & ND_OP_FLAG_SILENT_SUCCESS) != 0 )
+    {
+        wr.send_opt = 0;
+    }
+    else
+    {
+        wr.send_opt = IB_SEND_OPT_SIGNALED;
+    }
+    if( (flags & ND_OP_FLAG_READ_FENCE) != 0 )
+    {
+        wr.send_opt |= IB_SEND_OPT_FENCE;
+    }
+    if( (flags & ND_OP_FLAG_SEND_AND_SOLICIT_EVENT) != 0 )
+    {
+        wr.send_opt |= IB_SEND_OPT_SOLICITED;
+    }
+    if( (flags & ND_OP_FLAG_INLINE) != 0 )
+    {
+        wr.send_opt |= IB_SEND_OPT_INLINE;
+    }
+    wr.num_ds = nSge;
+#ifdef _WIN64
+    wr.ds_array = reinterpret_cast<ib_local_ds_t*>(const_cast<ND2_SGE*>(sge));
+#else
+    ib_local_ds_t ds[2];
+    switch( nSge )
+    {
+    case 0:
+        wr.ds_array = NULL;
+        break;
+
+    case 2:
+        ds[1].vaddr = reinterpret_cast<ULONG_PTR>(sge[1].Buffer);
+        ds[1].length = sge[1].BufferLength;
+        ds[1].lkey = sge[1].MemoryRegionToken;
+        __fallthrough;
+
+    case 1:
+        ds[0].vaddr = reinterpret_cast<ULONG_PTR>(sge[0].Buffer);
+        ds[0].length = sge[0].BufferLength;
+        ds[0].lkey = sge[0].MemoryRegionToken;
+        wr.ds_array = ds;
+        break;
+
+    default:
+        return E_NOTIMPL;
+    }
+#endif
+
+    return PostSend(&wr);
+}
+
+
+STDMETHODIMP Qp::Receive(
+    __in_opt VOID* requestContext,
+    __in_ecount_opt(nSge) const ND2_SGE sge[],
+    ULONG nSge
+    )
+{
+    ib_recv_wr_t wr;
+    wr.p_next = NULL;
+    wr.wr_id = reinterpret_cast<ULONG_PTR>(requestContext);
+    wr.num_ds = nSge;
+#ifdef _WIN64
+    wr.ds_array = reinterpret_cast<ib_local_ds_t*>(const_cast<ND2_SGE*>(sge));
+#else
+    ib_local_ds_t ds;
+    switch( nSge )
+    {
+    case 0:
+        wr.ds_array = NULL;
+        break;
+
+    case 1:
+        ds.vaddr = reinterpret_cast<ULONG_PTR>(sge[0].Buffer);
+        ds.length = sge[0].BufferLength;
+        ds.lkey = sge[0].MemoryRegionToken;
+        wr.ds_array = &ds;
+        break;
+
+    default:
+        return E_NOTIMPL;
+    }
+#endif
+
+    ib_api_status_t ibStatus = mlx4_post_recv( m_uQp, &wr, NULL );
+    switch( ibStatus )
+    {
+    case IB_SUCCESS:
+        return S_OK;
+    case IB_INSUFFICIENT_RESOURCES:
+        return ND_NO_MORE_ENTRIES;
+    case IB_INVALID_MAX_SGE:
+        return ND_DATA_OVERRUN;
+    case IB_INVALID_QP_STATE:
+        return ND_CONNECTION_INVALID;
+    default:
+        return ND_UNSUCCESSFUL;
+    }
+}
+
+
+// RemoteToken available thorugh IND2Mw::GetRemoteToken.
+STDMETHODIMP Qp::Bind(
+    __in_opt VOID* requestContext,
+    __in IUnknown* pMemoryRegion,
+    __inout IUnknown* pMemoryWindow,
+    __in_bcount(cbBuffer) const VOID* pBuffer,
+    SIZE_T cbBuffer,
+    ULONG flags
+    )
+{
+    Mr* pMr;
+    HRESULT hr = pMemoryRegion->QueryInterface(Mr::_Guid, reinterpret_cast<void**>(&pMr));
+    if( FAILED(hr) )
+    {
+        return STATUS_INVALID_PARAMETER_2;
+    }
+
+    Mw* pMw;
+    hr = pMemoryWindow->QueryInterface(Mw::_Guid, reinterpret_cast<void**>(&pMw));
+    if( FAILED(hr) )
+    {
+        pMr->Release();
+        return STATUS_INVALID_PARAMETER_3;
+    }
+
+    MwOpContext* pOpContext = new MwOpContext( requestContext, pMw, Nd2RequestTypeBind );
+    if( pOpContext == NULL )
+    {
+        pMw->Release();
+        pMr->Release();
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    hr = pMw->Bind(pMr, pBuffer, cbBuffer, flags);
+    pMr->Release();
+
+    if( SUCCEEDED(hr) )
+    {
+        hr = PostNoop(pOpContext, flags);
+        if( FAILED(hr) )
+        {
+            pMw->Invalidate();
+            delete pOpContext;
+        }
+    }
+    else
+    {
+        delete pOpContext;
+    }
+    return hr;
+}
+
+
+STDMETHODIMP Qp::Invalidate(
+    __in_opt VOID* requestContext,
+    __in IUnknown* pMemoryWindow,
+    ULONG flags
+    )
+{
+    Mw* pMw;
+    HRESULT hr = pMemoryWindow->QueryInterface(Mw::_Guid, reinterpret_cast<void**>(&pMw));
+    if( FAILED(hr) )
+    {
+        return STATUS_INVALID_PARAMETER_2;
+    }
+
+    MwOpContext* pOpContext = new MwOpContext(requestContext, pMw, Nd2RequestTypeInvalidate );
+    if( pOpContext == NULL )
+    {
+        pMw->Release();
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    hr = PostNoop(pOpContext, flags);
+    if( FAILED(hr) )
+    {
+        delete pOpContext;
+    }
+    return hr;
+}
+
+
+STDMETHODIMP Qp::Read(
+    __in_opt VOID* requestContext,
+    __in_ecount_opt(nSge) const ND2_SGE sge[],
+    ULONG nSge,
+    UINT64 remoteAddress,
+    UINT32 remoteToken,
+    ULONG flags
+    )
+{
+    ib_send_wr_t wr;
+    wr.p_next = NULL;
+    wr.wr_id = reinterpret_cast<ULONG_PTR>(requestContext);
+    wr.wr_type = WR_RDMA_READ;
+    if( (flags & ND_OP_FLAG_SILENT_SUCCESS) != 0 )
+    {
+        wr.send_opt = 0;
+    }
+    else
+    {
+        wr.send_opt = IB_SEND_OPT_SIGNALED;
+    }
+    if( (flags & ND_OP_FLAG_READ_FENCE) != 0 )
+    {
+        wr.send_opt |= IB_SEND_OPT_FENCE;
+    }
+    wr.num_ds = nSge;
+#ifdef _WIN64
+    wr.ds_array = reinterpret_cast<ib_local_ds_t*>(const_cast<ND2_SGE*>(sge));
+#else
+    ib_local_ds_t ds;
+    switch( nSge )
+    {
+    case 0:
+        wr.ds_array = NULL;
+        break;
+
+    case 1:
+        ds.vaddr = reinterpret_cast<ULONG_PTR>(sge[0].Buffer);
+        ds.length = sge[0].BufferLength;
+        ds.lkey = sge[0].MemoryRegionToken;
+        wr.ds_array = &ds;
+        break;
+
+    default:
+        return E_NOTIMPL;
+    }
+#endif
+    wr.remote_ops.vaddr = remoteAddress;
+    wr.remote_ops.rkey = remoteToken;
+
+    return PostSend(&wr);
+}
+
+
+STDMETHODIMP Qp::Write(
+    __in_opt VOID* requestContext,
+    __in_ecount_opt(nSge) const ND2_SGE sge[],
+    ULONG nSge,
+    UINT64 remoteAddress,
+    UINT32 remoteToken,
+    ULONG flags
+    )
+{
+    ib_send_wr_t wr;
+    wr.p_next = NULL;
+    wr.wr_id = reinterpret_cast<ULONG_PTR>(requestContext);
+    wr.wr_type = WR_RDMA_WRITE;
+    if( (flags & ND_OP_FLAG_SILENT_SUCCESS) != 0 )
+    {
+        wr.send_opt = 0;
+    }
+    else
+    {
+        wr.send_opt = IB_SEND_OPT_SIGNALED;
+    }
+    if( (flags & ND_OP_FLAG_READ_FENCE) != 0 )
+    {
+        wr.send_opt |= IB_SEND_OPT_FENCE;
+    }
+    if( (flags & ND_OP_FLAG_INLINE) != 0 )
+    {
+        wr.send_opt |= IB_SEND_OPT_INLINE;
+    }
+    wr.num_ds = nSge;
+#ifdef _WIN64
+    wr.ds_array = reinterpret_cast<ib_local_ds_t*>(const_cast<ND2_SGE*>(sge));
+#else
+    ib_local_ds_t ds;
+    switch( nSge )
+    {
+    case 0:
+        wr.ds_array = NULL;
+        break;
+
+    case 1:
+        ds.vaddr = reinterpret_cast<ULONG_PTR>(sge[0].Buffer);
+        ds.length = sge[0].BufferLength;
+        ds.lkey = sge[0].MemoryRegionToken;
+        wr.ds_array = &ds;
+        break;
+
+    default:
+        return E_NOTIMPL;
+    }
+#endif
+    wr.remote_ops.vaddr = remoteAddress;
+    wr.remote_ops.rkey = remoteToken;
+
+    return PostSend(&wr);
+}
+
+} // namespace NDv2
+
+namespace NDv1
+{
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// HPC Pack Beta 2 SPI
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+Endpoint::Endpoint(IND2QueuePair& qp)
+    : m_Qp(qp)
+{
+}
+
+
+Endpoint::~Endpoint(void)
+{
+    m_Qp.Release();
+}
+
+
+HRESULT Endpoint::Create(
+    __in IND2QueuePair& qp,
+    __out_opt SIZE_T* pMaxInlineData,
+    __out INDEndpoint** ppEndpoint
+    )
+{
+    Endpoint* pEp = new Endpoint(qp);
+    if( pEp == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    if( pMaxInlineData != NULL )
+    {
+        *pMaxInlineData = _MaxInline;
+    }
+
+    *ppEndpoint = pEp;
+    return S_OK;
+}
+
+
+void* Endpoint::GetInterface(REFIID riid)
+{
+    if( riid == IID_INDEndpoint )
+    {
+        return static_cast<INDEndpoint*>(this);
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+// *** INDEndpoint methods ***
+HRESULT Endpoint::Flush(void)
+{
+    return m_Qp.Flush();
+}
+
+
+void Endpoint::StartRequestBatch(void)
+{
+    return;
+}
+
+
+void Endpoint::SubmitRequestBatch(void)
+{
+    return;
+}
+
+
+static __forceinline
+void
+TranslateSge(
+    __in SIZE_T nSge,
+    __in_ecount(nSge) const ND_SGE* pSgl,
+    __out_ecount(nSge) ND2_SGE sge[],
+    __out ND_RESULT* pResult
+    )
+{
+    assert(nSge <= Adapter::_MaxSge);
+
+    pResult->BytesTransferred = 0;
+    for( SIZE_T i = 0; i < nSge; i++ )
+    {
+        sge[i].Buffer = pSgl[i].pAddr;
+        sge[i].BufferLength = static_cast<ULONG>(pSgl[i].Length);
+        sge[i].MemoryRegionToken = reinterpret_cast<Mr*>(pSgl[i].hMr)->GetMr()->GetLocalToken();
+        // Send completions don't include the length.  It's going to
+        // be all or nothing, so store it now and we can reset if the
+        // request fails.
+        pResult->BytesTransferred += pSgl[i].Length;
+    }
+}
+
+
+HRESULT Endpoint::Send(
+    __out ND_RESULT* pResult,
+    __in_ecount(nSge) const ND_SGE* pSgl,
+    __in SIZE_T nSge,
+    __in DWORD Flags
+    )
+{
+    ND2_SGE sge[Adapter::_MaxSge];
+    TranslateSge(nSge, pSgl, sge, pResult);
+
+    if( pResult->BytesTransferred <= _MaxInline )
+    {
+        Flags |= ND_OP_FLAG_INLINE;
+    }
+
+    return m_Qp.Send(pResult, sge, static_cast<ULONG>(nSge), Flags);
+}
+
+
+HRESULT Endpoint::SendAndInvalidate(
+    __out ND_RESULT* /*pResult*/,
+    __in_ecount(nSge) const ND_SGE* /*pSgl*/,
+    __in SIZE_T /*nSge*/,
+    __in const ND_MW_DESCRIPTOR* /*pRemoteMwDescriptor*/,
+    __in DWORD /*Flags*/
+    )
+{
+    return E_NOTIMPL;
+}
+
+
+HRESULT Endpoint::Receive(
+    __out ND_RESULT* pResult,
+    __in_ecount(nSge) const ND_SGE* pSgl,
+    __in SIZE_T nSge
+    )
+{
+    ND2_SGE sge[Adapter::_MaxSge];
+    TranslateSge(nSge, pSgl, sge, pResult);
+
+    return m_Qp.Receive(pResult, sge, static_cast<ULONG>(nSge));
+}
+
+
+HRESULT Endpoint::Bind(
+    __out ND_RESULT* pResult,
+    __in ND_MR_HANDLE hMr,
+    __in INDMemoryWindow* pMw,
+    __in_bcount(BufferSize) const void* pBuffer,
+    __in SIZE_T BufferSize,
+    __in DWORD Flags,
+    __out ND_MW_DESCRIPTOR* pMwDescriptor
+    )
+{
+    HRESULT hr = m_Qp.Bind(
+        pResult,
+        reinterpret_cast<Mr*>(hMr)->GetMr(),
+        static_cast<Mw*>(pMw)->GetMw(),
+        pBuffer,
+        BufferSize,
+        Flags
+        );
+    if( SUCCEEDED(hr) )
+    {
+        pMwDescriptor->Base = _byteswap_uint64( (UINT64)(ULONG_PTR)pBuffer );
+        pMwDescriptor->Length = _byteswap_uint64( BufferSize );
+        pMwDescriptor->Token = static_cast<Mw*>(pMw)->GetMw()->GetRemoteToken();
+    }
+    return hr;
+}
+
+
+HRESULT Endpoint::Invalidate(
+    __out ND_RESULT* pResult,
+    __in INDMemoryWindow* pMw,
+    __in DWORD Flags
+    )
+{
+    return m_Qp.Invalidate(pResult, static_cast<Mw*>(pMw)->GetMw(), Flags);
+}
+
+
+HRESULT Endpoint::Read(
+    __out ND_RESULT* pResult,
+    __in_ecount(nSge) const ND_SGE* pSgl,
+    __in SIZE_T nSge,
+    __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor,
+    __in ULONGLONG Offset,
+    __in DWORD Flags
+    )
+{
+    ND2_SGE sge[Adapter::_MaxSge];
+    TranslateSge(nSge, pSgl, sge, pResult);
+
+    return m_Qp.Read(
+        pResult,
+        sge,
+        static_cast<ULONG>(nSge),
+        _byteswap_uint64(pRemoteMwDescriptor->Base) + Offset,
+        pRemoteMwDescriptor->Token,
+        Flags
+        );
+}
+
+
+HRESULT Endpoint::Write(
+    __out ND_RESULT* pResult,
+    __in_ecount(nSge) const ND_SGE* pSgl,
+    __in SIZE_T nSge,
+    __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor,
+    __in ULONGLONG Offset,
+    __in DWORD Flags
+    )
+{
+    ND2_SGE sge[Adapter::_MaxSge];
+    TranslateSge(nSge, pSgl, sge, pResult);
+
+    if( pResult->BytesTransferred <= _MaxInline )
+    {
+        Flags |= ND_OP_FLAG_INLINE;
+    }
+
+    return m_Qp.Write(
+        pResult,
+        sge,
+        static_cast<ULONG>(nSge),
+        _byteswap_uint64(pRemoteMwDescriptor->Base) + Offset,
+        pRemoteMwDescriptor->Token,
+        Flags
+        );
+}
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/adapter.cpp
===================================================================
--- hw/mlx4/user/nd/adapter.cpp	(revision 0)
+++ hw/mlx4/user/nd/adapter.cpp	(revision 0)
@@ -0,0 +1,1029 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+namespace NDv2
+{
+// {22681265-CE87-401F-83B7-EE8DF85C270A}
+const GUID Adapter::_Guid = 
+    { 0x22681265, 0xce87, 0x401f, { 0x83, 0xb7, 0xee, 0x8d, 0xf8, 0x5c, 0x27, 0xa } };
+
+Adapter::Adapter(Provider& provider)
+    : m_hCa(0),
+    m_hPd(0),
+    m_uCa(NULL),
+    m_uPd(NULL),
+    m_Provider(provider)
+{
+    provider.AddRef();
+#if DBG
+    InterlockedIncrement(&g_nRef[NdAdapter]);
+#endif
+}
+
+
+Adapter::~Adapter(void)
+{
+    if( m_hPd )
+    {
+        DeallocPd();
+    }
+
+    if( m_hCa )
+    {
+        CloseCa();
+    }
+
+    m_Provider.Release();
+#if DBG
+    InterlockedDecrement(&g_nRef[NdAdapter]);
+#endif
+}
+
+
+HRESULT Adapter::Initialize(
+    UINT64 adapterId
+    )
+{
+    HRESULT hr = OpenCa(adapterId);
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    hr = AllocPd();
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    return S_OK;
+}
+
+
+void* Adapter::GetInterface(const IID &riid)
+{
+    if( riid == IID_IND2Adapter )
+    {
+        return static_cast<IND2Adapter*>(this);
+    }
+
+    if( riid == _Guid )
+    {
+        return this;
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+HRESULT Adapter::CreateOverlappedFile(
+    UCHAR flags,
+    __deref_out HANDLE* phOverlappedFile
+    )
+{
+    HANDLE hFile = CreateFileW(
+        ND_WIN32_DEVICE_NAME,
+        GENERIC_READ | GENERIC_WRITE,
+        FILE_SHARE_READ | FILE_SHARE_WRITE,
+        NULL,
+        OPEN_EXISTING,
+        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+        NULL
+        );
+    if( hFile == INVALID_HANDLE_VALUE )
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    if( flags != 0 )
+    {
+        BOOL ret = SetFileCompletionNotificationModes(hFile, flags);
+        if( ret == FALSE )
+        {
+            CloseHandle(hFile);
+            return HRESULT_FROM_WIN32(GetLastError());
+        }
+    }
+
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = reinterpret_cast<ULONG_PTR>(hFile);
+
+    HRESULT hr = m_Provider.Ioctl(IOCTL_ND_PROVIDER_BIND_FILE, &in, sizeof(in));
+    if( FAILED(hr) )
+    {
+        CloseHandle(hFile);
+    }
+    else
+    {
+        *phOverlappedFile = hFile;
+    }
+    return hr;
+}
+
+
+HRESULT Adapter::CreateOverlappedFile(
+    __deref_out HANDLE* phOverlappedFile
+    )
+{
+    return CreateOverlappedFile(
+        FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | FILE_SKIP_SET_EVENT_ON_HANDLE,
+        phOverlappedFile
+        );
+}
+
+
+HRESULT Adapter::Query(
+    __inout_bcount_opt(*pcbInfo) ND2_ADAPTER_INFO* pInfo,
+    __inout ULONG* pcbInfo
+    )
+{
+    ND_ADAPTER_QUERY in;
+    in.Version = ND_IOCTL_VERSION;
+    if( pInfo == NULL || *pcbInfo < sizeof(pInfo->InfoVersion) )
+    {
+        in.InfoVersion = ND_VERSION_2;
+    }
+    else
+    {
+        in.InfoVersion = pInfo->InfoVersion;
+    }
+    in.AdapterHandle = m_hCa;
+
+    HRESULT hr = m_Provider.Ioctl(IOCTL_ND_ADAPTER_QUERY, &in, sizeof(in), pInfo, pcbInfo);
+    if( SUCCEEDED(hr) )
+    {
+        TCHAR buf[14];
+        DWORD ret = GetEnvironmentVariable( _T("MLX4ND_INLINE_THRESHOLD"), buf, sizeof(buf) );
+        if( ret > 0 && ret < sizeof(buf) )
+        {
+            pInfo->InlineRequestThreshold = _tstol( buf );
+        }
+    }
+    return hr;
+}
+
+
+HRESULT Adapter::QueryAddressList(
+    __out_bcount_part_opt(*pcbAddressList, *pcbAddressList) SOCKET_ADDRESS_LIST* pAddressList,
+    __inout ULONG* pcbAddressList
+    )
+{
+    NDFLTR_QUERY_ADDRESS_LIST in;
+    in.Header.Version = ND_IOCTL_VERSION;
+    in.Header.Reserved = 0;
+    in.Header.Handle = m_hCa;
+    in.DriverId = GUID_MLX4_DRIVER;
+
+    return m_Provider.Ioctl(
+        IOCTL_ND_ADAPTER_QUERY_ADDRESS_LIST,
+        &in,
+        sizeof(in),
+        pAddressList,
+        pcbAddressList
+        );
+}
+
+
+HRESULT Adapter::CreateCompletionQueue(
+    __in REFIID riid,
+    __in HANDLE hOverlappedFile,
+    ULONG queueDepth,
+    USHORT group,
+    KAFFINITY affinity,
+    __deref_out VOID** ppCompletionQueue
+    )
+{
+    Cq* pCq = new Cq(*this);
+    if( pCq == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    HRESULT hr = pCq->Initialize(hOverlappedFile, queueDepth, group, affinity);
+    if( SUCCEEDED(hr) )
+    {
+        hr = pCq->QueryInterface(riid, ppCompletionQueue);
+    }
+    pCq->Release();
+    return hr;
+}
+
+
+HRESULT Adapter::CreateMemoryRegion(
+    __in REFIID iid,
+    __in HANDLE hOverlappedFile,
+    __deref_out VOID** ppMemoryRegion
+    )
+{
+    Mr* pMr = new Mr(*this);
+    if( pMr == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    HRESULT hr = pMr->Initialize(hOverlappedFile);
+    if( SUCCEEDED(hr) )
+    {
+        hr = pMr->QueryInterface(iid, ppMemoryRegion);
+    }
+    pMr->Release();
+    return hr;
+}
+
+
+HRESULT Adapter::CreateMemoryWindow(
+    __in REFIID iid,
+    __deref_out VOID** ppMemoryWindow
+    )
+{
+    Mr* pMr;
+    HRESULT hr = CreateMemoryRegion(
+        Mr::_Guid,
+        GetProvider().GetFileHandle(),
+        reinterpret_cast<void**>(&pMr)
+        );
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    Mw* pMw = new Mw(*this,*pMr);
+    pMr->Release();
+
+    if( pMw == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    hr = pMw->Initialize();
+    if( SUCCEEDED(hr) )
+    {
+        hr = pMw->QueryInterface(iid, ppMemoryWindow);
+    }
+    pMw->Release();
+    return hr;
+}
+
+
+HRESULT Adapter::CreateSharedReceiveQueue(
+    __in REFIID iid,
+    __in HANDLE hOverlappedFile,
+    ULONG queueDepth,
+    ULONG maxSge,
+    ULONG notifyThreshold,
+    USHORT group,
+    KAFFINITY affinity,
+    __deref_out VOID** ppSharedReceiveQueue
+    )
+{
+    UNREFERENCED_PARAMETER(iid);
+    UNREFERENCED_PARAMETER(hOverlappedFile);
+    UNREFERENCED_PARAMETER(queueDepth);
+    UNREFERENCED_PARAMETER(maxSge);
+    UNREFERENCED_PARAMETER(notifyThreshold);
+    UNREFERENCED_PARAMETER(group);
+    UNREFERENCED_PARAMETER(affinity);
+    UNREFERENCED_PARAMETER(ppSharedReceiveQueue);
+    return E_NOTIMPL;
+}
+
+
+HRESULT Adapter::CreateQueuePair(
+    __in REFIID iid,
+    __in IUnknown* pReceiveCompletionQueue,
+    __in IUnknown* pInitiatorCompletionQueue,
+    __in_opt VOID* context,
+    ULONG receiveQueueDepth,
+    ULONG initiatorQueueDepth,
+    ULONG maxReceiveRequestSge,
+    ULONG maxInitiatorRequestSge,
+    ULONG inlineDataSize,
+    __deref_out VOID** ppQueuePair
+    )
+{
+    Cq* pReceiveCq;
+    HRESULT hr = pReceiveCompletionQueue->QueryInterface(
+        Cq::_Guid,
+        reinterpret_cast<void**>(&pReceiveCq)
+        );
+    if( FAILED(hr) )
+    {
+        return STATUS_INVALID_PARAMETER_2;
+    }
+
+    Cq* pInitiatorCq;
+    hr = pInitiatorCompletionQueue->QueryInterface(
+        Cq::_Guid,
+        reinterpret_cast<void**>(&pInitiatorCq)
+        );
+    if( FAILED(hr) )
+    {
+        pReceiveCq->Release();
+        return STATUS_INVALID_PARAMETER_3;
+    }
+
+    Qp* pQp = new Qp(*this, *pReceiveCq, *pInitiatorCq, NULL);
+    pInitiatorCq->Release();
+    pReceiveCq->Release();
+    if( pQp == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    hr = pQp->Initialize(
+        context,
+        receiveQueueDepth,
+        initiatorQueueDepth,
+        maxReceiveRequestSge,
+        maxInitiatorRequestSge,
+        inlineDataSize
+        );
+    if( SUCCEEDED(hr) )
+    {
+        hr = pQp->QueryInterface(iid, ppQueuePair);
+    }
+    pQp->Release();
+    return hr;
+}
+
+
+HRESULT Adapter::CreateQueuePairWithSrq(
+    __in REFIID iid,
+    __in IUnknown* pReceiveCompletionQueue,
+    __in IUnknown* pInitiatorCompletionQueue,
+    __in IUnknown* pSharedReceiveQueue,
+    __in_opt VOID* context,
+    ULONG initiatorQueueDepth,
+    ULONG maxInitiatorRequestSge,
+    ULONG inlineDataSize,
+    __deref_out VOID** ppQueuePair
+    )
+{
+    Cq* pReceiveCq;
+    HRESULT hr = pReceiveCompletionQueue->QueryInterface(
+        Cq::_Guid,
+        reinterpret_cast<void**>(&pReceiveCq)
+        );
+    if( FAILED(hr) )
+    {
+        return STATUS_INVALID_PARAMETER_2;
+    }
+
+    Cq* pInitiatorCq;
+    hr = pInitiatorCompletionQueue->QueryInterface(
+        Cq::_Guid,
+        reinterpret_cast<void**>(&pInitiatorCq)
+        );
+    if( FAILED(hr) )
+    {
+        pReceiveCq->Release();
+        return STATUS_INVALID_PARAMETER_3;
+    }
+
+    Srq* pSrq;
+    hr = pSharedReceiveQueue->QueryInterface(
+        Srq::_Guid,
+        reinterpret_cast<void**>(&pSrq)
+        );
+    if( FAILED(hr) )
+    {
+        pInitiatorCq->Release();
+        pReceiveCq->Release();
+    }
+
+    Qp* pQp = new Qp(*this, *pReceiveCq, *pInitiatorCq, pSrq);
+    pSrq->Release();
+    pInitiatorCq->Release();
+    pReceiveCq->Release();
+    if( pQp == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    hr = pQp->Initialize(
+        context,
+        0,
+        initiatorQueueDepth,
+        0,
+        maxInitiatorRequestSge,
+        inlineDataSize
+        );
+    if( SUCCEEDED(hr) )
+    {
+        hr = pQp->QueryInterface(iid, ppQueuePair);
+    }
+    pQp->Release();
+    return hr;
+}
+
+
+HRESULT Adapter::CreateConnector(
+    __in REFIID iid,
+    __in HANDLE hOverlappedFile,
+    BOOLEAN Ndv1TimeoutSemantics,
+    __deref_out VOID** ppConnector
+    )
+{
+    Connector* pConn = new Connector(*this);
+    if( pConn == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    HRESULT hr = pConn->Initialize(hOverlappedFile, Ndv1TimeoutSemantics);
+    if( SUCCEEDED(hr) )
+    {
+        hr = pConn->QueryInterface(iid, ppConnector);
+    }
+    pConn->Release();
+    return hr;
+}
+
+
+HRESULT Adapter::CreateConnector(
+    __in REFIID iid,
+    __in HANDLE hOverlappedFile,
+    __deref_out VOID** ppConnector
+    )
+{
+    return CreateConnector(iid, hOverlappedFile, FALSE, ppConnector);
+}
+
+
+HRESULT Adapter::CreateListener(
+    __in REFIID iid,
+    __in HANDLE hOverlappedFile,
+    __deref_out VOID** ppListener
+    )
+{
+    Listener* pListener = new Listener(*this);
+    if( pListener == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    HRESULT hr = pListener->Initialize(hOverlappedFile);
+    if( SUCCEEDED(hr) )
+    {
+        hr = pListener->QueryInterface(iid, ppListener);
+    }
+    pListener->Release();
+    return hr;
+}
+
+
+HRESULT Adapter::OpenCa(__in UINT64 caGuid)
+{
+    struct _open
+    {
+        union _ioctl
+        {
+            ND_OPEN_ADAPTER in;
+            ND_RESOURCE_DESCRIPTOR out;
+        } ioctl;
+
+        union _dev
+        {
+            struct ibv_get_context_req req;
+            struct ibv_get_context_resp resp;
+        } dev;
+    } open;
+
+    open.ioctl.in.Version = ND_IOCTL_VERSION;
+    open.ioctl.in.CeMappingCount = _countof(open.dev.req.mappings);
+    open.ioctl.in.CbMappingsOffset = FIELD_OFFSET(struct _open, dev.req.mappings);
+    open.ioctl.in.AdapterId = caGuid;
+
+    ci_umv_buf_t umvBuf;
+    ib_api_status_t ibStatus = mlx4_pre_open_ca(caGuid, &umvBuf, &m_uCa);
+    if( ibStatus != IB_SUCCESS )
+    {
+        return ConvertIbStatus( ibStatus );
+    }
+
+    if( umvBuf.input_size != sizeof(open.dev.req) ||
+        umvBuf.output_size != sizeof(open.dev.resp) )
+    {
+        mlx4_post_open_ca(caGuid, IB_INSUFFICIENT_RESOURCES, &m_uCa, &umvBuf);
+        return E_UNEXPECTED;
+    }
+
+    RtlCopyMemory(
+        &open.dev.req,
+        reinterpret_cast<const void*>(umvBuf.p_inout_buf),
+        sizeof(open.dev.req)
+        );
+
+    ULONG cbOut = sizeof(open.ioctl) + sizeof(open.dev.resp);
+    HRESULT hr = m_Provider.Ioctl(
+        IOCTL_ND_ADAPTER_OPEN,
+        &open,
+        sizeof(open.ioctl) + sizeof(open.dev.req),
+        &open,
+        &cbOut
+        );
+    if( FAILED(hr) )
+    {
+        mlx4_post_open_ca(caGuid, IB_INSUFFICIENT_RESOURCES, &m_uCa, &umvBuf);
+        return hr;
+    }
+
+    m_hCa = open.ioctl.out.Handle;
+
+    if( cbOut != sizeof(open.ioctl) + sizeof(open.dev.resp) )
+    {
+        ibStatus = IB_INSUFFICIENT_RESOURCES;
+        mlx4_post_open_ca(caGuid, ibStatus, &m_uCa, &umvBuf);
+    }
+    else
+    {
+        RtlCopyMemory(
+            reinterpret_cast<void*>(umvBuf.p_inout_buf),
+            &open.dev.resp,
+            sizeof(open.dev.resp)
+            );
+        ibStatus = mlx4_post_open_ca(caGuid, IB_SUCCESS, &m_uCa, &umvBuf);
+    }
+
+    if( ibStatus != IB_SUCCESS )
+    {
+        m_Provider.FreeHandle(m_hCa, IOCTL_ND_ADAPTER_CLOSE);
+        m_hCa = 0;
+        return ConvertIbStatus( ibStatus );
+    }
+
+    return hr;
+}
+
+
+void Adapter::CloseCa(void)
+{
+    m_Provider.FreeHandle(m_hCa, IOCTL_ND_ADAPTER_CLOSE);
+    mlx4_post_close_ca(m_uCa, IB_SUCCESS);
+    m_hCa = 0;
+}
+
+
+HRESULT Adapter::AllocPd(void)
+{
+    struct _createPd
+    {
+        union _ioctl
+        {
+            ND_HANDLE in;
+            UINT64 Handle;
+        } ioctl;
+        struct ibv_alloc_pd_resp resp;
+    } createPd;
+
+    createPd.ioctl.in.Version = ND_IOCTL_VERSION;
+    createPd.ioctl.in.Reserved = 0;
+    createPd.ioctl.in.Handle = m_hCa;
+
+    ci_umv_buf_t umvBuf;
+    ib_api_status_t ibStatus = mlx4_pre_alloc_pd(m_uCa, &umvBuf, &m_uPd);
+    if( ibStatus != IB_SUCCESS )
+    {
+        return ConvertIbStatus( ibStatus );
+    }
+
+    if( umvBuf.output_size != sizeof(createPd.resp) )
+    {
+        mlx4_post_alloc_pd(m_uCa, IB_INSUFFICIENT_RESOURCES, &m_uPd, &umvBuf);
+        return E_UNEXPECTED;
+    }
+
+    ULONG cbOut = sizeof(createPd);
+    HRESULT hr = m_Provider.Ioctl(
+        IOCTL_ND_PD_CREATE,
+        &createPd,
+        sizeof(createPd.ioctl.in),
+        &createPd,
+        &cbOut
+        );
+    if( FAILED(hr) )
+    {
+        mlx4_post_alloc_pd(m_uCa, IB_INSUFFICIENT_RESOURCES, &m_uPd, &umvBuf);
+        return hr;
+    }
+
+    m_hPd = createPd.ioctl.Handle;
+
+    if( cbOut != sizeof(createPd) )
+    {
+        mlx4_post_alloc_pd(m_uCa, IB_INSUFFICIENT_RESOURCES, &m_uPd, &umvBuf);
+        m_Provider.FreeHandle(m_hPd, IOCTL_ND_PD_FREE);
+        m_hPd = 0;
+        return E_UNEXPECTED;
+    }
+    else
+    {
+        RtlCopyMemory(
+            reinterpret_cast<void*>(umvBuf.p_inout_buf),
+            &createPd.resp,
+            sizeof(createPd.resp)
+            );
+        mlx4_post_alloc_pd(m_uCa, IB_SUCCESS, &m_uPd, &umvBuf);
+    }
+
+    return hr;
+}
+
+
+void Adapter::DeallocPd(void)
+{
+    m_Provider.FreeHandle(m_hPd, IOCTL_ND_PD_FREE);
+
+    mlx4_post_free_pd(m_uPd, IB_SUCCESS);
+    m_hPd = 0;
+}
+
+} // namespace NDv2
+
+namespace NDv1
+{
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// HPC Pack Beta 2 SPI
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+Adapter::Adapter(Provider& provider, NDv2::Adapter& adapter)
+    : m_Provider(provider),
+    m_Adapter(adapter)
+{
+    provider.AddRef();
+    adapter.AddRef();
+
+    InitializeCriticalSection(&m_MrLock);
+}
+
+
+Adapter::~Adapter(void)
+{
+    DeleteCriticalSection(&m_MrLock);
+    m_Adapter.Release();
+    m_Provider.Release();
+}
+
+
+HRESULT Adapter::Initialize(
+    __in_bcount(AddressLength) const struct sockaddr* pAddress,
+    __in SIZE_T AddressLength
+    )
+{
+    //
+    // The address has been resolved and validated to be valid by the caller.
+    //
+    switch( pAddress->sa_family )
+    {
+    case AF_INET:
+        AddressLength = sizeof(m_Addr.Ipv4);
+        break;
+
+    case AF_INET6:
+        AddressLength = sizeof(m_Addr.Ipv6);
+        break;
+
+    default:
+        return STATUS_INVALID_ADDRESS;
+    }
+
+    CopyMemory(&m_Addr, pAddress, AddressLength);
+
+    return m_Adapter.CreateOverlappedFile(0, &m_hAsync);
+}
+
+
+HRESULT Adapter::Create(
+    __in Provider& provider,
+    __in NDv2::Adapter& adapter,
+    __in_bcount(addressLength) const struct sockaddr* pAddress,
+    __in SIZE_T addressLength,
+    __out INDAdapter** ppAdapter
+    )
+{
+    Adapter* pAdapter = new Adapter(provider, adapter);
+    if( pAdapter == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    HRESULT hr = pAdapter->Initialize(pAddress, addressLength);
+    if( FAILED(hr) ) 
+    {
+        pAdapter->Release();
+    }
+    else
+    {
+        *ppAdapter = pAdapter;
+    }
+    return hr;
+}
+
+
+void* Adapter::GetInterface(REFIID riid)
+{
+    if( riid == IID_INDOverlapped )
+    {
+        return static_cast<INDOverlapped*>(this);
+    }
+
+    if( riid == IID_INDAdapter )
+    {
+        return static_cast<INDAdapter*>(this);
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+// *** INDOverlapped methods ***
+HRESULT Adapter::CancelOverlappedRequests(void)
+{
+    EnterCriticalSection(&m_MrLock);
+    for( ListEntry* pEntry = m_MrList.Next(); pEntry != m_MrList.End(); pEntry = pEntry->Next() )
+    {
+        static_cast<Mr*>(pEntry)->CancelOverlappedRequests();
+    }
+    LeaveCriticalSection(&m_MrLock);
+    return S_OK;
+}
+
+
+HRESULT Adapter::GetOverlappedResult(
+    __inout OVERLAPPED *pOverlapped,
+    __out SIZE_T *pNumberOfBytesTransferred,
+    __in BOOL bWait
+    )
+{
+    //
+    // Clear output param so we can treat it as a DWORD pointer below.
+    //
+    *pNumberOfBytesTransferred = 0;
+    ::GetOverlappedResult(
+        m_hAsync,
+        pOverlapped,
+        reinterpret_cast<DWORD*>(pNumberOfBytesTransferred),
+        bWait );
+    return static_cast<HRESULT>(pOverlapped->Internal);
+}
+
+
+// INDAdapter overrides.
+HANDLE Adapter::GetFileHandle(void)
+{
+    return m_hAsync;
+}
+
+
+HRESULT Adapter::Query(
+    __in DWORD VersionRequested,
+    __out_bcount_part_opt(*pBufferSize, *pBufferSize) ND_ADAPTER_INFO* pInfo,
+    __inout_opt SIZE_T* pBufferSize
+    )
+{
+    if( VersionRequested != 1 )
+        return ND_NOT_SUPPORTED;
+
+    if( *pBufferSize < sizeof(ND_ADAPTER_INFO1) )
+    {
+        *pBufferSize = sizeof(ND_ADAPTER_INFO1);
+        return ND_BUFFER_OVERFLOW;
+    }
+
+    ND2_ADAPTER_INFO info;
+    info.InfoVersion = ND_VERSION_2;
+    ULONG cbInfo = sizeof(info);
+    HRESULT hr = m_Adapter.Query(&info, &cbInfo);
+    if( SUCCEEDED(hr) )
+    {
+        pInfo->VendorId = info.VendorId;
+        pInfo->DeviceId = info.DeviceId;
+        pInfo->MaxInboundSge = min(info.MaxReceiveSge, _MaxSge);
+        pInfo->MaxInboundRequests = info.MaxReceiveQueueDepth;
+        pInfo->MaxInboundLength = info.MaxTransferLength;
+        pInfo->MaxOutboundSge = min(info.MaxInitiatorSge, _MaxSge);
+        pInfo->MaxOutboundRequests = info.MaxInitiatorQueueDepth;
+        pInfo->MaxOutboundLength = info.MaxTransferLength;
+        pInfo->MaxInlineData = info.MaxInlineDataSize;
+        pInfo->MaxInboundReadLimit = info.MaxInboundReadLimit;
+        pInfo->MaxOutboundReadLimit = info.MaxOutboundReadLimit;
+        pInfo->MaxCqEntries = info.MaxCompletionQueueDepth;
+        pInfo->MaxRegistrationSize = info.MaxRegistrationSize;
+        pInfo->MaxWindowSize = info.MaxWindowSize;
+        pInfo->LargeRequestThreshold = info.LargeRequestThreshold;
+        pInfo->MaxCallerData = info.MaxCallerData;
+        pInfo->MaxCalleeData = info.MaxCalleeData;
+    }
+
+    return hr;
+}
+
+
+HRESULT Adapter::Control(
+    __in DWORD,
+    __in_bcount_opt(InBufferSize) const void*,
+    __in SIZE_T,
+    __out_bcount_opt(OutBufferSize) void*,
+    __in SIZE_T,
+    __out SIZE_T*,
+    __inout OVERLAPPED*
+    )
+{
+    return E_NOTIMPL;
+}
+
+
+HRESULT Adapter::CreateCompletionQueue(
+    __in SIZE_T nEntries,
+    __deref_out INDCompletionQueue** ppCq
+    )
+{
+    if( nEntries > ULONG_MAX )
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    IND2CompletionQueue* pCq;
+    HRESULT hr = m_Adapter.CreateCompletionQueue(
+        IID_IND2CompletionQueue,
+        m_hAsync,
+        static_cast<ULONG>(nEntries),
+        0,
+        0,
+        reinterpret_cast<void**>(&pCq)
+        );
+    if( SUCCEEDED(hr) )
+    {
+        hr = Cq::Create(*pCq, ppCq);
+        pCq->Release();
+    }
+
+    return hr;
+}
+
+
+HRESULT Adapter::RegisterMemory(
+    __in_bcount(BufferSize) const void* pBuffer,
+    __in SIZE_T BufferSize,
+    __inout OVERLAPPED* pOverlapped,
+    __deref_out ND_MR_HANDLE* phMr
+    )
+{
+    IND2MemoryRegion* pIMr;
+    HRESULT hr = m_Adapter.CreateMemoryRegion(
+        IID_IND2MemoryRegion,
+        m_hAsync,
+        reinterpret_cast<void**>(&pIMr)
+        );
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    Mr* pMr = new Mr(*this, *pIMr);
+    pIMr->Release();
+
+    if( pMr != NULL )
+    {
+        hr = pMr->Register(pBuffer, BufferSize, pOverlapped);
+        if( FAILED(hr) )
+        {
+            delete pMr;
+        }
+        else
+        {
+            m_MrList.InsertTail(pMr);
+            *phMr = reinterpret_cast<ND_MR_HANDLE>(pMr);
+        }
+    }
+    return hr;
+}
+
+
+HRESULT Adapter::DeregisterMemory(
+    __in ND_MR_HANDLE hMr,
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    Mr* pMr = reinterpret_cast<Mr*>(hMr);
+
+    HRESULT hr = pMr->Deregister(pOverlapped);
+    if( SUCCEEDED(hr) )
+    {
+        pMr->RemoveFromList();
+        delete pMr;
+    }
+    return hr;
+}
+
+
+HRESULT Adapter::CreateMemoryWindow(
+    __out ND_RESULT* pInvalidateResult,
+    __deref_out INDMemoryWindow** ppMw
+    )
+{
+    IND2MemoryWindow* pIMw;
+    HRESULT hr = m_Adapter.CreateMemoryWindow(
+        IID_IND2MemoryWindow,
+        reinterpret_cast<void**>(&pIMw)
+        );
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    Mw* pMw = new Mw(*this, *pIMw, pInvalidateResult);
+    pIMw->Release();
+
+    if( pMw == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    *ppMw = pMw;
+    return S_OK;
+}
+
+
+HRESULT Adapter::CreateConnector(
+    __deref_out INDConnector** ppConnector
+    )
+{
+    IND2Connector* pConn;
+    HRESULT hr = m_Adapter.CreateConnector(
+        IID_IND2Connector,
+        m_hAsync,
+        TRUE,
+        reinterpret_cast<void**>(&pConn)
+        );
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    hr = Connector::Create(*this, *pConn, ppConnector);
+    pConn->Release();
+    return hr;
+}
+
+
+HRESULT Adapter::Listen(
+    __in SIZE_T Backlog,
+    __in INT /*Protocol*/,
+    __in USHORT Port,
+    __out_opt USHORT* pAssignedPort,
+    __deref_out INDListen** ppListen
+    )
+{
+    IND2Listener* pListener;
+
+    HRESULT hr = m_Adapter.CreateListener(
+        IID_IND2Listener,
+        m_hAsync,
+        reinterpret_cast<void**>(&pListener)
+        );
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    hr = Listener::Create(*this, *pListener, Backlog, Port, pAssignedPort, ppListen);
+    pListener->Release();
+    return hr;
+}
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/mlx4nd.def
===================================================================
--- hw/mlx4/user/nd/mlx4nd.def	(revision 0)
+++ hw/mlx4/user/nd/mlx4nd.def	(revision 0)
@@ -0,0 +1,7 @@
+LIBRARY		IbNdProv.dll
+
+EXPORTS
+	DllGetClassObject	private
+	WSPStartup			
+	DllCanUnloadNow	private
+    RegisterProviderW   private
Index: hw/mlx4/user/nd/mr.h
===================================================================
--- hw/mlx4/user/nd/mr.h	(revision 0)
+++ hw/mlx4/user/nd/mr.h	(revision 0)
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+namespace NDv2
+{
+
+class Mr
+    : public Overlapped<Mr, IND2MemoryRegion>
+{
+    typedef Overlapped<Mr, IND2MemoryRegion> _Base;
+
+public:
+    static const GUID _Guid;
+
+private:
+    Adapter& m_Adapter;
+
+    UINT64 m_hMr;
+    const void* m_pBuffer;
+    SIZE_T m_cbBuffer;
+
+    NDFLTR_MR_KEYS m_Keys;
+
+    LONG m_nBoundWindows;
+
+private:
+    operator =(Mr&) {};
+
+public:
+    Mr(Adapter& adapter);
+    ~Mr();
+
+    HRESULT Initialize(HANDLE hFile);
+
+    void* GetInterface(REFIID riid);
+
+    UINT64 GetHandle() const { return m_hMr; }
+    static ULONG GetCancelIoctlCode() { return IOCTL_ND_MR_CANCEL_IO; }
+
+    //
+    // The following methods support memory windows.  Once the hardware supports
+    // memory windows properly these should go away.
+    //
+    HRESULT BindMr(
+        __in Mr* pMr,
+        __in_bcount(cbBuffer) const VOID* pBuffer,
+        SIZE_T cbBuffer,
+        ULONG flags
+        );
+    HRESULT InvalidateMr(Mr* pMr);
+
+public:
+    // *** IND2MemoryRegion methods ***
+    STDMETHODIMP Register(
+        __in_bcount(cbBuffer) const VOID* pBuffer,
+        SIZE_T cbBuffer,
+        ULONG flags,
+        __inout OVERLAPPED* pOverlapped
+        );
+
+    STDMETHODIMP Deregister(
+        __inout OVERLAPPED* pOverlapped
+        );
+
+    STDMETHODIMP_(UINT32) GetLocalToken() { return m_Keys.LKey; }
+
+    STDMETHODIMP_(UINT32) GetRemoteToken() { return m_Keys.RKey; }
+};
+
+} // namespace NDv2
+
+namespace NDv1
+{
+
+class Mr : public ListEntry
+{
+    INDAdapter& m_Adapter;
+    IND2MemoryRegion& m_Mr;
+
+private:
+    operator =(Mr&){}
+
+public:
+    Mr(INDAdapter& adapter, IND2MemoryRegion& mr);
+    ~Mr(void);
+
+    HRESULT Register(const void* pBuf, SIZE_T cbBuf, __inout OVERLAPPED* pOverlapped);
+    HRESULT Deregister(__inout OVERLAPPED* pOverlapped);
+    void CancelOverlappedRequests();
+
+    IND2MemoryRegion* GetMr() const { return &m_Mr; }
+};
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/mw.cpp
===================================================================
--- hw/mlx4/user/nd/mw.cpp	(revision 0)
+++ hw/mlx4/user/nd/mw.cpp	(revision 0)
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+namespace NDv2
+{
+// {6A148B1D-A8F8-4935-863D-F9F85D40399C}
+const GUID Mw::_Guid = 
+{ 0x6a148b1d, 0xa8f8, 0x4935, { 0x86, 0x3d, 0xf9, 0xf8, 0x5d, 0x40, 0x39, 0x9c } };
+
+Mw::Mw(Adapter& adapter, Mr& mr)
+    : m_Adapter(adapter),
+    m_hMw(0),
+    m_uMw(NULL),
+    m_Mr(mr),
+    m_pBoundMr(NULL)
+{
+    m_Adapter.AddRef();
+    m_Mr.AddRef();
+#if DBG
+    InterlockedIncrement(&g_nRef[NdMw]);
+#endif
+}
+
+
+Mw::~Mw(void)
+{
+    if( m_pBoundMr != NULL )
+    {
+        Invalidate();
+    }
+    m_Mr.Release();
+
+    if( m_hMw != 0 )
+    {
+        m_Adapter.GetProvider().FreeHandle(m_hMw, IOCTL_ND_MW_FREE);
+
+        //
+        // TODO: Clean up user-space MW context.
+        //
+    }
+
+    m_Adapter.Release();
+#if DBG
+    InterlockedDecrement(&g_nRef[NdMw]);
+#endif
+}
+
+
+HRESULT Mw::Initialize()
+{
+    //
+    // TODO: Once the hardware supports MWs, this code will need to be modified to setup user
+    // mode context for the memory window, similar to how CQs, PDs, QPs, etc work.
+    //
+    union _createMw
+    {
+        ND_HANDLE   in;
+        UINT64      out;
+    } createMw;
+
+    createMw.in.Version = ND_IOCTL_VERSION;
+    createMw.in.Reserved = 0;
+    createMw.in.Handle = m_Adapter.GetPdHandle();
+
+    ULONG cbOut = sizeof(createMw);
+    HRESULT hr = m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_MW_CREATE,
+        &createMw,
+        sizeof(createMw),
+        &createMw,
+        &cbOut
+        );
+    if( SUCCEEDED(hr) )
+    {
+        m_hMw = createMw.out;
+    }
+
+    return hr;
+}
+
+
+void* Mw::GetInterface(REFIID riid)
+{
+    if( riid == IID_IND2MemoryWindow )
+    {
+        return static_cast<IND2MemoryWindow*>(this);
+    }
+
+    if( riid == _Guid )
+    {
+        return this;
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+HRESULT Mw::Bind(Mr* pMr, __in_bcount(cbBuffer) const void* pBuffer, SIZE_T cbBuffer, ULONG Flags)
+{
+    if( m_pBoundMr != NULL )
+    {
+        return STATUS_INVALID_DEVICE_STATE;
+    }
+
+    HRESULT hr = pMr->BindMr(&m_Mr, pBuffer, cbBuffer, Flags);
+    if( SUCCEEDED(hr) )
+    {
+        pMr->AddRef();
+        m_pBoundMr = pMr;
+    }
+    return hr;
+}
+
+
+HRESULT Mw::Invalidate()
+{
+    if( m_pBoundMr == NULL )
+    {
+        return STATUS_INVALID_DEVICE_STATE;
+    }
+
+    HRESULT hr = m_pBoundMr->InvalidateMr(&m_Mr);
+    if( SUCCEEDED(hr) )
+    {
+        m_pBoundMr->Release();
+        m_pBoundMr = NULL;
+    }
+    return hr;
+}
+
+}
+
+namespace NDv1
+{
+
+Mw::Mw(INDAdapter& adapter, IND2MemoryWindow& mw, ND_RESULT* pInvalidateResult)
+    : m_Adapter(adapter),
+    m_Mw(mw),
+    m_pInvalidateResult(pInvalidateResult)
+{
+    m_Adapter.AddRef();
+    m_Mw.AddRef();
+}
+
+
+Mw::~Mw(void)
+{
+    m_Mw.Release();
+    m_Adapter.Release();
+}
+
+
+void* Mw::GetInterface(REFIID riid)
+{
+    if( riid == IID_INDMemoryWindow )
+    {
+        return static_cast<INDMemoryWindow*>(this);
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/main.cpp
===================================================================
--- hw/mlx4/user/nd/main.cpp	(revision 0)
+++ hw/mlx4/user/nd/main.cpp	(revision 0)
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <initguid.h>
+#include "ndspi.h"
+
+#include "precomp.h"
+
+
+HANDLE g_hHeap;
+#if DBG
+LONG g_nRef[ND_RESOURCE_TYPE_COUNT];
+#else
+LONG g_nRef[1];
+#endif
+
+extern "C"
+{
+typedef NTSTATUS (WINAPI *PFN_NtDeviceIoControlFile)(
+    __in   HANDLE FileHandle,
+    __in   HANDLE Event,
+    __in   PIO_APC_ROUTINE ApcRoutine,
+    __in   PVOID ApcContext,
+    __out  PIO_STATUS_BLOCK IoStatusBlock,
+    __in   ULONG IoControlCode,
+    __in   PVOID InputBuffer,
+    __in   ULONG InputBufferLength,
+    __out  PVOID OutputBuffer,
+    __in   ULONG OutputBufferLength
+    );
+}
+
+static PFN_NtDeviceIoControlFile pfnNtDeviceIoControlFile;
+static HANDLE g_hIoctlEvent;
+static INIT_ONCE g_InitOnce;
+static CRITICAL_SECTION g_CritSec;
+
+BOOL CALLBACK InitIoctl(
+    INIT_ONCE*,
+    void*,
+    void**
+    )
+{
+    g_hIoctlEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
+    if( g_hIoctlEvent == NULL )
+    {
+        return FALSE;
+    }
+
+    //
+    // Set the low bit of the event, so that if we issue an IOCTL on a file bound to
+    // an I/O completion port, the completion gets reported via the event and not the
+    // IOCP.
+    //
+    g_hIoctlEvent = reinterpret_cast<HANDLE>(
+        reinterpret_cast<SIZE_T>(g_hIoctlEvent) | 1
+        );
+
+    HMODULE hNtDll = GetModuleHandleW( L"ntdll.dll" );
+    if( hNtDll == NULL )
+    {
+        return FALSE;
+    }
+    pfnNtDeviceIoControlFile = reinterpret_cast<PFN_NtDeviceIoControlFile>(
+        GetProcAddress( hNtDll, "NtDeviceIoControlFile" )
+        );
+    if( pfnNtDeviceIoControlFile == NULL )
+    {
+        return FALSE;
+    }
+    return TRUE;
+}
+
+
+HRESULT Ioctl(
+    __in HANDLE hFile,
+    __in ULONG IoControlCode,
+    __in_bcount(cbInput) void* pInput,
+    __in ULONG cbInput,
+    __out_bcount_part_opt(*pcbOutput,*pcbOutput) void* pOutput,
+    __inout ULONG* pcbOutput
+    )
+{
+    IO_STATUS_BLOCK iosb;
+    EnterCriticalSection( &g_CritSec );
+
+    NTSTATUS status = pfnNtDeviceIoControlFile(
+        hFile,
+        g_hIoctlEvent,
+        NULL,
+        NULL,
+        &iosb,
+        IoControlCode,
+        pInput,
+        cbInput,
+        pOutput,
+        *pcbOutput
+        );
+    if( status == STATUS_PENDING )
+    {
+        WaitForSingleObject( g_hIoctlEvent, INFINITE );
+    }
+
+    LeaveCriticalSection( &g_CritSec );
+
+    *pcbOutput = static_cast<ULONG>(iosb.Information);
+    return status;
+}
+
+
+HRESULT IoctlAsync(
+    __in HANDLE hFile,
+    __in ULONG IoControlCode,
+    __in_bcount(cbInput) void* pInput,
+    __in ULONG cbInput,
+    __out_bcount_part_opt(*pcbOutput,*pcbOutput) void* pOutput,
+    __in ULONG cbOutput,
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    pOverlapped->Internal = STATUS_PENDING;
+    NTSTATUS status = pfnNtDeviceIoControlFile(
+        hFile,
+        pOverlapped->hEvent,
+        NULL,
+        reinterpret_cast<ULONG_PTR>(pOverlapped->hEvent) & 1 ? NULL : pOverlapped,
+        reinterpret_cast<IO_STATUS_BLOCK*>(&pOverlapped->Internal),
+        IoControlCode,
+        pInput,
+        cbInput,
+        pOutput,
+        cbOutput
+        );
+    return status;
+}
+
+
+HRESULT ConvertIbStatus( __in ib_api_status_t status )
+{
+    switch( status )
+    {
+    case IB_SUCCESS:
+        return STATUS_SUCCESS;
+    case IB_INVALID_PARAMETER:
+    case IB_INVALID_SETTING:
+        return STATUS_INVALID_PARAMETER;
+    case IB_INSUFFICIENT_MEMORY:
+    case IB_INSUFFICIENT_RESOURCES:
+        return STATUS_INSUFFICIENT_RESOURCES;
+    default:
+        return STATUS_UNSUCCESSFUL;
+    }
+}
+
+
+void* __cdecl operator new(
+    size_t count
+    )
+{
+    return HeapAlloc( g_hHeap, 0, count );
+}
+
+
+void __cdecl operator delete(
+    void* object
+    )
+{
+    HeapFree( g_hHeap, 0, object );
+}
+
+
+STDAPI DllGetClassObject(
+    REFCLSID,
+    REFIID riid,
+    LPVOID * ppv
+    )
+{
+    if( InitOnceExecuteOnce( &g_InitOnce, InitIoctl, NULL, NULL ) == FALSE )
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    if( IsEqualIID( riid, IID_IClassFactory ) )
+    {
+        IClassFactory* pFactory = static_cast<IClassFactory*>( new ClassFactory() );
+        if( pFactory == NULL )
+            return E_OUTOFMEMORY;
+
+        *ppv = pFactory;
+        return S_OK;
+    }
+
+    return NDv2::Provider::Create( riid, ppv );
+}
+
+
+STDAPI DllCanUnloadNow(void)
+{
+    return g_nRef[NdProvider] != 0;
+}
+
+
+extern "C" {
+int
+WSPAPI
+WSPStartup(
+    IN WORD wVersionRequested,
+    OUT LPWSPDATA lpWSPData,
+    IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
+    IN WSPUPCALLTABLE UpcallTable,
+    OUT LPWSPPROC_TABLE lpProcTable
+    )
+{
+    UNREFERENCED_PARAMETER( wVersionRequested );
+    UNREFERENCED_PARAMETER( lpWSPData );
+    UNREFERENCED_PARAMETER( lpProtocolInfo );
+    UNREFERENCED_PARAMETER( UpcallTable );
+    UNREFERENCED_PARAMETER( lpProcTable );
+    return WSASYSNOTREADY;
+}
+
+
+static BOOL
+_DllMain(
+    __in HINSTANCE,
+    DWORD Reason,
+    __in LPVOID
+    )
+{
+    switch( Reason )
+    {
+    case DLL_PROCESS_ATTACH:
+        g_hHeap = HeapCreate( 0, 0, 0 );
+        if( g_hHeap == NULL )
+        {
+            return FALSE;
+        }
+
+        RtlZeroMemory( g_nRef, sizeof(g_nRef) );
+        g_hIoctlEvent = NULL;
+
+        InitOnceInitialize( &g_InitOnce );
+        InitializeCriticalSection( &g_CritSec );
+        break;
+
+    case DLL_PROCESS_DETACH:
+        if( g_hIoctlEvent != NULL )
+        {
+            CloseHandle( g_hIoctlEvent );
+        }
+        DeleteCriticalSection( &g_CritSec );
+        HeapDestroy( g_hHeap );
+        break;
+    }
+
+    return TRUE;
+}
+
+
+extern BOOL APIENTRY
+_DllMainCRTStartupForGS(
+    __in HINSTANCE hModule,
+    DWORD Reason,
+    __in LPVOID Reserved
+    );
+
+
+BOOL APIENTRY
+DllMain(
+    __in HINSTANCE hModule,
+    DWORD Reason,
+    __in LPVOID Reserved
+    )
+{
+    switch( Reason )
+    {
+    case DLL_PROCESS_ATTACH:
+        if( !_DllMainCRTStartupForGS(
+            hModule, Reason, Reserved ) )
+        {
+            return FALSE;
+        }
+
+        return _DllMain( hModule, Reason, Reserved );
+
+    case DLL_THREAD_ATTACH:
+        break;
+
+    case DLL_THREAD_DETACH:
+        break;
+
+    case DLL_PROCESS_DETACH:
+        _DllMain( hModule, Reason, Reserved );
+
+        return _DllMainCRTStartupForGS(
+            hModule, Reason, Reserved );
+    }
+    return TRUE;
+}
+
+
+/*
+* Function: RegisterProviderW
+*   Description: installs the service provider
+*
+* Note: most of the information setup here comes from "MSDN Home >
+* MSDN Library > Windows Development > Network Devices and
+* Protocols > Design Guide > System Area Networks > Windows Sockets
+* Direct > Windows Sockets Direct Component Operation > Installing
+* Windows Sockets Direct Components".
+* The direct link is http://msdn.microsoft.com/library/default.asp?url=/library/en-us/network/hh/network/wsdp_2xrb.asp
+*/
+void CALLBACK RegisterProviderW(HWND, HINSTANCE, LPWSTR, int)
+{
+#ifndef _WIN64
+    return;
+#else
+
+#ifndef PFL_NETWORKDIRECT_PROVIDER
+#define PFL_NETWORKDIRECT_PROVIDER          0x00000010
+#endif
+
+    int err_no;
+    WSAPROTOCOL_INFOW provider;
+    WSADATA wsd;
+    static GUID providerId = 
+        { 0xc42da8c6, 0xd1a1, 0x4f78, { 0x9f, 0x52, 0x27, 0x6c, 0x74, 0x93, 0x55, 0x96 } };
+
+    if( WSAStartup(MAKEWORD(2, 2), &wsd) != 0 )
+    {
+        return;
+    }
+
+    if( LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2 )
+    {
+        WSACleanup();
+        return;
+    }
+
+    /* Setup the values in PROTOCOL_INFO */
+    provider.dwServiceFlags1 = 
+        XP1_GUARANTEED_DELIVERY | 
+        XP1_GUARANTEED_ORDER | 
+        XP1_MESSAGE_ORIENTED |
+        XP1_CONNECT_DATA;  /*XP1_GRACEFUL_CLOSE;*/
+    provider.dwServiceFlags2 = 0;	/* Reserved */
+    provider.dwServiceFlags3 = 0;	/* Reserved */
+    provider.dwServiceFlags4 = 0;	/* Reserved */
+    provider.dwProviderFlags = PFL_HIDDEN | PFL_NETWORKDIRECT_PROVIDER;
+    provider.ProviderId = providerId;
+    provider.dwCatalogEntryId = 0;
+    provider.ProtocolChain.ChainLen = 1;	/* Base Protocol Service Provider */
+    provider.iVersion = 1;
+    provider.iAddressFamily = AF_INET;
+    provider.iMaxSockAddr = sizeof(SOCKADDR_IN);
+    provider.iMinSockAddr = 16;
+    provider.iSocketType = -1;
+    provider.iProtocol = 0;
+    provider.iProtocolMaxOffset = 0;
+    provider.iNetworkByteOrder = BIGENDIAN;
+    provider.iSecurityScheme = SECURITY_PROTOCOL_NONE;
+    provider.dwMessageSize = 0xFFFFFFFF; /* IB supports 32-bit lengths for data transfers on RC */
+    provider.dwProviderReserved = 0;
+    wcscpy( provider.szProtocol, L"OpenFabrics Network Direct Provider for Mellanox ConnectX" );
+
+    WSCInstallProvider64_32(
+        &providerId, L"%SYSTEMROOT%\\system32\\mlx4nd.dll", &provider, 1, &err_no );
+
+    WSACleanup ();
+#endif
+}
+
+}   // extern "C"
+
Index: hw/mlx4/user/nd/adapter.h
===================================================================
--- hw/mlx4/user/nd/adapter.h	(revision 0)
+++ hw/mlx4/user/nd/adapter.h	(revision 0)
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+
+namespace NDv2
+{
+
+class Adapter
+    : public Unknown<Adapter, IND2Adapter>
+{
+    typedef Unknown<Adapter, IND2Adapter> _Base;
+
+public:
+    static const GUID _Guid;
+
+private:
+    Provider& m_Provider;
+
+    // Kernel handles.
+    UINT64 m_hCa;
+    UINT64 m_hPd;
+
+    // UVP handles.
+    ib_ca_handle_t m_uCa;
+    ib_pd_handle_t m_uPd;
+
+private:
+    operator =(Adapter&){}
+
+public:
+    Adapter(Provider& provider);
+    ~Adapter(void);
+
+    HRESULT Initialize(
+        UINT64 adapterId
+        );
+
+public:
+    STDMETHODIMP CreateOverlappedFile(
+        __deref_out HANDLE* phOverlappedFile
+        );
+
+    STDMETHODIMP Query(
+        __inout_bcount_opt(*pcbInfo) ND2_ADAPTER_INFO* pInfo,
+        __inout ULONG* pcbInfo
+        );
+
+    STDMETHODIMP QueryAddressList(
+        __out_bcount_part_opt(*pcbAddressList, *pcbAddressList) SOCKET_ADDRESS_LIST* pAddressList,
+        __inout ULONG* pcbAddressList
+        );
+
+    STDMETHODIMP CreateCompletionQueue(
+        __in REFIID riid,
+        __in HANDLE hOverlappedFile,
+        ULONG queueDepth,
+        USHORT group,
+        KAFFINITY affinity,
+        __deref_out VOID** ppCompletionQueue
+        );
+
+    STDMETHODIMP CreateMemoryRegion(
+        __in REFIID riid,
+        __in HANDLE hOverlappedFile,
+        __deref_out VOID** ppMemoryRegion
+        );
+
+    STDMETHODIMP CreateMemoryWindow(
+        __in REFIID riid,
+        __deref_out VOID** ppMemoryWindow
+        );
+
+    STDMETHODIMP CreateSharedReceiveQueue(
+        __in REFIID riid,
+        __in HANDLE hOverlappedFile,
+        ULONG queueDepth,
+        ULONG maxSge,
+        ULONG notifyThreshold,
+        USHORT group,
+        KAFFINITY affinity,
+        __deref_out VOID** ppSharedReceiveQueue
+        );
+
+    STDMETHODIMP CreateQueuePair(
+        __in REFIID riid,
+        __in IUnknown* pReceiveCompletionQueue,
+        __in IUnknown* pInitiatorCompletionQueue,
+        __in_opt VOID* context,
+        ULONG receiveQueueDepth,
+        ULONG initiatorQueueDepth,
+        ULONG maxReceiveRequestSge,
+        ULONG maxInitiatorRequestSge,
+        ULONG inlineDataSize,
+        __deref_out VOID** ppQueuePair
+        );
+
+    STDMETHODIMP CreateQueuePairWithSrq(
+        __in REFIID riid,
+        __in IUnknown* pReceiveCompletionQueue,
+        __in IUnknown* pInitiatorCompletionQueue,
+        __in IUnknown* pSharedReceiveQueue,
+        __in_opt VOID* context,
+        ULONG initiatorQueueDepth,
+        ULONG maxInitiatorRequestSge,
+        ULONG inlineDataSize,
+        __deref_out VOID** ppQueuePair
+        );
+
+    STDMETHODIMP CreateConnector(
+        __in REFIID riid,
+        __in HANDLE hOverlappedFile,
+        __deref_out VOID** ppConnector
+        );
+
+    STDMETHODIMP CreateListener(
+        __in REFIID riid,
+        __in HANDLE hOverlappedFile,
+        __deref_out VOID** ppListener
+        );
+
+public:
+    void* Adapter::GetInterface(const IID &riid);
+
+    HRESULT CreateOverlappedFile(
+       UCHAR flags,
+        __deref_out HANDLE* phOverlappedFile
+        );
+
+    HRESULT CreateConnector(
+        __in REFIID riid,
+        __in HANDLE hOverlappedFile,
+        BOOLEAN Ndv1TimeoutSemantics,
+        __deref_out VOID** ppConnector
+        );
+
+    Provider& GetProvider() const { return m_Provider; }
+
+    ib_ca_handle_t GetUvpCa() const { return m_uCa; }
+
+    UINT64 GetHandle() const { return m_hCa; }
+
+    ib_pd_handle_t GetUvpPd() const { return m_uPd; }
+
+    UINT64 GetPdHandle() const { return m_hPd; }
+
+private:
+    HRESULT OpenCa(__in UINT64 caGuid);
+
+    void CloseCa(void);
+
+    HRESULT AllocPd(void);
+
+    void DeallocPd(void);
+
+};
+
+} // namespace NDv2
+
+
+namespace NDv1
+{
+
+class Adapter
+    : public Unknown<Adapter, INDAdapter>
+{
+    typedef Unknown<Adapter, INDAdapter> _Base;
+
+    Provider& m_Provider;
+    NDv2::Adapter& m_Adapter;
+
+    HANDLE m_hAsync;
+
+    SOCKADDR_INET m_Addr;
+
+    CRITICAL_SECTION m_MrLock;
+    ListEntry m_MrList;
+
+public:
+    static const _MaxSge = 4;
+
+private:
+    operator =(Adapter&){}
+
+private:
+    Adapter(Provider& provider, NDv2::Adapter& adapter);
+
+    HRESULT Initialize(
+        __in_bcount(addressLength) const struct sockaddr* pAddress,
+        __in SIZE_T addressLength
+        );
+
+public:
+    static HRESULT Create(
+        __in Provider& provider,
+        __in NDv2::Adapter& adapter,
+        __in_bcount(addressLength) const struct sockaddr* pAddress,
+        __in SIZE_T addressLength,
+        __out INDAdapter** ppAdapter
+        );
+    ~Adapter(void);
+
+    void* GetInterface(REFIID riid);
+
+    IND2Adapter* GetAdapter() const
+    {
+        return static_cast<IND2Adapter*>(&m_Adapter);
+    }
+
+    const SOCKADDR_INET& GetAddress() const { return m_Addr; }
+
+public:
+    // *** INDOverlapped methods ***
+    STDMETHODIMP CancelOverlappedRequests();
+
+    STDMETHODIMP GetOverlappedResult(
+        __inout OVERLAPPED *pOverlapped,
+        __out SIZE_T *pNumberOfBytesTransferred,
+        BOOL bWait
+        );
+
+    // *** INDAdapter methods ***
+    STDMETHODIMP_(HANDLE) GetFileHandle();
+
+    STDMETHODIMP Query(
+        DWORD VersionRequested,
+        __out_bcount_part_opt(*pBufferSize, *pBufferSize) ND_ADAPTER_INFO* pInfo,
+        __inout_opt SIZE_T* pBufferSize
+        );
+
+    STDMETHODIMP Control(
+        DWORD IoControlCode,
+        __in_bcount_opt(InBufferSize) const void* pInBuffer,
+        SIZE_T InBufferSize,
+        __out_bcount_opt(OutBufferSize) void* pOutBuffer,
+        SIZE_T OutBufferSize,
+        __out SIZE_T* pBytesReturned,
+        __inout OVERLAPPED* pOverlapped
+        );
+
+    STDMETHODIMP CreateCompletionQueue(
+        SIZE_T nEntries,
+        __deref_out INDCompletionQueue** ppCq
+        );
+
+    STDMETHODIMP RegisterMemory(
+        __in_bcount(BufferSize) const void* pBuffer,
+        SIZE_T BufferSize,
+        __inout OVERLAPPED* pOverlapped,
+        __deref_out ND_MR_HANDLE* phMr
+        );
+
+    STDMETHODIMP DeregisterMemory(
+        __in ND_MR_HANDLE hMr,
+        __inout OVERLAPPED* pOverlapped
+        );
+
+    STDMETHODIMP CreateMemoryWindow(
+        __out ND_RESULT* pInvalidateResult,
+        __deref_out INDMemoryWindow** ppMw
+        );
+
+    STDMETHODIMP CreateConnector(
+        __deref_out INDConnector** ppConnector
+        );
+
+    STDMETHODIMP Listen(
+        SIZE_T Backlog,
+        INT Protocol,
+        USHORT Port,
+        __out_opt USHORT* pAssignedPort,
+        __deref_out INDListen** ppListen
+        );
+};
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/qp.h
===================================================================
--- hw/mlx4/user/nd/qp.h	(revision 0)
+++ hw/mlx4/user/nd/qp.h	(revision 0)
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+namespace NDv2
+{
+
+class MwOpContext
+{
+    VOID* m_RequestContext;
+    Mw* m_pMw;
+    ND2_REQUEST_TYPE m_RequestType;
+
+private:
+    MwOpContext();
+
+public:
+    MwOpContext( VOID* requestContext, Mw* pMw, ND2_REQUEST_TYPE requestType )
+        : m_RequestContext( requestContext ),
+        m_pMw( pMw ),
+        m_RequestType( requestType )
+    {
+    }
+
+    ~MwOpContext();
+
+    HRESULT Complete();
+    inline ND2_REQUEST_TYPE GetRequestType() const { return m_RequestType; }
+    inline VOID* GetRequestContext() const { return m_RequestContext; }
+};
+
+
+class Qp
+    : public Unknown<Qp, IND2QueuePair>
+{
+    typedef Unknown<Qp, IND2QueuePair> _Base;
+
+public:
+    static const GUID _Guid;
+
+private:
+    Adapter& m_Adapter;
+    Cq& m_ReceiveCq;
+    Cq& m_InitiatorCq;
+    Srq* m_pSrq;
+
+    UINT64 m_hQp;
+    ib_qp_handle_t m_uQp;
+
+private:
+    operator =(Qp&){}
+
+public:
+    Qp(Adapter& adapter, Cq& receiveCq, Cq& initiatorCq, Srq* pSrq);
+    ~Qp();
+
+    HRESULT Initialize(
+        __in_opt VOID* context,
+        ULONG receiveQueueDepth,
+        ULONG initiatorQueueDepth,
+        ULONG maxReceiveRequestSge,
+        ULONG maxInitiatorRequestSge,
+        ULONG inlineDataSize
+        );
+
+    void* GetInterface(REFIID riid);
+
+    ib_qp_handle_t GetUvpQp() const { return m_uQp; }
+
+    UINT64 GetHandle() const { return m_hQp; }
+
+    HRESULT PostSend( ib_send_wr_t* pWr );
+    //
+    // The following method is to workaround lack of MW support in the HW.
+    //
+    HRESULT PostNoop(__in MwOpContext* requestContext, ULONG flags);
+
+public:
+    // *** IND2QueuePair methods ***
+    STDMETHODIMP Flush();
+
+    STDMETHODIMP Send(
+        __in_opt VOID* requestContext,
+        __in_ecount_opt(nSge) const ND2_SGE sge[],
+        ULONG nSge,
+        ULONG flags
+        );
+
+    STDMETHODIMP Receive(
+        __in_opt VOID* requestContext,
+        __in_ecount_opt(nSge) const ND2_SGE sge[],
+        ULONG nSge
+        );
+
+    // RemoteToken available thorugh IND2Mw::GetRemoteToken.
+    STDMETHODIMP Bind(
+        __in_opt VOID* requestContext,
+        __in IUnknown* pMemoryRegion,
+        __inout IUnknown* pMemoryWindow,
+        __in_bcount(cbBuffer) const VOID* pBuffer,
+        SIZE_T cbBuffer,
+        ULONG flags
+        );
+
+    STDMETHODIMP Invalidate(
+        __in_opt VOID* requestContext,
+        __in IUnknown* pMemoryWindow,
+        ULONG flags
+        );
+
+    STDMETHODIMP Read(
+        __in_opt VOID* requestContext,
+        __in_ecount_opt(nSge) const ND2_SGE sge[],
+        ULONG nSge,
+        UINT64 remoteAddress,
+        UINT32 remoteToken,
+        ULONG flags
+        );
+
+    STDMETHODIMP Write(
+        __in_opt VOID* requestContext,
+        __in_ecount_opt(nSge) const ND2_SGE sge[],
+        ULONG nSge,
+        UINT64 remoteAddress,
+        UINT32 remoteToken,
+        ULONG flags
+        );
+
+};
+
+} // namespace NDv2
+
+namespace NDv1
+{
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// HPC Pack Beta 2 SPI
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+class Endpoint
+    : public Unknown<Endpoint, INDEndpoint>
+{
+    typedef Unknown<Endpoint, INDEndpoint> _Base;
+
+    IND2QueuePair& m_Qp;
+    //Adapter& m_Adapter;
+    //Cq& m_InboundCq;
+    //Cq& m_OutboundCq;
+
+    //uint64_t m_hQp;
+    //ib_qp_handle_t m_uQp;
+
+    //net32_t m_Qpn;
+
+    //UINT8 m_Ird;
+    //UINT8 m_Ord;
+    //UINT32 m_MaxInlineSize;
+
+public:
+    static const ULONG _MaxInline = 160;
+
+private:
+    operator =(Endpoint&) {};
+
+public:
+    Endpoint(IND2QueuePair& qp);
+    ~Endpoint(void);
+
+    void* GetInterface(REFIID riid);
+
+    IND2QueuePair* GetQp() const { return &m_Qp; }
+
+public:
+    static HRESULT Create(
+        __in IND2QueuePair& qp,
+        __out_opt SIZE_T* pMaxInlineData,
+        __out INDEndpoint** ppEndpoint
+        );
+
+public:
+    // *** INDEndpoint methods ***
+    HRESULT STDMETHODCALLTYPE Flush(void);
+
+    void STDMETHODCALLTYPE StartRequestBatch(void);
+
+    void STDMETHODCALLTYPE SubmitRequestBatch(void);
+
+    HRESULT STDMETHODCALLTYPE Send(
+        __out ND_RESULT* pResult,
+        __in_ecount(nSge) const ND_SGE* pSgl,
+        __in SIZE_T nSge,
+        __in DWORD Flags
+        );
+
+    HRESULT STDMETHODCALLTYPE SendAndInvalidate(
+        __out ND_RESULT* pResult,
+        __in_ecount(nSge) const ND_SGE* pSgl,
+        __in SIZE_T nSge,
+        __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor,
+        __in DWORD Flags
+        );
+
+    HRESULT STDMETHODCALLTYPE Receive(
+        __out ND_RESULT* pResult,
+        __in_ecount(nSge) const ND_SGE* pSgl,
+        __in SIZE_T nSge
+        );
+
+    HRESULT STDMETHODCALLTYPE Bind(
+        __out ND_RESULT* pResult,
+        __in ND_MR_HANDLE hMr,
+        __in INDMemoryWindow* pMw,
+        __in_bcount(BufferSize) const void* pBuffer,
+        __in SIZE_T BufferSize,
+        __in DWORD Flags,
+        __out ND_MW_DESCRIPTOR* pMwDescriptor
+        );
+
+    HRESULT STDMETHODCALLTYPE Invalidate(
+        __out ND_RESULT* pResult,
+        __in INDMemoryWindow* pMw,
+        __in DWORD Flags
+        );
+
+    HRESULT STDMETHODCALLTYPE Read(
+        __out ND_RESULT* pResult,
+        __in_ecount(nSge) const ND_SGE* pSgl,
+        __in SIZE_T nSge,
+        __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor,
+        __in ULONGLONG Offset,
+        __in DWORD Flags
+        );
+
+    HRESULT STDMETHODCALLTYPE Write(
+        __out ND_RESULT* pResult,
+        __in_ecount(nSge) const ND_SGE* pSgl,
+        __in SIZE_T nSge,
+        __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor,
+        __in ULONGLONG Offset,
+        __in DWORD Flags
+        );
+
+private:
+
+    HRESULT QueryQp(
+        __out ib_qp_attr_t *qp_attr
+        );
+
+    HRESULT ModifyQp(
+        __in ib_qp_state_t NewState
+        );
+
+};
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/listener.cpp
===================================================================
--- hw/mlx4/user/nd/listener.cpp	(revision 0)
+++ hw/mlx4/user/nd/listener.cpp	(revision 0)
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+namespace NDv2
+{
+
+Listener::Listener(Adapter& adapter)
+    : m_Adapter(adapter),
+    m_hListener(0)
+{
+    adapter.AddRef();
+#if DBG
+    InterlockedIncrement(&g_nRef[NdListener]);
+#endif
+}
+
+
+Listener::~Listener()
+{
+    if( m_hListener != 0 )
+    {
+        m_Adapter.GetProvider().FreeHandle(m_hListener, IOCTL_ND_LISTENER_FREE);
+    }
+
+    m_Adapter.Release();
+#if DBG
+    InterlockedDecrement(&g_nRef[NdListener]);
+#endif
+}
+
+
+HRESULT Listener::Initialize(HANDLE hFile)
+{
+    HRESULT hr = _Base::Initialize(hFile);
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    NDFLTR_EP_CREATE in;
+    in.Header.Version = ND_IOCTL_VERSION;
+    in.Header.Reserved = 0;
+    in.Header.Handle = m_Adapter.GetHandle();
+    in.Ndv1TimeoutSemantics = FALSE;
+
+    ULONG cbOut = sizeof(m_hListener);
+    return m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_LISTENER_CREATE,
+        &in,
+        sizeof(in),
+        &m_hListener,
+        &cbOut
+        );
+}
+
+
+void* Listener::GetInterface(REFIID riid)
+{
+    if( riid == IID_IND2Listener )
+    {
+        return static_cast<IND2Listener*>(this);
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+STDMETHODIMP Listener::Bind(
+    __in_bcount(cbAddress) const struct sockaddr* pAddress,
+    ULONG cbAddress
+    )
+{
+    ND_BIND bind;
+    bind.Version = ND_IOCTL_VERSION;
+    bind.Reserved = 0;
+    bind.Handle = m_hListener;
+    if( CopyAddress(pAddress, cbAddress, &bind.Address) == false )
+    {
+        return STATUS_INVALID_ADDRESS;
+    }
+
+    return m_Adapter.GetProvider().Ioctl(IOCTL_ND_LISTENER_BIND, &bind, sizeof(bind));
+}
+
+
+STDMETHODIMP Listener::Listen(
+    ULONG backlog
+    )
+{
+    ND_LISTEN listen;
+    listen.Version = ND_IOCTL_VERSION;
+    listen.Backlog = backlog;
+    listen.ListenerHandle = m_hListener;
+
+    return m_Adapter.GetProvider().Ioctl(IOCTL_ND_LISTENER_LISTEN, &listen, sizeof(listen));
+}
+
+
+STDMETHODIMP Listener::GetLocalAddress(
+    __out_bcount_part_opt(*pcbAddress, *pcbAddress) struct sockaddr* pAddress,
+    __inout ULONG* pcbAddress
+    )
+{
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = m_hListener;
+
+    SOCKADDR_INET out;
+    ULONG cbOut = sizeof(out);
+    HRESULT hr = m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_LISTENER_GET_ADDRESS,
+        &in,
+        sizeof(in),
+        &out,
+        &cbOut
+        );
+    if( SUCCEEDED(hr) )
+    {
+        hr = CopyAddress(out, pAddress, pcbAddress);
+    }
+    return hr;
+}
+
+
+STDMETHODIMP Listener::GetConnectionRequest(
+    __inout IUnknown* pConnector,
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    Connector* pConn;
+    HRESULT hr = pConnector->QueryInterface(
+        Connector::_Guid,
+        reinterpret_cast<void**>(&pConn)
+        );
+    if( FAILED(hr) )
+    {
+        return STATUS_INVALID_PARAMETER_1;
+    }
+
+    ND_GET_CONNECTION_REQUEST in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.ListenerHandle = m_hListener;
+    in.ConnectorHandle = pConn->GetHandle();
+    pConn->Release();
+
+    return ::IoctlAsync(
+        m_hFile,
+        IOCTL_ND_LISTENER_GET_CONNECTION_REQUEST,
+        &in,
+        sizeof(in),
+        NULL,
+        0,
+        pOverlapped
+        );
+}
+
+} // namespace NDv2
+
+
+namespace NDv1
+{
+
+Listener::Listener(IND2Listener& listener)
+    : m_Listener(listener)
+{
+    listener.AddRef();
+}
+
+
+Listener::~Listener(void)
+{
+    m_Listener.Release();
+}
+
+
+HRESULT Listener::Initialize(
+    __in Adapter& adapter,
+    __in SIZE_T Backlog,
+    __in USHORT Port,
+    __out_opt USHORT* pAssignedPort
+    )
+{
+    SOCKADDR_INET address = adapter.GetAddress();
+    address.Ipv4.sin_port = Port;
+    HRESULT hr = m_Listener.Bind(
+        reinterpret_cast<struct sockaddr*>(&address),
+        sizeof(address)
+        );
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    if( pAssignedPort != NULL )
+    {
+        ULONG cbAddress = sizeof(address);
+        hr = m_Listener.GetLocalAddress(
+            reinterpret_cast<struct sockaddr*>(&address),
+            &cbAddress
+            );
+        if( FAILED(hr) )
+        {
+            return hr;
+        }
+
+        *pAssignedPort = address.Ipv4.sin_port;
+    }
+
+    return m_Listener.Listen(static_cast<ULONG>(Backlog));
+}
+
+
+HRESULT Listener::Create(
+    __in Adapter& adapter,
+    __in IND2Listener& listener,
+    __in SIZE_T Backlog,
+    __in USHORT Port,
+    __out_opt USHORT* pAssignedPort,
+    __deref_out INDListen** ppListen
+    )
+{
+    Listener* pListen = new Listener(listener);
+    if( pListen == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    HRESULT hr = pListen->Initialize(
+        adapter,
+        Backlog,
+        Port,
+        pAssignedPort );
+    if( FAILED( hr ) )
+    {
+        delete pListen;
+        return hr;
+    }
+
+    *ppListen = pListen;
+    return S_OK;
+}
+
+
+void* Listener::GetInterface(REFIID riid)
+{
+    if( riid == IID_INDListen )
+    {
+        return static_cast<INDListen*>(this);
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+// *** INDListen methods ***
+HRESULT Listener::GetConnectionRequest(
+    __inout INDConnector* pConnector,
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    return m_Listener.GetConnectionRequest(
+        static_cast<Connector*>(pConnector)->GetConnector(),
+        pOverlapped
+        );
+}
+
+} // namespace
Index: hw/mlx4/user/nd/mlx4nd.rc
===================================================================
--- hw/mlx4/user/nd/mlx4nd.rc	(revision 0)
+++ hw/mlx4/user/nd/mlx4nd.rc	(revision 0)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id$
+ */
+
+
+#include <oib_ver.h>
+
+#define VER_FILETYPE				VFT_DLL
+#define VER_FILESUBTYPE				VFT2_UNKNOWN
+
+#ifdef _DEBUG_
+#define VER_FILEDESCRIPTION_STR		"OpenFabrics NetworkDirect Infiniband Provider (Debug)"
+#define VER_INTERNALNAME_STR		"ibndprov.dll"
+#define VER_ORIGINALFILENAME_STR	"ibndprov.dll"
+#else
+#define VER_FILEDESCRIPTION_STR		"OpenFabrics NetworkDirect Infiniband Provider"
+#define VER_INTERNALNAME_STR		"ibndprov.dll"
+#define VER_ORIGINALFILENAME_STR	"ibndprov.dll"
+#endif
+
+#include <common.ver>
+
Index: hw/mlx4/user/nd/mw.h
===================================================================
--- hw/mlx4/user/nd/mw.h	(revision 0)
+++ hw/mlx4/user/nd/mw.h	(revision 0)
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+namespace NDv2
+{
+
+class Mw
+    : public Unknown<Mw, IND2MemoryWindow>
+{
+    typedef Unknown<Mw, IND2MemoryWindow> _Base;
+
+public:
+    static const GUID _Guid;
+
+private:
+    Adapter& m_Adapter;
+
+    UINT64 m_hMw;
+    ib_mw_handle_t m_uMw;
+
+    //
+    // The following members are to work around lack of MW support in the ConnectX HW/drivers.
+    //
+    Mr& m_Mr;
+    Mr* m_pBoundMr;
+
+private:
+    operator =(Mw&){}
+
+public:
+    Mw(Adapter& adapter, Mr& mr);
+    ~Mw(void);
+
+    HRESULT Initialize();
+
+    void* GetInterface(REFIID riid);
+
+    HRESULT Bind(Mr* pMr, __in_bcount(cbBuffer) const void* pBuffer, SIZE_T cbBuffer, ULONG Flags);
+    HRESULT Invalidate();
+
+public:
+    // *** IND2MemoryWindow methods ***
+    STDMETHODIMP_(UINT32) GetRemoteToken(){ return m_Mr.GetRemoteToken(); }
+};
+
+} // namespace NDv2
+
+namespace NDv1
+{
+
+class Mw
+    : public Unknown<Mw, INDMemoryWindow>
+{
+    typedef Unknown<Mw, INDMemoryWindow> _Base;
+
+    INDAdapter& m_Adapter;
+    IND2MemoryWindow& m_Mw;
+
+    ND_RESULT* m_pInvalidateResult;
+
+private:
+    operator =(Mw&){}
+
+public:
+    Mw(INDAdapter& adapter, IND2MemoryWindow& mw, ND_RESULT* pInvalidateResult);
+    ~Mw(void);
+
+    void* GetInterface(REFIID riid);
+
+    IND2MemoryWindow* GetMw() const { return &m_Mw; }
+};
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/main.h
===================================================================
--- hw/mlx4/user/nd/main.h	(revision 0)
+++ hw/mlx4/user/nd/main.h	(revision 0)
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#if DBG
+extern LONG g_nRef[ND_RESOURCE_TYPE_COUNT];
+#else
+extern LONG g_nRef[1];
+#endif
+
+class ListEntry
+{
+    ListEntry* m_Flink;
+    ListEntry* m_Blink;
+
+public:
+    ListEntry()
+    {
+        m_Flink = this;
+        m_Blink = this;
+    }
+
+    ~ListEntry()
+    {
+    }
+
+    void InsertHead(ListEntry* pEntry)
+    {
+        pEntry->m_Flink = m_Flink;
+        pEntry->m_Blink = this;
+        m_Flink->m_Blink = pEntry;
+        m_Flink = pEntry;
+    }
+
+    void InsertTail(ListEntry* pEntry)
+    {
+        pEntry->m_Flink = this;
+        pEntry->m_Blink = m_Blink;
+        m_Blink->m_Flink = pEntry;
+        m_Blink = pEntry;
+    }
+
+    void RemoveFromList()
+    {
+        m_Flink->m_Blink = m_Blink;
+        m_Blink->m_Flink = m_Flink;
+    }
+
+    ListEntry* Next()
+    {
+        return m_Flink;
+    }
+
+    ListEntry* Prev()
+    {
+        return m_Blink;
+    }
+
+    const ListEntry* End()
+    {
+        return this;
+    }
+};
+
+
+void* __cdecl operator new(
+    size_t count
+    );
+
+
+void __cdecl operator delete(
+    void* object
+    );
+
+
+HRESULT Ioctl(
+    __in HANDLE hFile,
+    __in ULONG IoControlCode,
+    __in_bcount(cbInput) void* pInput,
+    __in ULONG cbInput,
+    __out_bcount_part_opt(*pcbOutput,*pcbOutput) void* pOutput,
+    __inout ULONG* pcbOutput
+    );
+
+
+HRESULT IoctlAsync(
+    __in HANDLE hFile,
+    __in ULONG IoControlCode,
+    __in_bcount(cbInput) void* pInput,
+    __in ULONG cbInput,
+    __out_bcount_part_opt(*pcbOutput,*pcbOutput) void* pOutput,
+    __in ULONG cbOutput,
+    __inout OVERLAPPED* pOverlapped
+    );
+
+
+HRESULT ConvertIbStatus( __in ib_api_status_t status );
Index: hw/mlx4/user/nd/listener.h
===================================================================
--- hw/mlx4/user/nd/listener.h	(revision 0)
+++ hw/mlx4/user/nd/listener.h	(revision 0)
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+namespace NDv2
+{
+
+class Listener
+    : public Overlapped<Listener, IND2Listener>
+{
+    typedef Overlapped<Listener, IND2Listener> _Base;
+
+    Adapter& m_Adapter;
+
+    UINT64 m_hListener;
+
+private:
+    operator =(Listener&) {}
+
+public:
+    Listener(Adapter& adapter);
+    ~Listener();
+
+    HRESULT Initialize(HANDLE hFile);
+
+    void* GetInterface(REFIID riid);
+
+    UINT64 GetHandle() const { return m_hListener; }
+    static ULONG GetCancelIoctlCode() { return IOCTL_ND_LISTENER_CANCEL_IO; }
+
+public:
+    // *** IND2Listen methods ***
+    STDMETHODIMP Bind(
+        __in_bcount(cbAddress) const struct sockaddr* pAddress,
+        ULONG cbAddress
+        );
+
+    STDMETHODIMP Listen(
+        ULONG backlog
+        );
+
+    STDMETHODIMP GetLocalAddress(
+        __out_bcount_part_opt(*pcbAddress, *pcbAddress) struct sockaddr* pAddress,
+        __inout ULONG* pcbAddress
+        );
+
+    STDMETHODIMP GetConnectionRequest(
+        __inout IUnknown* pConnector,
+        __inout OVERLAPPED* pOverlapped
+        );
+};
+
+} // namespace NDv2
+
+namespace NDv1
+{
+
+class Listener
+    : public Unknown<Listener, INDListen>
+{
+    typedef Unknown<Listener, INDListen> _Base;
+
+    IND2Listener& m_Listener;
+
+private:
+    Listener(IND2Listener& listener);
+
+    HRESULT Initialize(
+        __in Adapter& adapter,
+        __in SIZE_T Backlog,
+        __in USHORT Port,
+        __out_opt USHORT* pAssignedPort
+        );
+
+    operator =(Listener&){}
+
+public:
+    ~Listener(void);
+
+    static HRESULT Create(
+        __in Adapter& adapter,
+        __in IND2Listener& listener,
+        __in SIZE_T Backlog,
+        __in USHORT Port,
+        __out_opt USHORT* pAssignedPort,
+        __deref_out INDListen** ppListen
+        );
+
+    void* GetInterface(REFIID riid);
+
+public:
+    // *** INDOverlapped methods ***
+    HRESULT STDMETHODCALLTYPE CancelOverlappedRequests(void)
+    {
+        return m_Listener.CancelOverlappedRequests();
+    }
+
+    HRESULT STDMETHODCALLTYPE GetOverlappedResult(
+        __inout_opt OVERLAPPED *pOverlapped,
+        __out SIZE_T *pNumberOfBytesTransferred,
+        __in BOOL bWait
+        )
+    {
+        *pNumberOfBytesTransferred = 0;
+        HRESULT hr = m_Listener.GetOverlappedResult(pOverlapped, bWait);
+        if( hr == STATUS_CONNECTION_DISCONNECTED )
+        {
+            hr = STATUS_CANCELLED;
+        }
+        return hr;
+    }
+
+    // *** INDListen methods ***
+    HRESULT STDMETHODCALLTYPE GetConnectionRequest(
+        __inout INDConnector* pConnector,
+        __inout OVERLAPPED* pOverlapped
+        );
+};
+
+} // namespace
Index: hw/mlx4/user/nd/connector.cpp
===================================================================
--- hw/mlx4/user/nd/connector.cpp	(revision 0)
+++ hw/mlx4/user/nd/connector.cpp	(revision 0)
@@ -0,0 +1,808 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+namespace NDv2
+{
+// {4DF1A76E-2A27-428A-8482-AA66C4DADFAE}
+const GUID Connector::_Guid = 
+{ 0x4df1a76e, 0x2a27, 0x428a, { 0x84, 0x82, 0xaa, 0x66, 0xc4, 0xda, 0xdf, 0xae } };
+
+
+bool CopyAddress(
+    __in_bcount(cbAddress) const struct sockaddr* pAddress,
+    ULONG cbAddress,
+    __out SOCKADDR_INET* pInetAddress
+    )
+{
+    switch( pAddress->sa_family )
+    {
+    case AF_INET:
+        if( cbAddress < sizeof(pInetAddress->Ipv4) )
+        {
+            return false;
+        }
+        RtlCopyMemory(&pInetAddress->Ipv4, pAddress, sizeof(pInetAddress->Ipv4));
+        break;
+
+    case AF_INET6:
+        if( cbAddress < sizeof(pInetAddress->Ipv6) )
+        {
+            return false;
+        }
+        RtlCopyMemory(&pInetAddress->Ipv6, pAddress, sizeof(pInetAddress->Ipv6));
+        break;
+
+    default:
+        return false;
+    }
+    return true;
+}
+
+
+HRESULT CopyAddress(
+    __in SOCKADDR_INET& inetAddress,
+    __out_bcount_part_opt(*pcbAddress, *pcbAddress) struct sockaddr* pAddress,
+    __inout ULONG* pcbAddress
+    )
+{
+    if( pAddress == NULL && *pcbAddress != 0 )
+    {
+        return E_INVALIDARG;
+    }
+
+    ULONG cbReq;
+    switch( inetAddress.si_family )
+    {
+    case AF_INET:
+        cbReq = sizeof(inetAddress.Ipv4);
+        break;
+
+    case AF_INET6:
+        cbReq = sizeof(inetAddress.Ipv6);
+        break;
+
+    default:
+        __assume(0);
+    }
+
+    if( *pcbAddress < cbReq )
+    {
+        *pcbAddress = cbReq;
+        return STATUS_BUFFER_TOO_SMALL;
+    }
+
+    RtlCopyMemory(pAddress, &inetAddress, cbReq);
+    *pcbAddress = cbReq;
+    return STATUS_SUCCESS;
+}
+
+
+Connector::Connector(Adapter& adapter)
+    : m_Adapter(adapter),
+    m_hConnector(0),
+    m_pQp(NULL)
+{
+    adapter.AddRef();
+#if DBG
+    InterlockedIncrement(&g_nRef[NdConnector]);
+#endif
+}
+
+
+Connector::~Connector()
+{
+    m_Adapter.GetProvider().FreeHandle(m_hConnector, IOCTL_ND_CONNECTOR_FREE);
+
+    if( m_pQp != NULL )
+    {
+        m_pQp->Release();
+    }
+    m_Adapter.Release();
+#if DBG
+    InterlockedDecrement(&g_nRef[NdConnector]);
+#endif
+}
+
+
+HRESULT Connector::Initialize(HANDLE hFile, BOOLEAN Ndv1TimeoutSemantics)
+{
+    HRESULT hr = _Base::Initialize(hFile);
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    NDFLTR_EP_CREATE in;
+    in.Header.Version = ND_IOCTL_VERSION;
+    in.Header.Reserved = 0;
+    in.Header.Handle = m_Adapter.GetHandle();
+    in.Ndv1TimeoutSemantics = Ndv1TimeoutSemantics;
+
+    ULONG cbOut = sizeof(m_hConnector);
+    return m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_CONNECTOR_CREATE,
+        &in,
+        sizeof(in),
+        &m_hConnector,
+        &cbOut
+        );
+}
+
+
+void* Connector::GetInterface(REFIID riid)
+{
+    if( riid == IID_IND2Connector )
+    {
+        return static_cast<IND2Connector*>(this);
+    }
+
+    if( riid == _Guid )
+    {
+        return this;
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+STDMETHODIMP Connector::Bind(
+    __in_bcount(cbAddress) const struct sockaddr* pAddress,
+    ULONG cbAddress
+    )
+{
+    ND_BIND bind;
+    bind.Version = ND_IOCTL_VERSION;
+    bind.Reserved = 0;
+    bind.Handle = m_hConnector;
+    if( CopyAddress(pAddress, cbAddress, &bind.Address) == false )
+    {
+        return STATUS_INVALID_ADDRESS;
+    }
+
+    return m_Adapter.GetProvider().Ioctl(IOCTL_ND_CONNECTOR_BIND, &bind, sizeof(bind));
+}
+
+
+STDMETHODIMP Connector::Connect(
+    __in IUnknown* pQueuePair,
+    __in_bcount(cbDestAddress) const struct sockaddr* pDestAddress,
+    ULONG cbDestAddress,
+    ULONG inboundReadLimit,
+    ULONG outboundReadLimit,
+    __in_bcount_opt(cbPrivateData) const VOID* pPrivateData,
+    ULONG cbPrivateData,
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    if( m_pQp != NULL )
+    {
+        return STATUS_CONNECTION_ACTIVE;
+    }
+
+    NDFLTR_CONNECT in;
+    in.Header.Version = ND_IOCTL_VERSION;
+    in.Header.Reserved = 0;
+    in.Header.ReadLimits.Inbound = inboundReadLimit;
+    in.Header.ReadLimits.Outbound = outboundReadLimit;
+
+    if( cbPrivateData > sizeof(in.PrivateData) )
+    {
+        return STATUS_INVALID_BUFFER_SIZE;
+    }
+
+    in.Header.CbPrivateDataLength = cbPrivateData;
+    in.Header.CbPrivateDataOffset = FIELD_OFFSET(NDFLTR_CONNECT, PrivateData);
+
+    RtlCopyMemory(in.PrivateData, pPrivateData, cbPrivateData);
+
+    in.Header.ConnectorHandle = m_hConnector;
+
+    if( CopyAddress(pDestAddress, cbDestAddress, &in.Header.DestinationAddress) == false )
+    {
+        return STATUS_INVALID_ADDRESS;
+    }
+
+    HRESULT hr = pQueuePair->QueryInterface(
+        Qp::_Guid,
+        reinterpret_cast<void**>(&m_pQp)
+        );
+    if( FAILED(hr) )
+    {
+        return STATUS_INVALID_PARAMETER_1;
+    }
+
+    in.Header.QpHandle = m_pQp->GetHandle();
+
+    in.RetryCount = _MaxRetryCount;
+    in.RnrRetryCount = 0;
+
+    hr = ::IoctlAsync(
+        m_hFile,
+        IOCTL_ND_CONNECTOR_CONNECT,
+        &in,
+        sizeof(in),
+        NULL,
+        0,
+        pOverlapped
+        );
+    if( FAILED(hr) )
+    {
+        m_pQp->Release();
+        m_pQp = NULL;
+    }
+    return hr;
+}
+
+
+STDMETHODIMP Connector::CompleteConnect(
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    if( m_pQp == NULL )
+    {
+        return STATUS_CONNECTION_INVALID;
+    }
+
+    NDFLTR_COMPLETE_CONNECT in;
+    in.Header.Version = ND_IOCTL_VERSION;
+    in.Header.Reserved = 0;
+    in.Header.Handle = m_hConnector;
+    in.RnrNakTimeout = 0;
+
+    void* pOut;
+    ULONG cbOut;
+    mlx4_nd_modify_qp(m_pQp->GetUvpQp(), &pOut, &cbOut );
+
+    return ::IoctlAsync(
+        m_hFile,
+        IOCTL_ND_CONNECTOR_COMPLETE_CONNECT,
+        &in,
+        sizeof(in),
+        pOut,
+        cbOut,
+        pOverlapped
+        );
+}
+
+
+STDMETHODIMP Connector::Accept(
+    __in IUnknown* pQueuePair,
+    ULONG inboundReadLimit,
+    ULONG outboundReadLimit,
+    __in_bcount_opt(cbPrivateData) const VOID* pPrivateData,
+    ULONG cbPrivateData,
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    if( m_pQp != NULL )
+    {
+        return STATUS_CONNECTION_ACTIVE;
+    }
+
+    NDFLTR_ACCEPT in;
+    in.Header.Version = ND_IOCTL_VERSION;
+    in.Header.Reserved = 0;
+    in.Header.ReadLimits.Inbound = inboundReadLimit;
+    in.Header.ReadLimits.Outbound = outboundReadLimit;
+
+    if( cbPrivateData > sizeof(in.PrivateData) )
+    {
+        return STATUS_INVALID_BUFFER_SIZE;
+    }
+
+    in.Header.CbPrivateDataLength = cbPrivateData;
+    in.Header.CbPrivateDataOffset = FIELD_OFFSET(NDFLTR_ACCEPT, PrivateData);
+
+    RtlCopyMemory(in.PrivateData, pPrivateData, cbPrivateData);
+
+    in.Header.ConnectorHandle = m_hConnector;
+
+    HRESULT hr = pQueuePair->QueryInterface(
+        Qp::_Guid,
+        reinterpret_cast<void**>(&m_pQp)
+        );
+    if( FAILED(hr) )
+    {
+        return STATUS_INVALID_PARAMETER_1;
+    }
+
+    in.Header.QpHandle = m_pQp->GetHandle();
+
+    in.RnrRetryCount = 0;
+    in.RnrNakTimeout = 0;
+
+    void* pOut;
+    ULONG cbOut;
+    mlx4_nd_modify_qp(m_pQp->GetUvpQp(), &pOut, &cbOut );
+
+    hr = ::IoctlAsync(
+        m_hFile,
+        IOCTL_ND_CONNECTOR_ACCEPT,
+        &in,
+        sizeof(in),
+        pOut,
+        cbOut,
+        pOverlapped
+        );
+    if( FAILED(hr) )
+    {
+        m_pQp->Release();
+        m_pQp = NULL;
+    }
+    return hr;
+}
+
+
+STDMETHODIMP Connector::Reject(
+    __in_bcount_opt(cbPrivateData) const VOID* pPrivateData,
+    ULONG cbPrivateData
+    )
+{
+
+    NDFLTR_REJECT in;
+    in.Header.Version = ND_IOCTL_VERSION;
+    in.Header.Reserved = 0;
+
+    if( cbPrivateData > sizeof(in.PrivateData) )
+    {
+        return STATUS_INVALID_BUFFER_SIZE;
+    }
+
+    in.Header.CbPrivateDataLength = cbPrivateData;
+    in.Header.CbPrivateDataOffset = FIELD_OFFSET(NDFLTR_REJECT, PrivateData);
+
+    RtlCopyMemory(in.PrivateData, pPrivateData, cbPrivateData);
+
+    in.Header.ConnectorHandle = m_hConnector;
+
+    return m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_CONNECTOR_REJECT,
+        &in,
+        sizeof(in)
+        );
+}
+
+
+STDMETHODIMP Connector::GetReadLimits(
+    __out_opt ULONG* pInboundReadLimit,
+    __out_opt ULONG* pOutboundReadLimit
+    )
+{
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = m_hConnector;
+
+    ND_READ_LIMITS limits;
+    ULONG cbLimits = sizeof(limits);
+
+    HRESULT hr = m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_CONNECTOR_GET_READ_LIMITS,
+        &in,
+        sizeof(in),
+        &limits,
+        &cbLimits
+        );
+    if( SUCCEEDED(hr) )
+    {
+        if( pInboundReadLimit != NULL )
+        {
+            *pInboundReadLimit = limits.Inbound;
+        }
+        if( pOutboundReadLimit != NULL )
+        {
+            *pOutboundReadLimit = limits.Outbound;
+        }
+    }
+    return hr;
+}
+
+
+STDMETHODIMP Connector::GetPrivateData(
+    __out_bcount_opt(*pcbPrivateData) VOID* pPrivateData,
+    __inout ULONG* pcbPrivateData
+    )
+{
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = m_hConnector;
+
+    return m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_CONNECTOR_GET_PRIVATE_DATA,
+        &in,
+        sizeof(in),
+        pPrivateData,
+        pcbPrivateData
+        );
+}
+
+
+STDMETHODIMP Connector::GetLocalAddress(
+    __out_bcount_part_opt(*pcbAddress, *pcbAddress) struct sockaddr* pAddress,
+    __inout ULONG* pcbAddress
+    )
+{
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = m_hConnector;
+
+    SOCKADDR_INET out;
+    ULONG cbOut = sizeof(out);
+    HRESULT hr = m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_CONNECTOR_GET_ADDRESS,
+        &in,
+        sizeof(in),
+        &out,
+        &cbOut
+        );
+    if( SUCCEEDED(hr) )
+    {
+        hr = CopyAddress(out, pAddress, pcbAddress);
+    }
+    return hr;
+}
+
+
+STDMETHODIMP Connector::GetPeerAddress(
+    __out_bcount_part_opt(*pcbAddress, *pcbAddress) struct sockaddr* pAddress,
+    __inout ULONG* pcbAddress
+    )
+{
+    if( pAddress == NULL && *pcbAddress != 0 )
+    {
+        return E_INVALIDARG;
+    }
+
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = m_hConnector;
+
+    SOCKADDR_INET out;
+    ULONG cbOut = sizeof(out);
+    HRESULT hr = m_Adapter.GetProvider().Ioctl(
+        IOCTL_ND_CONNECTOR_GET_PEER_ADDRESS,
+        &in,
+        sizeof(in),
+        &out,
+        &cbOut
+        );
+    if( SUCCEEDED(hr) )
+    {
+        hr = CopyAddress(out, pAddress, pcbAddress);
+    }
+    return hr;
+}
+
+
+STDMETHODIMP Connector::NotifyDisconnect(
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = m_hConnector;
+
+    return ::IoctlAsync(
+        m_hFile,
+        IOCTL_ND_CONNECTOR_NOTIFY_DISCONNECT,
+        &in,
+        sizeof(in),
+        NULL,
+        0,
+        pOverlapped
+        );
+}
+
+
+STDMETHODIMP Connector::Disconnect(
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    if( m_pQp == NULL )
+    {
+        return STATUS_CONNECTION_INVALID;
+    }
+
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = m_hConnector;
+
+    void* pOut;
+    ULONG cbOut;
+    mlx4_nd_modify_qp(m_pQp->GetUvpQp(), &pOut, &cbOut );
+
+    return ::IoctlAsync(
+        m_hFile,
+        IOCTL_ND_CONNECTOR_DISCONNECT,
+        &in,
+        sizeof(in),
+        pOut,
+        cbOut,
+        pOverlapped
+        );
+}
+
+} // namespace NDv2
+
+namespace NDv1
+{
+
+Connector::Connector(Adapter& adapter, IND2Connector& connector)
+    : m_Adapter(adapter),
+    m_Connector(connector)
+{
+    adapter.AddRef();
+    connector.AddRef();
+}
+
+
+Connector::~Connector(void)
+{
+    m_Connector.Release();
+    m_Adapter.Release();
+}
+
+
+/*static*/
+HRESULT
+Connector::Create(
+    __in Adapter& adapter,
+    __in IND2Connector& connector,
+    __deref_out INDConnector** ppConnector
+    )
+{
+    Connector* pConnector = new Connector(adapter, connector);
+    if( pConnector == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    *ppConnector = pConnector;
+    return S_OK;
+}
+
+
+void* Connector::GetInterface(REFIID riid)
+{
+    if( riid == IID_INDConnector )
+    {
+        return static_cast<INDConnector*>(this);
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+HRESULT Connector::CreateEndpoint(
+    __in INDCompletionQueue* pInboundCq,
+    __in INDCompletionQueue* pOutboundCq,
+    __in SIZE_T nInboundEntries,
+    __in SIZE_T nOutboundEntries,
+    __in SIZE_T nInboundSge,
+    __in SIZE_T nOutboundSge,
+    __in SIZE_T InboundReadLimit,
+    __in SIZE_T OutboundReadLimit,
+    __out_opt SIZE_T* pMaxInlineData,
+    __deref_out INDEndpoint** ppEndpoint
+    )
+{
+    IND2QueuePair* pQp;
+    HRESULT hr = m_Adapter.GetAdapter()->CreateQueuePair(
+        IID_IND2QueuePair,
+        static_cast<Cq*>(pInboundCq)->GetCq(),
+        static_cast<Cq*>(pOutboundCq)->GetCq(),
+        NULL,
+        static_cast<ULONG>(nInboundEntries),
+        static_cast<ULONG>(nOutboundEntries),
+        static_cast<ULONG>(nInboundSge),
+        static_cast<ULONG>(nOutboundSge),
+        Endpoint::_MaxInline,
+        reinterpret_cast<void**>(&pQp)
+        );
+
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    m_InboundReadLimit = static_cast<ULONG>(InboundReadLimit);
+    m_OutboundReadLimit = static_cast<ULONG>(OutboundReadLimit);
+
+    return Endpoint::Create(*pQp, pMaxInlineData, ppEndpoint);
+}
+
+
+HRESULT Connector::Connect(
+    __inout INDEndpoint* pEndpoint,
+    __in_bcount(AddressLength) const struct sockaddr* pAddress,
+    __in SIZE_T AddressLength,
+    __in INT /*Protocol*/,
+    __in_opt USHORT LocalPort,
+    __in_bcount_opt(PrivateDataLength) const void* pPrivateData,
+    __in SIZE_T PrivateDataLength,
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    SOCKADDR_INET address = m_Adapter.GetAddress();
+    //
+    // IPv4 and IPv6 ports are in the same place, thankfully.
+    //
+    address.Ipv4.sin_port = LocalPort;
+
+    HRESULT hr = m_Connector.Bind(
+        reinterpret_cast<struct sockaddr*>(&address),
+        sizeof(address)
+        );
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    return m_Connector.Connect(
+        static_cast<Endpoint*>(pEndpoint)->GetQp(),
+        pAddress,
+        static_cast<ULONG>(AddressLength),
+        m_InboundReadLimit,
+        m_OutboundReadLimit,
+        pPrivateData,
+        static_cast<ULONG>(PrivateDataLength),
+        pOverlapped
+        );
+}
+
+
+HRESULT Connector::CompleteConnect(
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    return m_Connector.CompleteConnect(pOverlapped);
+}
+
+
+HRESULT Connector::Accept(
+    __in INDEndpoint* pEndpoint,
+    __in_bcount_opt(PrivateDataLength) const void* pPrivateData,
+    __in SIZE_T PrivateDataLength,
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    return m_Connector.Accept(
+        static_cast<Endpoint*>(pEndpoint)->GetQp(),
+        m_InboundReadLimit,
+        m_OutboundReadLimit,
+        pPrivateData,
+        static_cast<ULONG>(PrivateDataLength),
+        pOverlapped
+        );
+}
+
+
+HRESULT Connector::Reject(
+    __in_bcount_opt(PrivateDataLength) const void* pPrivateData,
+    __in SIZE_T PrivateDataLength
+    )
+{
+    return m_Connector.Reject(pPrivateData, static_cast<ULONG>(PrivateDataLength));
+}
+
+
+HRESULT Connector::GetConnectionData(
+    __out_opt SIZE_T* pInboundReadLimit,
+    __out_opt SIZE_T* pOutboundReadLimit,
+    __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData,
+    __inout SIZE_T* pPrivateDataLength
+    )
+{
+    HRESULT hr = S_OK;
+    if( pInboundReadLimit != NULL || pOutboundReadLimit != NULL )
+    {
+        //
+        // Clear the most significant bits so that we can cast to ULONG* to get the
+        // lower bits.
+        //
+        if( pInboundReadLimit != NULL )
+        {
+            *pInboundReadLimit = 0;
+        }
+        if( pOutboundReadLimit != NULL )
+        {
+            *pOutboundReadLimit = 0;
+        }
+        hr = m_Connector.GetReadLimits(
+            reinterpret_cast<ULONG*>(pInboundReadLimit),
+            reinterpret_cast<ULONG*>(pOutboundReadLimit)
+            );
+        if( FAILED(hr) )
+        {
+            return hr;
+        }
+    }
+
+    if( pPrivateDataLength != NULL )
+    {
+        ULONG len = static_cast<ULONG>(min(ULONG_MAX, *pPrivateDataLength));
+        hr = m_Connector.GetPrivateData(
+            pPrivateData,
+            &len
+            );
+        *pPrivateDataLength = len;
+    }
+    return hr;
+}
+
+
+HRESULT Connector::GetLocalAddress(
+    __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress,
+    __inout SIZE_T* pAddressLength
+    )
+{
+    *pAddressLength = min(*pAddressLength, ULONG_MAX);
+    return m_Connector.GetLocalAddress(
+        pAddress,
+        reinterpret_cast<ULONG*>(pAddressLength)
+        );
+}
+
+
+HRESULT Connector::GetPeerAddress(
+    __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress,
+    __inout SIZE_T* pAddressLength
+    )
+{
+    *pAddressLength = min(*pAddressLength, ULONG_MAX);
+    return m_Connector.GetPeerAddress(
+        pAddress,
+        reinterpret_cast<ULONG*>(pAddressLength)
+        );
+}
+
+
+HRESULT Connector::NotifyDisconnect(
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    return m_Connector.NotifyDisconnect(pOverlapped);
+}
+
+
+HRESULT Connector::Disconnect(
+    __inout OVERLAPPED* pOverlapped
+    )
+{
+    return m_Connector.Disconnect(pOverlapped);
+}
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/provider.cpp
===================================================================
--- hw/mlx4/user/nd/provider.cpp	(revision 0)
+++ hw/mlx4/user/nd/provider.cpp	(revision 0)
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+
+namespace NDv2
+{
+
+Provider::Provider()
+    : _Base(),
+    m_hProvider(INVALID_HANDLE_VALUE)
+{
+    InterlockedIncrement(&g_nRef[NdProvider]);
+}
+
+
+Provider::~Provider()
+{
+    if( m_hProvider != INVALID_HANDLE_VALUE )
+    {
+        CloseHandle(m_hProvider);
+    }
+    InterlockedDecrement(&g_nRef[NdProvider]);
+}
+
+
+HRESULT Provider::Create( __in REFIID riid, __out void** ppProvider )
+{
+    Provider* pProvider = new Provider();
+    if( pProvider == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    pProvider->m_hProvider = CreateFileW(
+        ND_WIN32_DEVICE_NAME,
+        GENERIC_READ | GENERIC_WRITE,
+        FILE_SHARE_READ | FILE_SHARE_WRITE,
+        NULL,
+        OPEN_EXISTING,
+        FILE_ATTRIBUTE_NORMAL,
+        NULL
+        );
+    if( pProvider->m_hProvider == INVALID_HANDLE_VALUE )
+    {
+        delete pProvider;
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = 0;
+    HRESULT hr = pProvider->Ioctl(IOCTL_ND_PROVIDER_INIT, &in, sizeof(in));
+    if( SUCCEEDED(hr) )
+    {
+        hr = pProvider->QueryInterface(riid, ppProvider);
+    }
+    pProvider->Release();
+    return hr;
+}
+
+
+void* Provider::GetInterface( REFIID riid )
+{
+    if( IsEqualIID(riid, IID_IND2Provider) )
+    {
+        return static_cast<IND2Provider*>(this);
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+HRESULT Provider::Ioctl(
+    __in ULONG IoControlCode,
+    __in_bcount(cbInput) void* pInput,
+    __in ULONG cbInput,
+    __out_bcount_part_opt(*pcbOutput,*pcbOutput) void* pOutput,
+    __inout ULONG* pcbOutput
+    )
+{
+    return ::Ioctl(
+        m_hProvider,
+        IoControlCode,
+        pInput,
+        cbInput,
+        pOutput,
+        pcbOutput
+        );
+}
+
+
+HRESULT Provider::Ioctl(
+    __in ULONG IoControlCode,
+    __in_bcount(cbInput) void* pInput,
+    __in ULONG cbInput
+    )
+{
+    ULONG cbOut = 0;
+    return ::Ioctl(
+        m_hProvider,
+        IoControlCode,
+        pInput,
+        cbInput,
+        NULL,
+        &cbOut
+        );
+}
+
+
+void Provider::FreeHandle( UINT64 handle, ULONG ctlCode )
+{
+    ND_HANDLE in;
+    in.Version = ND_IOCTL_VERSION;
+    in.Reserved = 0;
+    in.Handle = handle;
+    HRESULT hr = Ioctl(ctlCode, &in, sizeof(in));
+    assert( SUCCEEDED(hr) );
+    UNREFERENCED_PARAMETER(hr);
+}
+
+
+HRESULT Provider::QueryAddressList(
+        __out_bcount_part_opt(*pcbAddressList, *pcbAddressList) SOCKET_ADDRESS_LIST* pAddressList,
+        __inout ULONG* pcbAddressList )
+{
+    NDFLTR_QUERY_ADDRESS_LIST query;
+    query.Header.Version = ND_IOCTL_VERSION;
+    query.Header.Reserved = 0;
+    query.Header.Handle = 0;
+    query.DriverId = GUID_MLX4_DRIVER;
+
+    ULONG cbAddresses = 0;
+    HRESULT hr = Ioctl(
+        IOCTL_ND_PROVIDER_QUERY_ADDRESS_LIST,
+        &query,
+        sizeof(query),
+        NULL,
+        &cbAddresses
+        );
+    if( hr != STATUS_BUFFER_OVERFLOW )
+    {
+        return hr;
+    }
+
+    INT nAddresses = cbAddresses / sizeof(SOCKADDR_INET);
+    ULONG cbListHeader = 
+        sizeof(SOCKET_ADDRESS_LIST) +
+        (sizeof(SOCKET_ADDRESS) * (nAddresses - 1));
+    ULONG cbAddressList = cbListHeader + cbAddresses;
+
+    if( *pcbAddressList < cbAddressList )
+    {
+        *pcbAddressList = cbAddressList;
+        return STATUS_BUFFER_OVERFLOW;
+    }
+
+    SOCKADDR_INET* pAddresses = reinterpret_cast<SOCKADDR_INET*>(
+        reinterpret_cast<ULONG_PTR>(pAddressList) + cbListHeader
+        );
+
+    hr = Ioctl(
+        IOCTL_ND_PROVIDER_QUERY_ADDRESS_LIST,
+        &query,
+        sizeof(query),
+        pAddresses,
+        &cbAddresses
+        );
+    if( SUCCEEDED(hr) )
+    {
+        pAddressList->iAddressCount = nAddresses;
+        for( INT i = 0; i < nAddresses; i++ )
+        {
+            pAddressList->Address[i].iSockaddrLength = sizeof(SOCKADDR_INET);
+            pAddressList->Address[i].lpSockaddr = reinterpret_cast<SOCKADDR*>(&pAddresses[i]);
+        }
+    }
+    return hr;
+}
+
+
+HRESULT Provider::ResolveAddress(
+    __in_bcount(cbAddress) const struct sockaddr* pAddress,
+    ULONG cbAddress,
+    __out UINT64* pAdapterId
+    )
+{
+    NDFLTR_RESOLVE_ADDRESS resolve;
+    resolve.Header.Version = ND_IOCTL_VERSION;
+    resolve.Header.Reserved = 0;
+
+    if( cbAddress > sizeof(resolve.Header.Address) )
+    {
+        return STATUS_INVALID_ADDRESS;
+    }
+
+    CopyMemory(&resolve.Header.Address, pAddress, cbAddress);
+    resolve.DriverId = GUID_MLX4_DRIVER;
+
+    ULONG outLen = sizeof(*pAdapterId);
+    return Ioctl(
+        IOCTL_ND_PROVIDER_RESOLVE_ADDRESS,
+        &resolve,
+        sizeof(resolve),
+        pAdapterId,
+        &outLen
+        );
+}
+
+
+HRESULT Provider::OpenAdapter(
+    __in REFIID iid,
+    UINT64 adapterId,
+    __deref_out VOID** ppAdapter
+    )
+{
+    Adapter* pAdapter = new Adapter(*this);
+    if( pAdapter == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    HRESULT hr = pAdapter->Initialize(adapterId);
+    if( SUCCEEDED(hr) )
+    {
+        hr = pAdapter->QueryInterface(iid, ppAdapter);
+        pAdapter->Release();
+    }
+    return hr;
+}
+
+
+}   // namespace NDv2
+
+namespace NDv1
+{
+
+Provider::Provider()
+    : _Base(),
+    m_pProvider(NULL)
+{
+    InterlockedIncrement(&g_nRef[NdProvider]);
+}
+
+
+Provider::~Provider()
+{
+    if( m_pProvider != NULL )
+    {
+        m_pProvider->Release();
+    }
+    InterlockedDecrement(&g_nRef[NdProvider]);
+}
+
+
+HRESULT Provider::Create(__out void** ppProvider)
+{
+    Provider* pProvider = new Provider();
+    if( pProvider == NULL )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    HRESULT hr = NDv2::Provider::Create(
+        IID_IND2Provider,
+        reinterpret_cast<void**>(&pProvider->m_pProvider)
+        );
+    if( SUCCEEDED(hr) )
+    {
+        hr = pProvider->QueryInterface(IID_INDProvider, ppProvider);
+    }
+
+    pProvider->Release();
+    return hr;
+}
+
+
+void* Provider::GetInterface( REFIID riid )
+{
+    if( IsEqualIID(riid, IID_INDProvider) )
+    {
+        return static_cast<INDProvider*>(this);
+    }
+
+    return _Base::GetInterface(riid);
+}
+
+
+HRESULT Provider::QueryAddressList(
+        __out_bcount_part_opt(*pBufferSize, *pBufferSize) SOCKET_ADDRESS_LIST* pAddressList,
+        __inout SIZE_T* pBufferSize )
+{
+    ULONG cbBuffer = static_cast<ULONG>(min(ULONG_MAX, *pBufferSize));
+
+    HRESULT hr = m_pProvider->QueryAddressList(pAddressList, &cbBuffer);
+    *pBufferSize = cbBuffer;
+    if( SUCCEEDED(hr) )
+    {
+        //
+        // For NDv1 the address lengths are expected to be exact.
+        //
+        for( INT i = 0; i < pAddressList->iAddressCount; i++ )
+        {
+            if( pAddressList->Address[i].lpSockaddr->sa_family == AF_INET )
+            {
+                pAddressList->Address[i].iSockaddrLength = sizeof(sockaddr_in);
+            }
+        }
+    }
+    return hr;
+}
+
+
+HRESULT Provider::OpenAdapter(
+    __in_bcount(AddressLength) const struct sockaddr* pAddress,
+    __in SIZE_T AddressLength,
+    __deref_out INDAdapter** ppAdapter
+    )
+{
+    UINT64 adapterId;
+    HRESULT hr = m_pProvider->ResolveAddress(
+        pAddress,
+        static_cast<ULONG>(AddressLength),
+        &adapterId
+        );
+    if( FAILED(hr) )
+    {
+        return hr;
+    }
+
+    NDv2::Adapter* pAdapter;
+    hr = m_pProvider->OpenAdapter(
+        NDv2::Adapter::_Guid,
+        adapterId,
+        reinterpret_cast<void**>(&pAdapter)
+        );
+    if( SUCCEEDED(hr) )
+    {
+        hr = Adapter::Create(*this, *pAdapter, pAddress, AddressLength, ppAdapter);
+        pAdapter->Release();
+    }
+
+    return hr;
+}
+
+} // namespace NDv1
Index: hw/mlx4/user/nd/makefile
===================================================================
--- hw/mlx4/user/nd/makefile	(revision 0)
+++ hw/mlx4/user/nd/makefile	(revision 0)
@@ -0,0 +1,17 @@
+#
+# Edit .\sources. if you want to add a new source
+# file to this component.  This file merely indirects to the real make file
+# that is shared by all the driver components of the OpenIB Windows project.
+#
+
+# Never build for IA64.
+DDK_BLOCK_ON_IA64=1
+
+# If ND SDK is missing, defeat all builds.
+!IFNDEF ND_SDK_PATH
+!MESSAGE Skipping mxl4nd.dll build: ND_SD_PATH not set.
+DDK_BLOCK_ON_X86=1
+DDK_BLOCK_ON_AMD64=1
+!ENDIF
+
+!INCLUDE ..\..\..\..\inc\openib.def
Index: core/ndfltr/kernel/nd_partition.h
===================================================================
--- core/ndfltr/kernel/nd_partition.h	(revision 0)
+++ core/ndfltr/kernel/nd_partition.h	(revision 0)
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_PARTITION_H_
+#define _ND_PARTITION_H_
+
+
+#define ND_PARTITION_POOL_TAG 'pvdn'
+#define ND_PARTITION_ADDRESS_TAG 'apdn'
+
+class ND_PARTITION : public ObjBase
+{
+    typedef ObjBase _Base;
+
+    ERESOURCE           m_Lock;
+    LIST_ENTRY          m_ProvList;
+    LIST_ENTRY          m_AddrList;
+    UINT64              m_AdapterId;
+
+    struct ADDRESS_ENTRY : public LIST_ENTRY {
+        SOCKADDR_INET       Addr;
+        UINT64              GuestMac;
+        UINT64              Mac;
+    };
+
+public:
+    static
+    NTSTATUS
+    Create(
+        __in UINT64 AdapterId,
+        __out ND_PARTITION** ppPartition
+        );
+
+    NTSTATUS
+    PurgeAddressUnsafe(
+        __in const SOCKADDR_INET& Addr
+        );
+
+public:
+    ND_PARTITION(UINT64 AdapterId);
+    ~ND_PARTITION();
+
+    void Dispose();
+
+    NTSTATUS
+    BindAddress(
+        __in const SOCKADDR_INET& Addr,
+        __in const UINT64 GuestMac,
+        __in const UINT64 Mac
+        );
+
+    NTSTATUS
+    UnbindAddress(
+        __in const SOCKADDR_INET& Addr
+        );
+
+    NTSTATUS ResolveAddress(const SOCKADDR_INET& Addr, const GUID& DriverId, UINT64* pId);
+
+    void AddProvider(LIST_ENTRY* entry)
+    {
+        LockExclusive();
+        InsertTailList(&m_ProvList, entry);
+        Unlock();
+    }
+
+    void RemoveProvider(LIST_ENTRY* entry)
+    {
+        LockExclusive();
+        RemoveEntryList(entry);
+        Unlock();
+    }
+
+    NTSTATUS GetIpList(
+        __in REFGUID DriverId,
+        __in UINT64 AdapterId,
+        __inout ULONG* pnAddrs,
+        __out SOCKADDR_INET* pAddrs
+        );
+
+    NTSTATUS GetDeviceAddress(
+        __in const SOCKADDR_INET& Addr,
+        __in REFGUID DriverId,
+        __in UINT64 AdapterId,
+        __out IBAT_PORT_RECORD* pDeviceAddress
+        );
+
+    NTSTATUS
+    QueryPath(
+        __in const SOCKADDR_INET& pLocalAddress,
+        __in const SOCKADDR_INET& pRemoteAddress,
+        __in const IF_PHYSICAL_ADDRESS& RemoteHwAddress,
+        __in FN_IBAT_QUERY_PATH_CALLBACK* CompletionCallback,
+        __in VOID* CompletionContext,
+        __out ib_path_rec_t* pPath
+        );
+
+public:
+    static FN_REQUEST_HANDLER ResolveAdapterId;
+    static FN_REQUEST_HANDLER Free;
+    static FN_REQUEST_HANDLER BindAddress;
+    static FN_REQUEST_HANDLER UnbindAddress;
+    static FN_REQUEST_HANDLER BindLuid;
+
+private:
+    void LockExclusive();
+
+    void LockShared();
+
+    void Unlock();
+};
+
+
+#endif // _ND_PARTITION_H_
Index: core/ndfltr/kernel/nd_adapter.cpp
===================================================================
--- core/ndfltr/kernel/nd_adapter.cpp	(revision 0)
+++ core/ndfltr/kernel/nd_adapter.cpp	(revision 0)
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+
+ND_ADAPTER::ND_ADAPTER(
+    __in ND_PROVIDER* pProvider,
+    __in ND_RDMA_DEVICE* pDevice,
+    __in UINT64 AdapterId
+    )
+    : _Base(pProvider, &pDevice->Interface.Verbs),
+    m_pDevice(pDevice),
+    m_Id(AdapterId)
+{
+    InitializeListHead(&m_PdList);
+    InitializeListHead(&m_CqList);
+    InitializeListHead(&m_EpList);
+}
+
+
+ND_ADAPTER::~ND_ADAPTER()
+{
+    _Base::RunDown();
+
+    if (m_hIfc != NULL) {
+        //m_pDevice->m_pIfc->unregister_event_handler(m_pDevice->m_pDevice->hDevice,
+        //                                          &m_pDevice->EventHandler);
+        m_pIfc->um_close_ca(m_pDevice->hDevice, m_hIfc);
+    }
+
+    if (m_pDevice != NULL) {
+        NdRdmaDevicePut(m_pDevice);
+    }
+}
+
+
+NTSTATUS
+ND_ADAPTER::Initialize(
+    KPROCESSOR_MODE RequestorMode,
+    __inout ci_umv_buf_t* pVerbsData
+    )
+{
+    ib_api_status_t ibStatus = m_pIfc->um_open_ca(
+        m_pDevice->hDevice,
+        RequestorMode,
+        pVerbsData,
+        &m_hIfc
+        );
+    if (ibStatus != IB_SUCCESS) {
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
+//static
+NTSTATUS
+ND_ADAPTER::Create(
+    __in ND_PROVIDER* pProvider,
+    UINT64 AdapterId,
+    KPROCESSOR_MODE RequestorMode,
+    __inout ci_umv_buf_t* pVerbsData,
+    __out ND_ADAPTER** ppAdapter
+    )
+{
+    ND_RDMA_DEVICE* device = NdRdmaDeviceGet(AdapterId);
+    if (device == NULL) {
+        return STATUS_NO_SUCH_DEVICE;
+    }
+
+    ND_ADAPTER* adapter = reinterpret_cast<ND_ADAPTER*>(
+        ExAllocatePoolWithTag(NonPagedPool, sizeof(*adapter), ND_ADAPTER_POOL_TAG)
+        );
+    if (adapter == NULL) {
+        NdRdmaDevicePut(device);
+        return STATUS_NO_MEMORY;
+    }
+
+    new(adapter) ND_ADAPTER(pProvider, device, AdapterId);
+    NTSTATUS status = adapter->Initialize(RequestorMode, pVerbsData);
+    if (!NT_SUCCESS(status)) {
+        adapter->Dispose();
+        return status;
+    }
+    *ppAdapter = adapter;
+    return STATUS_SUCCESS;
+}
+
+
+void ND_ADAPTER::Dispose()
+{
+    this->ND_ADAPTER::~ND_ADAPTER();
+    ExFreePoolWithTag(this, ND_ADAPTER_POOL_TAG);
+}
+
+
+void ND_ADAPTER::RemoveHandler(__in ND_RDMA_DEVICE* pDevice)
+{
+    if (m_pDevice != pDevice) {
+        return;
+    }
+
+    LIST_ENTRY* entry;
+    for (entry = m_PdList.Flink; entry != &m_PdList; entry = entry->Flink) {
+        ND_PROTECTION_DOMAIN* pd = static_cast<ND_PROTECTION_DOMAIN*>(
+            ObjChild<ND_ADAPTER>::FromEntry(entry)
+            );
+        pd->RemoveHandler();
+    }
+
+    for (entry = m_CqList.Flink; entry != &m_CqList; entry = entry->Flink) {
+        ND_COMPLETION_QUEUE* cq = static_cast<ND_COMPLETION_QUEUE*>(
+            ObjChild<ND_ADAPTER>::FromEntry(entry)
+            );
+        cq->RemoveHandler();
+    }
+
+    for (entry = m_EpList.Flink; entry != &m_EpList; entry = entry->Flink) {
+        ND_ENDPOINT* ep = static_cast<ND_ENDPOINT*>(
+            ObjChild<ND_ADAPTER>::FromEntry(entry)
+            );
+        ep->RemoveHandler();
+    }
+
+    m_pIfc->um_close_ca(m_pDevice->hDevice, m_hIfc);
+    _Base::RemoveHandler();
+    NdRdmaDevicePut(m_pDevice);
+    m_pDevice = NULL;
+}
+
+
+NTSTATUS
+ND_ADAPTER::GetDeviceAddress(
+    __in const SOCKADDR_INET& Addr,
+    __out IBAT_PORT_RECORD* pDeviceAddress
+    )
+{
+    return GetProvider()->GetPartition()->GetDeviceAddress(
+        Addr,
+        GetInterface()->driver_id,
+        GetInterface()->guid,
+        pDeviceAddress
+        );
+}
+
+
+void
+NdAdapterOpen(
+    __in ND_PROVIDER *pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_OPEN_ADAPTER* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    //
+    // We expect the vendor data to be in the same place in the input and
+    // output buffers.  The input buffer is larger, so we use it as the
+    // minimum length when querying the output buffer.
+    //
+    ND_RESOURCE_DESCRIPTOR* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    ci_umv_buf_t verbsData;
+    NdInitVerbsData(&verbsData, inLen - sizeof(*in),
+                    outLen - sizeof(*in), in + 1);
+
+    pProvider->LockShared();
+
+    ND_ADAPTER* adapter;
+    status = ND_ADAPTER::Create(
+        pProvider,
+        in->AdapterId,
+        WdfRequestGetRequestorMode(Request),
+        &verbsData,
+        &adapter
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    out->Handle = pProvider->AddAdapter(adapter);
+    if (out->Handle == 0) {
+        adapter->Dispose();
+        status = STATUS_INSUFFICIENT_RESOURCES;
+    } else {
+        WdfRequestSetInformation(Request, outLen);
+    }
+
+err2:
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdAdapterClose(
+    __in ND_PROVIDER *pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE *in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    pProvider->LockShared();
+    status = pProvider->FreeAdapter(in->Handle);
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+//static
+void
+ND_ADAPTER::Query(
+    __in ND_PROVIDER *pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_ADAPTER_QUERY* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    if (in->InfoVersion != ND_VERSION_2) {
+        status = STATUS_NOT_SUPPORTED;
+        goto err;
+    }
+
+    pProvider->LockShared();
+
+    ND_ADAPTER* adapter;
+    status = pProvider->GetAdapter(in->AdapterHandle, &adapter);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+#ifdef _WIN64
+    if( WdfRequestIsFrom32BitProcess(Request) == TRUE) {
+        ND2_ADAPTER_INFO32* out;
+        status = WdfRequestRetrieveOutputBuffer(
+            Request,
+            sizeof(*out),
+            reinterpret_cast<VOID**>(&out),
+            NULL
+            );
+        if (!NT_SUCCESS(status)) {
+            goto err3;
+        }
+
+        NdThunkAdapterInfo(out, &adapter->GetDevice()->Info);
+        out->AdapterId = adapter->m_Id;
+        WdfRequestSetInformation(Request, sizeof(*out));
+    } else {
+#endif // _WIN64
+        ND2_ADAPTER_INFO* out;
+        status = WdfRequestRetrieveOutputBuffer(
+            Request,
+            sizeof(*out),
+            reinterpret_cast<VOID**>(&out),
+            NULL
+            );
+        if (!NT_SUCCESS(status)) {
+            goto err3;
+        }
+
+        RtlCopyMemory(out, &adapter->GetDevice()->Info, sizeof(*out));
+        out->AdapterId = adapter->m_Id;
+        WdfRequestSetInformation(Request, sizeof(*out));
+#ifdef _WIN64
+    }
+#endif // _WIN64
+
+err3:
+    adapter->Release();
+err2:
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+ND_ADAPTER::QueryAddressList(
+    __in ND_PROVIDER *pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    NDFLTR_QUERY_ADDRESS_LIST* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Header.Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    SOCKADDR_INET* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        0,
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (status == STATUS_BUFFER_TOO_SMALL) {
+        out = NULL;
+        outLen = 0;
+    } else if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    pProvider->LockShared();
+
+    ND_ADAPTER* adapter;
+    status = pProvider->GetAdapter(in->Header.Handle, &adapter);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    ULONG max = static_cast<ULONG>((outLen) / sizeof(SOCKADDR_INET));
+    ULONG count = max;
+
+    status = adapter->GetProvider()->GetPartition()->GetIpList(
+        adapter->GetInterface()->driver_id,
+        adapter->m_Id,
+        &count,
+        out
+        );
+    if (status == STATUS_MORE_ENTRIES) {
+        outLen = sizeof(*out) * max;
+    } else if (!NT_ERROR(status)) {
+        outLen = sizeof(*out) * count;
+    } else {
+        outLen = 0;
+    }
+    WdfRequestSetInformation(Request, outLen);
+
+    adapter->Release();
+err2:
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
Index: core/ndfltr/kernel/nd_util.h
===================================================================
--- core/ndfltr/kernel/nd_util.h	(revision 0)
+++ core/ndfltr/kernel/nd_util.h	(revision 0)
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE ANd
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_UTIL_H_
+#define _ND_UTIL_H_
+
+
+template<typename T> void* operator new(size_t, T* instance) { return instance; }
+
+#define HANDLE_TABLE_POOL_TAG 'thdn'
+
+template<typename T> class HANDLE_TABLE
+{
+    union ENTRY {
+            T*      object;
+            SSIZE_T nextFree;
+    };
+
+    ENTRY*          Table;
+    SSIZE_T         FirstFree;
+    SSIZE_T         Size;
+    ERESOURCE       Lock;
+
+    static const SSIZE_T GROW_SIZE = PAGE_SIZE / sizeof(ENTRY);
+
+private:
+    bool Valid(UINT64 index)
+    {
+        if (index >= static_cast<UINT64>(Size)) {
+            return false;
+        }
+
+        if (Table[index].nextFree >= 0) {
+            return false;
+        }
+        return true;
+    }
+
+    bool Grow()
+    {
+        if (Size > (LONG_MAX - GROW_SIZE)) {
+            return false;
+        }
+
+        ENTRY* newTable = reinterpret_cast<ENTRY*>(ExAllocatePoolWithTag(
+            NonPagedPool,
+            sizeof(ENTRY) * (Size + GROW_SIZE),
+            HANDLE_TABLE_POOL_TAG)
+            );
+        if (newTable == NULL) {
+            return false;
+        }
+
+        if (Table != NULL) {
+            RtlCopyMemory(newTable, Table, Size * sizeof(ENTRY));
+            ExFreePoolWithTag(Table, HANDLE_TABLE_POOL_TAG);
+        }
+        Table = newTable;
+
+        Size += GROW_SIZE;
+        for (SSIZE_T i = FirstFree; i < Size; i++) {
+            Table[i].nextFree = (i + 1);
+        }
+        return true;
+    }
+
+    static inline SSIZE_T HandleToIndex(UINT64 handle)
+    {
+        return static_cast<SSIZE_T>(handle - 1);
+    }
+
+    static inline UINT64 IndexToHandle(SSIZE_T index)
+    {
+        return static_cast<UINT64>(index + 1);
+    }
+
+    inline void FreeIndex(SSIZE_T index)
+    {
+        Table[index].nextFree = FirstFree;
+        FirstFree = index;
+    }
+
+public:
+    HANDLE_TABLE<T>()
+        : Table(NULL),
+        FirstFree(0),
+        Size(0)
+    {
+        ExInitializeResourceLite(&Lock);
+    }
+    
+    ~HANDLE_TABLE<T>()
+    {
+        if (Table != NULL) {
+            ExFreePoolWithTag(Table, HANDLE_TABLE_POOL_TAG);
+        }
+        ExDeleteResourceLite(&Lock);
+    }
+
+    void LockShared()
+    {
+        KeEnterCriticalRegion();
+        ExAcquireResourceSharedLite(&Lock, TRUE);
+    }
+
+    void LockExclusive()
+    {
+        KeEnterCriticalRegion();
+        ExAcquireResourceExclusiveLite(&Lock, TRUE);
+    }
+
+    void Unlock()
+    {
+        ExReleaseResourceLite(&Lock);
+        KeLeaveCriticalRegion();
+    }
+
+    T* At(UINT64 handle)
+    {
+        SSIZE_T index = HandleToIndex(handle);
+        if (Valid(index) == false) {
+            return NULL;
+        }
+
+        return Table[index].object;
+    }
+
+    UINT64 Reserve()
+    {
+        if (FirstFree == Size && Grow() == false) {
+            return 0;
+        }
+
+        SSIZE_T index = FirstFree;
+        FirstFree = Table[FirstFree].nextFree;
+        return IndexToHandle(index);
+    }
+
+    void Free(UINT64 handle)
+    {
+        FreeIndex(HandleToIndex(handle));
+    }
+
+    void Set(UINT64 handle, T* object)
+    {
+        SSIZE_T index = HandleToIndex(handle);
+        Table[index].object = object;
+    }
+
+    void Erase(UINT64 handle)
+    {
+        SSIZE_T index = HandleToIndex(handle);
+        NT_ASSERT(Valid(index));
+        FreeIndex(index);
+    }
+
+    UINT64 Insert(T* object)
+    {
+        UINT64 handle = Reserve();
+        if (handle != 0) {
+            Set(handle, object);
+        }
+
+        return handle;
+    }
+
+    template<typename F> void Iterate(F functor)
+    {
+        for (SSIZE_T index = 0; index < Size; index++) {
+            if (Valid(index) == true) {
+                if (functor(Table[index].object) == true) {
+                    FreeIndex(index);
+                }
+            }
+        }
+    }
+};
+
+
+class ObjBase
+{
+private:
+    KEVENT m_Event;
+    LONG m_nRef;
+    LONG m_UseCount;
+
+public:
+    ObjBase()
+        : m_nRef(1),
+        m_UseCount(0)
+    {
+        KeInitializeEvent(&m_Event, NotificationEvent, FALSE);
+    }
+
+    ~ObjBase()
+    {
+        NT_ASSERT(m_nRef == 0);
+    }
+
+    void Reference()
+    {
+        InterlockedIncrement(&m_nRef);
+    }
+
+    void Dereference()
+    {
+        if (InterlockedDecrement(&m_nRef) == 0) {
+            KeSetEvent(&m_Event, 0, FALSE);
+        }
+    }
+
+    void AddRef()
+    {
+        InterlockedIncrement(&m_UseCount);
+        Reference();
+    }
+
+    void Release()
+    {
+        InterlockedDecrement(&m_UseCount);
+        Dereference();
+    }
+
+    bool Busy() { return m_UseCount != 0; }
+
+    void RunDown()
+    {
+        if (InterlockedDecrement(&m_nRef) > 0) {
+            NT_ASSERT(m_UseCount == 0);
+            KeWaitForSingleObject(&m_Event, Executive, KernelMode, FALSE, NULL);
+        }
+    }
+};
+
+
+template <typename P> class ObjChild : public ObjBase
+{
+    typedef ObjBase _Base;
+
+protected:
+    P* m_pParent;
+    LIST_ENTRY m_Entry;
+
+private:
+    ObjChild() {};
+
+public:
+    ObjChild(P* pParent)
+        : m_pParent(pParent)
+    {
+        pParent->AddRef();
+    }
+
+    ~ObjChild()
+    {
+        m_pParent->Release();
+    }
+
+    static ObjChild* FromEntry(LIST_ENTRY* entry)
+    {
+        return CONTAINING_RECORD(entry, ObjChild, m_Entry);
+    }
+};
+
+
+template <typename P, typename T, typename I> class RdmaResource : public ObjChild<P>
+{
+    typedef ObjChild<P> _Base;
+
+protected:
+    T m_hIfc;
+    I* m_pIfc;
+
+private:
+    RdmaResource() {};
+
+public:
+    RdmaResource(P* pParent, I* pVerbs)
+        : _Base(pParent),
+        m_hIfc(NULL),
+        m_pIfc(pVerbs)
+    {
+    }
+
+    T GetIfcHandle() const { return m_hIfc; }
+    I* GetInterface() const { return m_pIfc; }
+
+    bool Removed() const { return m_pIfc == NULL; }
+
+    void RemoveHandler() { m_hIfc = NULL; m_pIfc = NULL; }
+};
+
+
+template <typename P, typename T, typename I> class RdmaParent : public RdmaResource<P, T, I>
+{
+    typedef RdmaResource<P, T, I> _Base;
+
+protected:
+    KGUARDED_MUTEX m_Lock;
+
+public:
+    RdmaParent(P* pParent, ci_interface_t* pVerbs)
+        : _Base(pParent, pVerbs)
+    {
+       KeInitializeGuardedMutex(&m_Lock);
+    }
+
+    void AddResource(__in LIST_ENTRY* list, LIST_ENTRY* entry)
+    {
+        KeAcquireGuardedMutex(&m_Lock);
+        InsertTailList(list, entry);
+        KeReleaseGuardedMutex(&m_Lock);
+    }
+
+    void RemoveResource(__in LIST_ENTRY* entry)
+    {
+        KeAcquireGuardedMutex(&m_Lock);
+        RemoveEntryList(entry);
+        KeReleaseGuardedMutex(&m_Lock);
+    }
+};
+
+
+template<typename T> class DisposeFunctor
+{
+public:
+    bool operator () (T* obj)
+    {
+        obj->Dispose();
+        return true;
+    }
+};
+
+
+
+#endif // _ND_UTIL_H_
Index: core/ndfltr/kernel/nd_mr.h
===================================================================
--- core/ndfltr/kernel/nd_mr.h	(revision 0)
+++ core/ndfltr/kernel/nd_mr.h	(revision 0)
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_MR_H_
+#define _ND_MR_H_
+
+#define ND_MEMORY_REGION_TAG 'rmdn'
+
+class ND_MEMORY_REGION
+    : public RdmaResource<ND_PROTECTION_DOMAIN, ib_mr_handle_t, ci_interface_t>
+{
+    typedef RdmaResource<ND_PROTECTION_DOMAIN, ib_mr_handle_t, ci_interface_t> _Base;
+
+    KGUARDED_MUTEX                          m_Lock;
+    net32_t                                 m_LKey;
+    net32_t                                 m_RKey;
+
+private:
+    ND_MEMORY_REGION(__in ND_PROTECTION_DOMAIN* pPd);
+    ~ND_MEMORY_REGION();
+    NTSTATUS Initialize(
+        KPROCESSOR_MODE RequestorMode,
+        __inout ci_umv_buf_t* pVerbsData
+        );
+
+public:
+    static
+    NTSTATUS
+    Create(
+        __in ND_PROTECTION_DOMAIN* pPd,
+        KPROCESSOR_MODE RequestorMode,
+        __inout ci_umv_buf_t* pVerbsData,
+        __out ND_MEMORY_REGION** ppMr
+        );
+
+    void Dispose();
+
+    void RemoveHandler();
+
+    NTSTATUS Register(
+        UINT64 Address,
+        UINT64 TargetAddress,
+        UINT64 Length,
+        ULONG Flags,
+        KPROCESSOR_MODE RequestorMode,
+        __out NDFLTR_MR_KEYS* pKeys
+        );
+
+    NTSTATUS Deregister();
+
+    bool Busy();
+};
+
+FN_REQUEST_HANDLER NdMrCreate;
+FN_REQUEST_HANDLER NdMrFree;
+FN_REQUEST_HANDLER NdMrCancelIo;
+FN_REQUEST_HANDLER NdMrRegister;
+FN_REQUEST_HANDLER NdMrDeregister;
+FN_REQUEST_HANDLER NdMrRegisterPages;
+
+#endif // _ND_MR_H_
Index: core/ndfltr/kernel/nd_qp.h
===================================================================
--- core/ndfltr/kernel/nd_qp.h	(revision 0)
+++ core/ndfltr/kernel/nd_qp.h	(revision 0)
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_QP_H_
+#define _ND_QP_H_
+
+#define ND_QUEUE_PAIR_TAG 'pqdn'
+
+class ND_QUEUE_PAIR
+    : public RdmaResource<ND_PROTECTION_DOMAIN, ib_qp_handle_t, ci_interface_t>
+{
+    typedef RdmaResource<ND_PROTECTION_DOMAIN, ib_qp_handle_t, ci_interface_t> _Base;
+
+    ND_COMPLETION_QUEUE                 *m_pInitiatorCq;
+    ND_COMPLETION_QUEUE                 *m_pReceiveCq;
+    ND_SHARED_RECEIVE_QUEUE             *m_pSrq;
+    ND_ENDPOINT                         *m_pEp;
+    UINT32                              m_Qpn;
+
+    LONG                                m_EpBound;
+
+private:
+    ND_QUEUE_PAIR(
+        __in ND_PROTECTION_DOMAIN* pPd,
+        __in ND_COMPLETION_QUEUE* pReceiveCq,
+        __in ND_COMPLETION_QUEUE* pInitiatorCq,
+        __in ND_SHARED_RECEIVE_QUEUE* pSrq
+        );
+    ~ND_QUEUE_PAIR();
+    NTSTATUS Initialize(
+        KPROCESSOR_MODE RequestorMode,
+        ULONG InitiatorQueueDepth,
+        ULONG MaxInitiatorRequestSge,
+        ULONG ReceiveQueueDepth,
+        ULONG MaxReceiveRequestSge,
+        ULONG MaxInlineDataSize,
+        __inout ci_umv_buf_t* pVerbsData
+        );
+
+public:
+    static
+    NTSTATUS
+    Create(
+        __in ND_PROTECTION_DOMAIN* pPd,
+        KPROCESSOR_MODE RequestorMode,
+        __in ND_COMPLETION_QUEUE* pReceiveCq,
+        __in ND_COMPLETION_QUEUE* pInitiatorCq,
+        __in ND_SHARED_RECEIVE_QUEUE* pSrq,
+        ULONG InitiatorQueueDepth,
+        ULONG MaxInitiatorRequestSge,
+        ULONG ReceiveQueueDepth,
+        ULONG MaxReceiveRequestSge,
+        ULONG MaxInlineDataSize,
+        __inout ci_umv_buf_t* pVerbsData,
+        __out ND_QUEUE_PAIR** ppQp
+        );
+
+    void Dispose();
+
+    void RemoveHandler();
+
+    NTSTATUS Modify(ib_qp_mod_t* pMod, BYTE* pOutBuf, ULONG OutLen);
+    NTSTATUS Flush(__out_opt BYTE* pOutBuf, ULONG OutLen);
+
+    NTSTATUS BindEp(__in ND_ENDPOINT* pEp)
+    {
+        LONG bound = InterlockedCompareExchange(&m_EpBound, 1, 0);
+        if (bound != 0) {
+            return STATUS_CONNECTION_ACTIVE;
+        }
+
+        pEp->Reference();
+        m_pEp = pEp;
+        return STATUS_SUCCESS;
+    }
+
+    ND_ENDPOINT* ClearEp()
+    {
+        ND_ENDPOINT* ep = reinterpret_cast<ND_ENDPOINT*>(
+            InterlockedExchangePointer(reinterpret_cast<VOID**>(&m_pEp), NULL)
+            );
+        return ep;
+    }
+
+    void UnbindEp()
+    {
+        InterlockedExchange(&m_EpBound, 0);
+    }
+
+    UINT32 Qpn() const { return m_Qpn; }
+
+    bool HasSrq() const { return m_pSrq != NULL; }
+
+private:
+    static void EventHandler(ib_event_rec_t* pEvent);
+};
+
+FN_REQUEST_HANDLER NdQpCreate;
+FN_REQUEST_HANDLER NdQpCreateWithSrq;
+FN_REQUEST_HANDLER NdQpFree;
+FN_REQUEST_HANDLER NdQpFlush;
+
+#endif // _ND_QP_H_
Index: core/ndfltr/kernel/nd_mw.h
===================================================================
--- core/ndfltr/kernel/nd_mw.h	(revision 0)
+++ core/ndfltr/kernel/nd_mw.h	(revision 0)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_MW_H_
+#define _ND_MW_H_
+
+#define ND_MEMORY_WINDOW_TAG 'wmdn'
+
+class ND_MEMORY_WINDOW
+    : public RdmaResource<ND_PROTECTION_DOMAIN, ib_mw_handle_t, ci_interface_t>
+{
+    typedef RdmaResource<ND_PROTECTION_DOMAIN, ib_mw_handle_t, ci_interface_t> _Base;
+
+    net32_t                                 m_RKey;
+
+private:
+    ND_MEMORY_WINDOW(__in ND_PROTECTION_DOMAIN* pPd);
+    ~ND_MEMORY_WINDOW();
+    NTSTATUS Initialize(
+        KPROCESSOR_MODE RequestorMode,
+        __inout ci_umv_buf_t* pVerbsData
+        );
+
+public:
+    static
+    NTSTATUS
+    Create(
+        __in ND_PROTECTION_DOMAIN* pPd,
+        KPROCESSOR_MODE RequestorMode,
+        __inout ci_umv_buf_t* pVerbsData,
+        __out ND_MEMORY_WINDOW** ppMw
+        );
+
+    void Dispose();
+
+    void RemoveHandler();
+};
+
+FN_REQUEST_HANDLER NdMwCreate;
+FN_REQUEST_HANDLER NdMwFree;
+
+#endif // _ND_MW_H_
Index: core/ndfltr/kernel/precomp.h
===================================================================
--- core/ndfltr/kernel/precomp.h	(revision 0)
+++ core/ndfltr/kernel/precomp.h	(revision 0)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#include <ntifs.h>
+#include <wdm.h>
+#include <wdf.h>
+#include <WinDef.h>
+#include <ntstatus.h>
+#include <ntstrsafe.h>
+#include <ndstatus.h>
+#include <limits.h>
+#include <netioapi.h>
+
+#include <iba\ib_types.h>
+#include <iba\ib_ci.h>
+#include <iba\ib_cm_ifc.h>
+#include <iba\ibat_ifc.h>
+#include <iba\ib_rdma_cm.h>
+#include <rdma\verbs.h>
+
+#include "ndfltr.h"
+#include "nd_util.h"
+#include "nd_decl.h"
+#include "nd_partition.h"
+#include "nd_adapter.h"
+#include "nd_ep.h"
+#include "nd_cq.h"
+#include "nd_pd.h"
+#include "nd_mr.h"
+#include "nd_mw.h"
+#include "nd_srq.h"
+#include "nd_qp.h"
+#include "nd_provider.h"
+#include "nd_driver.h"
Index: core/ndfltr/kernel/ndfltr.rc
===================================================================
--- core/ndfltr/kernel/ndfltr.rc	(revision 0)
+++ core/ndfltr/kernel/ndfltr.rc	(revision 0)
@@ -0,0 +1,44 @@
+/*
+ * 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 AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <oib_ver.h>
+
+#define VER_FILETYPE				VFT_DRV
+#define VER_FILESUBTYPE				VFT2_DRV_SYSTEM
+
+#ifdef _DEBUG_
+#define VER_FILEDESCRIPTION_STR		"NetworkDirect Support Filter Driver (Debug)"
+#else
+#define VER_FILEDESCRIPTION_STR		"NetworkDirect Support Filter Driver"
+#endif
+
+#define VER_INTERNALNAME_STR		"ndfltr.sys"
+#define VER_ORIGINALFILENAME_STR	"ndfltr.sys"
+
+#include <common.ver>
Index: core/ndfltr/kernel/nd_provider.h
===================================================================
--- core/ndfltr/kernel/nd_provider.h	(revision 0)
+++ core/ndfltr/kernel/nd_provider.h	(revision 0)
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_PROVIDER_H_
+#define _ND_PROVIDER_H_
+
+
+#define ND_PROVIDER_POOL_TAG 'rpdn'
+
+class ND_PROVIDER : public ObjChild<ND_PARTITION>
+{
+    typedef ObjChild<ND_PARTITION> _Base;
+
+    HANDLE_TABLE<ND_ADAPTER>                m_AdapterTable;
+    HANDLE_TABLE<ND_COMPLETION_QUEUE>       m_CqTable;
+    HANDLE_TABLE<ND_PROTECTION_DOMAIN>      m_PdTable;
+    HANDLE_TABLE<ND_MEMORY_REGION>          m_MrTable;
+    HANDLE_TABLE<ND_SHARED_RECEIVE_QUEUE>   m_SrqTable;
+    HANDLE_TABLE<ND_QUEUE_PAIR>             m_QpTable;
+    HANDLE_TABLE<ND_MEMORY_WINDOW>          m_MwTable;
+    HANDLE_TABLE<ND_ENDPOINT>               m_EpTable;
+
+    ERESOURCE                               m_Lock;
+    LONG                                    m_nFiles;
+
+private:
+    ND_PROVIDER(__in ND_PARTITION* pPartition);
+    ~ND_PROVIDER();
+
+    template <typename T> NTSTATUS Get(HANDLE_TABLE<T>& Table, UINT64 Handle, T** ppObj)
+    {
+        NTSTATUS status;
+
+        Table.LockShared();
+        T* obj = Table.At(Handle);
+        if (obj == NULL) {
+            status = STATUS_INVALID_HANDLE;
+        } else if (obj->Removed()) {
+            status = STATUS_DEVICE_REMOVED;
+        } else {
+            obj->AddRef();
+            *ppObj = obj;
+            status = STATUS_SUCCESS;
+        }
+        Table.Unlock();
+        return status;
+    }
+
+    template <typename T> UINT64 Add(HANDLE_TABLE<T>& Table, T* pObj)
+    {
+        Table.LockExclusive();
+        UINT64 handle = Table.Insert(pObj);
+        Table.Unlock();
+        return handle;
+    }
+
+    template <typename T> NTSTATUS Free(HANDLE_TABLE<T>& Table, UINT64 Handle)
+    {
+        NTSTATUS status;
+        Table.LockExclusive();
+        T* obj = Table.At(Handle);
+        if (obj == NULL) {
+            status = STATUS_INVALID_HANDLE;
+        } else if (obj->Busy()) {
+            status = STATUS_DEVICE_BUSY;
+        } else {
+            Table.Erase(Handle);
+            status = STATUS_SUCCESS;
+        }
+        Table.Unlock();
+
+        if (NT_SUCCESS(status)) {
+            obj->Dispose();
+        }
+        return status;
+    }
+
+public:
+    static NTSTATUS Create(__in ND_PARTITION* pPartition, __out ND_PROVIDER** ppProvider);
+
+    void Dispose();
+
+    NTSTATUS Bind(UINT64 Handle, FILE_OBJECT* File)
+    {
+        InterlockedIncrement(&m_nFiles);
+        VOID* prov = InterlockedCompareExchangePointer(
+                &File->FsContext,
+                reinterpret_cast<VOID*>(Handle),
+                NULL
+                );
+
+        if (prov != NULL) {
+            InterlockedDecrement(&m_nFiles);
+            return STATUS_INVALID_PARAMETER;
+        }
+
+        return STATUS_SUCCESS;
+    }
+
+    NTSTATUS Bind(UINT64 Handle, WDFFILEOBJECT File)
+    {
+        return Bind(Handle, WdfFileObjectWdmGetFileObject(File));
+    }
+
+    LONG Unbind(FILE_OBJECT* File)
+    {
+        InterlockedExchangePointer(&File->FsContext, NULL);
+        return InterlockedDecrement(&m_nFiles);
+    }
+
+    LONG Unbind(WDFFILEOBJECT File)
+    {
+        return Unbind(WdfFileObjectWdmGetFileObject(File));
+    }
+
+    static __inline UINT64 HandleFromFile(WDFFILEOBJECT File)
+    {
+        DEVICE_OBJECT* pDevObj = IoGetRelatedDeviceObject(WdfFileObjectWdmGetFileObject(File));
+        if (pDevObj != WdfDeviceWdmGetDeviceObject(ControlDevice)) {
+            return 0;
+        }
+        return reinterpret_cast<ULONG_PTR>(WdfFileObjectWdmGetFileObject(File)->FsContext);
+    }
+
+    void RemoveHandler(ND_RDMA_DEVICE* pDevice);
+
+    void LockExclusive();
+
+    void LockShared();
+
+    void Unlock();
+
+    ND_PARTITION* GetPartition() const { return m_pParent; }
+
+    inline UINT64 AddAdapter(__in ND_ADAPTER* pAdapter)
+    {
+        return Add<ND_ADAPTER>(m_AdapterTable, pAdapter);
+    }
+
+    inline NTSTATUS GetAdapter(UINT64 Id, __out ND_ADAPTER** ppAdapter)
+    {
+        return Get<ND_ADAPTER>(m_AdapterTable, Id, ppAdapter);
+    }
+
+    inline NTSTATUS FreeAdapter(__in UINT64 Handle)
+    {
+        return Free<ND_ADAPTER>(m_AdapterTable, Handle);
+    }
+
+    inline UINT64 AddCq(__in ND_COMPLETION_QUEUE* pCq)
+    {
+        return Add<ND_COMPLETION_QUEUE>(m_CqTable, pCq);
+    }
+
+    inline NTSTATUS GetCq(UINT64 Id, __out ND_COMPLETION_QUEUE** ppCq)
+    {
+        return Get<ND_COMPLETION_QUEUE>(m_CqTable, Id, ppCq);
+    }
+
+    inline NTSTATUS FreeCq(__in UINT64 Handle)
+    {
+        return Free<ND_COMPLETION_QUEUE>(m_CqTable, Handle);
+    }
+
+    inline UINT64 AddPd(__in ND_PROTECTION_DOMAIN* pPd)
+    {
+        return Add<ND_PROTECTION_DOMAIN>(m_PdTable, pPd);
+    }
+
+    inline NTSTATUS GetPd(UINT64 Id, __out ND_PROTECTION_DOMAIN** ppPd)
+    {
+        return Get<ND_PROTECTION_DOMAIN>(m_PdTable, Id, ppPd);
+    }
+
+    inline NTSTATUS FreePd(__in UINT64 Handle)
+    {
+        return Free<ND_PROTECTION_DOMAIN>(m_PdTable, Handle);
+    }
+
+    inline UINT64 AddMr(__in ND_MEMORY_REGION* pMr)
+    {
+        return Add<ND_MEMORY_REGION>(m_MrTable, pMr);
+    }
+
+    inline NTSTATUS GetMr(UINT64 Id, __out ND_MEMORY_REGION** ppMr)
+    {
+        return Get<ND_MEMORY_REGION>(m_MrTable, Id, ppMr);
+    }
+
+    inline NTSTATUS FreeMr(__in UINT64 Handle)
+    {
+        return Free<ND_MEMORY_REGION>(m_MrTable, Handle);
+    }
+
+    inline UINT64 AddSrq(__in ND_SHARED_RECEIVE_QUEUE* pSrq)
+    {
+        return Add<ND_SHARED_RECEIVE_QUEUE>(m_SrqTable, pSrq);
+    }
+
+    inline NTSTATUS GetSrq(UINT64 Id, __out ND_SHARED_RECEIVE_QUEUE** ppSrq)
+    {
+        return Get<ND_SHARED_RECEIVE_QUEUE>(m_SrqTable, Id, ppSrq);
+    }
+
+    inline NTSTATUS FreeSrq(__in UINT64 Handle)
+    {
+        return Free<ND_SHARED_RECEIVE_QUEUE>(m_SrqTable, Handle);
+    }
+
+    inline UINT64 AddQp(__in ND_QUEUE_PAIR* pQp)
+    {
+        return Add<ND_QUEUE_PAIR>(m_QpTable, pQp);
+    }
+
+    inline NTSTATUS GetQp(UINT64 Id, __out ND_QUEUE_PAIR** ppQp)
+    {
+        return Get<ND_QUEUE_PAIR>(m_QpTable, Id, ppQp);
+    }
+
+    inline NTSTATUS FreeQp(__in UINT64 Handle)
+    {
+        return Free<ND_QUEUE_PAIR>(m_QpTable, Handle);
+    }
+
+    inline UINT64 AddMw(__in ND_MEMORY_WINDOW* pMw)
+    {
+        return Add<ND_MEMORY_WINDOW>(m_MwTable, pMw);
+    }
+
+    inline NTSTATUS GetMw(UINT64 Id, __out ND_MEMORY_WINDOW** ppMw)
+    {
+        return Get<ND_MEMORY_WINDOW>(m_MwTable, Id, ppMw);
+    }
+
+    inline NTSTATUS FreeMw(__in UINT64 Handle)
+    {
+        return Free<ND_MEMORY_WINDOW>(m_MwTable, Handle);
+    }
+
+    inline UINT64 AddEp(__in ND_ENDPOINT* pEp)
+    {
+        return Add<ND_ENDPOINT>(m_EpTable, pEp);
+    }
+
+    inline NTSTATUS GetEp(UINT64 Id, __out ND_ENDPOINT** ppEp)
+    {
+        return Get<ND_ENDPOINT>(m_EpTable, Id, ppEp);
+    }
+
+    inline NTSTATUS FreeEp(__in UINT64 Handle)
+    {
+        return Free<ND_ENDPOINT>(m_EpTable, Handle);
+    }
+
+public:
+    static FN_REQUEST_HANDLER ResolveAddress;
+    static FN_REQUEST_HANDLER QueryAddressList;
+};
+
+FN_REQUEST_HANDLER NdProviderBindFile;
+
+#endif // _ND_PROVIDER_H_
Index: core/ndfltr/kernel/nd_driver.h
===================================================================
--- core/ndfltr/kernel/nd_driver.h	(revision 0)
+++ core/ndfltr/kernel/nd_driver.h	(revision 0)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE ANd
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_DRIVER_H_
+#define _ND_DRIVER_H_
+
+
+class ND_DRIVER
+{
+    LIST_ENTRY                  m_DevList;
+    HANDLE_TABLE<ND_PARTITION>  m_PartitionTable;
+    HANDLE_TABLE<ND_PROVIDER>   m_ProvTable;
+    KGUARDED_MUTEX              m_Lock;
+    ND_PARTITION                m_Partition0;
+
+public:
+    ND_DRIVER();
+    ~ND_DRIVER();
+
+    ND_RDMA_DEVICE* GetRdmaDevice(UINT64 AdapterId);
+    ND_PROVIDER* GetProvider(UINT64 Handle);
+    ND_PARTITION* GetPartition(UINT64 Handle, bool InternalDeviceControl);
+    NTSTATUS FreePartition(UINT64 Handle);
+
+    NTSTATUS ResolveAddress(const SOCKADDR_INET& Addr, const GUID& DriverId, UINT64* pId);
+    void FreeProvider(WDFFILEOBJECT FileObject);
+    NTSTATUS AddDevice(ND_RDMA_DEVICE* pDev);
+
+    void RemoveHandler(ND_RDMA_DEVICE* pDev);
+
+public:
+    static FN_REQUEST_HANDLER InitProvider;
+    static FN_REQUEST_HANDLER CreatePartition;
+};
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ND_DRIVER, NdDriverGetContext);
+
+ND_RDMA_DEVICE* NdRdmaDeviceGet( UINT64 AdapterId );
+void NdRdmaDevicePut(ND_RDMA_DEVICE *pDevice);
+
+void NdDisableRemove();
+void NdEnableRemove();
+void NdLockRemove();
+
+static inline void NdInitVerbsData(ci_umv_buf_t *pVerbsData,
+                                   SIZE_T InputLength, SIZE_T OutputLength,
+                                   void *pBuffer)
+{
+    pVerbsData->command = TRUE;
+    pVerbsData->input_size = (UINT32) InputLength;
+    pVerbsData->output_size = (UINT32) OutputLength;
+    pVerbsData->p_inout_buf = (ULONG_PTR) pBuffer;
+    pVerbsData->status = 0;
+}
+
+void NdCompleteRequests(WDFQUEUE Queue, NTSTATUS ReqStatus);
+void NdFlushQueue(WDFQUEUE Queue, NTSTATUS ReqStatus);
+void NdCompleteRequestsWithInformation(WDFQUEUE Queue, NTSTATUS ReqStatus);
+
+#endif // _ND_DRIVER_H_
Index: core/ndfltr/kernel/nd_cq.cpp
===================================================================
--- core/ndfltr/kernel/nd_cq.cpp	(revision 0)
+++ core/ndfltr/kernel/nd_cq.cpp	(revision 0)
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+
+void ND_COMPLETION_QUEUE::EventHandler(ib_event_rec_t *pEvent)
+{
+    ND_COMPLETION_QUEUE* cq = reinterpret_cast<ND_COMPLETION_QUEUE*>(pEvent->context);
+    if (pEvent->type == IB_AE_CQ_OVERFLOW) {
+        cq->m_Status = STATUS_DATA_OVERRUN;
+    } else {
+        cq->m_Status = STATUS_INTERNAL_ERROR;
+    }
+    NdFlushQueue(cq->m_Queue, cq->m_Status);
+    NdFlushQueue(cq->m_ErrorQueue, cq->m_Status);
+}
+
+
+void ND_COMPLETION_QUEUE::CompletionHandler(void *Context)
+{
+    ND_COMPLETION_QUEUE* cq = reinterpret_cast<ND_COMPLETION_QUEUE*>(Context);
+    NdFlushQueue(cq->m_Queue, STATUS_SUCCESS);
+}
+
+
+ND_COMPLETION_QUEUE::ND_COMPLETION_QUEUE(
+    __in ND_ADAPTER* pAdapter,
+    WDFQUEUE queue,
+    WDFQUEUE errorQueue
+    )
+    : _Base(pAdapter, pAdapter->GetInterface()),
+    m_Queue(queue),
+    m_ErrorQueue(errorQueue),
+    m_Status(STATUS_SUCCESS)
+{
+    pAdapter->AddCq(&m_Entry);
+}
+
+
+ND_COMPLETION_QUEUE::~ND_COMPLETION_QUEUE()
+{
+    _Base::RunDown();
+
+    m_pParent->RemoveCq(&m_Entry);
+
+    if (m_hIfc != NULL) {
+        m_pIfc->destroy_cq(m_hIfc);
+    }
+
+    WdfIoQueuePurgeSynchronously(m_Queue);
+    WdfIoQueuePurgeSynchronously(m_ErrorQueue);
+    WdfObjectDelete(m_Queue);
+    WdfObjectDelete(m_ErrorQueue);
+}
+
+
+NTSTATUS
+ND_COMPLETION_QUEUE::Initialize(
+    KPROCESSOR_MODE /*RequestorMode*/,
+    ULONG QueueDepth,
+    const GROUP_AFFINITY&,
+    __inout ci_umv_buf_t* pVerbsData
+    )
+{
+    //TODO: Use affinity settings.
+    ib_api_status_t ibStatus = m_pIfc->create_cq(
+        m_pParent->GetIfcHandle(),
+        this,
+        EventHandler,
+        CompletionHandler,
+        reinterpret_cast<uint32_t*>(&QueueDepth),
+        &m_hIfc,
+        pVerbsData
+        );
+    if (ibStatus != IB_SUCCESS) {
+        return STATUS_UNSUCCESSFUL;
+    }
+    return STATUS_SUCCESS;
+}
+
+
+//static
+NTSTATUS
+ND_COMPLETION_QUEUE::Create(
+    __in ND_ADAPTER* pAdapter,
+    KPROCESSOR_MODE RequestorMode,
+    ULONG QueueDepth,
+    const GROUP_AFFINITY& Affinity,
+    __inout ci_umv_buf_t* pVerbsData,
+    __out ND_COMPLETION_QUEUE** ppCq
+    )
+{
+    //TODO: Should really use ExAllocatePoolWithQuotaTag here, since we're allocating this on
+    // behalf of the user.
+    ND_COMPLETION_QUEUE* cq = reinterpret_cast<ND_COMPLETION_QUEUE*>(
+        ExAllocatePoolWithTag(NonPagedPool, sizeof(*cq), ND_COMPLETION_Q_POOL_TAG)
+        );
+    if (cq == NULL) {
+        return STATUS_NO_MEMORY;
+    }
+
+    WDFQUEUE queue;
+    WDF_IO_QUEUE_CONFIG config;
+    WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual);
+    NTSTATUS status = WdfIoQueueCreate(
+        ControlDevice,
+        &config,
+        WDF_NO_OBJECT_ATTRIBUTES,
+        &queue
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    WDFQUEUE errorQueue;
+    status = WdfIoQueueCreate(
+        ControlDevice,
+        &config,
+        WDF_NO_OBJECT_ATTRIBUTES,
+        &errorQueue
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    new(cq) ND_COMPLETION_QUEUE(pAdapter, queue, errorQueue);
+    status = cq->Initialize(RequestorMode, QueueDepth, Affinity, pVerbsData);
+    if (!NT_SUCCESS(status)) {
+        cq->Dispose();
+        return status;
+    }
+
+    *ppCq = cq;
+    return STATUS_SUCCESS;
+
+err2:
+    WdfObjectDelete(queue);
+err1:
+    ExFreePoolWithTag(cq, ND_COMPLETION_Q_POOL_TAG);
+    return status;
+}
+
+
+void ND_COMPLETION_QUEUE::Dispose()
+{
+    this->ND_COMPLETION_QUEUE::~ND_COMPLETION_QUEUE();
+    ExFreePoolWithTag(this, ND_COMPLETION_Q_POOL_TAG);
+}
+
+
+void ND_COMPLETION_QUEUE::RemoveHandler()
+{
+    if (m_hIfc != NULL) {
+        m_pIfc->destroy_cq(m_hIfc);
+    }
+    _Base::RemoveHandler();
+}
+
+
+void
+NdCqCreate(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_CREATE_CQ* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    //
+    // We expect the vendor data to be in the same place in the input and
+    // output buffers.  The input buffer is larger, so we use it as the
+    // minimum length when querying the output buffer.
+    //
+    ND_RESOURCE_DESCRIPTOR* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    ci_umv_buf_t verbsData;
+    NdInitVerbsData(&verbsData, inLen - sizeof(*in),
+                    outLen - sizeof(*in), in + 1);
+
+    pProvider->LockShared();
+
+    ND_ADAPTER *adapter;
+    status = pProvider->GetAdapter(in->AdapterHandle, &adapter);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    ND_COMPLETION_QUEUE *cq;
+    status = ND_COMPLETION_QUEUE::Create(
+        adapter,
+        WdfRequestGetRequestorMode(Request),
+        in->QueueDepth,
+        in->Affinity,
+        &verbsData,
+        &cq
+        );
+
+    if (!NT_SUCCESS(status)) {
+        goto err3;
+    }
+
+    out->Handle = pProvider->AddCq(cq);
+    if (out->Handle == 0) {
+        cq->Dispose();
+        status = STATUS_INSUFFICIENT_RESOURCES;
+    } else {
+        WdfRequestSetInformation(Request, outLen);
+    }
+
+err3:
+    adapter->Release();
+err2:
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdCqFree(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    pProvider->LockShared();
+    status = pProvider->FreeCq(in->Handle);
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+void ND_COMPLETION_QUEUE::CancelIo()
+{
+    WdfIoQueuePurgeSynchronously(m_Queue);
+    WdfIoQueuePurgeSynchronously(m_ErrorQueue);
+    WdfIoQueueStart(m_Queue);
+    WdfIoQueueStart(m_ErrorQueue);
+}
+
+
+void
+NdCqCancelIo(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    pProvider->LockShared();
+    ND_COMPLETION_QUEUE* cq;
+    status = pProvider->GetCq(in->Handle, &cq);
+    pProvider->Unlock();
+
+    if (NT_SUCCESS(status)) {
+        cq->CancelIo();
+        cq->Release();
+    }
+
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdCqGetAffinity(
+    __in ND_PROVIDER* /*pProvider*/,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    WdfRequestComplete(Request, STATUS_NOT_SUPPORTED);
+}
+
+
+NTSTATUS ND_COMPLETION_QUEUE::Modify(
+    ULONG QueueDepth,
+    __in ci_umv_buf_t* pVerbsData
+    )
+{
+    ib_api_status_t ibStatus = m_pIfc->resize_cq(
+        m_hIfc,
+        reinterpret_cast<uint32_t*>(QueueDepth),
+        pVerbsData
+        );
+
+    if (ibStatus != IB_SUCCESS) {
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+void
+NdCqModify(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_CQ_MODIFY* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    //
+    // We expect the vendor data to be in the same place in the input and
+    // output buffers.  The input buffer is larger, so we use it as the
+    // minimum length when querying the output buffer.
+    //
+    ND_RESOURCE_DESCRIPTOR* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    ci_umv_buf_t verbsData;
+    NdInitVerbsData(&verbsData, inLen - sizeof(*in),
+                    outLen - sizeof(*in), in + 1);
+
+    pProvider->LockShared();
+
+    ND_COMPLETION_QUEUE* cq;
+    status = pProvider->GetCq(in->CqHandle, &cq);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    status = cq->Modify(in->QueueDepth, &verbsData);
+    cq->Release();
+
+    if (NT_SUCCESS(status)) {
+        out->Handle = 0;
+        WdfRequestSetInformation(Request, outLen);
+    }
+
+err2:
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+NTSTATUS ND_COMPLETION_QUEUE::Notify(WDFREQUEST Request, ULONG Type)
+{
+    //TODO: Call into the verbs provider to arm the CQ.  Current design requires arming
+    // in user-mode.
+    WDFQUEUE queue = (Type == ND_CQ_NOTIFY_ERRORS) ? m_ErrorQueue : m_Queue;
+    NTSTATUS status = WdfRequestForwardToIoQueue(Request, queue);
+    if (NT_SUCCESS(status) && !NT_SUCCESS(m_Status)) {
+        NdFlushQueue(queue, m_Status);
+    }
+    return status;
+}
+
+
+void
+NdCqNotify(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_CQ_NOTIFY* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    pProvider->LockShared();
+
+    ND_COMPLETION_QUEUE* cq;
+    status = pProvider->GetCq(in->CqHandle, &cq);
+    if (NT_SUCCESS(status)) {
+        status = cq->Notify(Request, in->Type);
+        cq->Release();
+    }
+
+    pProvider->Unlock();
+err1:
+    if (!NT_SUCCESS(status)) {
+        WdfRequestComplete(Request, status);
+    }
+}
Index: core/ndfltr/kernel/nd_listen.h
===================================================================
--- core/ndfltr/kernel/nd_listen.h	(revision 0)
+++ core/ndfltr/kernel/nd_listen.h	(revision 0)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_LISTEN_H_
+#define _ND_LISTEN_H_
+
+#include <wdm.h>
+#include <iba\ib_types.h>
+#include <iba\ib_ci.h>
+#include "nd_provider.h"
+
+typedef struct _ND_LISTEN
+{
+	ND_PROVIDER		*pProvider;
+	UINT64			Id;
+	LONG			nRef;
+
+}	ND_LISTEN;
+
+#endif // _ND_LISTEN_H_
Index: core/ndfltr/kernel/nd_ep.cpp
===================================================================
--- core/ndfltr/kernel/nd_ep.cpp	(revision 0)
+++ core/ndfltr/kernel/nd_ep.cpp	(revision 0)
@@ -0,0 +1,2287 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <precomp.h>
+
+#define CM_LOCAL_TIMEOUT		(1)
+#define CM_REMOTE_TIMEOUT		(2)
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ND_ENDPOINT, NdEpGetContext);
+
+
+ULONG ND_ENDPOINT::s_RandomSeed;
+
+
+inline bool
+IsLoopback(const SOCKADDR_INET& addr)
+{
+    if (addr.si_family == AF_INET) {
+        if (addr.Ipv4.sin_addr.s_addr == _byteswap_ulong(INADDR_LOOPBACK)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    return IN6_IS_ADDR_LOOPBACK(&addr.Ipv6.sin6_addr) == TRUE;
+}
+
+
+ND_ENDPOINT::ND_ENDPOINT(ND_ADAPTER* pAdapter, ND_ENDPOINT::TYPE Type, WDFQUEUE Queue)
+    : _Base(pAdapter, &pAdapter->GetDevice()->CmInterface),
+    m_pProvider(pAdapter->GetProvider()),
+    m_pQp(NULL),
+    m_Type(Type),
+    m_State(NdEpIdle),
+    m_Backlog(0),
+    m_PrivateDataLength(0),
+    m_Queue(Queue),
+    m_StartingPsn(RtlRandomEx(&s_RandomSeed))
+{
+    m_pWork = reinterpret_cast<PIO_WORKITEM>(this + 1);
+    IoInitializeWorkItem(WdfDeviceWdmGetDeviceObject(pAdapter->GetDevice()->WdfDev), m_pWork);
+    RtlZeroMemory(&m_ReadLimits, sizeof(m_ReadLimits));
+    pAdapter->AddEp(&m_Entry);
+}
+
+
+ND_ENDPOINT::~ND_ENDPOINT()
+{
+    WdfObjectAcquireLock(m_Queue);
+    m_State = NdEpDestroying;
+    WdfObjectReleaseLock(m_Queue);
+
+    UnbindQp(true, NULL, 0);
+
+    _Base::RunDown();
+
+    if (m_hIfc != NULL) {
+        m_pIfc->CM.destroy_id(m_hIfc);
+    }
+
+    WdfIoQueuePurgeSynchronously(m_Queue);
+
+    IoUninitializeWorkItem(m_pWork);
+    m_pParent->RemoveEp(&m_Entry);
+}
+
+
+//static
+NTSTATUS
+ND_ENDPOINT::Create(
+    __in ND_ADAPTER* pAdapter,
+    KPROCESSOR_MODE /*RequestorMode*/,
+    __in ND_ENDPOINT::TYPE Type,
+    __out ND_ENDPOINT** ppEp
+    )
+{
+    WDF_IO_QUEUE_CONFIG config;
+    WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual);
+    config.EvtIoCanceledOnQueue = ND_ENDPOINT::EvtIoCanceled;
+
+    WDF_OBJECT_ATTRIBUTES attr;
+    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, ND_ENDPOINT);
+    attr.ExecutionLevel = WdfExecutionLevelDispatch;
+    attr.SynchronizationScope = WdfSynchronizationScopeNone;
+    attr.ContextSizeOverride = sizeof(ND_ENDPOINT) + IoSizeofWorkItem();
+
+    WDFQUEUE queue;
+    NTSTATUS status = WdfIoQueueCreate(ControlDevice, &config, &attr, &queue);
+    if (!NT_SUCCESS(status)) {
+        return status;
+    }
+
+    *ppEp = new(NdEpGetContext(queue)) ND_ENDPOINT(pAdapter, Type, queue);
+    return STATUS_SUCCESS;
+}
+
+
+void ND_ENDPOINT::Dispose()
+{
+    this->ND_ENDPOINT::~ND_ENDPOINT();
+    WdfObjectDelete(m_Queue);
+}
+
+
+void ND_ENDPOINT::RemoveHandler()
+{
+    WdfObjectAcquireLock(m_Queue);
+    m_State = NdEpDestroying;
+    WdfObjectReleaseLock(m_Queue);
+
+    if (m_hIfc != NULL) {
+        m_pIfc->CM.destroy_id(m_hIfc);
+    }
+    _Base::RemoveHandler();
+
+    WDFREQUEST    request;
+    NTSTATUS status = WdfIoQueueRetrieveNextRequest(m_Queue, &request);
+
+    while (NT_SUCCESS(status)) {
+        FlushRequest(request, STATUS_DEVICE_REMOVED);
+        status = WdfIoQueueRetrieveNextRequest(m_Queue, &request);
+    }
+}
+
+
+NTSTATUS ND_ENDPOINT::BindQp(ND_QUEUE_PAIR* pQp)
+{
+    NT_ASSERT(m_pQp == NULL);
+
+    //
+    // We need to protect against a user trying to use the same QP
+    // simultaneously for two connections.  The QP's EP pointer is
+    // only ever set through the connection paths.  If we succeed
+    // in setting the QP's EP pointer, then we are safe to set our
+    // QP pointer.
+    //
+    NTSTATUS status = pQp->BindEp(this);
+    if (NT_SUCCESS(status)) {
+        pQp->AddRef();
+        m_pQp = pQp;
+    }
+
+    return status;
+}
+
+
+void ND_ENDPOINT::UnbindQp(bool FlushQp, __out_opt BYTE* pOutBuf, ULONG OutLen)
+{
+    ND_QUEUE_PAIR* qp = reinterpret_cast<ND_QUEUE_PAIR*>(
+        InterlockedExchangePointer(reinterpret_cast<VOID**>(&m_pQp), NULL)
+        );
+
+    if (qp != NULL) {
+        ND_ENDPOINT* ep = qp->ClearEp();
+        if (ep != NULL) {
+            NT_ASSERT(ep == this);
+            ep->Dereference();
+        }
+        if (FlushQp) {
+            NT_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
+            qp->Flush(pOutBuf, OutLen);
+        }
+        qp->UnbindEp();
+        qp->Release();
+    }
+}
+
+
+void NdEpCreate(ND_PROVIDER *pProvider, ND_ENDPOINT::TYPE EpType, WDFREQUEST Request)
+{
+    NDFLTR_EP_CREATE* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Header.Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    if (in->Ndv1TimeoutSemantics == TRUE && EpType == ND_ENDPOINT::NdEpConnector) {
+        EpType = ND_ENDPOINT::NdEpConnectorV1;
+    }
+
+    UINT64* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*out),
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    pProvider->LockShared();
+
+    ND_ADAPTER* adapter;
+    status = pProvider->GetAdapter(in->Header.Handle, &adapter);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    ND_ENDPOINT* ep;
+    status = ND_ENDPOINT::Create(
+        adapter,
+        WdfRequestGetRequestorMode(Request),
+        EpType,
+        &ep
+        );
+
+    if (!NT_SUCCESS(status)) {
+        goto err3;
+    }
+
+    *out = pProvider->AddEp(ep);
+    if (*out == 0) {
+        ep->Dispose();
+        status = STATUS_INSUFFICIENT_RESOURCES;
+    } else {
+        WdfRequestSetInformation(Request, outLen);
+    }
+
+err3:
+    adapter->Release();
+err2:
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdConnectorCreate(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    NdEpCreate(pProvider, ND_ENDPOINT::NdEpConnector, Request);
+}
+
+
+void
+NdListenerCreate(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    NdEpCreate(pProvider, ND_ENDPOINT::NdEpListener, Request);
+}
+
+
+void
+NdEpFree(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    pProvider->LockShared();
+    status = pProvider->FreeEp(in->Handle);
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdEpCancelIo(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->Handle, &ep);
+    if (NT_SUCCESS(status)) {
+        ep->CancelIo();
+        ep->Release();
+    }
+
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+NTSTATUS
+ND_ENDPOINT::Bind(
+    __in const SOCKADDR_INET& address,
+    __in LUID /*AuthenticationId*/,
+    __in bool /*IsAdmin*/
+    )
+{
+    IBAT_PORT_RECORD deviceAddress;
+    NTSTATUS status = m_pParent->GetDeviceAddress(address, &deviceAddress);
+    if (!NT_SUCCESS(status)) {
+        return status;
+    }
+
+    WdfObjectAcquireLock(m_Queue);
+    if (m_State != NdEpIdle) {
+        WdfObjectReleaseLock(m_Queue);
+        return STATUS_ADDRESS_ALREADY_ASSOCIATED;
+    }
+
+    m_LocalAddress = address;
+    m_DeviceAddress = deviceAddress;
+
+    NT_ASSERT(m_hIfc == NULL);
+    if (m_Type == NdEpListener) {
+        status = m_pIfc->CM.create_id(ListenHandler, this, &m_hIfc);
+    } else {
+        status = m_pIfc->CM.create_id(CmHandler, this, &m_hIfc);
+    }
+    if (NT_SUCCESS(status)) {
+        //
+        // Note that the port number is in the same location in both the IPv4 and IPv6
+        // addresses.
+        //
+        //TODO: Sort port allocation/validation.
+        //
+        if (m_LocalAddress.Ipv4.sin_port == 0) {
+            m_LocalAddress.Ipv4.sin_port =
+                static_cast<USHORT>(m_hIfc->cid) ^
+                static_cast<USHORT>(m_hIfc->cid >> 16);
+        }
+        m_State = ND_ENDPOINT::NdEpAddressBound;
+    }
+
+    WdfObjectReleaseLock(m_Queue);
+    return status;
+}
+
+
+void
+NdEpBind(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    LUID luid = {0,0};
+    bool isAdmin = false;
+
+    ND_BIND* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    if (WdfRequestGetRequestorMode(Request) == UserMode) {
+        SECURITY_SUBJECT_CONTEXT context;
+        SeCaptureSubjectContext(&context);
+        SeLockSubjectContext(&context);
+        PACCESS_TOKEN token = SeQuerySubjectContextToken(&context);
+        status = SeQueryAuthenticationIdToken(token, &luid);
+        isAdmin = (SeTokenIsAdmin(token) == TRUE);
+        SeUnlockSubjectContext(&context);
+    } else {
+        NDK_BIND* in;
+        NTSTATUS status = WdfRequestRetrieveInputBuffer(
+            Request,
+            sizeof(*in),
+            reinterpret_cast<VOID**>(&in),
+            NULL
+            );
+        if (NT_SUCCESS(status)) {
+            luid = in->AuthenticationId;
+            isAdmin = (in->IsAdmin == TRUE);
+        }
+    }
+
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->Handle, &ep);
+    if (NT_SUCCESS(status)) {
+        status = ep->Bind(in->Address, luid, isAdmin);
+        ep->Release();
+    }
+    pProvider->Unlock();
+
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+ND_ENDPOINT::QueryPathHandler(
+    __in void* CompletionContext,
+    __in NTSTATUS QueryStatus,
+    __in ib_path_rec_t* const pPath
+    )
+{
+    ND_ENDPOINT* ep = reinterpret_cast<ND_ENDPOINT*>(CompletionContext);
+
+    if (NT_SUCCESS(QueryStatus)) {
+        RtlCopyMemory(&ep->m_Route, pPath, sizeof(ep->m_Route));
+    }
+    ep->SendConnectionRequest(QueryStatus);
+}
+
+
+void
+ND_ENDPOINT::SendConnectionRequest(NTSTATUS RouteStatus)
+{
+    WDFREQUEST request;
+    NTSTATUS status = WdfIoQueueRetrieveNextRequest(m_Queue, &request);
+    if (!NT_SUCCESS(status)) {
+        //
+        // EvtIoCanceled will have been called.
+        //
+        goto err1;
+    }
+
+    NDFLTR_CONNECT* in;
+    size_t inLen;
+    status = WdfRequestRetrieveInputBuffer(
+        request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    //
+    // We retrieved the input buffer successfully before, and should still be able to now.
+    //
+    NT_ASSERT(NT_SUCCESS(status));
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    NT_ASSERT(in->Header.CbPrivateDataOffset + in->Header.CbPrivateDataLength <= inLen);
+
+    WdfObjectAcquireLock(m_Queue);
+    if (m_State != NdEpResolving) {
+        status = STATUS_CANCELLED;
+        goto err2;
+    }
+
+    if (!NT_SUCCESS(RouteStatus)) {
+        m_State = NdEpAddressBound;
+        status = RouteStatus;
+        goto err2;
+    }
+
+    status = SendIbCmReq(in);
+    if (!NT_SUCCESS(status)) {
+        m_State = NdEpAddressBound;
+        goto err2;
+    }
+
+    m_State = NdEpReqSent;
+    WdfRequestRequeue(request);
+    WdfObjectReleaseLock(m_Queue);
+    Dereference();
+    return;
+
+err2:
+    UnbindQp(false, NULL, 0);
+    WdfObjectReleaseLock(m_Queue);
+    WdfRequestComplete(request, status);
+err1:
+    Dereference();
+}
+
+
+NTSTATUS
+ND_ENDPOINT::Connect(
+    WDFREQUEST Request,
+    __inout ND_QUEUE_PAIR* pQp,
+    __in const SOCKADDR_INET& DestinationAddress,
+    __in const IF_PHYSICAL_ADDRESS& DestinationHwAddress
+    )
+{
+    NTSTATUS status;
+    WdfObjectAcquireLock(m_Queue);
+    switch (m_State)
+    {
+    case NdEpAddressBound:
+        if (m_Type == NdEpListener) {
+            status = STATUS_INVALID_DEVICE_REQUEST;
+        } else {
+            status = BindQp(pQp);
+        }
+        break;
+    case NdEpIdle:
+        status = STATUS_ADDRESS_NOT_ASSOCIATED;
+        break;
+    case NdEpQueued:
+    case NdEpDisconnected:
+    case NdEpDestroying:
+        status = STATUS_INVALID_DEVICE_STATE;
+        break;
+    default:
+        status = STATUS_CONNECTION_ACTIVE;
+        break;
+    }
+    if (!NT_SUCCESS(status)) {
+        WdfObjectReleaseLock(m_Queue);
+        return status;
+    }
+    status = WdfRequestForwardToIoQueue(Request, m_Queue);
+    if (!NT_SUCCESS(status)) {
+        UnbindQp(false, NULL, 0);
+        WdfObjectReleaseLock(m_Queue);
+        return status;
+    }
+
+    m_State = NdEpResolving;
+
+    if (IsLoopback(DestinationAddress) == true) {
+        m_PeerAddress = m_LocalAddress;
+        //
+        // Port number is in the same place for IPv4 and IPv6 addresses.
+        //
+        m_PeerAddress.Ipv4.sin_port = DestinationAddress.Ipv4.sin_port;
+    } else {
+        m_PeerAddress = DestinationAddress;
+    }
+    WdfObjectReleaseLock(m_Queue);
+
+    Reference();
+    status = m_pParent->GetProvider()->GetPartition()->QueryPath(
+        m_LocalAddress,
+        m_PeerAddress,
+        DestinationHwAddress,
+        ND_ENDPOINT::QueryPathHandler,
+        this,
+        &m_Route
+        );
+    if (status != STATUS_PENDING) {
+        SendConnectionRequest(status);
+        status = STATUS_PENDING;
+    }
+    return status;
+}
+
+
+UINT64 ND_ENDPOINT::GetServiceId(const SOCKADDR_INET& Address)
+{
+    return ib_cm_rdma_cm_sid(IPPROTO_TCP, Address.Ipv4.sin_port);
+}
+
+
+void
+ND_ENDPOINT::FormatRdmaCmHeader(
+    __out ib_cm_rdma_req_t* pHeader,
+    __in const SOCKADDR_INET& LocalAddress,
+    __in const SOCKADDR_INET& PeerAddress
+    )
+{
+    pHeader->maj_min_ver = IB_REQ_CM_RDMA_VERSION;
+    if (LocalAddress.si_family == AF_INET) {
+        pHeader->ipv = 4 << 4;
+        pHeader->src_ip_addr[0] = pHeader->src_ip_addr[1] = pHeader->src_ip_addr[2] = 0;
+        pHeader->src_ip_addr[3] = LocalAddress.Ipv4.sin_addr.s_addr;
+        pHeader->dst_ip_addr[0] = pHeader->dst_ip_addr[1] = pHeader->dst_ip_addr[2] = 0;
+        pHeader->dst_ip_addr[3] = PeerAddress.Ipv4.sin_addr.s_addr;
+        pHeader->src_port = LocalAddress.Ipv4.sin_port;
+    } else {
+        pHeader->ipv = 6 << 4;
+        RtlCopyMemory(pHeader->src_ip_addr, &LocalAddress.Ipv6.sin6_addr, sizeof(IN6_ADDR));
+        RtlCopyMemory(pHeader->dst_ip_addr, &PeerAddress.Ipv6.sin6_addr, sizeof(IN6_ADDR));
+        pHeader->src_port = LocalAddress.Ipv6.sin6_port;
+    }
+}
+
+
+void ND_ENDPOINT::ProcessCmRep(iba_cm_rep_event* pReply)
+{
+    WdfObjectAcquireLock(m_Queue);
+    if (m_State == NdEpReqSent) {
+        //
+        // We don't distinguish between REP and REJ sizes - both are 'CalleeData'
+        // and REJ is smaller.
+        //
+        m_PrivateDataLength = IB_REJ_PDATA_SIZE;
+        RtlCopyMemory(m_PrivateData, pReply->rep.p_pdata, IB_REJ_PDATA_SIZE);
+
+        NT_ASSERT(pReply->rep.init_depth <= m_pParent->GetDevice()->Info.MaxInboundReadLimit);
+        m_ReadLimits.Inbound = pReply->rep.init_depth;
+
+        NT_ASSERT(pReply->rep.resp_res <= m_pParent->GetDevice()->Info.MaxOutboundReadLimit);
+        m_ReadLimits.Outbound = pReply->rep.resp_res;
+
+        m_State = NdEpRepReceived;
+        NdCompleteRequests(m_Queue, STATUS_SUCCESS);
+    }
+    WdfObjectReleaseLock(m_Queue);
+}
+
+
+void ND_ENDPOINT::ProcessCmRtu()
+{
+    WdfObjectAcquireLock(m_Queue);
+    if (m_State == NdEpRepSent) {
+        m_State = NdEpConnected;
+        //
+        // We no longer need the QP's back pointer to us, as we are now established.
+        //
+        ND_ENDPOINT* pEp = m_pQp->ClearEp();
+        if (pEp != NULL) {
+            NT_ASSERT(pEp == this);
+            pEp->Dereference();
+        }
+        NdCompleteRequests(m_Queue, STATUS_SUCCESS);
+    }
+    WdfObjectReleaseLock(m_Queue);
+}
+
+
+void ND_ENDPOINT::ProcessCmDreq()
+{
+    WdfObjectAcquireLock(m_Queue);
+    if (m_State == NdEpConnected) {
+        m_State = NdEpPassiveDisconnect;
+        //
+        // The only requests that can be queued in the NdEpConnected state are NotifyDisconnect
+        // requests.  We flush the request queue and the QP.
+        //
+        // Note that AsyncFlushQp will remove the first request in the queue, so flush the queue
+        // first to ensure timely delivery of the NotifyDisconnect.
+        //
+        NdCompleteRequests(m_Queue, STATUS_SUCCESS);
+        AsyncFlushQp(STATUS_SUCCESS);
+    } else if (m_State == NdEpRepSent) {
+        m_State = NdEpPassiveDisconnect;
+        //
+        // Note that the Accept() call is still oustanding at this point, but reception
+        // of the DREQ indicates that the RTU was sent (but must have been dropped).
+        // We complete the Accept() request with STATUS_SUCCESS since we were successfully
+        // connected.
+        //
+        NdCompleteRequests(m_Queue, STATUS_SUCCESS);
+    } else if (m_State == NdEpActiveDisconnect) {
+        m_State = NdEpDisconnected;
+        m_pIfc->CM.send_drep(m_hIfc, NULL, 0);
+        AsyncFlushQp(STATUS_SUCCESS);
+    }
+    WdfObjectReleaseLock(m_Queue);
+}
+
+
+void ND_ENDPOINT::CompleteDisconnect(NTSTATUS Status)
+{
+    WdfObjectAcquireLock(m_Queue);
+    if (m_State == NdEpActiveDisconnect) {
+        m_State = NdEpDisconnected;
+        AsyncFlushQp(Status);
+    }
+    WdfObjectReleaseLock(m_Queue);
+}
+
+
+void ND_ENDPOINT::ProcessCmRej(iba_cm_rej_event* pReject)
+{
+    WdfObjectAcquireLock(m_Queue);
+    if (m_State == NdEpReqSent) {
+        m_State = NdEpAddressBound;
+        m_PrivateDataLength = IB_REJ_PDATA_SIZE;
+        RtlCopyMemory(m_PrivateData, pReject->p_pdata, IB_REJ_PDATA_SIZE);
+        NdCompleteRequests(m_Queue, STATUS_CONNECTION_REFUSED);
+    } else if (m_State == NdEpRepSent) {
+        m_State = NdEpDisconnected;
+        m_PrivateDataLength = IB_REJ_PDATA_SIZE;
+        RtlCopyMemory(m_PrivateData, pReject->p_pdata, IB_REJ_PDATA_SIZE);
+        AsyncFlushQp(STATUS_CONNECTION_REFUSED);
+    } else if (m_State == NdEpConnected) {
+        m_State = NdEpPassiveDisconnect;
+        NdCompleteRequests(m_Queue, STATUS_SUCCESS);
+    }
+    WdfObjectReleaseLock(m_Queue);
+}
+
+
+void ND_ENDPOINT::CmReqError()
+{
+    WdfObjectAcquireLock(m_Queue);
+    if (m_State == NdEpReqSent) {
+        UnbindQp(false, NULL, 0);
+        m_State = NdEpAddressBound;
+        if (m_Type == NdEpConnectorV1) {
+            //
+            // NDSPIv1 wants STATUS_TIMEOUT for operations that can be retried.
+            //
+            NdCompleteRequests(m_Queue, STATUS_TIMEOUT);
+        } else {
+            NdCompleteRequests(m_Queue, STATUS_IO_TIMEOUT);
+        }
+    }
+    WdfObjectReleaseLock(m_Queue);
+}
+
+
+void ND_ENDPOINT::CmRepError()
+{
+    WdfObjectAcquireLock(m_Queue);
+    if (m_State != NdEpRepSent) {
+        WdfObjectReleaseLock(m_Queue);
+        return;
+    }
+    m_State = NdEpDisconnected;
+    AsyncFlushQp(STATUS_IO_TIMEOUT);
+    WdfObjectReleaseLock(m_Queue);
+}
+
+
+void
+ND_ENDPOINT::FlushQpWorker(
+    __in void* /*IoObject*/,
+    __in_opt void* Context,
+    __in PIO_WORKITEM IoWorkItem
+    )
+{
+    ND_ENDPOINT* ep = reinterpret_cast<ND_ENDPOINT*>(IoWorkItem) - 1;
+
+    ep->UnbindQp(true, NULL, 0);
+
+    WDFREQUEST request = static_cast<WDFREQUEST>(Context);
+    if (request != NULL) {
+        WdfRequestComplete(request, ep->AsyncFlushStatus);
+    }
+
+    InterlockedExchangePointer(reinterpret_cast<VOID**>(&ep->m_pWork), IoWorkItem);
+    ep->Dereference();
+}
+
+
+void ND_ENDPOINT::AsyncFlushQp(NTSTATUS Status)
+{
+    WDFREQUEST request;
+    WdfIoQueueRetrieveNextRequest(m_Queue, &request);
+
+    PIO_WORKITEM workItem = reinterpret_cast<PIO_WORKITEM>(
+        InterlockedExchangePointer(reinterpret_cast<VOID**>(&m_pWork), NULL)
+        );
+    NT_ASSERT(workItem != NULL);
+
+    if (workItem == NULL && request != NULL) {
+        WdfRequestComplete(request, Status);
+        return;
+    }
+
+    Reference();
+    AsyncFlushStatus = Status;
+    IoQueueWorkItemEx(
+        workItem,
+        FlushQpWorker,
+        DelayedWorkQueue,
+        request
+        );
+}
+
+
+NTSTATUS ND_ENDPOINT::CmHandler(iba_cm_id *pId, iba_cm_event *pEvent)
+{
+    ND_ENDPOINT *ep = reinterpret_cast<ND_ENDPOINT*>(pId->context);
+
+    switch (pEvent->type) {
+    case iba_cm_req_error:
+        ep->CmReqError();
+        break;
+    case iba_cm_rep_error:
+        ep->CmRepError();
+        break;
+    case iba_cm_dreq_error:
+        ep->CompleteDisconnect(STATUS_TIMEOUT);
+        break;
+    case iba_cm_rep_received:
+        ep->ProcessCmRep(&pEvent->data.rep);
+        break;
+    case iba_cm_rtu_received:
+        ep->ProcessCmRtu();
+        break;
+    case iba_cm_dreq_received:
+        ep->ProcessCmDreq();
+        break;
+    case iba_cm_drep_received:
+        ep->CompleteDisconnect(STATUS_SUCCESS);
+        break;
+    case iba_cm_rej_received:
+        ep->ProcessCmRej(&pEvent->data.rej);
+        break;
+    case iba_cm_lap_received:
+    case iba_cm_sidr_req_received:
+        //
+        // We don't support alternate paths or SIDR, we'll let the remote peer timeout.
+        // No need to assert, though, since we might interop with some peer that does
+        // support these.  It would be nicer to reject the request rather than letting
+        // it time out, but we wouldn't get test coverage without a bunch more effort.
+        //
+        break;
+    default:
+        NT_ASSERT(
+            pEvent->type != iba_cm_req_received &&      // ListenHandler for REQs
+            pEvent->type != iba_cm_lap_error &&         // Never sent a LAP
+            pEvent->type != iba_cm_apr_received &&      // Never sent a LAP
+            pEvent->type != iba_cm_sidr_req_error &&    // Don't support SIDR
+            pEvent->type != iba_cm_sidr_rep_received    // Don't support SIDR
+            );
+        break;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+ND_ENDPOINT::SendIbCmReq(const NDFLTR_CONNECT* pConnect)
+{
+    ib_cm_rdma_req_t data;
+    FormatRdmaCmHeader(&data, m_LocalAddress, m_PeerAddress);
+
+    iba_cm_req req;
+    req.service_id = GetServiceId(m_PeerAddress);
+    req.p_primary_path = &m_Route;
+    req.p_alt_path = NULL;
+    req.qpn = m_pQp->Qpn();
+    req.qp_type = IB_QPT_RELIABLE_CONN;
+    req.starting_psn = static_cast<net32_t>(m_StartingPsn);
+    req.p_pdata = &data;
+    RtlCopyMemory(
+        data.pdata,
+        reinterpret_cast<const BYTE*>(pConnect) + pConnect->Header.CbPrivateDataOffset,
+        pConnect->Header.CbPrivateDataLength
+        );
+    req.pdata_len = static_cast<UINT8>(sizeof(IB_CMA_HEADER) + pConnect->Header.CbPrivateDataLength);
+    req.max_cm_retries = IB_CMA_MAX_CM_RETRIES;
+
+    if (pConnect->Header.ReadLimits.Inbound > m_pParent->GetDevice()->Info.MaxInboundReadLimit) {
+        req.resp_res = static_cast<UINT8>(m_pParent->GetDevice()->Info.MaxInboundReadLimit);
+    } else {
+        req.resp_res = static_cast<UINT8>(pConnect->Header.ReadLimits.Inbound);
+    }
+
+    if (pConnect->Header.ReadLimits.Outbound > m_pParent->GetDevice()->Info.MaxOutboundReadLimit) {
+        req.init_depth = static_cast<UINT8>(m_pParent->GetDevice()->Info.MaxOutboundReadLimit);
+    } else {
+        req.init_depth = static_cast<UINT8>(pConnect->Header.ReadLimits.Outbound);
+    }
+
+    req.remote_resp_timeout = ib_path_rec_pkt_life(&m_Route) + CM_REMOTE_TIMEOUT;
+    if( req.remote_resp_timeout > 0x1F ) {
+        req.remote_resp_timeout = 0x1F;
+    } else if( req.remote_resp_timeout < IB_CMA_CM_RESPONSE_TIMEOUT ) {
+        req.remote_resp_timeout = IB_CMA_CM_RESPONSE_TIMEOUT;
+    }
+
+    req.flow_ctrl = TRUE;
+
+    req.local_resp_timeout = ib_path_rec_pkt_life(&m_Route) + CM_LOCAL_TIMEOUT;
+    if( req.local_resp_timeout > 0x1F ) {
+        req.local_resp_timeout = 0x1F;
+    } else if( req.local_resp_timeout < IB_CMA_CM_RESPONSE_TIMEOUT ) {
+        req.local_resp_timeout = IB_CMA_CM_RESPONSE_TIMEOUT;
+    }
+
+    req.rnr_retry_cnt = pConnect->RnrRetryCount;
+    req.retry_cnt = pConnect->RetryCount;
+    req.srq = m_pQp->HasSrq();
+
+    NTSTATUS status = m_pIfc->CM.send_req(
+        m_hIfc,
+        &req
+        );
+    return status;
+}
+
+
+void
+NdEpConnect(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    NDFLTR_CONNECT* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Header.Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    if (in->Header.CbPrivateDataLength > IB_REQ_CM_RDMA_PDATA_SIZE) {
+        status = STATUS_INVALID_BUFFER_SIZE;
+        goto err1;
+    }
+
+    if (in->Header.CbPrivateDataOffset + in->Header.CbPrivateDataLength > inLen) {
+        status = STATUS_INVALID_PARAMETER;
+        goto err1;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->Header.ConnectorHandle, &ep);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    ND_QUEUE_PAIR* qp;
+    status = pProvider->GetQp(in->Header.QpHandle, &qp);
+    if (NT_SUCCESS(status)) {
+        status = ep->Connect(
+            Request,
+            qp,
+            in->Header.DestinationAddress,
+            in->Header.DestinationHwAddress
+            );
+        qp->Release();
+    }
+
+    ep->Release();
+err2:
+    pProvider->Unlock();
+err1:
+    if (status != STATUS_PENDING) {
+        WdfRequestComplete(Request, status);
+    }
+}
+
+
+NTSTATUS ND_ENDPOINT::ModifyQp(ib_qp_state_t State, UINT8 RnrNakTimeout, BYTE* pOutBuf, ULONG OutLen)
+{
+    ib_qp_mod_t attr;
+    NTSTATUS status = m_pIfc->CM.get_qp_attr(m_hIfc, State, &attr);
+    if (!NT_SUCCESS(status)) {
+        return status;
+    }
+
+    if (State == IB_QPS_RTR) {
+        attr.state.rtr.resp_res = static_cast<UINT8>(m_ReadLimits.Inbound);
+        attr.state.rtr.rnr_nak_timeout = RnrNakTimeout;
+    } else if (State == IB_QPS_RTS) {
+        attr.state.rts.init_depth = static_cast<UINT8>(m_ReadLimits.Outbound);
+    }
+
+    status = m_pQp->Modify(&attr, pOutBuf, OutLen);
+    return status;
+}
+
+
+void
+NdEpCompleteConnect(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    NDFLTR_COMPLETE_CONNECT* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Header.Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    BYTE* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        0,
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (status == STATUS_BUFFER_TOO_SMALL) {
+        out = NULL;
+        outLen = 0;
+    } else if (!NT_SUCCESS(status)) {
+        goto err;
+    } else if (outLen > ULONG_MAX) {
+        status = STATUS_INVALID_PARAMETER;
+        goto err;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->Header.Handle, &ep);
+    if (NT_SUCCESS(status)) {
+        status = ep->CompleteConnect(in->RnrNakTimeout, out, static_cast<ULONG>(outLen));
+        ep->Release();
+        if (NT_SUCCESS(status)) {
+            WdfRequestSetInformation(Request, outLen);
+        }
+    }
+
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+NTSTATUS ND_ENDPOINT::CompleteConnect(UINT8 RnrNakTimeout, __out BYTE* pOutBuf, ULONG OutLen)
+{
+    NTSTATUS status;
+    WdfObjectAcquireLock(m_Queue);
+    switch (m_State) {
+    case NdEpRepReceived:
+        WdfObjectReleaseLock(m_Queue);
+        break;
+
+    case NdEpDisconnected:
+        WdfObjectReleaseLock(m_Queue);
+        return STATUS_CONNECTION_ABORTED;
+
+    default:
+        WdfObjectReleaseLock(m_Queue);
+        return STATUS_CONNECTION_INVALID;
+    }
+
+    status = ModifyQp(IB_QPS_INIT, 0, pOutBuf, OutLen);
+    if (!NT_SUCCESS(status)) {
+        return status;
+    }
+
+    status = ModifyQp(IB_QPS_RTR, RnrNakTimeout, pOutBuf, OutLen);
+    if (!NT_SUCCESS(status)) {
+        return status;
+    }
+
+    status = ModifyQp(IB_QPS_RTS, 0, pOutBuf, OutLen);
+    if (!NT_SUCCESS(status)) {
+        return status;
+    }
+
+    WdfObjectAcquireLock(m_Queue);
+    if (m_State != NdEpRepReceived) {
+        m_State = NdEpDisconnected;
+        WdfObjectReleaseLock(m_Queue);
+        return STATUS_IO_TIMEOUT;
+    }
+
+    status = m_pIfc->CM.send_rtu(m_hIfc, NULL, 0);
+    if (!NT_SUCCESS(status)) {
+        m_State = NdEpDisconnected;
+    } else {
+        m_State = NdEpConnected;
+    }
+
+    WdfObjectReleaseLock(m_Queue);
+    return status;
+}
+
+
+NTSTATUS
+ND_ENDPOINT::FormatIbCmRep(
+    __in const NDFLTR_ACCEPT* pAccept,
+    __out_opt ib_qp_mod_t* pQpMod
+    )
+{
+    iba_cm_rep rep;
+    rep.qpn = m_pQp->Qpn();
+    rep.starting_psn = static_cast<net32_t>(m_StartingPsn);
+    rep.p_pdata = reinterpret_cast<const BYTE*>(pAccept) + pAccept->Header.CbPrivateDataOffset;
+    rep.pdata_len = static_cast<UINT8>(pAccept->Header.CbPrivateDataLength);
+    rep.failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED;
+
+    if (pAccept->Header.ReadLimits.Inbound > m_ReadLimits.Inbound) {
+        rep.resp_res = static_cast<UINT8>(m_ReadLimits.Inbound);
+    } else {
+        rep.resp_res = static_cast<UINT8>(pAccept->Header.ReadLimits.Inbound);
+    }
+
+    if (pAccept->Header.ReadLimits.Outbound > m_ReadLimits.Outbound) {
+        if (m_ReadLimits.Outbound == 0) {
+            //
+            // Caller wants to issue RDMA reads, but the connected peer didn't
+            // give us any resources to do so.
+            //
+            return STATUS_INVALID_PARAMETER;
+        }
+        rep.init_depth = static_cast<UINT8>(m_ReadLimits.Outbound);
+    } else {
+        rep.init_depth = static_cast<UINT8>(pAccept->Header.ReadLimits.Outbound);
+    }
+
+    rep.flow_ctrl = TRUE;
+    rep.rnr_retry_cnt = pAccept->RnrRetryCount;
+    rep.srq = m_pQp->HasSrq();
+
+    return m_pIfc->CM.format_rep(
+        m_hIfc,
+        &rep,
+        pQpMod
+        );
+}
+
+
+void
+NdEpAccept(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    NDFLTR_ACCEPT* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Header.Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    if (in->Header.CbPrivateDataLength > IB_REJ_PDATA_SIZE) {
+        status = STATUS_INVALID_BUFFER_SIZE;
+        goto err1;
+    }
+
+    if (in->Header.CbPrivateDataOffset + in->Header.CbPrivateDataLength > inLen) {
+        status = STATUS_INVALID_PARAMETER;
+        goto err1;
+    }
+
+    BYTE* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        0,
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (status == STATUS_BUFFER_TOO_SMALL) {
+        out = NULL;
+        outLen = 0;
+    } else if (!NT_SUCCESS(status)) {
+        goto err1;
+    } else if (outLen > ULONG_MAX) {
+        status = STATUS_INVALID_PARAMETER;
+        goto err1;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->Header.ConnectorHandle, &ep);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    ND_QUEUE_PAIR* qp;
+    status = pProvider->GetQp(in->Header.QpHandle, &qp);
+    if (NT_SUCCESS(status)) {
+        status = ep->Accept(Request, qp, in, out, static_cast<ULONG>(outLen));
+        qp->Release();
+    }
+
+    ep->Release();
+err2:
+    pProvider->Unlock();
+err1:
+    if (status != STATUS_PENDING) {
+        WdfRequestComplete(Request, status);
+    }
+}
+
+
+NTSTATUS
+ND_ENDPOINT::Accept(
+    WDFREQUEST Request,
+    __inout ND_QUEUE_PAIR* pQp,
+    __in const NDFLTR_ACCEPT* pAccept,
+    __out BYTE* pOutBuf,
+    ULONG OutLen
+    )
+{
+    NTSTATUS status;
+    WdfObjectAcquireLock(m_Queue);
+    switch(m_State)
+    {
+    case NdEpReqReceived:
+        status = BindQp(pQp);
+        break;
+
+    case NdEpDisconnected:
+        status = STATUS_CONNECTION_ABORTED;
+        break;
+
+    default:
+        status = STATUS_CONNECTION_ACTIVE;
+        break;
+    }
+    if (!NT_SUCCESS(status)) {
+        WdfObjectReleaseLock(m_Queue);
+        return status;
+    }
+
+    m_State = NdEpRepSent;
+    WdfObjectReleaseLock(m_Queue);
+
+    ib_qp_mod_t qpMod;
+    status = FormatIbCmRep(pAccept, &qpMod);
+    if (!NT_SUCCESS(status)) {
+        UnbindQp(false, NULL, 0);
+        goto err;
+    }
+
+    status = m_pQp->Modify(&qpMod, pOutBuf, OutLen);
+    if (!NT_SUCCESS(status)) {
+        UnbindQp(false, NULL, 0);
+        goto err;
+    }
+
+    status = ModifyQp(IB_QPS_RTR, pAccept->RnrNakTimeout, pOutBuf, OutLen);
+    if (!NT_SUCCESS(status)) {
+        UnbindQp(false, NULL, 0);
+        goto err;
+    }
+
+    //
+    // TODO: Delay RTS until RTU/comm established event.
+    //
+    status = ModifyQp(IB_QPS_RTS, 0, pOutBuf, OutLen);
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    WdfObjectAcquireLock(m_Queue);
+    status = m_pIfc->CM.send_formatted_rep(m_hIfc);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    WdfRequestSetInformation(Request, OutLen);
+    status = WdfRequestForwardToIoQueue(Request, m_Queue);
+    if (!NT_SUCCESS(status)) {
+        WdfRequestSetInformation(Request, 0);
+        goto err2;
+    }
+    WdfObjectReleaseLock(m_Queue);
+
+    return STATUS_PENDING;
+
+err:
+    WdfObjectAcquireLock(m_Queue);
+err2:
+    m_State = NdEpDisconnected;
+    WdfObjectReleaseLock(m_Queue);
+    return status;
+}
+
+
+void
+NdEpReject(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_REJECT* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    if (in->CbPrivateDataLength > IB_REJ_PDATA_SIZE) {
+        status = STATUS_INVALID_BUFFER_SIZE;
+        goto err1;
+    }
+
+    if (in->CbPrivateDataOffset + in->CbPrivateDataLength > inLen) {
+        status = STATUS_INVALID_PARAMETER;
+        goto err1;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->ConnectorHandle, &ep);
+    if (NT_SUCCESS(status)) {
+        status = ep->Reject(
+            reinterpret_cast<BYTE*>(in) + in->CbPrivateDataOffset,
+            in->CbPrivateDataLength
+            );
+        ep->Release();
+    }
+
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+NTSTATUS ND_ENDPOINT::Reject(BYTE* PrivateData, ULONG PrivateDataLength)
+{
+    NTSTATUS status;
+    WdfObjectAcquireLock(m_Queue);
+    switch (m_State) {
+    case NdEpReqReceived:
+    case NdEpRepReceived:
+        status = m_pIfc->CM.send_rej(
+            m_hIfc,
+            IB_REJ_USER_DEFINED,
+            NULL,
+            0,
+            PrivateData,
+            static_cast<UINT8>(PrivateDataLength)
+            );
+        if (status == STATUS_SUCCESS) {
+            m_State = NdEpDisconnected;
+            break;
+        }
+        __fallthrough;
+
+    case NdEpDisconnected:
+        //
+        // Potentially here because the connection was aborted.
+        //
+        status = STATUS_CONNECTION_INVALID;
+        break;
+
+    default:
+        status = STATUS_INVALID_DEVICE_STATE;
+    }
+    WdfObjectReleaseLock(m_Queue);
+    return status;
+}
+
+
+void
+NdEpGetReadLimits(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    ND_READ_LIMITS* out;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*out),
+        reinterpret_cast<VOID**>(&out),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->Handle, &ep);
+    if (NT_SUCCESS(status)) {
+        status = ep->GetReadLimits(out);
+        ep->Release();
+        if (NT_SUCCESS(status)) {
+            WdfRequestSetInformation(Request, sizeof(*out));
+        }
+    }
+
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+NTSTATUS ND_ENDPOINT::GetReadLimits(__out ND_READ_LIMITS* pReadLimits)
+{
+    NTSTATUS status;
+    WdfObjectAcquireLock(m_Queue);
+    switch (m_State) {
+    case NdEpDisconnected:
+        status = STATUS_CONNECTION_INVALID;
+        break;
+
+    case NdEpReqReceived:
+    case NdEpRepReceived:
+        RtlCopyMemory(pReadLimits, &m_ReadLimits, sizeof(m_ReadLimits));
+        status = STATUS_SUCCESS;
+        break;
+
+    default:
+        status = STATUS_INVALID_DEVICE_STATE;
+    }
+    WdfObjectReleaseLock(m_Queue);
+    return status;
+}
+
+
+void
+NdEpGetPrivateData(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    VOID* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        0,
+        &out,
+        &outLen
+        );
+    if (status == STATUS_BUFFER_TOO_SMALL) {
+        outLen = 0;
+        out = NULL;
+    } else if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->Handle, &ep);
+    if (NT_SUCCESS(status)) {
+        status = ep->GetPrivateData(out, &outLen);
+        if (!NT_ERROR(status)) {
+            WdfRequestSetInformation(Request, outLen);
+        }
+        ep->Release();
+    }
+
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+NTSTATUS ND_ENDPOINT::GetPrivateData(__out VOID* pPrivateData, __inout size_t* pPrivateDataLength)
+{
+    NTSTATUS status;
+    WdfObjectAcquireLock(m_Queue);
+    switch (m_State) {
+    case NdEpAddressBound:
+    case NdEpDisconnected:
+        if (m_PrivateDataLength == 0) {
+            status = STATUS_CONNECTION_INVALID;
+            break;
+        }
+        //
+        // Reject() can provide private data.  We need to provide a means of retrieving it,
+        // though reception of a CM REJ will change our state to either NdEpAddressBound in
+        // the case the CM REQ was rejected, or NdEpDisconnected in the case the CM REP or
+        // RTU was rejected (the latter due to timeout).
+        //
+        __fallthrough;
+
+    case NdEpReqReceived:
+    case NdEpRepReceived:
+        if (*pPrivateDataLength == 0) {
+            if (pPrivateData != NULL) {
+                status = STATUS_INVALID_PARAMETER;
+            }
+
+            *pPrivateDataLength = m_PrivateDataLength;
+            status = STATUS_BUFFER_OVERFLOW;
+            break;
+        }
+
+        if (*pPrivateDataLength < m_PrivateDataLength) {
+            RtlCopyMemory(pPrivateData, m_PrivateData, *pPrivateDataLength);
+            status = STATUS_BUFFER_OVERFLOW;
+        } else {
+            *pPrivateDataLength = m_PrivateDataLength;
+            RtlCopyMemory(pPrivateData, m_PrivateData, m_PrivateDataLength);
+            status = STATUS_SUCCESS;
+        }
+        break;
+
+    default:
+        status = STATUS_INVALID_DEVICE_STATE;
+    }
+    WdfObjectReleaseLock(m_Queue);
+    return status;
+}
+
+
+void
+NdEpGetPeerAddress(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    SOCKADDR_INET* out;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*out),
+        reinterpret_cast<VOID**>(&out),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->Handle, &ep);
+    if (NT_SUCCESS(status)) {
+        status = ep->GetPeerAddress(out);
+        if (NT_SUCCESS(status)) {
+            WdfRequestSetInformation(Request, sizeof(*out));
+        }
+        ep->Release();
+    }
+
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+NTSTATUS ND_ENDPOINT::GetPeerAddress(__out SOCKADDR_INET* pAddress)
+{
+    NTSTATUS status;
+    WdfObjectAcquireLock(m_Queue);
+    switch (m_State) {
+    case NdEpDisconnected:
+        status = STATUS_CONNECTION_INVALID;
+        break;
+
+    case NdEpReqReceived:
+    case NdEpRepReceived:
+        *pAddress = m_PeerAddress;
+        status = STATUS_SUCCESS;
+        break;
+
+    default:
+        status = STATUS_INVALID_DEVICE_STATE;
+    }
+    WdfObjectReleaseLock(m_Queue);
+    return status;
+}
+
+
+void
+NdEpGetAddress(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    SOCKADDR_INET* out;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*out),
+        reinterpret_cast<VOID**>(&out),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->Handle, &ep);
+    if (NT_SUCCESS(status)) {
+        status = ep->GetAddress(out);
+        if (NT_SUCCESS(status)) {
+            WdfRequestSetInformation(Request, sizeof(*out));
+        }
+        ep->Release();
+    }
+
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+NTSTATUS ND_ENDPOINT::GetAddress(__out SOCKADDR_INET* pAddress)
+{
+    NTSTATUS status;
+    WdfObjectAcquireLock(m_Queue);
+    switch (m_State) {
+    case NdEpIdle:
+    case NdEpQueued:
+        status = STATUS_ADDRESS_NOT_ASSOCIATED;
+        break;
+
+    case NdEpAddressBound:
+    case NdEpListening:
+    case NdEpReqReceived:
+    case NdEpResolving:
+    case NdEpReqSent:
+    case NdEpRepReceived:
+        *pAddress = m_LocalAddress;
+        status = STATUS_SUCCESS;
+        break;
+
+    case NdEpDisconnected:
+        status = STATUS_CONNECTION_INVALID;
+        break;
+
+    default:
+        status = STATUS_INVALID_DEVICE_STATE;
+    }
+    WdfObjectReleaseLock(m_Queue);
+    return status;
+}
+
+
+void
+NdEpDisconnect(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    BYTE* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        0,
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (status == STATUS_BUFFER_TOO_SMALL) {
+        out = NULL;
+        outLen = 0;
+    } else if (!NT_SUCCESS(status)) {
+        goto err;
+    } else if (outLen > ULONG_MAX) {
+        status = STATUS_INVALID_PARAMETER;
+        goto err;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->Handle, &ep);
+    if (NT_SUCCESS(status)) {
+        WdfRequestSetInformation(Request, outLen);
+        status = ep->Disconnect(Request, out, static_cast<ULONG>(outLen));
+        ep->Release();
+        if (!NT_SUCCESS(status)) {
+            WdfRequestSetInformation(Request, 0);
+        }
+    }
+
+    pProvider->Unlock();
+err:
+    if (status != STATUS_PENDING) {
+        WdfRequestComplete(Request, status);
+    }
+}
+
+
+NTSTATUS ND_ENDPOINT::Disconnect(WDFREQUEST Request, __out_opt BYTE* pOutBuf, ULONG OutLen)
+{
+    NTSTATUS status;
+    WdfObjectAcquireLock(m_Queue);
+    switch (m_State) {
+    case NdEpConnected:
+        //
+        // Flush any NotifyDisconnect requests.
+        //
+        if (m_Type == NdEpConnectorV1) {
+            NdCompleteRequests(m_Queue, STATUS_CANCELLED);
+        } else {
+            NdCompleteRequests(m_Queue, STATUS_CONNECTION_DISCONNECTED);
+        }
+        // The IB CM could have received and processed a DREQ that we haven't seen yet.
+        status = m_pIfc->CM.send_dreq(m_hIfc, NULL, 0);
+        if (NT_SUCCESS(status)) {
+            status = WdfRequestForwardToIoQueue(Request, m_Queue);
+            if (NT_SUCCESS(status)) {
+                m_State = NdEpActiveDisconnect;
+                status = STATUS_PENDING;
+                break;
+            }
+        }
+        /* Fall through to passive disconnect case on failure */
+        __fallthrough;
+
+    case NdEpPassiveDisconnect:
+        m_State = NdEpDisconnected;
+        WdfObjectReleaseLock(m_Queue);
+
+        m_pIfc->CM.send_drep(m_hIfc, NULL, 0);
+
+        UnbindQp(true, pOutBuf, OutLen);
+        return STATUS_SUCCESS;
+
+    case NdEpActiveDisconnect:
+        status = STATUS_INVALID_DEVICE_STATE;
+        break;
+
+    default:
+        status = STATUS_CONNECTION_INVALID;
+        break;
+    }
+    WdfObjectReleaseLock(m_Queue);
+    return status;
+}
+
+
+void
+NdEpNotifyDisconnect(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->Handle, &ep);
+    if (NT_SUCCESS(status)) {
+        status = ep->NotifyDisconnect(Request);
+        ep->Release();
+    }
+
+    pProvider->Unlock();
+err:
+    if (!NT_SUCCESS(status)) {
+        WdfRequestComplete(Request, status);
+    }
+}
+
+
+NTSTATUS ND_ENDPOINT::NotifyDisconnect(WDFREQUEST Request)
+{
+    NTSTATUS status;
+    WdfObjectAcquireLock(m_Queue);
+    switch (m_State) {
+    case NdEpConnected:
+        status = WdfRequestForwardToIoQueue(Request, m_Queue);
+        break;
+    case NdEpPassiveDisconnect:
+        WdfRequestComplete(Request, STATUS_SUCCESS);
+        status = STATUS_SUCCESS;
+        break;
+    case NdEpDisconnected:
+    case NdEpActiveDisconnect:
+        status = STATUS_CONNECTION_DISCONNECTED;
+        break;
+    default:
+        status = STATUS_INVALID_DEVICE_STATE;
+        break;
+    }
+    WdfObjectReleaseLock(m_Queue);
+    return status;
+}
+
+
+void ND_ENDPOINT::Established(ND_ENDPOINT* pEp)
+{
+    WdfObjectAcquireLock(pEp->m_Queue);
+    if (pEp->m_State == NdEpRepSent) {
+        pEp->m_pIfc->CM.established(pEp->m_hIfc);
+    }
+    WdfObjectReleaseLock(pEp->m_Queue);
+
+    pEp->ProcessCmRtu();
+}
+
+
+NTSTATUS ND_ENDPOINT::ProcessCmReq(ND_ENDPOINT* pEp)
+{
+    iba_cm_event event;
+
+    NT_ASSERT(pEp->m_hIfc == NULL);
+    NTSTATUS status = m_pIfc->CM.get_request_ex(
+        m_hIfc,
+        CmHandler,
+        pEp,
+        &pEp->m_hIfc,
+        &event
+        );
+    if (!NT_SUCCESS(status)) {
+        return status;
+    }
+
+    pEp->m_LocalAddress = m_LocalAddress;
+    pEp->m_DeviceAddress = m_DeviceAddress;
+
+    ib_cm_rdma_req_t* hdr = reinterpret_cast<ib_cm_rdma_req_t*>(event.data.req.pdata);
+    NT_ASSERT(
+        (m_LocalAddress.si_family == AF_INET && hdr->ipv == 4 << 4) ||
+        (m_LocalAddress.si_family == AF_INET6 && hdr->ipv == 6 << 4)
+        );
+
+    if (hdr->ipv == 4 << 4) {
+        pEp->m_PeerAddress.si_family = AF_INET;
+        pEp->m_PeerAddress.Ipv4.sin_port = hdr->src_port;
+        pEp->m_PeerAddress.Ipv4.sin_addr.s_addr = hdr->src_ip_addr[3];
+        RtlZeroMemory(
+            pEp->m_PeerAddress.Ipv4.sin_zero,
+            sizeof(pEp->m_PeerAddress.Ipv4.sin_zero)
+            );
+    } else {
+        pEp->m_PeerAddress.si_family = AF_INET6;
+        pEp->m_PeerAddress.Ipv6.sin6_port = hdr->src_port;
+        pEp->m_PeerAddress.Ipv6.sin6_flowinfo = 0;
+        RtlCopyMemory(
+            &pEp->m_PeerAddress.Ipv6.sin6_addr,
+            hdr->src_ip_addr,
+            sizeof(pEp->m_PeerAddress.Ipv6.sin6_addr)
+            );
+        pEp->m_PeerAddress.Ipv6.sin6_scope_id = 0;
+    }
+
+    NT_ASSERT(m_DeviceAddress.CaGuid == event.data.req.local_ca_guid);
+    NT_ASSERT(m_DeviceAddress.PKey == event.data.req.primary_path.pkey);
+    NT_ASSERT(m_DeviceAddress.PortNum == event.data.req.port_num);
+
+    pEp->m_ReadLimits.Inbound = event.data.req.init_depth;
+    pEp->m_ReadLimits.Outbound = event.data.req.resp_res;
+    pEp->m_PrivateDataLength = IB_REQ_CM_RDMA_PDATA_SIZE;
+    RtlCopyMemory(pEp->m_PrivateData, hdr->pdata, sizeof(hdr->pdata));
+    pEp->m_Route = event.data.req.primary_path;
+
+    pEp->m_State = NdEpReqReceived;
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS ND_ENDPOINT::ListenHandler(iba_cm_id *pId, iba_cm_event*)
+{
+    ND_ENDPOINT* listener = reinterpret_cast<ND_ENDPOINT*>(pId->context);
+
+    WdfObjectAcquireLock(listener->m_Queue);
+    if (listener->m_State != NdEpListening) {
+        WdfObjectReleaseLock(listener->m_Queue);
+        return STATUS_INVALID_DEVICE_STATE;
+    }
+
+    WDFREQUEST request;
+    NTSTATUS status;
+    for (status = WdfIoQueueRetrieveNextRequest(listener->m_Queue, &request);
+        NT_SUCCESS(status);
+        status = WdfIoQueueRetrieveNextRequest(listener->m_Queue, &request)) {
+
+        ND_ENDPOINT* ep = reinterpret_cast<ND_ENDPOINT*>(WdfRequestGetInformation(request));
+
+        status = listener->ProcessCmReq(ep);
+        if (!NT_SUCCESS(status)) {
+            WdfRequestRequeue(request);
+            break;
+        } else {
+            ep->Release();
+            WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, 0);
+        }
+    }
+    WdfObjectReleaseLock(listener->m_Queue);
+    return STATUS_SUCCESS;
+}
+
+
+void
+NdEpListen(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_LISTEN* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->ListenerHandle, &ep);
+    if (NT_SUCCESS(status)) {
+        status = ep->Listen(in->Backlog);
+        ep->Release();
+    }
+
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+NTSTATUS ND_ENDPOINT::Listen(ULONG)
+{
+    NTSTATUS status;
+    WdfObjectAcquireLock(m_Queue);
+    switch (m_State) {
+    case NdEpAddressBound:
+        break;
+
+    default:
+        status = STATUS_INVALID_DEVICE_STATE;
+        goto unlock;
+    }
+
+    ib_cm_rdma_req_t pdata;
+    FormatRdmaCmHeader(&pdata, m_LocalAddress, m_LocalAddress);
+
+    //
+    // TODO: This call should take as input the port GUID to bind the listen to that single port.
+    //
+    status = m_pIfc->CM.listen(
+        m_hIfc,
+        GetServiceId(m_LocalAddress),
+        &pdata,
+        FIELD_OFFSET(ib_cm_rdma_req_t, pdata),
+        IB_REQ_CM_RDMA_CMP_DST_IP
+        );
+    if (NT_SUCCESS(status)) {
+        m_State = NdEpListening;
+    }
+
+unlock:
+    WdfObjectReleaseLock(m_Queue);
+    return status;
+}
+
+
+void
+NdEpGetConnectionRequest(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_GET_CONNECTION_REQUEST* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    pProvider->LockShared();
+    ND_ENDPOINT* listener;
+    status = pProvider->GetEp(in->ListenerHandle, &listener);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    ND_ENDPOINT* ep;
+    status = pProvider->GetEp(in->ConnectorHandle, &ep);
+    if (NT_SUCCESS(status)) {
+        status = listener->GetConnectionRequest(Request, ep);
+        ep->Release();
+    }
+
+    listener->Release();
+err2:
+    pProvider->Unlock();
+err1:
+    if (status != STATUS_PENDING) {
+        WdfRequestComplete(Request, status);
+    }
+}
+
+
+NTSTATUS ND_ENDPOINT::GetConnectionRequest(WDFREQUEST Request, ND_ENDPOINT* pEp)
+{
+    NTSTATUS status;
+    WdfObjectAcquireLock(m_Queue);
+    if (m_State != NdEpListening) {
+        status = STATUS_INVALID_DEVICE_STATE;
+        goto err1;
+    }
+
+    WdfObjectAcquireLock(pEp->m_Queue);
+    if (pEp->m_State != NdEpIdle) {
+        status = STATUS_CONNECTION_ACTIVE;
+        goto err2;
+    }
+
+    status = ProcessCmReq(pEp);
+    if (!NT_SUCCESS(status)) {
+        pEp->m_State = NdEpQueued;
+        pEp->AddRef();
+        WdfRequestSetInformation(Request, reinterpret_cast<ULONG_PTR>(pEp));
+        status = WdfRequestForwardToIoQueue(Request, m_Queue);
+        if (!NT_SUCCESS(status)) {
+            WdfRequestSetInformation(Request, 0);
+            pEp->Release();
+        } else {
+            status = STATUS_PENDING;
+        }
+    }
+
+err2:
+    WdfObjectReleaseLock(pEp->m_Queue);
+err1:
+    WdfObjectReleaseLock(m_Queue);
+    return status;
+}
+
+
+void ND_ENDPOINT::CancelIo()
+{
+    WdfIoQueuePurgeSynchronously(m_Queue);
+    WdfIoQueueStart(m_Queue);
+}
+
+
+void ND_ENDPOINT::FlushRequest(WDFREQUEST Request, NTSTATUS Status)
+{
+    NT_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+    if (m_Type == NdEpListener) {
+        ND_ENDPOINT* connector = reinterpret_cast<ND_ENDPOINT*>(
+            WdfRequestGetInformation(Request)
+            );
+        WdfObjectAcquireLock(connector->m_Queue);
+        if (connector->m_State == NdEpQueued) {
+            connector->m_State = NdEpIdle;
+        }
+        WdfObjectReleaseLock(connector->m_Queue);
+        connector->Release();
+    } else {
+        WdfObjectAcquireLock(m_Queue);
+        switch (m_State) {
+        case NdEpAddressBound:
+            //
+            // We could have raced with ProcessCmRej, where the IRP was removed from the
+            // queue due to cancellation, ProcessCmRej flips the state to NdEpAddressBound
+            // but does not complete the IRP (since it was removed from the queue).
+            //
+            break;
+
+        case NdEpResolving:
+            //
+            // Because address resolution is asnychronous, going back to NdEpAddressBound
+            // would require proper synchronization with the resolution callback.  For now
+            // just fall through.
+            //
+            //m_State = NdEpAddressBound;
+            //break;
+
+        case NdEpReqSent:
+        case NdEpRepSent:
+        case NdEpActiveDisconnect:
+            m_State = NdEpDisconnected;
+            break;
+
+        case NdEpConnected:
+            //
+            // No state change, this is a NotifyDisconnect.
+            //
+            break;
+
+        default:
+            NT_ASSERT(
+                m_State != NdEpIdle &&
+                m_State != NdEpListening &&
+                m_State != NdEpQueued &&
+                m_State != NdEpReqReceived &&
+                m_State != NdEpPassiveDisconnect &&
+                m_State != NdEpDisconnected
+                );
+            break;
+        }
+        WdfObjectReleaseLock(m_Queue);
+    }
+
+    WdfRequestCompleteWithInformation(Request, Status, 0);
+}
+
+
+void ND_ENDPOINT::EvtIoCanceled(WDFQUEUE Queue, WDFREQUEST Request)
+{
+    ND_ENDPOINT* ep = NdEpGetContext(Queue);
+
+    ep->FlushRequest(Request, STATUS_CANCELLED);
+}
Index: core/ndfltr/kernel/nd_srq.cpp
===================================================================
--- core/ndfltr/kernel/nd_srq.cpp	(revision 0)
+++ core/ndfltr/kernel/nd_srq.cpp	(revision 0)
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+
+void ND_SHARED_RECEIVE_QUEUE::EventHandler(ib_event_rec_t *pEvent)
+{
+    ND_SHARED_RECEIVE_QUEUE *srq = reinterpret_cast<ND_SHARED_RECEIVE_QUEUE*>(pEvent->context);
+
+    switch (pEvent->type) {
+    case IB_AE_SRQ_QP_LAST_WQE_REACHED:
+    case IB_AE_SRQ_LIMIT_REACHED:
+        NdFlushQueue(srq->m_Queue, STATUS_SUCCESS);
+        break;
+    default:
+        NdFlushQueue(srq->m_Queue, STATUS_INTERNAL_ERROR);
+        break;
+    }
+}
+
+
+ND_SHARED_RECEIVE_QUEUE::ND_SHARED_RECEIVE_QUEUE(
+    __in ND_PROTECTION_DOMAIN* pPd,
+    WDFQUEUE queue
+    )
+    : _Base(pPd, pPd->GetInterface()),
+    m_Queue(queue)
+{
+    pPd->AddSrq(&m_Entry);
+}
+
+
+ND_SHARED_RECEIVE_QUEUE::~ND_SHARED_RECEIVE_QUEUE()
+{
+    _Base::RunDown();
+
+    m_pParent->RemoveSrq(&m_Entry);
+
+    if (m_hIfc != NULL) {
+        m_pIfc->destroy_srq(m_hIfc);
+    }
+
+    WdfIoQueuePurgeSynchronously(m_Queue);
+    WdfObjectDelete(m_Queue);
+}
+
+
+NTSTATUS
+ND_SHARED_RECEIVE_QUEUE::Initialize(
+    KPROCESSOR_MODE /*RequestorMode*/,
+    ULONG QueueDepth,
+    ULONG MaxRequestSge,
+    ULONG NotifyThreshold,
+    __inout ci_umv_buf_t* pVerbsData
+    )
+{
+    ib_srq_attr_t attr;
+    attr.max_wr =       QueueDepth;
+    attr.max_sge =      MaxRequestSge;
+    attr.srq_limit =    NotifyThreshold;
+
+    ib_api_status_t ibStatus = m_pIfc->create_srq(
+        m_pParent->GetIfcHandle(),
+        this,
+        EventHandler,
+        &attr,
+        &m_hIfc,
+        pVerbsData
+        );
+    if (ibStatus != IB_SUCCESS) {
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
+//static
+NTSTATUS
+ND_SHARED_RECEIVE_QUEUE::Create(
+    __in ND_PROTECTION_DOMAIN* pPd,
+    KPROCESSOR_MODE RequestorMode,
+    ULONG QueueDepth,
+    ULONG MaxRequestSge,
+    ULONG NotifyThreshold,
+    __inout ci_umv_buf_t* pVerbsData,
+    __out ND_SHARED_RECEIVE_QUEUE** ppSrq
+    )
+{
+    ND_SHARED_RECEIVE_QUEUE* srq = reinterpret_cast<ND_SHARED_RECEIVE_QUEUE*>(
+        ExAllocatePoolWithTag(NonPagedPool, sizeof(*srq), ND_SHARED_RECEIVE_Q_POOL_TAG)
+        );
+    if (srq == NULL) {
+        return STATUS_NO_MEMORY;
+    }
+
+    WDFQUEUE queue;
+    WDF_IO_QUEUE_CONFIG config;
+    WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual);
+    NTSTATUS status = WdfIoQueueCreate(ControlDevice, &config,
+                              WDF_NO_OBJECT_ATTRIBUTES, &queue);
+    if (!NT_SUCCESS(status)) {
+        ExFreePoolWithTag(srq, ND_SHARED_RECEIVE_Q_POOL_TAG);
+        return status;
+    }
+
+    new(srq) ND_SHARED_RECEIVE_QUEUE(pPd, queue);
+    status = srq->Initialize(
+        RequestorMode,
+        QueueDepth,
+        MaxRequestSge,
+        NotifyThreshold,
+        pVerbsData
+        );
+    if (!NT_SUCCESS(status)) {
+        srq->Dispose();
+        return status;
+    }
+
+    *ppSrq = srq;
+    return STATUS_SUCCESS;
+}
+
+
+void ND_SHARED_RECEIVE_QUEUE::Dispose()
+{
+    this->ND_SHARED_RECEIVE_QUEUE::~ND_SHARED_RECEIVE_QUEUE();
+    ExFreePoolWithTag(this, ND_SHARED_RECEIVE_Q_POOL_TAG);
+}
+
+
+void ND_SHARED_RECEIVE_QUEUE::RemoveHandler()
+{
+    if (m_hIfc != NULL) {
+        m_pIfc->destroy_srq(m_hIfc);
+    }
+    _Base::RemoveHandler();
+}
+
+
+void
+NdSrqCreate(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_CREATE_SRQ* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    //
+    // We expect the vendor data to be in the same place in the input and
+    // output buffers.  The input buffer is larger, so we use it as the
+    // minimum length when querying the output buffer.
+    //
+    ND_RESOURCE_DESCRIPTOR* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    ci_umv_buf_t verbsData;
+    NdInitVerbsData(&verbsData, inLen - sizeof(*in),
+                    outLen - sizeof(*in), in + 1);
+
+    pProvider->LockShared();
+
+    ND_PROTECTION_DOMAIN* pd;
+    status = pProvider->GetPd(in->PdHandle, &pd);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    ND_SHARED_RECEIVE_QUEUE* srq;
+    status = ND_SHARED_RECEIVE_QUEUE::Create(
+        pd,
+        WdfRequestGetRequestorMode(Request),
+        in->QueueDepth,
+        in->MaxRequestSge,
+        in->NotifyThreshold,
+        &verbsData,
+        &srq
+        );
+
+    if (NT_SUCCESS(status)) {
+        out->Handle = pProvider->AddSrq(srq);
+        if (out->Handle == 0) {
+            srq->Dispose();
+            status = STATUS_INSUFFICIENT_RESOURCES;
+        } else {
+            WdfRequestSetInformation(Request, outLen);
+        }
+    }
+
+    pd->Release();
+err2:
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdSrqFree(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    pProvider->LockShared();
+    status = pProvider->FreeSrq(in->Handle);
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+void ND_SHARED_RECEIVE_QUEUE::CancelIo()
+{
+    WdfIoQueuePurgeSynchronously(m_Queue);
+    WdfIoQueueStart(m_Queue);
+}
+
+
+void
+NdSrqCancelIo(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    pProvider->LockShared();
+    ND_SHARED_RECEIVE_QUEUE* srq;
+    status = pProvider->GetSrq(in->Handle, &srq);
+    pProvider->Unlock();
+
+    if (NT_SUCCESS(status)) {
+        srq->CancelIo();
+        srq->Release();
+    }
+
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdSrqGetAffinity(
+    __in ND_PROVIDER* /*pProvider*/,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    WdfRequestComplete(Request, STATUS_NOT_SUPPORTED);
+}
+
+
+NTSTATUS
+ND_SHARED_RECEIVE_QUEUE::Modify(
+    ULONG QueueDepth,
+    ULONG NotifyThreshold,
+    ci_umv_buf_t* pVerbsData
+    )
+{
+    ib_srq_attr_t attr;
+    attr.max_wr = QueueDepth;
+    attr.max_sge = 0;
+    attr.srq_limit = NotifyThreshold;
+
+    //
+    // We don't use ib_srq_attr_mask_t here because it is defined as an enum,
+    // so OR-ing values in gives compiler errors.  Lame.
+    //
+    int mask = 0;
+    if (QueueDepth != 0) {
+        mask |= IB_SRQ_MAX_WR;
+    }
+    if (NotifyThreshold != 0) {
+        mask |= IB_SRQ_LIMIT;
+    }
+    ib_api_status_t ibStatus = m_pIfc->modify_srq(
+        m_hIfc,
+        &attr,
+        static_cast<ib_srq_attr_mask_t>(mask),
+        pVerbsData
+        );
+
+    if (ibStatus != IB_SUCCESS) {
+        return STATUS_UNSUCCESSFUL;
+    }
+    
+    return STATUS_SUCCESS;
+}
+
+
+void
+NdSrqModify(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_SRQ_MODIFY* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    //
+    // We expect the vendor data to be in the same place in the input and
+    // output buffers.  The input buffer is larger, so we use it as the
+    // minimum length when querying the output buffer.
+    //
+    ND_RESOURCE_DESCRIPTOR* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    ci_umv_buf_t verbsData;
+    NdInitVerbsData(&verbsData, inLen - sizeof(*in),
+                    outLen - sizeof(*in), in + 1);
+
+    pProvider->LockShared();
+
+    ND_SHARED_RECEIVE_QUEUE* srq;
+    status = pProvider->GetSrq(in->SrqHandle, &srq);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    status = srq->Modify(in->QueueDepth, in->NotifyThreshold, &verbsData);
+    srq->Release();
+
+    if (NT_SUCCESS(status)) {
+        out->Handle = 0;
+        WdfRequestSetInformation(Request, outLen);
+    }
+
+err2:
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+NTSTATUS ND_SHARED_RECEIVE_QUEUE::Notify(WDFREQUEST Request)
+{
+    WdfObjectAcquireLock(m_Queue);
+    NTSTATUS status = WdfRequestForwardToIoQueue(Request, m_Queue);
+    WdfObjectReleaseLock(m_Queue);
+    return status;
+}
+
+
+void
+NdSrqNotify(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    pProvider->LockShared();
+
+    ND_SHARED_RECEIVE_QUEUE* srq;
+    status = pProvider->GetSrq(in->Handle, &srq);
+    if (NT_SUCCESS(status)) {
+        status = srq->Notify(Request);
+        srq->Release();
+    }
+
+    pProvider->Unlock();
+err1:
+    if (!NT_SUCCESS(status)) {
+        WdfRequestComplete(Request, status);
+    }
+}
Index: core/ndfltr/kernel/nd_pd.h
===================================================================
--- core/ndfltr/kernel/nd_pd.h	(revision 0)
+++ core/ndfltr/kernel/nd_pd.h	(revision 0)
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_PD_H_
+#define _ND_PD_H_
+
+
+#define ND_PD_POOL_TAG 'dpdn'
+
+class ND_PROTECTION_DOMAIN
+    : public RdmaParent<ND_ADAPTER, ib_pd_handle_t, ci_interface_t>
+{
+    typedef RdmaParent<ND_ADAPTER, ib_pd_handle_t, ci_interface_t> _Base;
+
+    LIST_ENTRY                                  m_QpList;
+    LIST_ENTRY                                  m_SrqList;
+    LIST_ENTRY                                  m_MrList;
+    LIST_ENTRY                                  m_MwList;
+
+private:
+    ND_PROTECTION_DOMAIN(__in ND_ADAPTER* pAdapter);
+    ~ND_PROTECTION_DOMAIN();
+
+    NTSTATUS Initialize(
+        KPROCESSOR_MODE RequestorMode,
+        __inout ci_umv_buf_t* pVerbsData
+        );
+
+public:
+    static
+    NTSTATUS
+    Create(
+        __in ND_ADAPTER* pAdapter,
+        KPROCESSOR_MODE RequestorMode,
+        __inout ci_umv_buf_t* pVerbsData,
+        __out ND_PROTECTION_DOMAIN** ppPd
+        );
+
+    void Dispose();
+
+    void RemoveHandler();
+
+    void AddQp(LIST_ENTRY* entry) { AddResource(&m_QpList, entry); }
+    void RemoveQp(LIST_ENTRY* entry) { RemoveResource(entry); }
+    void AddSrq(LIST_ENTRY* entry) { AddResource(&m_SrqList, entry); }
+    void RemoveSrq(LIST_ENTRY* entry) { RemoveResource(entry); }
+    void AddMr(LIST_ENTRY* entry) { AddResource(&m_MrList, entry); }
+    void RemoveMr(LIST_ENTRY* entry) { RemoveResource(entry); }
+    void AddMw(LIST_ENTRY* entry) { AddResource(&m_MwList, entry); }
+    void RemoveMw(LIST_ENTRY* entry) { RemoveResource(entry); }
+};
+
+FN_REQUEST_HANDLER NdPdCreate;
+FN_REQUEST_HANDLER NdPdFree;
+
+#endif // _ND_PD_H_
Index: core/ndfltr/kernel/nd_partition.cpp
===================================================================
--- core/ndfltr/kernel/nd_partition.cpp	(revision 0)
+++ core/ndfltr/kernel/nd_partition.cpp	(revision 0)
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+#include <InitGuid.h>
+#include <coguid.h>
+
+
+inline
+bool
+IsEqual(const SOCKADDR_IN6& lhs, const SOCKADDR_IN6& rhs )
+{
+    if (IN6_IS_ADDR_LOOPBACK(&lhs.sin6_addr) ||
+        IN6_IS_ADDR_LOOPBACK(&rhs.sin6_addr))
+    {
+        return true;
+    }
+    return IN6_ADDR_EQUAL( &lhs.sin6_addr, &rhs.sin6_addr ) == TRUE;
+}
+
+
+inline void MapTo6(__in const SOCKADDR_INET& in, __out SOCKADDR_IN6* out)
+{
+    if (in.si_family == AF_INET) {
+        if (in.Ipv4.sin_addr.s_addr == _byteswap_ulong(INADDR_LOOPBACK)) {
+            IN6ADDR_SETLOOPBACK(out);
+        } else {
+            out->sin6_family = AF_INET6;
+            out->sin6_port = 0;
+            out->sin6_flowinfo = 0;
+            out->sin6_addr = in6addr_v4mappedprefix;
+            out->sin6_addr.u.Word[6] = in.Ipv4.sin_addr.S_un.S_un_w.s_w1;
+            out->sin6_addr.u.Word[7] = in.Ipv4.sin_addr.S_un.S_un_w.s_w2;
+            out->sin6_scope_id = 0;
+        }
+    } else {
+        *out = in.Ipv6;
+    }
+}
+
+inline
+bool
+IsEqual(const SOCKADDR_INET& lhs, const SOCKADDR_INET& rhs)
+{
+    SOCKADDR_IN6 lhs6;
+    SOCKADDR_IN6 rhs6;
+
+    MapTo6(lhs, &lhs6);
+    MapTo6(rhs, &rhs6);
+
+    return IsEqual(lhs6, rhs6 );
+}
+
+
+inline UINT64 HwAddressToMac(__in const IF_PHYSICAL_ADDRESS& HwAddress)
+{
+    UINT64 mac = 0;
+    if (HwAddress.Length <= sizeof(mac)) {
+        RtlCopyMemory(&mac, HwAddress.Address, HwAddress.Length);
+    }
+    NT_ASSERT(mac != 0);
+    return mac;
+}
+
+
+ND_PARTITION::ND_PARTITION(UINT64 AdapterId)
+    : m_AdapterId(AdapterId)
+{
+    InitializeListHead(&m_ProvList);
+    InitializeListHead(&m_AddrList);
+    ExInitializeResourceLite(&m_Lock);
+}
+
+
+ND_PARTITION::~ND_PARTITION()
+{
+    _Base::RunDown();
+    ExDeleteResourceLite(&m_Lock);
+}
+
+
+/*static*/
+NTSTATUS
+ND_PARTITION::Create(
+    __in UINT64 AdapterId,
+    __out ND_PARTITION** ppPartition
+    )
+{
+    ND_PARTITION* part = reinterpret_cast<ND_PARTITION*>(
+        ExAllocatePoolWithTag(NonPagedPool, sizeof(*part), ND_PARTITION_POOL_TAG)
+        );
+    if (part == NULL) {
+        return STATUS_NO_MEMORY;
+    }
+
+    new(part) ND_PARTITION(AdapterId);
+    *ppPartition = part;
+    return STATUS_SUCCESS;
+}
+
+
+void ND_PARTITION::Dispose()
+{
+    this->ND_PARTITION::~ND_PARTITION();
+    ExFreePoolWithTag(this, ND_PARTITION_POOL_TAG);
+}
+
+
+void ND_PARTITION::LockShared()
+{
+    KeEnterCriticalRegion();
+    ExAcquireResourceSharedLite(&m_Lock, TRUE);
+}
+
+
+void ND_PARTITION::LockExclusive()
+{
+    KeEnterCriticalRegion();
+    ExAcquireResourceExclusiveLite(&m_Lock, TRUE);
+}
+
+
+void ND_PARTITION::Unlock()
+{
+    ExReleaseResourceLite(&m_Lock);
+    KeLeaveCriticalRegion();
+}
+
+
+NTSTATUS
+ND_PARTITION::PurgeAddressUnsafe(
+    __in const SOCKADDR_INET& Addr
+    )
+{
+    NTSTATUS status = STATUS_INVALID_PARAMETER;
+    for (ADDRESS_ENTRY* entry = static_cast<ADDRESS_ENTRY*>(m_AddrList.Flink);
+        entry != &m_AddrList;
+        entry = static_cast<ADDRESS_ENTRY*>(entry->Flink))
+    {
+        if (IsEqual(entry->Addr, Addr) == true) {
+            RemoveEntryList(entry);
+            ExFreePoolWithTag(entry, ND_PARTITION_ADDRESS_TAG);
+            status = STATUS_SUCCESS;
+            break;
+        }
+    }
+    return status;
+}
+
+
+NTSTATUS
+ND_PARTITION::BindAddress(
+    __in const SOCKADDR_INET& Addr,
+    __in const UINT64 GuestMac,
+    __in const UINT64 Mac
+    )
+{
+    if (GuestMac == 0 || Mac == 0) {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    ADDRESS_ENTRY* entry = reinterpret_cast<ADDRESS_ENTRY*>(
+        ExAllocatePoolWithTag(PagedPool, sizeof(*entry), ND_PARTITION_ADDRESS_TAG)
+        );
+    if (entry == NULL) {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    entry->Addr = Addr;
+    entry->GuestMac = GuestMac;
+    entry->Mac = Mac;
+
+    LockExclusive();
+    PurgeAddressUnsafe(Addr);
+    InsertTailList(&m_AddrList, entry);
+    Unlock();
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS ND_PARTITION::UnbindAddress(
+    __in const SOCKADDR_INET& Addr
+    )
+{
+    LockExclusive();
+    NTSTATUS status = PurgeAddressUnsafe(Addr);
+    Unlock();
+    return status;
+}
+
+
+NTSTATUS
+ND_PARTITION::ResolveAddress(
+    const SOCKADDR_INET& Addr,
+    const GUID& DriverId,
+    UINT64* pId
+    )
+{
+    NTSTATUS status = STATUS_INVALID_ADDRESS;
+    IBAT_PORT_RECORD info = {0};
+
+    if (m_AdapterId == 0) {
+        status = IbatInterface.IpToPort(&Addr, &DriverId, &info);
+    } else {
+        LockShared();
+        for(ADDRESS_ENTRY* entry = static_cast<ADDRESS_ENTRY*>(m_AddrList.Flink);
+            entry != &m_AddrList;
+            entry = static_cast<ADDRESS_ENTRY*>(entry->Flink))
+        {
+            if (IsEqual(entry->Addr, Addr) == true) {
+                status = IbatInterface.MacToPort(entry->Mac, &DriverId, &info);
+                break;
+            }
+        }
+        Unlock();
+    }
+
+    if (NT_SUCCESS(status)) {
+        *pId = info.CaGuid;
+    }
+    return status;
+}
+
+
+NTSTATUS
+ND_PARTITION::GetIpList(
+    __in REFGUID DriverId,
+    __in UINT64 AdapterId,
+    __inout ULONG* pnAddrs,
+    __out SOCKADDR_INET* pAddrs
+    )
+{
+    if (m_AdapterId == 0) {
+        return IbatInterface.GetIpList(
+            &DriverId,
+            AdapterId,
+            0,
+            0,
+            pnAddrs,
+            pAddrs
+            );
+    }
+
+    if (AdapterId != 0 && AdapterId != m_AdapterId) {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    ULONG count = 0;
+    LockShared();
+    ADDRESS_ENTRY* entry;
+    for(entry = static_cast<ADDRESS_ENTRY*>(m_AddrList.Flink);
+        entry != &m_AddrList;
+        entry = static_cast<ADDRESS_ENTRY*>(entry->Flink))
+    {
+        count++;
+        if (pAddrs != NULL) {
+            if (count <= *pnAddrs) {
+                *pAddrs = entry->Addr;
+                pAddrs++;
+            } else {
+                break;
+            }
+        }
+    }
+    Unlock();
+    if (entry != static_cast<ADDRESS_ENTRY*>(&m_AddrList)) {
+        return STATUS_MORE_ENTRIES;
+    }
+    *pnAddrs = count;
+    if (pAddrs == NULL) {
+        return STATUS_BUFFER_OVERFLOW;
+    }
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+ND_PARTITION::GetDeviceAddress(
+    __in const SOCKADDR_INET& Addr,
+    __in REFGUID DriverId,
+    __in UINT64 AdapterId,
+    __out IBAT_PORT_RECORD* pDeviceAddress
+    )
+{
+    NTSTATUS status;
+    if (m_AdapterId == 0) {
+        status = IbatInterface.IpToPort(&Addr, &DriverId, pDeviceAddress);
+        if (NT_SUCCESS(status) && pDeviceAddress->CaGuid != AdapterId) {
+            status = STATUS_INVALID_ADDRESS;
+        }
+        return status;
+    }
+
+    status = STATUS_INVALID_ADDRESS;
+    if (AdapterId == m_AdapterId) {
+        LockShared();
+        for(ADDRESS_ENTRY* entry = static_cast<ADDRESS_ENTRY*>(m_AddrList.Flink);
+            entry != &m_AddrList;
+            entry = static_cast<ADDRESS_ENTRY*>(entry->Flink))
+        {
+            if (IsEqual(entry->Addr, Addr) == true) {
+                status = IbatInterface.MacToPort(entry->Mac, &DriverId, pDeviceAddress);
+                break;
+            }
+        }
+        Unlock();
+    }
+    return status;
+}
+
+
+NTSTATUS
+ND_PARTITION::QueryPath(
+    __in const SOCKADDR_INET& LocalAddress,
+    __in const SOCKADDR_INET& RemoteAddress,
+    __in const IF_PHYSICAL_ADDRESS& RemoteHwAddress,
+    __in FN_IBAT_QUERY_PATH_CALLBACK* CompletionCallback,
+    __in VOID* CompletionContext,
+    __out ib_path_rec_t* pPath
+    )
+{
+    if (m_AdapterId == 0) {
+        return IbatInterface.QueryPathByIpAddress(
+        &LocalAddress,
+        &RemoteAddress,
+        CompletionCallback,
+        CompletionContext,
+        pPath
+        );
+    }
+
+    UINT64 remoteMac = HwAddressToMac(RemoteHwAddress);
+    if (remoteMac == 0) {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    NTSTATUS status = STATUS_INVALID_ADDRESS;
+    LockShared();
+    for(ADDRESS_ENTRY* entry = static_cast<ADDRESS_ENTRY*>(m_AddrList.Flink);
+        entry != &m_AddrList;
+        entry = static_cast<ADDRESS_ENTRY*>(entry->Flink))
+    {
+        if (IsEqual(entry->Addr, LocalAddress) == true) {
+            status = IbatInterface.QueryPathByPhysicalAddress(
+                entry->Mac,
+                remoteMac,
+                CompletionCallback,
+                CompletionContext,
+                pPath
+                );
+            break;
+        }
+    }
+    Unlock();
+    return status;
+}
+
+
+//static
+void
+ND_PARTITION::ResolveAdapterId(
+    ND_PROVIDER* /*pProvider*/,
+    WDFREQUEST Request,
+    bool InternalDeviceControl
+    )
+{
+    NTSTATUS status;
+
+    if (InternalDeviceControl == false) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    NDV_RESOLVE_ADAPTER_ID* in;
+    status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    UINT64* out;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*out),
+        reinterpret_cast<VOID**>(&out),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    UINT64 mac = HwAddressToMac(in->HwAddress);
+    if (mac == 0) {
+        status = STATUS_INVALID_PARAMETER;
+        goto out;
+    }
+
+    IBAT_PORT_RECORD rec;
+    status = IbatInterface.MacToPort(mac, NULL, &rec);
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    *out = rec.CaGuid;
+    WdfRequestSetInformation(Request, sizeof(*out));
+
+out:
+    WdfRequestComplete(Request, status);
+}
+
+
+//static
+void
+ND_PARTITION::Free(
+    ND_PROVIDER* /*pProvider*/,
+    WDFREQUEST Request,
+    bool InternalDeviceControl
+    )
+{
+    NTSTATUS status;
+
+    if (InternalDeviceControl == false) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    ND_HANDLE* in;
+    status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    ND_DRIVER* driver = NdDriverGetContext(WdfGetDriver());
+    status = driver->FreePartition(in->Handle);
+
+out:
+    WdfRequestComplete(Request, status);
+}
+
+
+//static
+void
+ND_PARTITION::BindAddress(
+    ND_PROVIDER* /*pProvider*/,
+    WDFREQUEST Request,
+    bool InternalDeviceControl
+    )
+{
+    NTSTATUS status;
+
+    if (InternalDeviceControl == false) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    NDV_PARTITION_BIND_ADDRESS* in;
+    status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    ND_DRIVER* driver = NdDriverGetContext(WdfGetDriver());
+    ND_PARTITION* part = driver->GetPartition(in->PartitionHandle, true);
+    if (part == NULL) {
+        status = STATUS_INVALID_HANDLE;
+        goto out;
+    }
+
+    UINT64 guestMac = HwAddressToMac(in->GuestHwAddress);
+    UINT64 mac = HwAddressToMac(in->HwAddress);
+    status = part->BindAddress(in->Address, guestMac, mac);
+    part->Release();
+
+out:
+    WdfRequestComplete(Request, status);
+}
+
+
+//static
+void
+ND_PARTITION::UnbindAddress(
+    ND_PROVIDER* /*pProvider*/,
+    WDFREQUEST Request,
+    bool InternalDeviceControl
+    )
+{
+    NTSTATUS status;
+
+    if (InternalDeviceControl == false) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    NDV_PARTITION_UNBIND_ADDRESS* in;
+    status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    ND_DRIVER* driver = NdDriverGetContext(WdfGetDriver());
+    ND_PARTITION* part = driver->GetPartition(in->Handle, true);
+    if (part == NULL) {
+        status = STATUS_INVALID_HANDLE;
+        goto out;
+    }
+
+    status = part->UnbindAddress(in->Address);
+    part->Release();
+
+out:
+    WdfRequestComplete(Request, status);
+}
+
+
+//static
+void
+ND_PARTITION::BindLuid(
+    ND_PROVIDER* /*pProvider*/,
+    WDFREQUEST Request,
+    bool InternalDeviceControl
+    )
+{
+    NTSTATUS status;
+
+    if (InternalDeviceControl == false) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    NDV_PARTITION_BIND_LUID* in;
+    status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    UINT64 mac = HwAddressToMac(in->HwAddress);
+    if (mac == 0) {
+        status = STATUS_INVALID_PARAMETER;
+        goto out;
+    }
+
+    status = IbatInterface.UpdateRegistration(mac, in->Luid.Value);
+
+out:
+    WdfRequestComplete(Request, status);
+}
Index: core/ndfltr/kernel/ndfltr.h
===================================================================
--- core/ndfltr/kernel/ndfltr.h	(revision 0)
+++ core/ndfltr/kernel/ndfltr.h	(revision 0)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE ANd
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _NDFLTR_H_
+#define _NDFLTR_H_
+
+#include <ndioctl.h>
+
+
+#pragma warning(push)
+#pragma warning(disable:4201)
+
+struct NDFLTR_QUERY_ADDRESS_LIST {
+    ND_HANDLE   Header;
+    GUID        DriverId;
+};
+
+struct NDFLTR_RESOLVE_ADDRESS {
+    ND_RESOLVE_ADDRESS  Header;
+    GUID                DriverId;
+};
+
+struct NDFLTR_MR_KEYS {
+    UINT32 LKey;
+    UINT32 RKey;
+};
+
+struct NDFLTR_EP_CREATE {
+    ND_HANDLE   Header;
+    BOOLEAN     Ndv1TimeoutSemantics;
+};
+
+struct NDFLTR_CONNECT {
+    ND_CONNECT  Header;
+    UINT8       RetryCount;
+    UINT8       RnrRetryCount;
+    BYTE        PrivateData[56];
+};
+
+struct NDFLTR_COMPLETE_CONNECT {
+    ND_HANDLE   Header;
+    UINT8       RnrNakTimeout;
+};
+
+struct NDFLTR_ACCEPT {
+    ND_ACCEPT   Header;
+    UINT8       RnrRetryCount;
+    UINT8       RnrNakTimeout;
+    BYTE        PrivateData[148];
+};
+
+struct NDFLTR_REJECT {
+    ND_REJECT   Header;
+    BYTE        PrivateData[148];
+};
+
+#pragma warning(pop)
+
+#endif // _NDFLTR_H_
Index: core/ndfltr/kernel/nd_mr.cpp
===================================================================
--- core/ndfltr/kernel/nd_mr.cpp	(revision 0)
+++ core/ndfltr/kernel/nd_mr.cpp	(revision 0)
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+
+ND_MEMORY_REGION::ND_MEMORY_REGION(__in ND_PROTECTION_DOMAIN* pPd)
+    : _Base(pPd, pPd->GetInterface()),
+    m_LKey(0),
+    m_RKey(0)
+{
+    KeInitializeGuardedMutex(&m_Lock);
+    pPd->AddMr(&m_Entry);
+}
+
+
+ND_MEMORY_REGION::~ND_MEMORY_REGION()
+{
+    _Base::RunDown();
+
+    m_pParent->RemoveMr(&m_Entry);
+
+    if (m_hIfc != NULL) {
+        m_pIfc->deregister_mr(m_hIfc);
+    }
+}
+
+
+//NOTE: OFED drivers do not expose memory region objects.  The object is implicitly
+// created when memory is registered.
+NTSTATUS
+ND_MEMORY_REGION::Initialize(
+    KPROCESSOR_MODE /*RequestorMode*/,
+    __inout ci_umv_buf_t* /*pVerbsData*/
+    )
+{
+    //ib_api_status_t ibStatus = pPd->m_pIfc->create_mr(pPd->hVerbsPd, &mr->RKey,
+    //                                        &mr->m_hIfc, pVerbsData);
+    //if (ibStatus != IB_SUCCESS) {
+    //    return STATUS_UNSUCCESSFUL;
+    //}
+    return STATUS_SUCCESS;
+}
+
+
+//static
+NTSTATUS
+ND_MEMORY_REGION::Create(
+    __in ND_PROTECTION_DOMAIN* pPd,
+    KPROCESSOR_MODE RequestorMode,
+    __inout ci_umv_buf_t* pVerbsData,
+    __out ND_MEMORY_REGION** ppMr
+    )
+{
+    ND_MEMORY_REGION* mr = reinterpret_cast<ND_MEMORY_REGION*>(
+        ExAllocatePoolWithTag(NonPagedPool, sizeof(*mr), ND_MEMORY_REGION_TAG)
+        );
+    if (mr == NULL) {
+        return STATUS_NO_MEMORY;
+    }
+
+    new(mr) ND_MEMORY_REGION(pPd);
+    NTSTATUS status = mr->Initialize(RequestorMode, pVerbsData);
+    if (!NT_SUCCESS(status)) {
+        mr->Dispose();
+        return status;
+    }
+
+    *ppMr = mr;
+    return STATUS_SUCCESS;
+}
+
+
+void ND_MEMORY_REGION::Dispose()
+{
+    this->ND_MEMORY_REGION::~ND_MEMORY_REGION();
+    ExFreePoolWithTag(this, ND_MEMORY_REGION_TAG);
+}
+
+
+void ND_MEMORY_REGION::RemoveHandler()
+{
+    if (m_hIfc != NULL) {
+        m_pIfc->deregister_mr(m_hIfc);
+    }
+    _Base::RemoveHandler();
+}
+
+
+NTSTATUS
+ND_MEMORY_REGION::Register(
+    UINT64 Address,
+    UINT64 TargetAddress,
+    UINT64 Length,
+    ULONG Flags,
+    KPROCESSOR_MODE RequestorMode,
+    __out NDFLTR_MR_KEYS* pKeys
+    )
+{
+    if (Address == 0) {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (Length == 0) {
+        return STATUS_INVALID_BUFFER_SIZE;
+    }
+
+    ib_mr_create_t attr;
+    attr.vaddr_padding = Address;
+    attr.length = Length;
+    attr.access_ctrl = 0;
+
+    if (Flags & ND_MR_FLAG_ALLOW_LOCAL_WRITE) {
+        attr.access_ctrl |= IB_AC_LOCAL_WRITE;
+    }
+    if (Flags & ND_MR_FLAG_ALLOW_REMOTE_READ) {
+        attr.access_ctrl |= IB_AC_RDMA_READ;
+    }
+    if (Flags & ND_MR_FLAG_ALLOW_REMOTE_WRITE) {
+        attr.access_ctrl |= IB_AC_RDMA_WRITE;
+    }
+    //NOTE: OFED drivers do not support iWARP.  Because iWARP performs an RDMA write to
+    // satisfy the peer's RDMA read request, and because there can only be a single
+    // target buffer, the read is limited to a single sink buffer.  These buffers must
+    // be registered to allow the remote peer write access.
+    //if (Flags & ND_MR_FLAG_RDMA_READ_SINK) {
+    //    attr.access_ctrl |=
+    //}
+    if (Flags & ND_MR_FLAG_DO_NOT_SECURE_VM) {
+        attr.access_ctrl |= IB_AC_NOT_CACHABLE;
+    }
+
+    boolean_t umCall = (RequestorMode == UserMode);
+
+    NTSTATUS status;
+    KeAcquireGuardedMutex(&m_Lock);
+    if (m_pIfc == NULL) {
+        status = STATUS_DEVICE_REMOVED;
+    } else if (m_hIfc != NULL) {
+        status = STATUS_INVALID_DEVICE_STATE;
+    } else {
+        ib_api_status_t ibStatus = m_pIfc->register_mr_remap(
+            m_pParent->GetIfcHandle(),
+            &attr,
+            TargetAddress,
+            &m_LKey,
+            &m_RKey,
+            &m_hIfc,
+            umCall
+            );
+        if (ibStatus == IB_INVALID_PERMISSION) {
+            status = STATUS_ACCESS_VIOLATION;
+        } else if (ibStatus != IB_SUCCESS) {
+            status = STATUS_UNSUCCESSFUL;
+        } else {
+            status = STATUS_SUCCESS;
+            pKeys->LKey = m_LKey;
+            pKeys->RKey = m_RKey;
+        }
+    }
+    KeReleaseGuardedMutex(&m_Lock);
+    return status;
+}
+
+
+NTSTATUS ND_MEMORY_REGION::Deregister()
+{
+    NTSTATUS status;
+    KeAcquireGuardedMutex(&m_Lock);
+    if (m_pIfc == NULL) {
+        status = STATUS_DEVICE_REMOVED;
+    } else if (m_hIfc == NULL) {
+        status = STATUS_INVALID_DEVICE_STATE;
+    } else {
+        ib_api_status_t ibStatus = m_pIfc->deregister_mr(m_hIfc);
+        if (ibStatus == IB_RESOURCE_BUSY) {
+            status = STATUS_DEVICE_BUSY;
+        } else if (ibStatus != IB_SUCCESS) {
+            status = STATUS_UNSUCCESSFUL;
+        } else {
+            m_hIfc = NULL;
+            status = STATUS_SUCCESS;
+        }
+    }
+    KeReleaseGuardedMutex(&m_Lock);
+    return status;
+}
+
+
+bool ND_MEMORY_REGION::Busy()
+{
+    if (_Base::Busy()) {
+        return true;
+    }
+
+    NTSTATUS status = Deregister();
+    return (status == STATUS_DEVICE_BUSY);
+}
+
+
+void
+NdMrCreate(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    //
+    // We expect the vendor data to be in the same place in the input and
+    // output buffers.  The input buffer is larger, so we use it as the
+    // minimum length when querying the output buffer.
+    //
+    UINT64* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    ci_umv_buf_t verbsData;
+    NdInitVerbsData(&verbsData, inLen - sizeof(*in),
+                    outLen - sizeof(*in), in + 1);
+
+    pProvider->LockShared();
+
+    ND_PROTECTION_DOMAIN* pd;
+    status = pProvider->GetPd(in->Handle, &pd);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    ND_MEMORY_REGION* mr;
+    status = ND_MEMORY_REGION::Create(
+        pd,
+        WdfRequestGetRequestorMode(Request),
+        &verbsData,
+        &mr
+        );
+
+    if (!NT_SUCCESS(status)) {
+        goto err3;
+    }
+
+    *out = pProvider->AddMr(mr);
+    if (*out == 0) {
+        mr->Dispose();
+        status = STATUS_INSUFFICIENT_RESOURCES;
+    } else {
+        WdfRequestSetInformation(Request, outLen);
+    }
+
+err3:
+    pd->Release();
+err2:
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdMrFree(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    pProvider->LockShared();
+    status = pProvider->FreeMr(in->Handle);
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdMrCancelIo(
+    __in ND_PROVIDER* /*pProvider*/,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    WdfRequestComplete(Request, STATUS_SUCCESS);
+}
+
+
+void
+NdMrRegister(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_MR_REGISTER* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Header.Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    NDFLTR_MR_KEYS* out;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*out),
+        reinterpret_cast<VOID**>(&out),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    pProvider->LockShared();
+
+    ND_MEMORY_REGION* mr;
+    status = pProvider->GetMr(in->Header.MrHandle, &mr);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    status = mr->Register(
+        in->Address,
+        in->Header.TargetAddress,
+        in->Header.CbLength,
+        in->Header.Flags,
+        WdfRequestGetRequestorMode(Request),
+        out
+        );
+
+    if (NT_SUCCESS(status)) {
+        WdfRequestSetInformation(Request, sizeof(*out));
+    }
+
+    mr->Release();
+err2:
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdMrDeregister(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    pProvider->LockShared();
+
+    ND_MEMORY_REGION* mr;
+    status = pProvider->GetMr(in->Handle, &mr);
+    if (NT_SUCCESS(status)) {
+        status = mr->Deregister();
+        mr->Release();
+    }
+
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdMrRegisterPages(
+    __in ND_PROVIDER* /*pProvider*/,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    if (WdfRequestGetRequestorMode(Request) == UserMode) {
+        WdfRequestComplete(Request, STATUS_INVALID_DEVICE_REQUEST);
+    }
+
+    WdfRequestComplete(Request, STATUS_NOT_SUPPORTED);
+}
Index: core/ndfltr/kernel/nd_qp.cpp
===================================================================
--- core/ndfltr/kernel/nd_qp.cpp	(revision 0)
+++ core/ndfltr/kernel/nd_qp.cpp	(revision 0)
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+
+void ND_QUEUE_PAIR::EventHandler(ib_event_rec_t* pEvent)
+{
+    if (pEvent->type != IB_AE_QP_COMM) {
+        return;
+    }
+
+    ND_QUEUE_PAIR* qp = reinterpret_cast<ND_QUEUE_PAIR*>(pEvent->context);
+    ND_ENDPOINT* ep = qp->ClearEp();
+
+    if (ep != NULL) {
+        ND_ENDPOINT::Established(ep);
+        ep->Dereference();
+    }
+}
+
+
+ND_QUEUE_PAIR::ND_QUEUE_PAIR(
+    __in ND_PROTECTION_DOMAIN* pPd,
+    __in ND_COMPLETION_QUEUE* pReceiveCq,
+    __in ND_COMPLETION_QUEUE* pInitiatorCq,
+    __in ND_SHARED_RECEIVE_QUEUE* pSrq
+    )
+    : _Base(pPd, pPd->GetInterface()),
+    m_pReceiveCq(pReceiveCq),
+    m_pInitiatorCq(pInitiatorCq),
+    m_pSrq(pSrq),
+    m_pEp(NULL),
+    m_EpBound(0)
+{
+    pReceiveCq->AddRef();
+    pInitiatorCq->AddRef();
+    if (pSrq != NULL) {
+        pSrq->AddRef();
+    }
+
+    pPd->AddQp(&m_Entry);
+}
+
+
+ND_QUEUE_PAIR::~ND_QUEUE_PAIR()
+{
+    _Base::RunDown();
+
+    m_pParent->RemoveQp(&m_Entry);
+
+    if (m_hIfc != NULL) {
+        m_pIfc->destroy_qp(m_hIfc, 0);
+    }
+
+    if (m_pSrq != NULL) {
+        m_pSrq->Release();
+    }
+    m_pReceiveCq->Release();
+    m_pInitiatorCq->Release();
+}
+
+
+NTSTATUS
+ND_QUEUE_PAIR::Initialize(
+    KPROCESSOR_MODE /*RequestorMode*/,
+    ULONG InitiatorQueueDepth,
+    ULONG MaxInitiatorRequestSge,
+    ULONG ReceiveQueueDepth,
+    ULONG MaxReceiveRequestSge,
+    ULONG MaxInlineDataSize,
+    __inout ci_umv_buf_t* pVerbsData
+    )
+{
+    ib_qp_create_t create;
+    create.qp_type =        IB_QPT_RELIABLE_CONN;
+    create.sq_max_inline =  MaxInlineDataSize;
+    create.sq_depth =       InitiatorQueueDepth;
+    create.rq_depth =       ReceiveQueueDepth;
+    create.sq_sge =         MaxInitiatorRequestSge;
+    create.rq_sge =         MaxReceiveRequestSge;
+    create.h_sq_cq =        m_pInitiatorCq->GetIfcHandle();
+    create.h_rq_cq =        m_pReceiveCq->GetIfcHandle();
+    create.h_srq =          (m_pSrq != NULL) ? m_pSrq->GetIfcHandle() : NULL;
+    create.sq_signaled =    FALSE;
+
+    ib_qp_attr_t attr;
+    ib_api_status_t ibStatus = m_pIfc->create_qp(
+        m_pParent->GetIfcHandle(),
+        this,
+        EventHandler,
+        &create,
+        &attr,
+        &m_hIfc,
+        pVerbsData
+        );
+    switch (ibStatus) {
+    case IB_SUCCESS:
+        break;
+    case IB_INVALID_PARAMETER:
+    case IB_INVALID_SETTING:
+        return STATUS_INVALID_PARAMETER;
+    case IB_INSUFFICIENT_MEMORY:
+        return STATUS_INSUFFICIENT_RESOURCES;
+    default:
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    m_Qpn = attr.num;
+
+    ib_qp_mod_t mod;
+    mod.req_state = IB_QPS_INIT;
+    mod.state.init.primary_port = 1;
+    mod.state.init.qkey = 0;
+    mod.state.init.pkey_index = 0;
+    mod.state.init.access_ctrl = 0;
+    return Modify(&mod, NULL, 0);
+}
+
+
+//static
+NTSTATUS
+ND_QUEUE_PAIR::Create(
+    __in ND_PROTECTION_DOMAIN* pPd,
+    KPROCESSOR_MODE RequestorMode,
+    __in ND_COMPLETION_QUEUE* pReceiveCq,
+    __in ND_COMPLETION_QUEUE* pInitiatorCq,
+    __in ND_SHARED_RECEIVE_QUEUE* pSrq,
+    ULONG InitiatorQueueDepth,
+    ULONG MaxInitiatorRequestSge,
+    ULONG ReceiveQueueDepth,
+    ULONG MaxReceiveRequestSge,
+    ULONG MaxInlineDataSize,
+    __inout ci_umv_buf_t* pVerbsData,
+    __out ND_QUEUE_PAIR** ppQp
+    )
+{
+    ND_QUEUE_PAIR* qp = reinterpret_cast<ND_QUEUE_PAIR*>(
+        ExAllocatePoolWithTag(NonPagedPool, sizeof(*qp), ND_QUEUE_PAIR_TAG)
+        );
+    if (qp == NULL) {
+        return STATUS_NO_MEMORY;
+    }
+
+    new(qp) ND_QUEUE_PAIR(pPd, pReceiveCq, pInitiatorCq, pSrq);
+    NTSTATUS status = qp->Initialize(
+        RequestorMode,
+        InitiatorQueueDepth,
+        MaxInitiatorRequestSge,
+        ReceiveQueueDepth,
+        MaxReceiveRequestSge,
+        MaxInlineDataSize,
+        pVerbsData
+        );
+
+    if (!NT_SUCCESS(status)) {
+        qp->Dispose();
+        return status;
+    }
+
+    *ppQp = qp;
+    return STATUS_SUCCESS;
+}
+
+
+void ND_QUEUE_PAIR::Dispose()
+{
+    this->ND_QUEUE_PAIR::~ND_QUEUE_PAIR();
+    ExFreePoolWithTag(this, ND_QUEUE_PAIR_TAG);
+}
+
+
+void ND_QUEUE_PAIR::RemoveHandler()
+{
+    if (m_hIfc != NULL) {
+        m_pIfc->destroy_qp(m_hIfc, 0);
+    }
+    _Base::RemoveHandler();
+}
+
+
+void
+NdQpCreate(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_CREATE_QP* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Header.Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    //
+    // We expect the vendor data to be in the same place in the input and
+    // output buffers.  The input buffer is larger, so we use it as the
+    // minimum length when querying the output buffer.
+    //
+    ND_RESOURCE_DESCRIPTOR* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    ci_umv_buf_t verbsData;
+    NdInitVerbsData(&verbsData, inLen - sizeof(*in),
+                    outLen - sizeof(*in), in + 1);
+
+    pProvider->LockShared();
+
+    ND_PROTECTION_DOMAIN* pd;
+    status = pProvider->GetPd(in->Header.PdHandle, &pd);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    ND_COMPLETION_QUEUE* recvCq;
+    status = pProvider->GetCq(in->Header.ReceiveCqHandle, &recvCq);
+    if (!NT_SUCCESS(status)) {
+        goto err3;
+    }
+
+    ND_COMPLETION_QUEUE* initiatorCq;
+    status = pProvider->GetCq(in->Header.InitiatorCqHandle, &initiatorCq);
+    if (!NT_SUCCESS(status)) {
+        goto err4;
+    }
+
+    ND_QUEUE_PAIR* qp;
+    status = ND_QUEUE_PAIR::Create(
+        pd,
+        WdfRequestGetRequestorMode(Request),
+        recvCq,
+        initiatorCq,
+        NULL,
+        in->Header.InitiatorQueueDepth,
+        in->Header.MaxInitiatorRequestSge,
+        in->ReceiveQueueDepth,
+        in->MaxReceiveRequestSge,
+        in->Header.CbMaxInlineData,
+        &verbsData,
+        &qp
+        );
+
+    if (NT_SUCCESS(status)) {
+        out->Handle = pProvider->AddQp(qp);
+        if (out->Handle == 0) {
+            qp->Dispose();
+            status = STATUS_INSUFFICIENT_RESOURCES;
+        } else {
+            WdfRequestSetInformation(Request, outLen);
+        }
+    }
+
+    initiatorCq->Release();
+err4:
+    recvCq->Release();
+err3:
+    pd->Release();
+err2:
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdQpCreateWithSrq(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_CREATE_QP_WITH_SRQ* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Header.Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    //
+    // We expect the vendor data to be in the same place in the input and
+    // output buffers.  The input buffer is larger, so we use it as the
+    // minimum length when querying the output buffer.
+    //
+    ND_RESOURCE_DESCRIPTOR* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    ci_umv_buf_t verbsData;
+    NdInitVerbsData(&verbsData, inLen - sizeof(*in),
+                    outLen - sizeof(*in), in + 1);
+
+    pProvider->LockShared();
+
+    ND_PROTECTION_DOMAIN* pd;
+    status = pProvider->GetPd(in->Header.PdHandle, &pd);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    ND_COMPLETION_QUEUE* recvCq;
+    status = pProvider->GetCq(in->Header.ReceiveCqHandle, &recvCq);
+    if (!NT_SUCCESS(status)) {
+        goto err3;
+    }
+
+    ND_COMPLETION_QUEUE* initiatorCq;
+    status = pProvider->GetCq(in->Header.InitiatorCqHandle, &initiatorCq);
+    if (!NT_SUCCESS(status)) {
+        goto err4;
+    }
+
+    ND_SHARED_RECEIVE_QUEUE* srq;
+    status = pProvider->GetSrq(in->SrqHandle, &srq);
+    if (!NT_SUCCESS(status)) {
+        goto err5;
+    }
+
+    ND_QUEUE_PAIR* qp;
+    status = ND_QUEUE_PAIR::Create(
+        pd,
+        WdfRequestGetRequestorMode(Request),
+        recvCq,
+        initiatorCq,
+        srq,
+        in->Header.InitiatorQueueDepth,
+        in->Header.MaxInitiatorRequestSge,
+        0,
+        0,
+        in->Header.CbMaxInlineData,
+        &verbsData,
+        &qp
+        );
+
+    if (!NT_SUCCESS(status)) {
+        goto err6;
+    }
+
+    out->Handle = pProvider->AddQp(qp);
+    if (out->Handle == 0) {
+        qp->Dispose();
+        status = STATUS_INSUFFICIENT_RESOURCES;
+    } else {
+        WdfRequestSetInformation(Request, outLen);
+    }
+
+err6:
+    srq->Release();
+err5:
+    initiatorCq->Release();
+err4:
+    recvCq->Release();
+err3:
+    pd->Release();
+err2:
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdQpFree(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    pProvider->LockShared();
+    status = pProvider->FreeQp(in->Handle);
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdQpFlush(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    BYTE* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        0,
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (status == STATUS_BUFFER_TOO_SMALL) {
+        out = NULL;
+        outLen = 0;
+    } else if (!NT_SUCCESS(status)) {
+        goto err;
+    } else if (outLen > ULONG_MAX) {
+        status = STATUS_INVALID_PARAMETER;
+        goto err;
+    }
+
+    pProvider->LockShared();
+
+    ND_QUEUE_PAIR* qp;
+    status = pProvider->GetQp(in->Handle, &qp);
+    if (NT_SUCCESS(status)) {
+        status = qp->Flush(out, static_cast<ULONG>(outLen));
+        qp->Release();
+        WdfRequestSetInformation(Request, outLen);
+    }
+
+    pProvider->Unlock();
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+NTSTATUS ND_QUEUE_PAIR::Modify(ib_qp_mod_t* pMod, BYTE* pOutBuf, ULONG OutLen)
+{
+    if (Removed()) {
+        return STATUS_DEVICE_REMOVED;
+    }
+
+    ib_api_status_t ibStatus = m_pIfc->ndi_modify_qp(m_hIfc, pMod, NULL, OutLen, pOutBuf);
+    //
+    // TODO: report finer grained errors.
+    //
+    if (ibStatus != IB_SUCCESS) {
+        return STATUS_UNSUCCESSFUL;
+    } else {
+        return STATUS_SUCCESS;
+    }
+}
+
+
+NTSTATUS ND_QUEUE_PAIR::Flush(__out_opt BYTE* pOutBuf, ULONG OutLen)
+{
+    ib_qp_mod_t mod;
+    mod.req_state = IB_QPS_ERROR;
+    return Modify(&mod, pOutBuf, OutLen);
+}
Index: core/ndfltr/kernel/SOURCES
===================================================================
--- core/ndfltr/kernel/SOURCES	(revision 0)
+++ core/ndfltr/kernel/SOURCES	(revision 0)
@@ -0,0 +1,39 @@
+TARGETNAME = ndfltr
+TARGETPATH = ..\..\..\bin\kernel\obj$(BUILD_ALT_DIR)
+TARGETTYPE = DRIVER
+
+KMDF_VERSION_MAJOR = 1
+TARGETLIBS = $(TARGETLIBS) \
+             $(DDK_LIB_PATH)\wdmsec.lib \
+             $(DDK_LIB_PATH)\msnetioid.lib \
+
+TARGET_DESTINATION=$(RELDIR)\mlx4_bus
+
+PRECOMPILED_INCLUDE=precomp.h
+PRECOMPILED_CXX=1
+USECXX_FLAG=1
+
+SOURCES = \
+    ndfltr.rc \
+    nd_driver.cpp \
+    nd_partition.cpp \
+    nd_provider.cpp \
+    nd_adapter.cpp \
+    nd_pd.cpp \
+    nd_cq.cpp \
+    nd_mr.cpp \
+    nd_mw.cpp \
+    nd_srq.cpp \
+    nd_qp.cpp \
+    nd_ep.cpp \
+
+INCLUDES = \
+    ..;..\..\..\inc; \
+    ..\..\..\inc\kernel; \
+    ..\..\..\inc\user; \
+    ..\..\..\etc\kernel; \
+    $(ND_SDK_PATH)\include \
+
+C_DEFINES = $(C_DEFINES) -DIOCTL_INTERFACE=1
+
+MSC_WARNING_LEVEL = /W4
Index: core/ndfltr/kernel/nd_mw.cpp
===================================================================
--- core/ndfltr/kernel/nd_mw.cpp	(revision 0)
+++ core/ndfltr/kernel/nd_mw.cpp	(revision 0)
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+
+ND_MEMORY_WINDOW::ND_MEMORY_WINDOW(__in ND_PROTECTION_DOMAIN* pPd)
+    : _Base(pPd, pPd->GetInterface()),
+    m_RKey(0)
+{
+    pPd->AddMw(&m_Entry);
+}
+
+
+ND_MEMORY_WINDOW::~ND_MEMORY_WINDOW()
+{
+    _Base::RunDown();
+
+    m_pParent->RemoveMw(&m_Entry);
+
+    if (m_hIfc != NULL) {
+        m_pIfc->destroy_mw(m_hIfc);
+    }
+}
+
+
+//
+//NOTE: Current OFED drivers do *not* support MWs.
+//
+NTSTATUS
+ND_MEMORY_WINDOW::Initialize(
+    KPROCESSOR_MODE /*RequestorMode*/,
+    __inout ci_umv_buf_t* /*pVerbsData*/
+    )
+{
+    //ib_api_status_t ibStatus = pPd->pVerbs->create_mw(pPd->hVerbsPd, &mw->RKey,
+    //                                        &mw->hVerbsMw, pVerbsData);
+    //if (ibStatus != IB_SUCCESS) {
+    //    return STATUS_UNSUCCESSFUL;
+    //}
+
+    return STATUS_SUCCESS;
+}
+
+
+//static
+NTSTATUS
+ND_MEMORY_WINDOW::Create(
+    __in ND_PROTECTION_DOMAIN* pPd,
+    KPROCESSOR_MODE RequestorMode,
+    __inout ci_umv_buf_t* pVerbsData,
+    __out ND_MEMORY_WINDOW** ppMw
+    )
+{
+    //TODO: Evaluate whether we can allocate some of these objects as PagedPool.
+    ND_MEMORY_WINDOW* mw = reinterpret_cast<ND_MEMORY_WINDOW*>(
+        ExAllocatePoolWithTag(NonPagedPool, sizeof(*mw), ND_MEMORY_WINDOW_TAG)
+        );
+    if (mw == NULL) {
+        return STATUS_NO_MEMORY;
+    }
+
+    new(mw) ND_MEMORY_WINDOW(pPd);
+
+    NTSTATUS status = mw->Initialize(RequestorMode, pVerbsData);
+    if (!NT_SUCCESS(status)) {
+        mw->Dispose();
+        return status;
+    }
+
+    *ppMw = mw;
+    return STATUS_SUCCESS;
+}
+
+
+void ND_MEMORY_WINDOW::Dispose()
+{
+    this->ND_MEMORY_WINDOW::~ND_MEMORY_WINDOW();
+    ExFreePoolWithTag(this, ND_MEMORY_WINDOW_TAG);
+}
+
+
+void ND_MEMORY_WINDOW::RemoveHandler()
+{
+    //TODO: OFED drivers don't support memory windows.
+    //pVerbs->destroy_mw(hVerbsMw);
+    _Base::RemoveHandler();
+}
+
+
+void
+NdMwCreate(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    //
+    // We expect the vendor data to be in the same place in the input and
+    // output buffers.  The input buffer is larger, so we use it as the
+    // minimum length when querying the output buffer.
+    //
+    UINT64* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    ci_umv_buf_t verbsData;
+    NdInitVerbsData(&verbsData, inLen - sizeof(*in),
+                    outLen - sizeof(*in), in + 1);
+
+    pProvider->LockShared();
+
+    ND_PROTECTION_DOMAIN *pd;
+    status = pProvider->GetPd(in->Handle, &pd);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    ND_MEMORY_WINDOW *mw;
+    status = ND_MEMORY_WINDOW::Create(
+        pd,
+        WdfRequestGetRequestorMode(Request),
+        &verbsData,
+        &mw
+        );
+
+    if (!NT_SUCCESS(status)) {
+        goto err3;
+    }
+
+    *out = pProvider->AddMw(mw);
+    if (*out == 0) {
+        mw->Dispose();
+        status = STATUS_INSUFFICIENT_RESOURCES;
+    } else {
+        WdfRequestSetInformation(Request, outLen);
+    }
+
+err3:
+    pd->Release();
+err2:
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdMwFree(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    pProvider->LockShared();
+    status = pProvider->FreeMw(in->Handle);
+    pProvider->Unlock();
+out:
+    WdfRequestComplete(Request, status);
+}
Index: core/ndfltr/kernel/makefile.inc
===================================================================
--- core/ndfltr/kernel/makefile.inc	(revision 0)
+++ core/ndfltr/kernel/makefile.inc	(revision 0)
@@ -0,0 +1,13 @@
+_LNG=$(LANGUAGE)
+
+!IF !DEFINED(_INX)
+_INX=.
+!ENDIF
+
+STAMP=stampinf -a $(_BUILDARCH) -k $(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR)
+
+!INCLUDE mod_ver.def
+
+$(INF_TARGET) : $(_INX)\$(INF_NAME).inx 
+    copy $(_INX)\$(@B).inx $@
+    $(STAMP) -f $@ -d * -v $(IB_MAJORVERSION).$(IB_MINORVERSION).$(IB_BUILDVERSION).$(OPENIB_REV) 
Index: core/ndfltr/kernel/nd_adapter.h
===================================================================
--- core/ndfltr/kernel/nd_adapter.h	(revision 0)
+++ core/ndfltr/kernel/nd_adapter.h	(revision 0)
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_ADAPTER_H_
+#define _ND_ADAPTER_H_
+
+
+#define ND_ADAPTER_POOL_TAG 'dadn'
+
+class ND_ADAPTER
+    : public RdmaParent<ND_PROVIDER, ib_ca_handle_t, ci_interface_t>
+{
+    typedef RdmaParent<ND_PROVIDER, ib_ca_handle_t, ci_interface_t> _Base;
+
+    ND_RDMA_DEVICE  *m_pDevice;
+
+    LIST_ENTRY      m_PdList;
+    LIST_ENTRY      m_CqList;
+    LIST_ENTRY      m_EpList;
+
+    UINT64          m_Id;
+
+private:
+    ND_ADAPTER(
+        __in ND_PROVIDER* pProvider,
+        __in ND_RDMA_DEVICE* pDevice,
+        __in UINT64 AdapterId
+        );
+    ~ND_ADAPTER();
+
+    NTSTATUS Initialize(
+        KPROCESSOR_MODE RequestorMode,
+        __inout ci_umv_buf_t* pVerbsData
+        );
+
+public:
+    static
+    NTSTATUS
+    Create(
+        __in ND_PROVIDER* pProvider,
+        UINT64 AdapterId,
+        KPROCESSOR_MODE RequestorMode,
+        __inout ci_umv_buf_t* pVerbsData,
+        __out ND_ADAPTER** ppAdapter
+        );
+
+    void Dispose();
+
+    void RemoveHandler(__in ND_RDMA_DEVICE* pDevice);
+
+    ND_PROVIDER* GetProvider() const { return m_pParent; }
+    ND_RDMA_DEVICE* GetDevice() const { return m_pDevice; }
+
+    void AddCq(LIST_ENTRY* entry) { AddResource(&m_CqList, entry); }
+    void RemoveCq(LIST_ENTRY* entry) { RemoveResource(entry); }
+    void AddPd(LIST_ENTRY* entry) { AddResource(&m_PdList, entry); }
+    void RemovePd(LIST_ENTRY* entry) { RemoveResource(entry); }
+    void AddEp(LIST_ENTRY* entry) { AddResource(&m_EpList, entry); }
+    void RemoveEp(LIST_ENTRY* entry) { RemoveResource(entry); }
+
+    NTSTATUS
+    GetDeviceAddress(
+        __in const SOCKADDR_INET& Addr,
+        __out IBAT_PORT_RECORD* pDeviceAddress
+        );
+
+public:
+    static FN_REQUEST_HANDLER QueryAddressList;
+    static FN_REQUEST_HANDLER Query;
+
+};
+
+FN_REQUEST_HANDLER NdAdapterOpen;
+FN_REQUEST_HANDLER NdAdapterClose;
+
+#endif // __ND_ADAPTER_H_
Index: core/ndfltr/kernel/nd_provider.cpp
===================================================================
--- core/ndfltr/kernel/nd_provider.cpp	(revision 0)
+++ core/ndfltr/kernel/nd_provider.cpp	(revision 0)
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+
+ND_PROVIDER::ND_PROVIDER(__in ND_PARTITION* pPartition)
+    : _Base(pPartition),
+    m_nFiles(0)
+{
+    ExInitializeResourceLite(&m_Lock);
+    pPartition->AddProvider(&m_Entry);
+}
+
+class CancelIoFunctor
+{
+public:
+    bool operator () (ND_ENDPOINT* ep)
+    {
+        ep->CancelIo();
+        return false;
+    }
+};
+
+ND_PROVIDER::~ND_PROVIDER()
+{
+    LockExclusive();
+
+    m_EpTable.LockExclusive();
+    m_EpTable.Iterate(CancelIoFunctor());
+    m_EpTable.Iterate(DisposeFunctor<ND_ENDPOINT>());
+    m_EpTable.Unlock();
+
+    m_MwTable.LockExclusive();
+    m_MwTable.Iterate(DisposeFunctor<ND_MEMORY_WINDOW>());
+    m_MwTable.Unlock();
+
+    m_QpTable.LockExclusive();
+    m_QpTable.Iterate(DisposeFunctor<ND_QUEUE_PAIR>());
+    m_QpTable.Unlock();
+
+    m_SrqTable.LockExclusive();
+    m_SrqTable.Iterate(DisposeFunctor<ND_SHARED_RECEIVE_QUEUE>());
+    m_SrqTable.Unlock();
+
+    m_MrTable.LockExclusive();
+    m_MrTable.Iterate(DisposeFunctor<ND_MEMORY_REGION>());
+    m_MrTable.Unlock();
+
+    m_PdTable.LockExclusive();
+    m_PdTable.Iterate(DisposeFunctor<ND_PROTECTION_DOMAIN>());
+    m_PdTable.Unlock();
+
+    m_CqTable.LockExclusive();
+    m_CqTable.Iterate(DisposeFunctor<ND_COMPLETION_QUEUE>());
+    m_CqTable.Unlock();
+
+    m_AdapterTable.LockExclusive();
+    m_AdapterTable.Iterate(DisposeFunctor<ND_ADAPTER>());
+    m_AdapterTable.Unlock();
+
+    Unlock();
+
+    _Base::RunDown();
+
+    m_pParent->RemoveProvider(&m_Entry);
+    ExDeleteResourceLite(&m_Lock);
+}
+
+
+/*static*/
+NTSTATUS
+ND_PROVIDER::Create(
+    __in ND_PARTITION* pPartition,
+    __out ND_PROVIDER** ppProvider
+    )
+{
+    ND_PROVIDER* prov = reinterpret_cast<ND_PROVIDER*>(
+        ExAllocatePoolWithTag(NonPagedPool, sizeof(*prov), ND_PROVIDER_POOL_TAG)
+        );
+    if (prov == NULL) {
+        return STATUS_NO_MEMORY;
+    }
+
+    new(prov) ND_PROVIDER(pPartition);
+    *ppProvider = prov;
+    return STATUS_SUCCESS;
+}
+
+
+void ND_PROVIDER::LockShared()
+{
+    KeEnterCriticalRegion();
+    ExAcquireResourceSharedLite(&m_Lock, TRUE);
+}
+
+
+void ND_PROVIDER::LockExclusive()
+{
+    KeEnterCriticalRegion();
+    ExAcquireResourceExclusiveLite(&m_Lock, TRUE);
+}
+
+
+void ND_PROVIDER::Unlock()
+{
+    ExReleaseResourceLite(&m_Lock);
+    KeLeaveCriticalRegion();
+}
+
+
+/*
+ * We could be processing asynchronous requests or have them queued
+ * when cleaning up.  To synchronize with async request processing,
+ * acquire the provider lock with exclusive access until we're done
+ * destroying all resoureces.  This will allow active requests to
+ * complete their processing, but prevent queued requests from
+ * running until cleanup is done.  At that point, queued requests will
+ * be unable to acquire any resources.
+ */
+
+void ND_PROVIDER::Dispose()
+{
+    this->ND_PROVIDER::~ND_PROVIDER();
+    ExFreePoolWithTag(this, ND_PROVIDER_POOL_TAG);
+}
+
+
+void ND_PROVIDER::RemoveHandler(ND_RDMA_DEVICE *pDevice)
+{
+    LockExclusive();
+    m_AdapterTable.LockExclusive();
+    m_AdapterTable.Iterate(RemoveDeviceFunctor<ND_ADAPTER>(pDevice));
+    m_AdapterTable.Unlock();
+    Unlock();
+}
+
+
+void NdProviderBindFile(ND_PROVIDER *pProvider, WDFREQUEST Request, bool /*InternalDeviceControl*/)
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    FILE_OBJECT* fileObject;
+    status = ObReferenceObjectByHandle(
+        reinterpret_cast<HANDLE>(in->Handle),
+        0,
+        *IoFileObjectType,
+        WdfRequestGetRequestorMode(Request),
+        reinterpret_cast<VOID**>(&fileObject),
+        NULL
+        );
+
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    DEVICE_OBJECT* pDevObj = IoGetRelatedDeviceObject(fileObject);
+    if (pDevObj != WdfDeviceWdmGetDeviceObject(ControlDevice)) {
+        status = STATUS_INVALID_PARAMETER;
+    } else {
+        status = pProvider->Bind(
+            ND_PROVIDER::HandleFromFile(WdfRequestGetFileObject(Request)),
+            fileObject);
+    }
+    ObDereferenceObject(fileObject);
+
+out:
+    WdfRequestComplete(Request, status);
+}
+
+
+//static
+void
+ND_PROVIDER::ResolveAddress(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    NDFLTR_RESOLVE_ADDRESS* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Header.Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    UINT64* out;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*out),
+        reinterpret_cast<VOID**>(&out),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    status = pProvider->m_pParent->ResolveAddress(in->Header.Address, in->DriverId, out);
+    if (NT_SUCCESS(status)) {
+        WdfRequestSetInformation(Request, sizeof(*out));
+    }
+
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+//static
+void
+ND_PROVIDER::QueryAddressList(
+    ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    size_t                      outLen = 0;
+    ULONG                       count;
+    ULONG                       max;
+    NTSTATUS                    status;
+    NDFLTR_QUERY_ADDRESS_LIST*  in;
+    SOCKADDR_INET*              list;
+    GUID                        driverId;
+
+    status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    if (in->Header.Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    driverId = in->DriverId;
+
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        0,
+        reinterpret_cast<VOID**>(&list),
+        &outLen
+        );
+    if (status == STATUS_BUFFER_TOO_SMALL) {
+        list = NULL;
+    } else if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    max = static_cast<ULONG>((outLen) / sizeof(SOCKADDR_INET));
+    count = max;
+
+    status = pProvider->m_pParent->GetIpList(
+        driverId,
+        0,
+        &count,
+        list
+        );
+    if (status == STATUS_MORE_ENTRIES) {
+        outLen = sizeof(*list) * max;
+    } else if (!NT_ERROR(status)) {
+        outLen = sizeof(*list) * count;
+    } else {
+        outLen = 0;
+    }
+
+out:
+    WdfRequestCompleteWithInformation(Request, status, outLen);
+}
Index: core/ndfltr/kernel/nd_driver.cpp
===================================================================
--- core/ndfltr/kernel/nd_driver.cpp	(revision 0)
+++ core/ndfltr/kernel/nd_driver.cpp	(revision 0)
@@ -0,0 +1,983 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE ANd
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+#include <initguid.h>
+#include <rdma\verbs.h>
+#include <iba\ib_cm_ifc.h>
+#include <iba\ibat_ifc.h>
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ND_RDMA_DEVICE, NdRdmaDeviceGetContext);
+
+WDFDEVICE                           ControlDevice;
+IBAT_IFC                            IbatInterface;
+
+
+static EVT_WDF_DRIVER_DEVICE_ADD            NdRdmaDeviceAdd;
+static EVT_WDF_OBJECT_CONTEXT_CLEANUP       NdRdmaDeviceCleanup;
+static EVT_WDF_DEVICE_D0_ENTRY              NdPowerD0Entry;
+static EVT_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED NdPowerD0Exit;
+static EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL   NdIoDeviceControl;
+static EVT_WDF_DEVICE_FILE_CREATE           NdFileCreate;
+static EVT_WDF_FILE_CLEANUP                 NdFileCleanup;
+
+static FN_REQUEST_HANDLER NdInvalidRequest;
+static FN_REQUEST_HANDLER NdProviderQueryAddressList;
+static FN_REQUEST_HANDLER NdProviderResolveAddress;
+
+#define ND_DISPATCH_COUNT(name_) \
+    ((UCHAR)(FIELD_SIZE(ND_DISPATCH_TABLE,##name_)/sizeof(FN_REQUEST_HANDLER*)))
+
+#define ND_DISPATCH_OFFSET(name_) \
+    ((UCHAR)(FIELD_OFFSET(ND_DISPATCH_TABLE,##name_)/sizeof(FN_REQUEST_HANDLER*))+1)
+
+#define ND_DISPATCH_INDEX(name_) \
+    MAKEWORD(ND_DISPATCH_OFFSET(name_),ND_DISPATCH_COUNT(name_))
+
+struct ND_DISPATCH_TABLE {
+    FN_REQUEST_HANDLER* NdProvider[IOCTL_ND_PROVIDER_MAX_OPERATION];
+    FN_REQUEST_HANDLER* NdAdapter[IOCTL_ND_ADAPTER_MAX_OPERATION];
+    FN_REQUEST_HANDLER* NdPd[IOCTL_ND_PD_MAX_OPERATION];
+    FN_REQUEST_HANDLER* NdCq[IOCTL_ND_CQ_MAX_OPERATION];
+    FN_REQUEST_HANDLER* NdMr[IOCTL_ND_MR_MAX_OPERATION];
+    FN_REQUEST_HANDLER* NdMw[IOCTL_ND_MW_MAX_OPERATION];
+    FN_REQUEST_HANDLER* NdSrq[IOCTL_ND_SRQ_MAX_OPERATION];
+    FN_REQUEST_HANDLER* NdConnector[IOCTL_ND_CONNECTOR_MAX_OPERATION];
+    FN_REQUEST_HANDLER* NdListener[IOCTL_ND_LISTENER_MAX_OPERATION];
+    FN_REQUEST_HANDLER* NdQp[IOCTL_ND_QP_MAX_OPERATION];
+    FN_REQUEST_HANDLER* NdVirtualPartition[IOCTL_NDV_PARTITION_MAX_OPERATION];
+};
+
+static const struct ND_IOCTL_DISPATCH {
+    WORD Index[ND_RESOURCE_TYPE_COUNT];
+    FN_REQUEST_HANDLER* Table[1];
+    ND_DISPATCH_TABLE Dispatch;
+} IoctlDispatch = {
+    { ND_DISPATCH_INDEX(NdProvider),
+    ND_DISPATCH_INDEX(NdAdapter),
+    ND_DISPATCH_INDEX(NdPd),
+    ND_DISPATCH_INDEX(NdCq),
+    ND_DISPATCH_INDEX(NdMr),
+    ND_DISPATCH_INDEX(NdMw),
+    ND_DISPATCH_INDEX(NdSrq),
+    ND_DISPATCH_INDEX(NdConnector),
+    ND_DISPATCH_INDEX(NdListener),
+    ND_DISPATCH_INDEX(NdQp),
+    ND_DISPATCH_INDEX(NdVirtualPartition) },
+
+    { NULL },
+
+    {
+        { ND_DRIVER::InitProvider,
+        NdProviderBindFile,
+        ND_PROVIDER::QueryAddressList,
+        ND_PROVIDER::ResolveAddress },
+
+        { NdAdapterOpen,
+        NdAdapterClose,
+        ND_ADAPTER::Query,
+        ND_ADAPTER::QueryAddressList },
+
+        { NdPdCreate,
+        NdPdFree },
+
+        { NdCqCreate,
+        NdCqFree,
+        NdCqCancelIo,
+        NdCqGetAffinity,
+        NdCqModify,
+        NdCqNotify },
+
+        { NdMrCreate,
+        NdMrFree,
+        NdMrCancelIo,
+        NdMrRegister,
+        NdMrDeregister,
+        NdMrRegisterPages },
+
+        { NdMwCreate,
+        NdMwFree },
+
+        { NdSrqCreate,
+        NdSrqFree,
+        NdSrqCancelIo,
+        NdSrqGetAffinity,
+        NdSrqModify,
+        NdSrqNotify },
+
+        { NdConnectorCreate,
+        NdEpFree,
+        NdEpCancelIo,
+        NdEpBind,
+        NdEpConnect,
+        NdEpCompleteConnect,
+        NdEpAccept,
+        NdEpReject,
+        NdEpGetReadLimits,
+        NdEpGetPrivateData,
+        NdEpGetPeerAddress,
+        NdEpGetAddress,
+        NdEpNotifyDisconnect,
+        NdEpDisconnect },
+
+        { NdListenerCreate,
+        NdEpFree,
+        NdEpCancelIo,
+        NdEpBind,
+        NdEpListen,
+        NdEpGetAddress,
+        NdEpGetConnectionRequest },
+
+        { NdQpCreate,
+        NdQpCreateWithSrq,
+        NdQpFree,
+        NdQpFlush },
+
+        { ND_PARTITION::ResolveAdapterId,
+        ND_DRIVER::CreatePartition,
+        ND_PARTITION::Free,
+        ND_PARTITION::BindAddress,
+        ND_PARTITION::UnbindAddress,
+        ND_PARTITION::BindLuid }
+    }
+};
+
+
+static
+void
+NdInvalidRequest(
+    __in ND_PROVIDER* /*pProvider*/,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    WdfRequestComplete(Request, STATUS_INVALID_DEVICE_REQUEST);
+}
+
+
+void* operator new(size_t, void* pObj)
+{
+    return pObj;
+}
+
+
+ND_DRIVER::ND_DRIVER()
+    : m_Partition0(0)
+{
+    InitializeListHead(&m_DevList);
+    KeInitializeGuardedMutex(&m_Lock);
+}
+
+
+ND_DRIVER::~ND_DRIVER()
+{
+    m_ProvTable.Iterate(DisposeFunctor<ND_PROVIDER>());
+    m_PartitionTable.Iterate(DisposeFunctor<ND_PARTITION>());
+}
+
+
+ND_RDMA_DEVICE*
+ND_DRIVER::GetRdmaDevice(
+    UINT64 AdapterId
+    )
+{
+    ND_RDMA_DEVICE    *curDev, *dev = NULL;
+    LIST_ENTRY        *entry;
+
+    KeAcquireGuardedMutex(&m_Lock);
+    for (entry = m_DevList.Flink; entry != &m_DevList; entry = entry->Flink) {
+        curDev = CONTAINING_RECORD(entry, ND_RDMA_DEVICE, Entry);
+        // TODO: Need to check against possible MACs somehow.
+        if (curDev->Interface.Verbs.guid == AdapterId) {
+            InterlockedIncrement(&curDev->Ref);
+            dev = curDev;
+            break;
+        }
+    }
+    KeReleaseGuardedMutex(&m_Lock);
+    return dev;
+}
+
+
+ND_PROVIDER* ND_DRIVER::GetProvider(UINT64 Handle)
+{
+    m_ProvTable.LockShared();
+    ND_PROVIDER* prov = m_ProvTable.At(Handle);
+    if (prov != NULL) {
+        prov->AddRef();
+    }
+    m_ProvTable.Unlock();
+    return prov;
+}
+
+
+ND_PARTITION* ND_DRIVER::GetPartition(UINT64 Handle, bool InternalDeviceControl)
+{
+    if (InternalDeviceControl == false) {
+        m_Partition0.AddRef();
+        return &m_Partition0;
+    }
+
+    m_PartitionTable.LockShared();
+    ND_PARTITION* part = m_PartitionTable.At(Handle);
+    if (part != NULL) {
+        part->AddRef();
+    }
+    m_PartitionTable.Unlock();
+    return part;
+}
+
+
+NTSTATUS ND_DRIVER::FreePartition(UINT64 Handle)
+{
+    NTSTATUS status;
+    m_PartitionTable.LockExclusive();
+    ND_PARTITION* part = m_PartitionTable.At(Handle);
+    if (part == NULL) {
+        status = STATUS_INVALID_HANDLE;
+    } else if (part->Busy()) {
+        status = STATUS_DEVICE_BUSY;
+    } else {
+        m_PartitionTable.Erase(Handle);
+        status = STATUS_SUCCESS;
+    }
+    m_PartitionTable.Unlock();
+
+    if (NT_SUCCESS(status)) {
+        part->Dispose();
+    }
+    return status;
+}
+
+
+//static
+void
+ND_DRIVER::InitProvider(
+    ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool InternalDeviceControl
+    )
+{
+    if (pProvider != NULL) {
+        WdfRequestComplete(Request, STATUS_INVALID_DEVICE_STATE);
+        return;
+    }
+
+    WDFFILEOBJECT file = WdfRequestGetFileObject(Request);
+    ND_DRIVER* driver = NdDriverGetContext(WdfGetDriver());
+
+    ND_HANDLE* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    ND_PARTITION* part = driver->GetPartition(in->Handle, InternalDeviceControl);
+    if (part == NULL) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err;
+    }
+
+    driver->m_ProvTable.LockExclusive();
+    UINT64 hProv = driver->m_ProvTable.Reserve();
+    if (hProv == 0) {
+        status = STATUS_INSUFFICIENT_RESOURCES;
+        goto unlock;
+    }
+
+    ND_PROVIDER *prov;
+    status = ND_PROVIDER::Create(part, &prov);
+    if (!NT_SUCCESS(status)) {
+        driver->m_ProvTable.Free(hProv);
+        goto unlock;
+    }
+
+    status = prov->Bind(hProv, file);
+    if (!NT_SUCCESS(status)) {
+        prov->Dispose();
+        driver->m_ProvTable.Free(hProv);
+    } else {
+        driver->m_ProvTable.Set(hProv, prov);
+    }
+
+unlock:
+    driver->m_ProvTable.Unlock();
+    part->Release();
+
+err:
+    WdfRequestComplete(Request, status);
+}
+
+
+//static
+void
+ND_DRIVER::CreatePartition(
+    ND_PROVIDER* /*pProvider*/,
+    WDFREQUEST Request,
+    bool InternalDeviceControl
+    )
+{
+    if (InternalDeviceControl == false) {
+        WdfRequestComplete(Request, STATUS_INVALID_DEVICE_REQUEST);
+        return;
+    }
+
+    NDV_PARTITION_CREATE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    if (in->MmioType != NdPartitionKernelVirtual) {
+        status = STATUS_NOT_SUPPORTED;
+        goto out;
+    }
+
+    if (in->XmitCap != 0) {
+        status = STATUS_NOT_SUPPORTED;
+        goto out;
+    }
+
+    UINT64* out;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*out),
+        reinterpret_cast<VOID**>(&out),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    ND_PARTITION* part;
+    status = ND_PARTITION::Create(in->AdapterId, &part);
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    ND_DRIVER* driver = NdDriverGetContext(WdfGetDriver());
+    driver->m_PartitionTable.LockExclusive();
+    *out = driver->m_PartitionTable.Insert(part);
+    driver->m_PartitionTable.Unlock();
+
+    if (*out == 0) {
+        part->Dispose();
+        status = STATUS_INSUFFICIENT_RESOURCES;
+    } else {
+        WdfRequestSetInformation(Request, sizeof(*out));
+    }
+
+out:
+    WdfRequestComplete(Request, status);
+}
+
+
+ND_RDMA_DEVICE*
+NdRdmaDeviceGet(
+    UINT64 AdapterId
+    )
+{
+    ND_DRIVER* driver = NdDriverGetContext(WdfGetDriver());
+    return driver->GetRdmaDevice(AdapterId);
+}
+
+
+void
+NdRdmaDevicePut(
+    ND_RDMA_DEVICE *pDevice
+    )
+{
+    if (InterlockedDecrement(&pDevice->Ref) == 0) {
+        KeSetEvent(&pDevice->Event, 0, FALSE);
+    }
+}
+
+
+static
+ND_PROVIDER*
+NdGetProvider(
+    WDFFILEOBJECT File
+    )
+{
+    ND_DRIVER* driver = NdDriverGetContext(WdfGetDriver());
+    return driver->GetProvider(ND_PROVIDER::HandleFromFile(File));
+}
+
+
+void
+NdCompleteRequests(
+    WDFQUEUE Queue,
+    NTSTATUS ReqStatus
+    )
+{
+    WDFREQUEST    request;
+    NTSTATUS    status;
+
+    status = WdfIoQueueRetrieveNextRequest(Queue, &request);
+
+    while (NT_SUCCESS(status)) {
+        WdfRequestComplete(request, ReqStatus);
+        status = WdfIoQueueRetrieveNextRequest(Queue, &request);
+    }
+}
+
+
+void
+NdFlushQueue(
+    WDFQUEUE Queue,
+    NTSTATUS ReqStatus
+    )
+{
+    //TODO: Don't think we need the locking here...
+    WdfObjectAcquireLock(Queue);
+    NdCompleteRequests(Queue, ReqStatus);
+    WdfObjectReleaseLock(Queue);
+}
+
+
+void
+NdCompleteRequestsWithInformation(
+    WDFQUEUE Queue,
+    NTSTATUS ReqStatus
+    )
+{
+    WDFREQUEST  request;
+    NTSTATUS    status;
+    VOID        *out;
+    size_t      outlen;
+
+    status = WdfIoQueueRetrieveNextRequest(Queue, &request);
+
+    while (NT_SUCCESS(status)) {
+        outlen = 0;
+        WdfRequestRetrieveOutputBuffer(request, 0, &out, &outlen);
+        WdfRequestCompleteWithInformation(request, ReqStatus, outlen);
+        status = WdfIoQueueRetrieveNextRequest(Queue, &request);
+    }
+}
+
+
+static
+VOID
+IoctlHandler(
+    WDFREQUEST Request,
+    ULONG IoControlCode,
+    bool InternalDeviceControl
+    )
+{
+    ND_PROVIDER* prov = NULL;
+
+    ULONG res = ND_RESOURCE_FROM_CTL_CODE(IoControlCode);
+    ULONG op = ND_OPERATION_FROM_CTRL_CODE(IoControlCode);
+
+    if (res != NdVirtualPartition) {
+        prov = NdGetProvider(WdfRequestGetFileObject(Request));
+        if (prov == NULL) {
+            if (IoControlCode != IOCTL_ND_PROVIDER_INIT) {
+                WdfRequestComplete(Request, STATUS_INVALID_DEVICE_STATE);
+            } else {
+                ND_DRIVER::InitProvider(NULL, Request, InternalDeviceControl);
+            }
+            return;
+        }
+    }
+
+    WORD index = IoctlDispatch.Index[res];
+    if (op < HIBYTE(index)) {
+        IoctlDispatch.Table[LOBYTE(index) + op](prov, Request, InternalDeviceControl);
+    } else {
+        NdInvalidRequest(NULL, Request, InternalDeviceControl);
+    }
+
+    if (prov != NULL) {
+        prov->Release();
+    }
+}
+
+
+static
+VOID
+NdDeviceControl(
+    WDFQUEUE,
+    WDFREQUEST Request,
+    size_t,
+    size_t,
+    ULONG IoControlCode
+    )
+{
+    IoctlHandler(Request, IoControlCode, false);
+}
+
+
+static
+VOID
+NdInternalDeviceControl(
+    WDFQUEUE,
+    WDFREQUEST Request,
+    size_t,
+    size_t,
+    ULONG IoControlCode
+    )
+{
+    IoctlHandler(Request, IoControlCode, true);
+}
+
+
+static VOID
+NdFileCreate(
+    WDFDEVICE,
+    WDFREQUEST Request,
+    WDFFILEOBJECT
+    )
+{
+    WdfRequestComplete(Request, STATUS_SUCCESS);
+}
+
+
+void ND_DRIVER::FreeProvider(WDFFILEOBJECT FileObject)
+{
+    m_ProvTable.LockExclusive();
+    UINT64 hProv = ND_PROVIDER::HandleFromFile(FileObject);
+    ND_PROVIDER* prov = m_ProvTable.At(hProv);
+    if (prov != NULL && prov->Unbind(FileObject) == 0 ) {
+        m_ProvTable.Erase(hProv);
+        m_ProvTable.Unlock();
+        prov->Dispose();
+    } else {
+        m_ProvTable.Unlock();
+    }
+}
+
+
+static
+VOID
+NdFileCleanup(
+    WDFFILEOBJECT FileObject
+    )
+{
+    ND_DRIVER* driver = NdDriverGetContext(WdfGetDriver());
+    driver->FreeProvider(FileObject);
+}
+
+
+VOID
+NdCreateControlDevice(
+    WDFDRIVER Driver
+    )
+{
+    PWDFDEVICE_INIT         pInit;
+    WDF_FILEOBJECT_CONFIG   fileConfig;
+    WDF_OBJECT_ATTRIBUTES   attr;
+    WDF_IO_QUEUE_CONFIG     ioConfig;
+    NTSTATUS                status;
+    WDFQUEUE                queue;
+    DECLARE_CONST_UNICODE_STRING(name, L"\\Device\\Ndfltr");
+    DECLARE_CONST_UNICODE_STRING(symlink, ND_DOS_DEVICE_NAME);
+
+    pInit = WdfControlDeviceInitAllocate(
+        Driver,
+        &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R
+        );
+    if (pInit == NULL) {
+        return;
+    }
+
+    WdfDeviceInitSetExclusive(pInit, FALSE);
+    status = WdfDeviceInitAssignName(pInit, &name);
+    if (!NT_SUCCESS(status)) {
+        WdfDeviceInitFree(pInit);
+        return;
+    }
+
+    WDF_FILEOBJECT_CONFIG_INIT(
+        &fileConfig,
+        NdFileCreate,
+        WDF_NO_EVENT_CALLBACK,
+        NdFileCleanup
+        );
+    //
+    // We will use FsContext to store our app context.  This allows us to have
+    // multiple files associated with a single app context.
+    //
+    fileConfig.FileObjectClass = WdfFileObjectWdfCanUseFsContext2;
+
+    WDF_OBJECT_ATTRIBUTES_INIT(&attr);
+    attr.SynchronizationScope = WdfSynchronizationScopeNone;
+    WdfDeviceInitSetFileObjectConfig(pInit, &fileConfig, &attr);
+
+    WDF_OBJECT_ATTRIBUTES_INIT(&attr);
+    status = WdfDeviceCreate(&pInit, &attr, &ControlDevice);
+    if (!NT_SUCCESS(status)) {
+        WdfDeviceInitFree(pInit);
+        return;
+    }
+
+    status = WdfDeviceCreateSymbolicLink(ControlDevice, &symlink);
+    if (!NT_SUCCESS(status)) {
+        WdfObjectDelete(ControlDevice);
+        ControlDevice = NULL;
+        return;
+    }
+
+    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioConfig, WdfIoQueueDispatchParallel);
+    ioConfig.PowerManaged = WdfFalse;
+    ioConfig.EvtIoDeviceControl = NdDeviceControl;
+    ioConfig.EvtIoInternalDeviceControl = NdInternalDeviceControl;
+    status = WdfIoQueueCreate(
+        ControlDevice,
+        &ioConfig,
+        WDF_NO_OBJECT_ATTRIBUTES,
+        &queue
+        );
+    if (!NT_SUCCESS(status)) {
+        WdfObjectDelete(ControlDevice);
+        ControlDevice = NULL;
+        return;
+    }
+
+    WdfControlFinishInitializing(ControlDevice);
+}
+
+
+NTSTATUS ND_DRIVER::AddDevice(ND_RDMA_DEVICE* pDev)
+{
+    KeAcquireGuardedMutex(&m_Lock);
+    BOOLEAN create = IsListEmpty(&m_DevList);
+    InsertTailList(&m_DevList, &pDev->Entry);
+    KeReleaseGuardedMutex(&m_Lock);
+
+    if (create) {
+        NTSTATUS status = WdfFdoQueryForInterface(
+            pDev->WdfDev,
+            &GUID_IBAT_INTERFACE,
+            (PINTERFACE) &IbatInterface,
+            sizeof(IbatInterface),
+            IBAT_INTERFACE_VERSION,
+            NULL
+            );
+        if (!NT_SUCCESS(status)) {
+            return status;
+        }
+        //
+        // We are in the same device stack, so no need to hold on to the interface.
+        //
+        IbatInterface.InterfaceHeader.InterfaceDereference(
+            IbatInterface.InterfaceHeader.Context
+            );
+        NdCreateControlDevice(WdfGetDriver());
+    }
+    return STATUS_SUCCESS;
+}
+
+
+static
+NTSTATUS
+NdPowerD0Entry(
+    WDFDEVICE Device,
+    WDF_POWER_DEVICE_STATE
+    )
+{
+    ND_RDMA_DEVICE  *dev;
+    NTSTATUS        status;
+
+    dev = NdRdmaDeviceGetContext(Device);
+    if (dev->hDevice != NULL) {
+        return STATUS_SUCCESS;
+    }
+
+    status = WdfFdoQueryForInterface(
+        Device,
+        &GUID_INFINIBAND_INTERFACE_CM,
+        (PINTERFACE) &dev->CmInterface,
+        sizeof(dev->CmInterface),
+        INFINIBAND_INTERFACE_CM_VERSION,
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        return status;
+    }
+    //
+    // We are in the same device stack, so no need to hold on to the interface.
+    //
+    dev->CmInterface.InterfaceHeader.InterfaceDereference(
+        dev->CmInterface.InterfaceHeader.Context
+        );
+
+    status = WdfFdoQueryForInterface(
+        Device,
+        &GUID_RDMA_INTERFACE_VERBS,
+        (PINTERFACE) &dev->Interface,
+        sizeof(dev->Interface),
+        RDMA_INTERFACE_VERBS_VERSION,
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        return status;
+    }
+    //
+    // We are in the same device stack, so no need to hold on to the interface.
+    //
+    dev->Interface.InterfaceHeader.InterfaceDereference(
+        dev->Interface.InterfaceHeader.Context
+        );
+
+    dev->hDevice = reinterpret_cast<ib_ca_handle_t>(dev->Interface.Verbs.p_hca_obj);
+
+    ib_ca_attr_t* attr = dev->QueryCaAttributes();
+    if (attr == NULL) {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    dev->Info.InfoVersion =                 ND_VERSION_2;
+    dev->Info.VendorId =                    static_cast<UINT16>(attr->vend_id);
+    dev->Info.DeviceId =                    static_cast<UINT16>(attr->dev_id);
+    dev->Info.AdapterId =                   attr->ca_guid;
+    dev->Info.MaxRegistrationSize =         static_cast<SIZE_T>(attr->init_region_size);
+    dev->Info.MaxWindowSize =               static_cast<SIZE_T>(attr->init_region_size);
+    dev->Info.MaxInitiatorSge =             attr->max_sges;
+    dev->Info.MaxReceiveSge =               attr->max_sges;
+    dev->Info.MaxReadSge =                  attr->max_sges;
+    if (attr->num_ports == 0) {
+        dev->Info.MaxTransferLength =       0;
+    } else {
+        dev->Info.MaxTransferLength =       static_cast<ULONG>(attr->p_port_attr->max_msg_size);
+    }
+    dev->Info.MaxInlineDataSize =           0;
+    dev->Info.MaxInboundReadLimit =         attr->max_qp_resp_res;
+    dev->Info.MaxOutboundReadLimit =        attr->max_qp_init_depth;
+    dev->Info.MaxReceiveQueueDepth =        attr->max_wrs;
+    dev->Info.MaxInitiatorQueueDepth =      attr->max_wrs;
+    dev->Info.MaxSharedReceiveQueueDepth =  attr->max_srq_wrs;
+    dev->Info.MaxCompletionQueueDepth =     attr->max_cqes;
+    dev->Info.InlineRequestThreshold =      172;
+    dev->Info.LargeRequestThreshold =       65536;
+    dev->Info.MaxCallerData =               IB_REQ_CM_RDMA_PDATA_SIZE;
+    dev->Info.MaxCalleeData =               IB_REJ_PDATA_SIZE;
+    dev->Info.AdapterFlags =                ND_ADAPTER_FLAG_IN_ORDER_DMA_SUPPORTED |
+                                            ND_ADAPTER_FLAG_MULTI_ENGINE_SUPPORTED |
+                                            ND_ADAPTER_FLAG_LOOPBACK_CONNECTIONS_SUPPORTED;
+
+    ExFreePoolWithTag(attr, ND_RDMA_DEVICE_POOL_TAG);
+
+    ND_DRIVER* driver = NdDriverGetContext(WdfGetDriver());
+    return driver->AddDevice(dev);
+}
+
+
+static
+NTSTATUS
+NdRdmaDeviceAdd(
+    WDFDRIVER,
+    PWDFDEVICE_INIT DeviceInit
+    )
+{
+    WDF_OBJECT_ATTRIBUTES           attr;
+    WDF_PNPPOWER_EVENT_CALLBACKS    power;
+    WDFDEVICE                       dev;
+    ND_RDMA_DEVICE                  *pDev;
+    NTSTATUS                        status;
+
+    WdfFdoInitSetFilter(DeviceInit);
+
+    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, ND_RDMA_DEVICE);
+    attr.EvtCleanupCallback = NdRdmaDeviceCleanup;
+
+    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&power);
+    power.EvtDeviceD0EntryPostInterruptsEnabled = NdPowerD0Entry;
+    power.EvtDeviceD0ExitPreInterruptsDisabled = NdPowerD0Exit;
+    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &power);
+
+    status = WdfDeviceCreate(&DeviceInit, &attr, &dev);
+    if (!NT_SUCCESS(status)) {
+        return status;
+    }
+
+    pDev = NdRdmaDeviceGetContext(dev);
+    pDev->Ref = 1;
+    pDev->WdfDev = dev;
+    KeInitializeEvent(&pDev->Event, NotificationEvent, FALSE);
+
+    return STATUS_SUCCESS;
+}
+
+
+void ND_DRIVER::RemoveHandler(ND_RDMA_DEVICE* pDev)
+{
+    KeAcquireGuardedMutex(&m_Lock);
+    RemoveEntryList(&pDev->Entry);
+    BOOLEAN destroy = IsListEmpty(&m_DevList);
+    KeReleaseGuardedMutex(&m_Lock);
+
+    m_ProvTable.LockExclusive();
+    m_ProvTable.Iterate(RemoveDeviceFunctor<ND_PROVIDER>(pDev));
+    m_ProvTable.Unlock();
+
+    if (destroy == TRUE && ControlDevice != NULL) {
+        WdfObjectDelete(ControlDevice);
+        ControlDevice = NULL;
+    }
+}
+
+
+static
+NTSTATUS
+NdPowerD0Exit(
+    WDFDEVICE Device,
+    WDF_POWER_DEVICE_STATE TargetState
+    )
+{
+    if (TargetState == WdfPowerDeviceD3Final) {
+        NdRdmaDeviceCleanup(Device);
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
+static
+VOID
+NdRdmaDeviceCleanup(
+    WDFOBJECT Device
+    )
+{
+    ND_RDMA_DEVICE* dev = NdRdmaDeviceGetContext(Device);
+
+    if (dev->hDevice == NULL) {
+        return;
+    }
+
+    ND_DRIVER* driver = NdDriverGetContext(WdfGetDriver());
+    driver->RemoveHandler(dev);
+
+    if (InterlockedDecrement(&dev->Ref) > 0) {
+        KeWaitForSingleObject(&dev->Event, Executive, KernelMode, FALSE, NULL);
+    }
+
+    dev->hDevice = NULL;
+}
+
+
+EVT_WDF_DRIVER_UNLOAD NdDriverUnload;
+
+VOID
+NdDriverUnload(
+    IN WDFDRIVER Driver
+    )
+{
+    ND_DRIVER* driver = NdDriverGetContext(Driver);
+    driver->ND_DRIVER::~ND_DRIVER();
+    //ProvTable.Dispose();
+}
+
+
+EXTERN_C
+NTSTATUS
+DriverEntry(
+    PDRIVER_OBJECT DriverObject,
+    PUNICODE_STRING RegistryPath
+    )
+{
+    WDF_OBJECT_ATTRIBUTES   attr;
+    WDF_DRIVER_CONFIG       config;
+    NTSTATUS                status;
+    WDFDRIVER               driver;
+
+    ControlDevice = NULL;
+
+    ND_ENDPOINT::SetStartingPsn(reinterpret_cast<ULONG>(DriverObject));
+    IbatInterface.InterfaceHeader.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
+
+    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, ND_DRIVER);
+
+    WDF_DRIVER_CONFIG_INIT(&config, NdRdmaDeviceAdd);
+    config.EvtDriverUnload = NdDriverUnload;
+    status = WdfDriverCreate(
+        DriverObject,
+        RegistryPath,
+        &attr,
+        &config,
+        &driver
+        );
+    if (!NT_SUCCESS(status)) {
+        return status;
+    }
+
+    ND_DRIVER* pDriver = NdDriverGetContext(driver);
+    new(pDriver) ND_DRIVER();
+
+    return STATUS_SUCCESS;
+}
+
+
+ib_ca_attr_t* ND_RDMA_DEVICE::QueryCaAttributes()
+{
+    UINT32 size = 0;
+    ib_api_status_t ibStatus = Interface.Verbs.query_ca(hDevice, NULL, &size, NULL);
+    if (ibStatus != IB_INSUFFICIENT_MEMORY) {
+        return NULL;
+    }
+
+    ib_ca_attr_t* attr = reinterpret_cast<ib_ca_attr_t*>(
+        ExAllocatePoolWithTag(PagedPool, size, ND_RDMA_DEVICE_POOL_TAG)
+        );
+    if (attr == NULL) {
+        return NULL;
+    }
+
+    ibStatus = Interface.Verbs.query_ca(hDevice, attr, &size, NULL);
+    if (ibStatus != IB_SUCCESS) {
+        ExFreePoolWithTag(attr, ND_RDMA_DEVICE_POOL_TAG);
+        return NULL;
+    }
+
+    return attr;
+}
Index: core/ndfltr/kernel/nd_pd.cpp
===================================================================
--- core/ndfltr/kernel/nd_pd.cpp	(revision 0)
+++ core/ndfltr/kernel/nd_pd.cpp	(revision 0)
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "precomp.h"
+
+
+ND_PROTECTION_DOMAIN::ND_PROTECTION_DOMAIN(__in ND_ADAPTER* pAdapter)
+    : _Base(pAdapter, pAdapter->GetInterface())
+{
+    InitializeListHead(&m_QpList);
+    InitializeListHead(&m_SrqList);
+    InitializeListHead(&m_MrList);
+    InitializeListHead(&m_MwList);
+
+    pAdapter->AddPd(&m_Entry);
+}
+
+
+ND_PROTECTION_DOMAIN::~ND_PROTECTION_DOMAIN()
+{
+    _Base::RunDown();
+
+    if (m_hIfc != NULL) {
+        m_pIfc->deallocate_pd(m_hIfc);
+    }
+
+    m_pParent->RemovePd(&m_Entry);
+}
+
+
+NTSTATUS
+ND_PROTECTION_DOMAIN::Initialize(
+    KPROCESSOR_MODE /*RequestorMode*/,
+    __inout ci_umv_buf_t* pVerbsData
+    )
+{
+    ib_api_status_t ibStatus = m_pIfc->allocate_pd(
+        m_pParent->GetIfcHandle(),
+        IB_PDT_NORMAL,
+        &m_hIfc,
+        pVerbsData
+        );
+    if (ibStatus != IB_SUCCESS) {
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
+//static
+NTSTATUS
+ND_PROTECTION_DOMAIN::Create(
+    __in ND_ADAPTER* pAdapter,
+    KPROCESSOR_MODE RequestorMode,
+    __inout ci_umv_buf_t* pVerbsData,
+    __out ND_PROTECTION_DOMAIN** ppPd
+    )
+{
+    ND_PROTECTION_DOMAIN* pd = reinterpret_cast<ND_PROTECTION_DOMAIN*>(
+        ExAllocatePoolWithTag(NonPagedPool, sizeof(*pd), ND_PD_POOL_TAG)
+        );
+    if (pd == NULL) {
+        return STATUS_NO_MEMORY;
+    }
+
+    new(pd) ND_PROTECTION_DOMAIN(pAdapter);
+    NTSTATUS status = pd->Initialize(RequestorMode, pVerbsData);
+    if (!NT_SUCCESS(status)) {
+        pd->Dispose();
+        return status;
+    }
+
+    *ppPd = pd;
+    return STATUS_SUCCESS;
+}
+
+
+void ND_PROTECTION_DOMAIN::Dispose()
+{
+    this->ND_PROTECTION_DOMAIN::~ND_PROTECTION_DOMAIN();
+    ExFreePoolWithTag(this, ND_PD_POOL_TAG);
+}
+
+
+void ND_PROTECTION_DOMAIN::RemoveHandler()
+{
+    ND_MEMORY_WINDOW        *mw;
+    ND_MEMORY_REGION        *mr;
+    ND_QUEUE_PAIR           *qp;
+    ND_SHARED_RECEIVE_QUEUE *srq;
+    LIST_ENTRY              *entry;
+
+    for (entry = m_MwList.Flink; entry != &m_MwList; entry = entry->Flink) {
+        mw = static_cast<ND_MEMORY_WINDOW*>(
+            ObjChild<ND_PROTECTION_DOMAIN>::FromEntry(entry)
+            );
+        mw->RemoveHandler();
+    }
+
+    for (entry = m_MrList.Flink; entry != &m_MrList; entry = entry->Flink) {
+        mr = static_cast<ND_MEMORY_REGION*>(
+            ObjChild<ND_PROTECTION_DOMAIN>::FromEntry(entry)
+            );
+        mr->RemoveHandler();
+    }
+
+    for (entry = m_QpList.Flink; entry != &m_QpList; entry = entry->Flink) {
+        qp = static_cast<ND_QUEUE_PAIR*>(
+            ObjChild<ND_PROTECTION_DOMAIN>::FromEntry(entry)
+            );
+        qp->RemoveHandler();
+    }
+
+    for (entry = m_SrqList.Flink; entry != &m_SrqList; entry = entry->Flink) {
+        srq = static_cast<ND_SHARED_RECEIVE_QUEUE*>(
+            ObjChild<ND_PROTECTION_DOMAIN>::FromEntry(entry)
+            );
+        srq->RemoveHandler();
+    }
+
+    m_pIfc->deallocate_pd(m_hIfc);
+    _Base::RemoveHandler();
+}
+
+
+void
+NdPdCreate(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    size_t inLen;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        &inLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto err1;
+    }
+
+    //
+    // We expect the vendor data to be in the same place in the input and
+    // output buffers.  The input buffer is larger, so we use it as the
+    // minimum length when querying the output buffer.
+    //
+    UINT64* out;
+    size_t outLen;
+    status = WdfRequestRetrieveOutputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&out),
+        &outLen
+        );
+    if (!NT_SUCCESS(status)) {
+        goto err1;
+    }
+
+    ci_umv_buf_t verbsData;
+    NdInitVerbsData(&verbsData, inLen - sizeof(*in),
+                    outLen - sizeof(*in), in + 1);
+
+    pProvider->LockShared();
+
+    ND_ADAPTER* adapter;
+    status = pProvider->GetAdapter(in->Handle, &adapter);
+    if (!NT_SUCCESS(status)) {
+        goto err2;
+    }
+
+    ND_PROTECTION_DOMAIN* pd;
+    status = ND_PROTECTION_DOMAIN::Create(
+        adapter,
+        WdfRequestGetRequestorMode(Request),
+        &verbsData,
+        &pd
+        );
+
+    if (!NT_SUCCESS(status)) {
+        goto err3;
+    }
+
+    *out = pProvider->AddPd(pd);
+    if (*out == 0) {
+        pd->Dispose();
+        status = STATUS_INSUFFICIENT_RESOURCES;
+    } else {
+        WdfRequestSetInformation(Request, outLen);
+    }
+
+err3:
+    adapter->Release();
+err2:
+    pProvider->Unlock();
+err1:
+    WdfRequestComplete(Request, status);
+}
+
+
+void
+NdPdFree(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool /*InternalDeviceControl*/
+    )
+{
+    ND_HANDLE* in;
+    NTSTATUS status = WdfRequestRetrieveInputBuffer(
+        Request,
+        sizeof(*in),
+        reinterpret_cast<VOID**>(&in),
+        NULL
+        );
+    if (!NT_SUCCESS(status)) {
+        goto out;
+    }
+
+    if (in->Version != ND_IOCTL_VERSION) {
+        status = STATUS_INVALID_DEVICE_REQUEST;
+        goto out;
+    }
+
+    pProvider->LockShared();
+    status = pProvider->FreePd(in->Handle);
+    pProvider->Unlock();
+out:
+    WdfRequestComplete(Request, status);
+}
Index: core/ndfltr/kernel/nd_cq.h
===================================================================
--- core/ndfltr/kernel/nd_cq.h	(revision 0)
+++ core/ndfltr/kernel/nd_cq.h	(revision 0)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_CQ_H_
+#define _ND_CQ_H_
+
+#define ND_COMPLETION_Q_POOL_TAG 'qcdn'
+
+class ND_COMPLETION_QUEUE
+    : public RdmaResource<ND_ADAPTER, ib_cq_handle_t, ci_interface_t>
+{
+    typedef RdmaResource<ND_ADAPTER, ib_cq_handle_t, ci_interface_t> _Base;
+
+    WDFQUEUE                                    m_Queue;
+    WDFQUEUE                                    m_ErrorQueue;
+    NTSTATUS                                    m_Status;
+
+private:
+    ND_COMPLETION_QUEUE(__in ND_ADAPTER* pAdapter, WDFQUEUE queue, WDFQUEUE errorQueue);
+    ~ND_COMPLETION_QUEUE();
+
+    NTSTATUS Initialize(
+        KPROCESSOR_MODE RequestorMode,
+        ULONG QueueDepth,
+        const GROUP_AFFINITY& Affinity,
+        __inout ci_umv_buf_t* pVerbsData
+        );
+
+public:
+    static
+    NTSTATUS
+    Create(
+        __in ND_ADAPTER* pAdapter,
+        KPROCESSOR_MODE RequestorMode,
+        ULONG QueueDepth,
+        const GROUP_AFFINITY& Affinity,
+        __inout ci_umv_buf_t* pVerbsData,
+        __out ND_COMPLETION_QUEUE** ppCq
+        );
+
+    NTSTATUS Modify(
+        ULONG QueueDepth,
+        __in ci_umv_buf_t* pVerbsData
+        );
+
+    void Dispose();
+
+    void RemoveHandler();
+
+    void CancelIo();
+
+    NTSTATUS Notify(WDFREQUEST Request, ULONG Type);
+
+private:
+    static void EventHandler(ib_event_rec_t *pEvent);
+    static void CompletionHandler(void* Context);
+
+};
+
+FN_REQUEST_HANDLER NdCqCreate;
+FN_REQUEST_HANDLER NdCqFree;
+FN_REQUEST_HANDLER NdCqCancelIo;
+FN_REQUEST_HANDLER NdCqGetAffinity;
+FN_REQUEST_HANDLER NdCqModify;
+FN_REQUEST_HANDLER NdCqNotify;
+
+#endif //_ND_CQ_H_
Index: core/ndfltr/kernel/nd_ep.h
===================================================================
--- core/ndfltr/kernel/nd_ep.h	(revision 0)
+++ core/ndfltr/kernel/nd_ep.h	(revision 0)
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Copyright (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_EP_H_
+#define _ND_EP_H_
+
+#define ND_ENDPOINT_POOL_TAG 'pedn'
+
+class ND_QUEUE_PAIR;
+
+class ND_ENDPOINT
+    : public RdmaResource<ND_ADAPTER, iba_cm_id*, INFINIBAND_INTERFACE_CM>
+{
+    typedef RdmaResource<ND_ADAPTER, iba_cm_id*, INFINIBAND_INTERFACE_CM> _Base;
+
+    ND_PROVIDER                         *m_pProvider;
+    ND_QUEUE_PAIR                       *m_pQp;
+    PIO_WORKITEM                        m_pWork;
+
+    // TODO: Where is this used?
+    IBAT_PORT_RECORD                    m_DeviceAddress;
+    SOCKADDR_INET                       m_LocalAddress;
+    SOCKADDR_INET                       m_PeerAddress;
+    ib_path_rec_t                       m_Route;
+
+    WDFQUEUE                            m_Queue;
+    ULONG                               m_Backlog;
+    NTSTATUS                            AsyncFlushStatus;
+
+public:
+    enum TYPE {
+        NdEpConnector,
+        NdEpConnectorV1,
+        NdEpListener
+    }                                   m_Type;
+
+private:
+    //
+    // State diagram
+    //
+    // NdEpIdle -----> NdEpAddressBound ----------------> NdEpListening
+    //     |                   |                                   |
+    //     V                   V                                   |
+    // NdEpQueued        NdEpResolving*                            |
+    //     |                   |                                   |
+    //     V                   V                                   |
+    // NdEpReqReceived    NdEpReqSent*                             |
+    //     |                   |                                   |
+    //     V                   V                                   |
+    // NdEpRepSent*     NdEpRepReceived                            |
+    //     |                   |                                   |
+    //     \___________________/                                   |
+    //               |                                             |
+    //               V                                             |
+    //         NdEpConnected -----> NdEpActiveDisconnect*          |
+    //               |                        |                    |
+    //               V                        V                    V
+    //     NdEpPassiveDisconnect -----> NdDisconnected ----> NdEpDestroying
+    //
+    // NdEpIdle: via NdEpCreate()
+    // NdEpAddressBound:
+    //  - from NdEpAddressBound via NdEpBind()
+    //  - from NdEpResolving due to path resolution error
+    //  - from NdEpReqSent due to timeout or rejection
+    // NdEpListening: via NdEpListen()
+    // NdEpQueued: via NdEpGetConnectionRequest()
+    // NdEpReqReceived: via CM REQ callback
+    // NdEpRepSent: via NdEpAccept()
+    // NdEpResolving: via NdEpConnect()
+    // NdEpReqSent: via IBAT path query callback
+    // NdEpRepReceived: enter via CM REP callback, completes NdEpConnect()
+    // NdEpConnected:
+    //  - from NdEpRepReceived via NdEpCompleteConnect()
+    //  - from NdEpRepSent via CM RTU callback or QP established event from hardware,
+    //    completes NdAccept()
+    // NdEpActiveDisconnect: via NdEpDisconnect()
+    // NdEpPassiveDisconnect: via CM DREQ callback
+    // NdEpDisconnected:
+    //  - from NdEpPassiveDisconnect via NdEpDisconnect()
+    //  - from NdEpActiveDisconnect via CM DREP callback or DREQ timeout,
+    //    completes NdEpDisconnect()
+    //  - from NdEpReqReceived due to REJ received
+    //  - from NdEpRepSent due to REP timeout
+    //  - from NdEpRepReceived due to REJ received
+    //  - from NdEpConnected due to REJ received
+    // NdEpDestroying: enter via NdEpFree()
+    enum STATE
+    {
+        NdEpIdle,
+        NdEpAddressBound,
+        NdEpListening,
+        NdEpQueued,
+        NdEpReqReceived,
+        NdEpRepSent,
+        NdEpResolving,
+        NdEpReqSent,
+        NdEpRepReceived,
+        NdEpConnected,
+        NdEpActiveDisconnect,
+        NdEpPassiveDisconnect,
+        NdEpDisconnected,
+        NdEpDestroying
+    }                                   m_State;
+
+    ULONG                               m_StartingPsn;
+    ND_READ_LIMITS                      m_ReadLimits;
+    UINT8                               m_PrivateDataLength;
+    BYTE                                m_PrivateData[IB_REJ_PDATA_SIZE];
+
+    static ULONG                        s_RandomSeed;
+
+private:
+    ND_ENDPOINT(__in ND_ADAPTER* pAdapter, ND_ENDPOINT::TYPE Type, WDFQUEUE Queue);
+    ~ND_ENDPOINT();
+
+public:
+    static
+    NTSTATUS
+    Create(
+        __in ND_ADAPTER* pAdapter,
+        KPROCESSOR_MODE RequestorMode,
+        ND_ENDPOINT::TYPE Type,
+        __out ND_ENDPOINT** ppEp
+        );
+
+    void Dispose();
+
+    void RemoveHandler();
+
+    NTSTATUS Bind(
+        __in const SOCKADDR_INET& address,
+        __in LUID AuthenticationId,
+        __in bool IsAdmin
+        );
+
+    NTSTATUS Connect(
+        WDFREQUEST Request,
+        __inout ND_QUEUE_PAIR* pQp,
+        __in const SOCKADDR_INET& DestinationAddress,
+        __in const IF_PHYSICAL_ADDRESS& DestinationHwAddress
+        );
+
+    NTSTATUS CompleteConnect(UINT8 RnrNakTimeout, __out BYTE* pOutBuf, ULONG OutLen);
+
+    NTSTATUS
+    Accept(
+        WDFREQUEST Request,
+        __inout ND_QUEUE_PAIR* pQp,
+        __in const NDFLTR_ACCEPT* pAccept,
+        __out BYTE* pOutBuf,
+        ULONG OutLen
+        );
+
+    NTSTATUS Reject(BYTE* PrivateData, ULONG PrivateDataLength);
+    NTSTATUS GetReadLimits(__out ND_READ_LIMITS* pReadLimits);
+    NTSTATUS GetPrivateData(__out VOID* pPrivateData, __inout size_t* pPrivateDataLength);
+    NTSTATUS GetPeerAddress(__out SOCKADDR_INET* pAddress);
+    NTSTATUS GetAddress(__out SOCKADDR_INET* pAddress);
+    NTSTATUS NotifyDisconnect(WDFREQUEST Request);
+    NTSTATUS Disconnect(WDFREQUEST Request, __out_opt BYTE* pOutBuf, ULONG OutLen);
+    NTSTATUS Listen(ULONG Backlog);
+    void CancelIo();
+    NTSTATUS GetConnectionRequest(WDFREQUEST Request, ND_ENDPOINT* pEp);
+
+    static void Established(ND_ENDPOINT* pEp);
+    static void SetStartingPsn(ULONG RandomSeed) { s_RandomSeed = RandomSeed; }
+
+    void FlushRequest(WDFREQUEST Request, NTSTATUS Status);
+
+private:
+    static EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceled;
+    static FN_IBAT_QUERY_PATH_CALLBACK QueryPathHandler;
+    static NTSTATUS CmHandler(iba_cm_id *pIbCmId, iba_cm_event *pEvent);
+    static NTSTATUS ListenHandler(iba_cm_id *pIbCmId, iba_cm_event *pEvent);
+
+    static
+    void
+    FlushQpWorker(
+        __in void* IoObject,
+        __in_opt void* Context,
+        __in PIO_WORKITEM IoWorkItem
+        );
+
+private:
+    NTSTATUS BindQp(ND_QUEUE_PAIR* pQp);
+    void UnbindQp(bool FlushQp, __out_opt BYTE* pOutBuf, ULONG OutLen);
+    NTSTATUS ModifyQp(
+        ib_qp_state_t State,
+        UINT8 RnrNakTimeout,
+        __out BYTE* pOutBuf,
+        ULONG OutLen
+        );
+
+    static
+    void
+    FormatRdmaCmHeader(
+        __out ib_cm_rdma_req_t* pHeader,
+        __in const SOCKADDR_INET& LocalAddress,
+        __in const SOCKADDR_INET& PeerAddress
+        );
+    static UINT64 GetServiceId(__in const SOCKADDR_INET& pAddress);
+    NTSTATUS SendIbCmReq(__in const NDFLTR_CONNECT* pConnect);
+    void SendConnectionRequest(NTSTATUS RouteStatus);
+    NTSTATUS FormatIbCmRep(__in const NDFLTR_ACCEPT* pAccept, __out_opt ib_qp_mod_t* pQpMod);
+
+    NTSTATUS ProcessCmReq(ND_ENDPOINT* pEp);
+    void ProcessCmRep(iba_cm_rep_event* pReply);
+    void ProcessCmRtu();
+    void ProcessCmDreq();
+    void ProcessCmRej(iba_cm_rej_event* pReject);
+    void CmReqError();
+    void CmRepError();
+    void CompleteDisconnect(NTSTATUS Status);
+
+    void AsyncFlushQp(NTSTATUS Status);
+};
+
+void NdEpCreate(ND_PROVIDER *pProvider, ND_ENDPOINT::TYPE EpType, WDFREQUEST Request);
+
+FN_REQUEST_HANDLER NdConnectorCreate;
+FN_REQUEST_HANDLER NdListenerCreate;
+FN_REQUEST_HANDLER NdEpFree;
+FN_REQUEST_HANDLER NdEpCancelIo;
+FN_REQUEST_HANDLER NdEpBind;
+FN_REQUEST_HANDLER NdEpConnect;
+FN_REQUEST_HANDLER NdEpCompleteConnect;
+FN_REQUEST_HANDLER NdEpAccept;
+FN_REQUEST_HANDLER NdEpReject;
+FN_REQUEST_HANDLER NdEpGetReadLimits;
+FN_REQUEST_HANDLER NdEpGetPrivateData;
+FN_REQUEST_HANDLER NdEpGetPeerAddress;
+FN_REQUEST_HANDLER NdEpGetAddress;
+FN_REQUEST_HANDLER NdEpNotifyDisconnect;
+FN_REQUEST_HANDLER NdEpDisconnect;
+FN_REQUEST_HANDLER NdEpListen;
+FN_REQUEST_HANDLER NdEpGetConnectionRequest;
+
+#endif // _ND_EP_H_
Index: core/ndfltr/kernel/nd_srq.h
===================================================================
--- core/ndfltr/kernel/nd_srq.h	(revision 0)
+++ core/ndfltr/kernel/nd_srq.h	(revision 0)
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_SRQ_H_
+#define _ND_SRQ_H_
+
+#define ND_SHARED_RECEIVE_Q_POOL_TAG 'rsdn'
+
+class ND_SHARED_RECEIVE_QUEUE
+    : public RdmaResource<ND_PROTECTION_DOMAIN, ib_srq_handle_t, ci_interface_t>
+{
+    typedef RdmaResource<ND_PROTECTION_DOMAIN, ib_srq_handle_t, ci_interface_t> _Base;
+
+    WDFQUEUE m_Queue;
+
+private:
+    ND_SHARED_RECEIVE_QUEUE(
+        __in ND_PROTECTION_DOMAIN* pPd,
+        WDFQUEUE queue
+        );
+    ~ND_SHARED_RECEIVE_QUEUE();
+
+    NTSTATUS Initialize(
+        KPROCESSOR_MODE RequestorMode,
+        ULONG QueueDepth,
+        ULONG MaxRequestSge,
+        ULONG NotifyThreshold,
+        __inout ci_umv_buf_t* pVerbsData
+        );
+
+public:
+    static
+    NTSTATUS
+    Create(
+        __in ND_PROTECTION_DOMAIN* pPd,
+        KPROCESSOR_MODE RequestorMode,
+        ULONG QueueDepth,
+        ULONG MaxRequestSge,
+        ULONG NotifyThreshold,
+        __inout ci_umv_buf_t* pVerbsData,
+        __out ND_SHARED_RECEIVE_QUEUE** ppSrq
+        );
+
+    void Dispose();
+
+    NTSTATUS
+    Modify(
+        ULONG QueueDepth,
+        ULONG NotifyThreshold,
+        ci_umv_buf_t* pVerbsData
+        );
+
+    void CancelIo();
+
+    NTSTATUS Notify(WDFREQUEST Request);
+
+    void RemoveHandler();
+
+public:
+    static void EventHandler(ib_event_rec_t *pEvent);
+};
+
+FN_REQUEST_HANDLER NdSrqCreate;
+FN_REQUEST_HANDLER NdSrqFree;
+FN_REQUEST_HANDLER NdSrqCancelIo;
+FN_REQUEST_HANDLER NdSrqGetAffinity;
+FN_REQUEST_HANDLER NdSrqModify;
+FN_REQUEST_HANDLER NdSrqNotify;
+
+#endif // _ND_SRQ_H_
Index: core/ndfltr/kernel/makefile
===================================================================
--- core/ndfltr/kernel/makefile	(revision 0)
+++ core/ndfltr/kernel/makefile	(revision 0)
@@ -0,0 +1,13 @@
+#
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
+# file to this component.  This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+#
+# prevent the Build utility from building the driver for an earlier
+# version of the operating system than vista/Win 2008.
+#
+MINIMUM_NT_TARGET_VERSION=0x600
+
+!INCLUDE ..\..\..\inc\openib.def
Index: core/ndfltr/kernel/nd_decl.h
===================================================================
--- core/ndfltr/kernel/nd_decl.h	(revision 0)
+++ core/ndfltr/kernel/nd_decl.h	(revision 0)
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ * Portions (c) Microsoft Corporation.  All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE ANd
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef _ND_DECL_H_
+#define _ND_DECL_H_
+
+
+extern WDFDEVICE    ControlDevice;
+extern IBAT_IFC     IbatInterface;
+
+class ND_PARTITION;
+class ND_PROVIDER;
+
+typedef void
+FN_REQUEST_HANDLER(
+    __in ND_PROVIDER* pProvider,
+    WDFREQUEST Request,
+    bool InternalDeviceControl
+    );
+
+#define ND_RDMA_DEVICE_POOL_TAG 'vddn'
+
+struct ND_RDMA_DEVICE
+{
+    LIST_ENTRY              Entry;
+    LONG                    Ref;
+    KEVENT                  Event;
+    WDFDEVICE               WdfDev;
+    ib_ca_handle_t          hDevice;
+    RDMA_INTERFACE_VERBS    Interface;
+    // TODO: This should really be an RDMA_INTERFACE_CM, not IB specific.
+    INFINIBAND_INTERFACE_CM CmInterface;
+
+    ND2_ADAPTER_INFO        Info;
+
+public:
+    ib_ca_attr_t* QueryCaAttributes();
+
+};
+
+
+template<typename T> class RemoveDeviceFunctor
+{
+    ND_RDMA_DEVICE* dev;
+
+public:
+    RemoveDeviceFunctor(ND_RDMA_DEVICE* pDev) : dev(pDev) {}
+
+    bool operator() (T* obj)
+    {
+        obj->RemoveHandler(dev);
+        return false;
+    }
+};
+
+#endif // _ND_DECL_H_
Index: core/ndfltr/dirs
===================================================================
--- core/ndfltr/dirs	(revision 0)
+++ core/ndfltr/dirs	(revision 0)
@@ -0,0 +1,2 @@
+DIRS=\
+	kernel \
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ndv2.47.patch
Type: application/octet-stream
Size: 462001 bytes
Desc: ndv2.47.patch
URL: <http://lists.openfabrics.org/pipermail/ofw/attachments/20130221/0e21cf84/attachment.obj>


More information about the ofw mailing list