[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