From: ftillier Date: Tue, 7 Apr 2009 23:21:37 +0000 (+0000) Subject: ND Provider source. X-Git-Url: https://openfabrics.org/gitweb/?a=commitdiff_plain;h=adc79e5959be249cf46881da47a164e9c579c371;p=~shefty%2Frdma-win.git ND Provider source. Signed-off-by: Fab Tillier git-svn-id: svn://openib.tc.cornell.edu/gen1@2087 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86 --- diff --git a/trunk/ulp/nd/user/NdAdapter.cpp b/trunk/ulp/nd/user/NdAdapter.cpp new file mode 100644 index 00000000..a174d94c --- /dev/null +++ b/trunk/ulp/nd/user/NdAdapter.cpp @@ -0,0 +1,950 @@ +/* + * Copyright (c) 2008 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 "NdCq.h" +#include "NdAdapter.h" +#include "NdMw.h" +#include "NdEndpoint.h" +#include "NdProv.h" +#include "NdMr.h" +#include "NdListen.h" +#include "NdConnector.h" + +#include "al_dev.h" +#pragma warning( push, 3 ) +#include "winternl.h" +#pragma warning( pop ) + +#include +#include +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdAdapter.tmh" +#endif + + +namespace NetworkDirect +{ + +/////////////////////////////////////////////////////////////////////////////// +// +// HPC Pack 2008 Beta 2 SPI +// +/////////////////////////////////////////////////////////////////////////////// + + +CAdapter::CAdapter(void) : + m_nRef( 1 ), + m_hSync( INVALID_HANDLE_VALUE ), + m_hAsync( INVALID_HANDLE_VALUE ), + m_hCa( 0 ), + m_hPd( 0 ), + m_uCa( NULL ), + m_uPd( NULL ), + m_pParent( NULL ) +{ + m_Ifc.h_uvp_lib = NULL; +} + +CAdapter::~CAdapter(void) +{ + if( m_hPd ) + DeallocPd(); + + if( m_hCa ) + CloseCa(); + + if( m_hSync != INVALID_HANDLE_VALUE ) + CloseHandle( m_hSync ); + + if( m_hAsync != INVALID_HANDLE_VALUE ) + CloseHandle( m_hAsync ); + + if( m_pParent ) + m_pParent->Release(); +} + +HRESULT CAdapter::Initialize( + CProvider* pParent, + const struct sockaddr* pAddr, + const IBAT_PORT_RECORD* pPortRecord ) +{ + m_pParent = pParent; + m_pParent->AddRef(); + + HRESULT hr = OpenFiles(); + if( FAILED( hr ) ) + return hr; + + hr = OpenCa( pPortRecord->CaGuid ); + if( FAILED( hr ) ) + return hr; + + hr = AllocPd(); + if( FAILED( hr ) ) + return hr; + + m_PortNum = pPortRecord->PortNum; + m_PortGuid = pPortRecord->PortGuid; + + switch( pAddr->sa_family ) + { + case AF_INET: + RtlCopyMemory( &m_Addr.v4, pAddr, sizeof(m_Addr.v4) ); + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Local address: IP %#x, port %#hx\n", + cl_hton32(m_Addr.v4.sin_addr.S_un.S_addr), cl_hton16(m_Addr.v4.sin_port) ) ); + break; + case AF_INET6: + RtlCopyMemory( &m_Addr.v6, pAddr, sizeof(m_Addr.v6) ); + break; + default: + return ND_INVALID_ADDRESS; + } + return S_OK; +} + +HRESULT CAdapter::Create( + CProvider* pParent, + const struct sockaddr* pAddr, + const IBAT_PORT_RECORD* pPortRecord, + __out INDAdapter** ppAdapter + ) +{ + CAdapter* pAdapter = new CAdapter(); + if( pAdapter == NULL ) + return ND_NO_MEMORY; + + HRESULT hr = pAdapter->Initialize( pParent, pAddr, pPortRecord ); + if( FAILED( hr ) ) + { + delete pAdapter; + return hr; + } + + *ppAdapter = pAdapter; + return ND_SUCCESS; +} + +// IUnknown overrides. +HRESULT CAdapter::QueryInterface( + const IID &riid, + LPVOID FAR *ppvObj ) +{ + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppvObj = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDAdapter ) ) + { + *ppvObj = this; + return S_OK; + } + + return E_NOINTERFACE; +} + +ULONG CAdapter::AddRef(void) +{ + return InterlockedIncrement( &m_nRef ); +} + +ULONG CAdapter::Release(void) +{ + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; +} + +// *** INDOverlapped methods *** +HRESULT CAdapter::CancelOverlappedRequests(void) +{ + // Memory registration IOCTLs can't be cancelled. + return S_OK; +} + +HRESULT CAdapter::GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ) +{ + ND_ENTER( ND_DBG_NDI ); + + *pNumberOfBytesTransferred = 0; + ::GetOverlappedResult( + m_hAsync, + pOverlapped, + (DWORD*)pNumberOfBytesTransferred, + bWait ); + return (HRESULT)pOverlapped->Internal; +} + +// INDAdapter overrides. +HANDLE CAdapter::GetFileHandle(void) +{ + return m_hAsync; +} + +HRESULT CAdapter::Query( + __in DWORD VersionRequested, + __out_bcount_part_opt(*pBufferSize, *pBufferSize) ND_ADAPTER_INFO* pInfo, + __inout_opt SIZE_T* pBufferSize + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( VersionRequested != 1 ) + return ND_NOT_SUPPORTED; + + if( *pBufferSize < sizeof(ND_ADAPTER_INFO1) ) + { + *pBufferSize = sizeof(ND_ADAPTER_INFO1); + return ND_BUFFER_OVERFLOW; + } + + ib_ca_attr_t* pAttr = NULL; + DWORD size = 0; + HRESULT hr = QueryCa( pAttr, &size ); + if( hr != ND_BUFFER_OVERFLOW ) + return hr; + + pAttr = (ib_ca_attr_t*)HeapAlloc( GetProcessHeap(), 0, size ); + if( !pAttr ) + return ND_UNSUCCESSFUL; + + hr = QueryCa( pAttr, &size ); + if( FAILED( hr ) ) + { + HeapFree( GetProcessHeap(), 0, pAttr ); + return hr; + } + + pInfo->MaxInboundSge = pAttr->max_sges; + pInfo->MaxInboundRequests = pAttr->max_wrs; + pInfo->MaxInboundLength = INT_MAX; + pInfo->MaxOutboundSge = pAttr->max_sges; + pInfo->MaxOutboundRequests = pAttr->max_wrs; + pInfo->MaxOutboundLength = INT_MAX; + pInfo->MaxInboundReadLimit = pAttr->max_qp_resp_res; + pInfo->MaxOutboundReadLimit = pAttr->max_qp_init_depth; + pInfo->MaxCqEntries = pAttr->max_cqes; +#ifndef SIZE_MAX +#ifdef _WIN64 +#define SIZE_MAX _UI64_MAX +#else +#define SIZE_MAX UINT_MAX +#endif +#endif + if( pAttr->init_region_size > SIZE_MAX ) + pInfo->MaxRegistrationSize = SIZE_MAX; + else + pInfo->MaxRegistrationSize = (SIZE_T)pAttr->init_region_size; + pInfo->MaxWindowSize = pInfo->MaxRegistrationSize; + pInfo->LargeRequestThreshold = 16 * 1024; + pInfo->MaxCallerData = 56; + pInfo->MaxCalleeData = 148; + *pBufferSize = sizeof(ND_ADAPTER_INFO1); + return S_OK; +} + +HRESULT CAdapter::Control( + __in DWORD IoControlCode, + __in_bcount_opt(InBufferSize) const void* pInBuffer, + __in SIZE_T InBufferSize, + __out_bcount_opt(OutBufferSize) void* pOutBuffer, + __in SIZE_T OutBufferSize, + __out SIZE_T* pBytesReturned, + __inout OVERLAPPED* pOverlapped + ) +{ + UNREFERENCED_PARAMETER( IoControlCode ); + UNREFERENCED_PARAMETER( pInBuffer ); + UNREFERENCED_PARAMETER( InBufferSize ); + UNREFERENCED_PARAMETER( pOutBuffer ); + UNREFERENCED_PARAMETER( OutBufferSize ); + UNREFERENCED_PARAMETER( pBytesReturned ); + UNREFERENCED_PARAMETER( pOverlapped ); + + return ND_NOT_SUPPORTED; +} + +HRESULT CAdapter::CreateCompletionQueue( + __in SIZE_T nEntries, + __deref_out INDCompletionQueue** ppCq + ) +{ + ND_ENTER( ND_DBG_NDI ); + + CCq* pCq = new CCq(); + if( pCq == NULL ) + return ND_NO_MEMORY; + + HRESULT hr = pCq->Initialize( this, nEntries ); + if( FAILED(hr) ) + { + delete pCq; + return hr; + } + + *ppCq = pCq; + return S_OK; +} + + +HRESULT CAdapter::RegisterMemory( + __in_bcount(BufferSize) const void* pBuffer, + __in SIZE_T BufferSize, + __inout OVERLAPPED* pOverlapped, + __deref_out ND_MR_HANDLE* phMr + ) +{ + ND_ENTER( ND_DBG_NDI ); + + /* Get a MR tracking structure. */ + CMr* pMr = new CMr(); + if( pMr == NULL ) + return ND_NO_MEMORY; + + pMr->pBase = (const char*)pBuffer; + + if( BufferSize > ULONG_MAX ) + return ND_INVALID_PARAMETER_2; + pMr->Length = (uint32_t)BufferSize; + + /* Clear the mr_ioctl */ + pMr->mr_ioctl.in.h_pd = m_hPd; + pMr->mr_ioctl.in.mem_create.vaddr_padding = (ULONG_PTR)pBuffer; + pMr->mr_ioctl.in.mem_create.length = BufferSize; + // No support for MWs yet, so simulate it. + pMr->mr_ioctl.in.mem_create.access_ctrl = + IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE; + + *phMr = (ND_MR_HANDLE)pMr; + // + // We must issue the IOCTL on the synchronous file handle. + // If the user bound the async file handle to an I/O completion port + // DeviceIoControl could succeed, but not return data, so the MR + // wouldn't be updated. + // + // We use a second IOCTL to complet the user's overlapped. + // + DWORD bytes_ret = 0; + BOOL ret = DeviceIoControl( m_hSync, UAL_REG_MR, + &pMr->mr_ioctl.in, sizeof(pMr->mr_ioctl.in), + &pMr->mr_ioctl.out, sizeof(pMr->mr_ioctl.out), + &bytes_ret, NULL ); + if( !ret ) + { + CL_ASSERT( GetLastError() != ERROR_IO_PENDING ); + + delete pMr; + return ND_UNSUCCESSFUL; + } + if( bytes_ret != sizeof(pMr->mr_ioctl.out) || + pMr->mr_ioctl.out.status != IB_SUCCESS ) + { + delete pMr; + return ND_UNSUCCESSFUL; + } + + // + // The registration succeeded. Now issue the user's IOCTL. + // + pOverlapped->Internal = ND_PENDING; + HRESULT hr = NtDeviceIoControlFile( + m_hAsync, + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_NOOP, + NULL, + 0, + NULL, + 0 ); + + if( hr != ND_PENDING && hr != ND_SUCCESS ) + { + delete pMr; + return hr; + } + + AddRef(); + return ND_SUCCESS; +} + +HRESULT CAdapter::DeregisterMemory( + __in ND_MR_HANDLE hMr, + __inout OVERLAPPED* pOverlapped + ) +{ + ND_ENTER( ND_DBG_NDI ); + + CMr* pMr = (CMr*)hMr; + + // + // We must issue the IOCTL on the synchronous file handle. + // If the user bound the async file handle to an I/O completion port + // DeviceIoControl could succeed, but not return data, so the MR + // wouldn't be updated. + // + // We use a second IOCTL to complet the user's overlapped. + // + DWORD bytes_ret = 0; + BOOL ret = DeviceIoControl( m_hSync, UAL_DEREG_MR, + &pMr->mr_ioctl.out.h_mr, sizeof(pMr->mr_ioctl.out.h_mr), + &pMr->mr_ioctl.out.status, sizeof(pMr->mr_ioctl.out.status), + &bytes_ret, NULL ); + if( !ret ) + { + CL_ASSERT( GetLastError() != ERROR_IO_PENDING ); + pMr->mr_ioctl.out.status = IB_ERROR; + } + if( bytes_ret != sizeof(pMr->mr_ioctl.out.status) ) + return ND_UNSUCCESSFUL; + + switch( pMr->mr_ioctl.out.status ) + { + case IB_SUCCESS: + { + delete pMr; + Release(); + + // + // The deregistration succeeded. Now issue the user's IOCTL. + // + pOverlapped->Internal = ND_PENDING; + HRESULT hr = NtDeviceIoControlFile( + m_hAsync, + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_NOOP, + NULL, + 0, + NULL, + 0 ); + CL_ASSERT( SUCCEEDED( hr ) ); + return hr; + } + case IB_RESOURCE_BUSY: + return ND_DEVICE_BUSY; + + default: + return ND_UNSUCCESSFUL; + } +} + +HRESULT CAdapter::CreateMemoryWindow( + __out ND_RESULT* pInvalidateResult, + __deref_out INDMemoryWindow** ppMw + ) +{ + ND_ENTER( ND_DBG_NDI ); + + CMw* pMw = new CMw(); + if( pMw == NULL ) + return ND_NO_MEMORY; + + HRESULT hr = pMw->Initialize( this, pInvalidateResult ); + if( FAILED(hr) ) + { + delete pMw; + return hr; + } + + *ppMw = pMw; + return S_OK; +} + +HRESULT CAdapter::CreateConnector( + __deref_out INDConnector** ppConnector + ) +{ + ND_ENTER( ND_DBG_NDI ); + + return CConnector::Create( this, ppConnector ); +} + +HRESULT CAdapter::Listen( + __in SIZE_T Backlog, + __in INT Protocol, + __in USHORT Port, + __out_opt USHORT* pAssignedPort, + __deref_out INDListen** ppListen + ) +{ + ND_ENTER( ND_DBG_NDI ); + + return CListen::Create( + this, + Backlog, + Protocol, + Port, + pAssignedPort, + ppListen + ); +} + +HRESULT CAdapter::GetLocalAddress( + __out_bcount_part(*pAddressLength, *pAddressLength) struct sockaddr *pAddr, + __inout SIZE_T *pAddressLength ) +{ + ND_ENTER( ND_DBG_NDI ); + + switch( m_Addr.v4.sin_family ) + { + case AF_INET: + if( *pAddressLength < sizeof(struct sockaddr_in) ) + { + *pAddressLength = sizeof(struct sockaddr_in); + return ND_BUFFER_OVERFLOW; + } + *(struct sockaddr_in*)pAddr = m_Addr.v4; + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Local address: IP %#x, port %#hx\n", + cl_hton32(m_Addr.v4.sin_addr.S_un.S_addr), cl_hton16(m_Addr.v4.sin_port) ) ); + return S_OK; + + case AF_INET6: + if( *pAddressLength < sizeof(struct sockaddr_in6) ) + { + *pAddressLength = sizeof(struct sockaddr_in6); + return ND_BUFFER_OVERFLOW; + } + *(struct sockaddr_in6*)pAddr = m_Addr.v6; + return S_OK; + + default: + return ND_INVALID_ADDRESS; + } +} + +HRESULT CAdapter::OpenFiles(void) +{ + ND_ENTER( ND_DBG_NDI ); + + /* First open the kernel device. */ + CL_ASSERT( m_hSync == INVALID_HANDLE_VALUE ); + m_hSync = CreateFile( + "\\\\.\\ibal", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if( m_hSync == INVALID_HANDLE_VALUE ) + return ND_UNSUCCESSFUL; + + // Now issue the BIND IOCTL which associates us as a client. + ULONG ver = AL_IOCTL_VERSION; + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_hSync, + UAL_BIND, + &ver, + sizeof(ver), + NULL, + 0, + &BytesRet, + NULL + ); + if( fSuccess != TRUE ) + return ND_UNSUCCESSFUL; + + // Now create the async file. + m_hAsync = CreateFile( + "\\\\.\\ibal", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL + ); + if( m_hAsync == INVALID_HANDLE_VALUE ) + return ND_UNSUCCESSFUL; + + /* + * Send an IOCTL down on the main file handle to bind this file + * handle with our proxy context. + */ + UINT64 hFile = (ULONG_PTR)m_hAsync; + fSuccess = DeviceIoControl( + m_hSync, + UAL_BIND_ND, + &hFile, + sizeof(hFile), + NULL, + 0, + &BytesRet, + NULL + ); + if( fSuccess != TRUE ) + return ND_UNSUCCESSFUL; + + return S_OK; +} + +HRESULT CAdapter::OpenCa( + __in UINT64 CaGuid ) +{ + ND_ENTER( ND_DBG_NDI ); + + ual_get_uvp_name_ioctl_t al_ioctl; + + /* Initialize assuming no user-mode support */ + cl_memclr( &al_ioctl, sizeof(al_ioctl) ); + cl_memclr( &m_Ifc, sizeof(m_Ifc) ); + + /* init with the guid */ + m_Ifc.guid = CaGuid; + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_hSync, + UAL_GET_VENDOR_LIBCFG, + &CaGuid, sizeof(CaGuid), + &al_ioctl.out, sizeof(al_ioctl.out), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(al_ioctl.out) ) + return ND_INSUFFICIENT_RESOURCES; + + if( !strlen( al_ioctl.out.uvp_lib_name ) ) + { + /* Vendor does not implement user-mode library */ + return ND_NOT_SUPPORTED; + } + + /* + * The vendor supports a user-mode library + * open the library and get the interfaces supported + */ +#if DBG + HRESULT hr = StringCbCatA( al_ioctl.out.uvp_lib_name, 32, "d.dll" ); +#else + HRESULT hr = StringCbCatA( al_ioctl.out.uvp_lib_name, 32, ".dll" ); +#endif + if( FAILED( hr ) ) + return ND_NOT_SUPPORTED; + + m_Ifc.h_uvp_lib = LoadLibrary( al_ioctl.out.uvp_lib_name ); + if( m_Ifc.h_uvp_lib == NULL ) + return ND_NOT_SUPPORTED; + + uvp_get_interface_t pfn_uvp_ifc = (uvp_get_interface_t)GetProcAddress( + m_Ifc.h_uvp_lib, + "uvp_get_interface" + ); + + if( pfn_uvp_ifc == NULL ) + return ND_NOT_SUPPORTED; + + /* Query the vendor-supported user-mode functions */ + pfn_uvp_ifc( IID_UVP, &m_Ifc.user_verbs ); + + ual_open_ca_ioctl_t ca_ioctl; + cl_memclr( &ca_ioctl, sizeof(ca_ioctl) ); + + /* Pre call to the UVP library */ + ib_api_status_t status = IB_ERROR; + if( m_Ifc.user_verbs.pre_open_ca ) + { + status = m_Ifc.user_verbs.pre_open_ca( + CaGuid, + &ca_ioctl.in.umv_buf, + (ib_ca_handle_t*)(ULONG_PTR)&m_uCa + ); + if( status != IB_SUCCESS ) + { + CL_ASSERT( status != IB_VERBS_PROCESSING_DONE ); + return ND_INSUFFICIENT_RESOURCES; + } + } + + ca_ioctl.in.guid = CaGuid; + ca_ioctl.in.context = (ULONG_PTR)this; + + fSuccess = DeviceIoControl( + m_hSync, + UAL_OPEN_CA, + &ca_ioctl.in, + sizeof(ca_ioctl.in), + &ca_ioctl.out, + sizeof(ca_ioctl.out), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(ca_ioctl.out) ) + { + status = IB_ERROR; + } + else + { + status = ca_ioctl.out.status; + m_hCa = ca_ioctl.out.h_ca; + } + + /* Post uvp call */ + if( m_Ifc.user_verbs.post_open_ca ) + { + status = m_Ifc.user_verbs.post_open_ca( + CaGuid, + status, + (ib_ca_handle_t*)(ULONG_PTR)&m_uCa, + &ca_ioctl.out.umv_buf ); + } + + // TODO: Does the UVP need a query call to succeed? + // IBAL always does this internally. + + return (status == IB_SUCCESS? S_OK : ND_INSUFFICIENT_RESOURCES ); +} + +HRESULT CAdapter::QueryCa( + __out_bcount(*pSize) ib_ca_attr_t* pAttr, + __inout DWORD* pSize ) +{ + ND_ENTER( ND_DBG_NDI ); + + ual_query_ca_ioctl_t ca_ioctl; + + cl_memclr( &ca_ioctl, sizeof(ca_ioctl) ); + + ca_ioctl.in.h_ca = m_hCa; + ca_ioctl.in.p_ca_attr = (ULONG_PTR)pAttr; + ca_ioctl.in.byte_cnt = *pSize; + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + ib_api_status_t status; + if( m_uCa && m_Ifc.user_verbs.pre_query_ca ) + { + /* Pre call to the UVP library */ + status = m_Ifc.user_verbs.pre_query_ca( + m_uCa, pAttr, *pSize, &ca_ioctl.in.umv_buf ); + if( status != IB_SUCCESS ) + return ND_UNSUCCESSFUL; + } + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_hSync, + UAL_QUERY_CA, + &ca_ioctl.in, + sizeof(ca_ioctl.in), + &ca_ioctl.out, + sizeof(ca_ioctl.out), + &BytesRet, + NULL + ); + if( fSuccess != TRUE || BytesRet != sizeof(ca_ioctl.out) ) + { + status = IB_ERROR; + } + else + { + *pSize = ca_ioctl.out.byte_cnt; + status = ca_ioctl.out.status; + } + + /* The attributes, if any, will be directly copied by proxy */ + /* Post uvp call */ + if( m_uCa && m_Ifc.user_verbs.post_query_ca ) + { + m_Ifc.user_verbs.post_query_ca( m_uCa, + status, pAttr, ca_ioctl.out.byte_cnt, &ca_ioctl.out.umv_buf ); + } + + switch( status ) + { + case IB_SUCCESS: + return S_OK; + case IB_INSUFFICIENT_MEMORY: + return ND_BUFFER_OVERFLOW; + default: + return ND_INSUFFICIENT_RESOURCES; + } +} + +void CAdapter::CloseCa(void) +{ + ND_ENTER( ND_DBG_NDI ); + + ib_api_status_t status; + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( m_uCa && m_Ifc.user_verbs.pre_close_ca ) + { + /* Pre call to the UVP library */ + status = m_Ifc.user_verbs.pre_close_ca( m_uCa ); + if( status != IB_SUCCESS ) + return; + } + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_hSync, + UAL_CLOSE_CA, + &m_hCa, + sizeof(m_hCa), + &status, + sizeof(status), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(status) ) + status = IB_ERROR; + + if( m_uCa && m_Ifc.user_verbs.post_close_ca ) + m_Ifc.user_verbs.post_close_ca( m_uCa, status ); + + if( m_Ifc.h_uvp_lib ) + FreeLibrary( m_Ifc.h_uvp_lib ); + + m_hCa = 0; +} + +HRESULT CAdapter::AllocPd(void) +{ + ND_ENTER( ND_DBG_NDI ); + + /* Clear the pd_ioctl */ + ual_alloc_pd_ioctl_t pd_ioctl; + cl_memclr( &pd_ioctl, sizeof(pd_ioctl) ); + + /* Pre call to the UVP library */ + ib_api_status_t status; + if( m_uCa && m_Ifc.user_verbs.pre_allocate_pd ) + { + status = m_Ifc.user_verbs.pre_allocate_pd( + m_uCa, + &pd_ioctl.in.umv_buf, + (ib_pd_handle_t*)(ULONG_PTR)&m_uPd + ); + if( status != IB_SUCCESS ) + return ND_INSUFFICIENT_RESOURCES; + } + + pd_ioctl.in.h_ca = m_hCa; + pd_ioctl.in.type = IB_PDT_NORMAL; + pd_ioctl.in.context = (ULONG_PTR)this; + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_hSync, + UAL_ALLOC_PD, + &pd_ioctl.in, + sizeof(pd_ioctl.in), + &pd_ioctl.out, + sizeof(pd_ioctl.out), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(pd_ioctl.out) ) + { + status = IB_ERROR; + } + else + { + status = pd_ioctl.out.status; + if( pd_ioctl.out.status == IB_SUCCESS ) + m_hPd = pd_ioctl.out.h_pd; + } + + /* Post uvp call */ + if( m_uCa && m_Ifc.user_verbs.post_allocate_pd ) + { + m_Ifc.user_verbs.post_allocate_pd( + m_uCa, + status, + (ib_pd_handle_t*)(ULONG_PTR)&m_uPd, + &pd_ioctl.out.umv_buf ); + } + + return (status == IB_SUCCESS? S_OK : ND_INSUFFICIENT_RESOURCES); +} + +void CAdapter::DeallocPd(void) +{ + ND_ENTER( ND_DBG_NDI ); + + ib_api_status_t status; + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( m_uPd && m_Ifc.user_verbs.pre_deallocate_pd ) + { + /* Pre call to the UVP library */ + status = m_Ifc.user_verbs.pre_deallocate_pd( m_uPd ); + if( status != IB_SUCCESS ) + return; + } + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_hSync, + UAL_DEALLOC_PD, + &m_hPd, + sizeof(m_hPd), + &status, + sizeof(status), + &BytesRet, + NULL + ); + + if( fSuccess == FALSE || BytesRet != sizeof(status) ) + status = IB_ERROR; + + /* Call vendor's post_close ca */ + if( m_uPd && m_Ifc.user_verbs.post_deallocate_pd ) + m_Ifc.user_verbs.post_deallocate_pd( m_uPd, status ); + + m_hPd = 0; +} + +} // namespace diff --git a/trunk/ulp/nd/user/NdAdapter.h b/trunk/ulp/nd/user/NdAdapter.h new file mode 100644 index 00000000..79b79e04 --- /dev/null +++ b/trunk/ulp/nd/user/NdAdapter.h @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2008 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:$ + */ + +#pragma once + +#include "ndspi.h" +#include "nddebug.h" +#include +#include +#include +#include "ual_ci_ca.h" + +#include "NdProv.h" + + +namespace NetworkDirect +{ + +class CCq; +class CAddr; +class CProvider; + +class CAdapter : + public INDAdapter +{ + friend class CCq; + friend class CEndpoint; + friend class CConnector; + friend class CMw; + friend class CMr; + friend class CListen; + +private: + CAdapter(void); + ~CAdapter(void); + + HRESULT Initialize( + CProvider* pParent, + const struct sockaddr* pAddr, + const IBAT_PORT_RECORD* pPortRecord + ); + +public: + static HRESULT Create( + CProvider* pParent, + const struct sockaddr* pAddr, + const IBAT_PORT_RECORD* pPortRecord, + __out INDAdapter** ppAdapter + ); + + // *** IUnknown methods *** + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + + ULONG STDMETHODCALLTYPE Release(void); + + // *** INDOverlapped methods *** + HRESULT STDMETHODCALLTYPE CancelOverlappedRequests(void); + + HRESULT STDMETHODCALLTYPE GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ); + + // *** INDAdapter methods *** + HANDLE STDMETHODCALLTYPE GetFileHandle(void); + + HRESULT STDMETHODCALLTYPE Query( + __in DWORD VersionRequested, + __out_bcount_part_opt(*pBufferSize, *pBufferSize) ND_ADAPTER_INFO* pInfo, + __inout_opt SIZE_T* pBufferSize + ); + + HRESULT STDMETHODCALLTYPE Control( + __in DWORD IoControlCode, + __in_bcount_opt(InBufferSize) const void* pInBuffer, + __in SIZE_T InBufferSize, + __out_bcount_opt(OutBufferSize) void* pOutBuffer, + __in SIZE_T OutBufferSize, + __out SIZE_T* pBytesReturned, + __inout OVERLAPPED* pOverlapped + ); + + HRESULT STDMETHODCALLTYPE CreateCompletionQueue( + __in SIZE_T nEntries, + __deref_out INDCompletionQueue** ppCq + ); + + HRESULT STDMETHODCALLTYPE RegisterMemory( + __in_bcount(BufferSize) const void* pBuffer, + __in SIZE_T BufferSize, + __inout OVERLAPPED* pOverlapped, + __deref_out ND_MR_HANDLE* phMr + ); + + HRESULT STDMETHODCALLTYPE CompleteRegisterMemory( + __in ND_MR_HANDLE hMr, + __in OVERLAPPED* pOverlapped + ); + + HRESULT STDMETHODCALLTYPE DeregisterMemory( + __in ND_MR_HANDLE hMr, + __inout OVERLAPPED* pOverlapped + ); + + HRESULT STDMETHODCALLTYPE CompleteDeregisterMemory( + __in ND_MR_HANDLE hMr, + __in OVERLAPPED* pOverlapped + ); + + HRESULT STDMETHODCALLTYPE CreateMemoryWindow( + __out ND_RESULT* pInvalidateResult, + __deref_out INDMemoryWindow** ppMw + ); + + HRESULT STDMETHODCALLTYPE CreateConnector( + __deref_out INDConnector** ppConnector + ); + + HRESULT STDMETHODCALLTYPE Listen( + __in SIZE_T Backlog, + __in INT Protocol, + __in USHORT Port, + __out_opt USHORT* pAssignedPort, + __deref_out INDListen** ppListen + ); + + HRESULT GetLocalAddress( + __out_bcount_part(*pAddressLength, *pAddressLength) struct sockaddr* pAddr, + __inout SIZE_T *pAddressLength ); + +private: + HRESULT OpenFiles(void); + + HRESULT OpenCa( + __in UINT64 CaGuid + ); + + HRESULT QueryCa( + __out_bcount(*pSize) ib_ca_attr_t* pAttr, + __inout DWORD* pSize + ); + + void CloseCa(void); + + HRESULT AllocPd(void); + + void DeallocPd(void); + +protected: + volatile LONG m_nRef; + + CProvider* m_pParent; + UINT64 m_PortGuid; + UINT8 m_PortNum; + + HANDLE m_hSync; + HANDLE m_hAsync; + + ual_ci_interface_t m_Ifc; + // Kernel IBAL handles. + uint64_t m_hCa; + uint64_t m_hPd; + // UVP handles. + ib_ca_handle_t m_uCa; + ib_pd_handle_t m_uPd; + + union _addr + { + struct sockaddr unspec; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + + } m_Addr; +}; + +} // namespace \ No newline at end of file diff --git a/trunk/ulp/nd/user/NdConnector.cpp b/trunk/ulp/nd/user/NdConnector.cpp new file mode 100644 index 00000000..3cb4aa2d --- /dev/null +++ b/trunk/ulp/nd/user/NdConnector.cpp @@ -0,0 +1,935 @@ +/* + * Copyright (c) 2008 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 "NdCq.h" +#include "NdAdapter.h" +#include "NdMw.h" +#include "NdEndpoint.h" +#include "NdProv.h" +#include "NdMr.h" +#include "NdListen.h" +#include "NdConnector.h" + +#include "al_dev.h" +#pragma warning( push, 3 ) +#include "winternl.h" +#pragma warning( pop ) +#include "iba/ibat.h" + +#include +#include +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdConnector.tmh" +#endif + + +namespace NetworkDirect +{ + +CConnector::CConnector(void) : + m_nRef( 1 ), + m_pParent( NULL ), + m_pEndpoint( NULL ), + m_Protocol( 0 ), + m_LocalPort( 0 ), + m_cid( 0 ), + m_fActive( false ) +{ +} + +CConnector::~CConnector(void) +{ + FreeCid(); + + if( m_pEndpoint ) + m_pEndpoint->Release(); + + if( m_pParent ) + m_pParent->Release(); +} + +void CConnector::FreeCid(void) +{ + if( m_cid != 0 ) + { + DWORD bytes_ret; + DeviceIoControl( + m_pParent->m_hSync, + UAL_DESTROY_CEP, + &m_cid, + sizeof(m_cid), + NULL, + 0, + &bytes_ret, + NULL ); + + m_cid = 0; + } +} + +HRESULT CConnector::Create( + __in CAdapter* pParent, + __deref_out INDConnector** ppConnector + ) +{ + CConnector* pConnector = new CConnector(); + if( pConnector == NULL ) + return ND_NO_MEMORY; + + pConnector->m_pParent = pParent; + pParent->AddRef(); + + *ppConnector = pConnector; + return S_OK; +} + +HRESULT CConnector::QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ) +{ + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppvObj = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDConnector ) ) + { + *ppvObj = this; + return S_OK; + } + + return E_NOINTERFACE; +} + +ULONG CConnector::AddRef(void) +{ + return InterlockedIncrement( &m_nRef ); +} + +ULONG CConnector::Release(void) +{ + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; +} + +// *** INDOverlapped methods *** +HRESULT CConnector::CancelOverlappedRequests(void) +{ + ND_ENTER( ND_DBG_NDI ); + + DWORD bytes_ret; + BOOL ret = DeviceIoControl( + m_pParent->m_hSync, + UAL_NDI_CANCEL_CM_IRPS, + &m_cid, + sizeof(m_cid), + NULL, + 0, + &bytes_ret, + NULL ); + + if( ret ) + return S_OK; + else + return ND_UNSUCCESSFUL; +} + +HRESULT CConnector::GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ) +{ + ND_ENTER( ND_DBG_NDI ); + + *pNumberOfBytesTransferred = 0; + ::GetOverlappedResult( + m_pParent->GetFileHandle(), + pOverlapped, + (DWORD*)pNumberOfBytesTransferred, + bWait ); + return (HRESULT)pOverlapped->Internal; +} + +HRESULT CConnector::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 + ) +{ + ND_ENTER( ND_DBG_NDI ); + + // + // Check that the verb provider supports user-mode operations. + // If not, a different class should be created. + // + if( m_pParent->m_Ifc.user_verbs.pre_create_qp == NULL || + m_pParent->m_Ifc.user_verbs.post_create_qp == NULL || + m_pParent->m_Ifc.user_verbs.nd_modify_qp == NULL || + m_pParent->m_Ifc.user_verbs.nd_get_qp_state == NULL || + m_pParent->m_Ifc.user_verbs.pre_destroy_qp == NULL || + m_pParent->m_Ifc.user_verbs.post_destroy_qp == NULL || + m_pParent->m_Ifc.user_verbs.post_send == NULL || + m_pParent->m_Ifc.user_verbs.post_recv == NULL /*|| + m_pParent->m_Ifc.user_verbs.bind_mw == NULL*/ ) + { + return ND_NOT_SUPPORTED; + } + + if( m_pEndpoint != NULL ) + return ND_NOT_SUPPORTED; + + HRESULT hr = CEndpoint::Create( + m_pParent, + static_cast(pInboundCq), + static_cast(pOutboundCq), + nInboundEntries, + nOutboundEntries, + nInboundSge, + nOutboundSge, + InboundReadLimit, + OutboundReadLimit, + pMaxInlineData, + (INDEndpoint**)&m_pEndpoint + ); + + if( SUCCEEDED( hr ) ) + { + m_pEndpoint->AddRef(); + *ppEndpoint = m_pEndpoint; + } + + return hr; +} + +// +// Connects an endpoint to the specified destinaton address. +// +// Only basic checks on input data are performed in user-mode, +// and request is handed to the kernel, where: +// 1. the destination address is resolved to a destination GID +// 2. the destination GID is used to get a path record +// 3. the path record is used to issue a CM REQ +// 4. a CM REP is received (or REJ or timeout). +// 5. the request is completed. +// +HRESULT CConnector::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 + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( AddressLength < sizeof(struct sockaddr) ) + return ND_INVALID_ADDRESS; + + if( Protocol > UCHAR_MAX || Protocol < 0 ) + return ND_INVALID_PARAMETER_4; + + m_Protocol = (UINT8)Protocol; + + // + // CM REQ supports 92 bytes of private data. We expect to use IP + // addressing annex, which eats up 36 bytes, leaving us with 56. + // + if( PrivateDataLength > 56 ) + return ND_BUFFER_OVERFLOW; + + // + // Only support connecting the endpoint we created. + // + if( pEndpoint != m_pEndpoint ) + return ND_INVALID_PARAMETER_1; + + // + // Format the private data to match the RDMA CM annex spec as we + // check the address validity. + // + ual_ndi_req_cm_ioctl_in_t ioctl; + ioctl.pdata.maj_min_ver = 0; + if( LocalPort == 0 ) + { + m_LocalPort = (USHORT)_byteswap_ulong( m_pEndpoint->m_Qpn ); + } + else + { + m_LocalPort = LocalPort; + } + ioctl.pdata.src_port = _byteswap_ushort( m_LocalPort ); + + // Resolve the GIDs. + HRESULT hr = IBAT::Resolve( + &m_pParent->m_Addr.unspec, + pAddress, + (IBAT_PATH_BLOB*)&ioctl.path + ); + if( FAILED( hr ) ) + { + if( hr == E_PENDING ) + { + // + // Complete the request with a timeout status. + // + pOverlapped->Internal = ND_PENDING; + hr = NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_NOOP, + &hr, + sizeof(hr), + NULL, + 0 ); + } + return hr; + } + + switch( ((struct sockaddr_in*)pAddress)->sin_family ) + { + case AF_INET: + if( AddressLength != sizeof(struct sockaddr_in) ) + return ND_INVALID_ADDRESS; + + if( m_pParent->m_Addr.v4.sin_family != AF_INET ) + return ND_INVALID_ADDRESS; + + // + // Copy the destination address so we can satisfy a + // GetPeerAddress request. + // + m_PeerAddr.v4 = *(struct sockaddr_in*)pAddress; + + ioctl.dst_port = m_PeerAddr.v4.sin_port; + ioctl.pdata.ipv = 0x40; + + // Local address. + RtlZeroMemory( &ioctl.pdata.src_ip_addr, ATS_IPV4_OFFSET ); + CopyMemory( + &ioctl.pdata.src_ip_addr[ATS_IPV4_OFFSET>>2], + (uint8_t*)&m_pParent->m_Addr.v4.sin_addr, + sizeof( m_pParent->m_Addr.v4.sin_addr ) + ); + + // Destination address. + RtlZeroMemory( &ioctl.pdata.dst_ip_addr, ATS_IPV4_OFFSET ); + CopyMemory( + &ioctl.pdata.dst_ip_addr[ATS_IPV4_OFFSET>>2], + (uint8_t*)&m_PeerAddr.v4.sin_addr, + sizeof( m_PeerAddr.v4.sin_addr ) + ); + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("local address: IP %#x, port %#hx, dest address: IP %#x, port %#hx\n", + cl_hton32(m_pParent->m_Addr.v4.sin_addr.S_un.S_addr), cl_hton16(m_pParent->m_Addr.v4.sin_port), + cl_hton32(m_PeerAddr.v4.sin_addr.S_un.S_addr), cl_hton16(m_PeerAddr.v4.sin_port) ) ); + break; + + case AF_INET6: + if( AddressLength != sizeof(struct sockaddr_in6) ) + return ND_INVALID_ADDRESS; + + // + // Copy the destination address so we can satisfy a + // GetPeerAddress request. + // + m_PeerAddr.v6 = *(struct sockaddr_in6*)pAddress; + + ioctl.dst_port = m_PeerAddr.v6.sin6_port; + ioctl.pdata.ipv = 0x60; + + // Local address. + CopyMemory( + ioctl.pdata.src_ip_addr, + m_pParent->m_Addr.v6.sin6_addr.u.Byte, + sizeof(ioctl.pdata.src_ip_addr) + ); + + // Destination address. + CopyMemory( ioctl.pdata.dst_ip_addr, + m_PeerAddr.v6.sin6_addr.u.Byte, + sizeof(ioctl.pdata.dst_ip_addr) + ); + break; + + default: + return ND_INVALID_ADDRESS; + } + + // Copy the user's private data. + CopyMemory( ioctl.pdata.pdata, pPrivateData, PrivateDataLength ); + + // + // It's only valid to call Connect with a new or reused endpoint: + // the QP must be in the INIT state. + // + switch( m_pParent->m_Ifc.user_verbs.nd_get_qp_state( m_pEndpoint->m_uQp ) ) + { + case IB_QPS_INIT: + break; + + case IB_QPS_RTS: + return ND_CONNECTION_ACTIVE; + + default: + return ND_UNSUCCESSFUL; + } + + // + // Create the CEP. We do this so that we have a valid CID in user-mode + // in case the user calls CancelOverlappedRequests or releases the object. + // + UINT64 context = 0; + ual_create_cep_ioctl_t create; + DWORD bytes_ret; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_CREATE_CEP, + &context, + sizeof(context), + &create, + sizeof(create), + &bytes_ret, + NULL + ); + if( !fSuccess || + bytes_ret != sizeof(create) || + create.status != IB_SUCCESS ) + { + return ND_INSUFFICIENT_RESOURCES; + } + + m_cid = create.cid; + + // + // Fill in the rest of the input buffer and send the request down + // to the kernel and let everything else be done there. + // + ioctl.h_qp = m_pEndpoint->m_hQp; + ioctl.guid = m_pParent->m_PortGuid; + ioctl.cid = m_cid; + ioctl.prot = m_Protocol; + ioctl.pdata_size = sizeof(ioctl.pdata); + ioctl.init_depth = m_pEndpoint->m_Ord; + ioctl.resp_res = m_pEndpoint->m_Ird; + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Connect QP %#I64x, QPn %#x, Guid %#I64x \n", + m_pEndpoint->m_hQp, + m_pEndpoint->m_Qpn, + m_pParent->m_PortGuid ) ); + + m_fActive = true; + + pOverlapped->Internal = ND_PENDING; + hr = NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_REQ_CM, + &ioctl, + sizeof(ioctl), + NULL, + 0 ); + + if( FAILED( hr ) ) + { + FreeCid(); + m_pEndpoint->Release(); + m_pEndpoint = NULL; + } + + return hr; +} + +HRESULT CConnector::CompleteConnect( + __inout OVERLAPPED* pOverlapped + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( !m_fActive ) + return ND_CONNECTION_INVALID; + + if( m_pEndpoint == NULL ) + return ND_CONNECTION_INVALID; + + // + // Get the UVP's buffer for modify operations. + // + void* pOutbuf; + DWORD szOutbuf; + + m_pParent->m_Ifc.user_verbs.nd_modify_qp( + (const ib_qp_handle_t)m_pEndpoint->m_uQp, + &pOutbuf, + &szOutbuf + ); + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("CompleteConnect QP %#I64x, QPn %#x\n", m_pEndpoint->m_hQp, m_pEndpoint->m_Qpn ) ); + + pOverlapped->Internal = ND_PENDING; + return NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_RTU_CM, + &m_cid, + sizeof(m_cid), + pOutbuf, + szOutbuf ); +} + +HRESULT CConnector::Accept( + __in INDEndpoint* pEndpoint, + __in_bcount_opt(PrivateDataLength) const void* pPrivateData, + __in SIZE_T PrivateDataLength, + __inout OVERLAPPED* pOverlapped + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( PrivateDataLength > IB_REJ_PDATA_SIZE ) + return ND_BUFFER_OVERFLOW; + + // + // Only support connecting the endpoint we created. + // + if( pEndpoint != m_pEndpoint ) + return ND_INVALID_PARAMETER_1; + + // + // Get the UVP's buffer for modify operations. + // + void* pOutbuf; + DWORD szOutbuf; + + m_pParent->m_Ifc.user_verbs.nd_modify_qp( + static_cast(pEndpoint)->m_uQp, + &pOutbuf, + &szOutbuf + ); + + ual_ndi_rep_cm_ioctl_in_t ioctl; + ioctl.h_qp = m_pEndpoint->m_hQp; + ioctl.cid = m_cid; + ioctl.init_depth = m_pEndpoint->m_Ord; + ioctl.resp_res = m_pEndpoint->m_Ird; + ioctl.pdata_size = (uint8_t)PrivateDataLength; + CopyMemory( &ioctl.pdata, pPrivateData, PrivateDataLength ); + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Accept QP %#I64x, cid %d \n", ioctl.h_qp, ioctl.cid ) ); + + pOverlapped->Internal = ND_PENDING; + HRESULT hr = NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_REP_CM, + &ioctl, + sizeof(ioctl), + pOutbuf, + szOutbuf ); + + if( FAILED( hr ) ) + { + m_pEndpoint->Release(); + m_pEndpoint = NULL; + } + return hr; +} + +HRESULT CConnector::Reject( + __in_bcount_opt(PrivateDataLength) const void* pPrivateData, + __in SIZE_T PrivateDataLength + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( PrivateDataLength > IB_REJ_PDATA_SIZE ) + return ND_BUFFER_OVERFLOW; + + ual_ndi_rej_cm_ioctl_in_t ioctl; + ioctl.cid = m_cid; + ioctl.pdata_size = (uint8_t)PrivateDataLength; + if( pPrivateData != NULL ) + { + CopyMemory( &ioctl.pdata, pPrivateData, PrivateDataLength ); + } + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Connection rejected with pdata_size %d, cid %d\n", + (int)PrivateDataLength, ioctl.cid )); + + IO_STATUS_BLOCK IoStatus; + return NtDeviceIoControlFile( + m_pParent->m_hSync, + NULL, + NULL, + NULL, + &IoStatus, + UAL_NDI_REJ_CM, + &ioctl, + sizeof(ioctl), + NULL, + 0 ); +} + +HRESULT CConnector::GetConnectionData( + __out_opt SIZE_T* pInboundReadLimit, + __out_opt SIZE_T* pOutboundReadLimit, + __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData, + __inout SIZE_T* pPrivateDataLength + ) +{ + ND_ENTER( ND_DBG_NDI ); + + IO_STATUS_BLOCK IoStatus; + ual_cep_get_pdata_ioctl_t IoctlBuf; + + IoctlBuf.in.cid = m_cid; + HRESULT hr = NtDeviceIoControlFile( + m_pParent->m_hSync, + NULL, + NULL, + NULL, + &IoStatus, + UAL_CEP_GET_PDATA, + &IoctlBuf, + sizeof(IoctlBuf.in), + &IoctlBuf, + sizeof(IoctlBuf.out) ); + + // UAL_CEP_GET_PDATA never returns pending. + if( FAILED( hr ) ) + return hr; + + // On the passive side, check that we got the REQ private data. + if( !m_fActive ) + { + hr = GetPdataForPassive( + IoctlBuf.out.pdata, + IoctlBuf.out.pdata_len, + pPrivateData, + pPrivateDataLength + ); + } + else + { + hr = GetPdataForActive( + IoctlBuf.out.pdata, + IoctlBuf.out.pdata_len, + pPrivateData, + pPrivateDataLength + ); + } + + if( FAILED( hr ) && hr != ND_BUFFER_OVERFLOW ) + return hr; + + if( pInboundReadLimit ) + { + *pInboundReadLimit = IoctlBuf.out.resp_res; + } + + if( pOutboundReadLimit ) + { + *pOutboundReadLimit = IoctlBuf.out.init_depth; + } + + return hr; +} + +HRESULT CConnector::GetLocalAddress( + __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress, + __inout SIZE_T* pAddressLength + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( m_pEndpoint == NULL ) + return ND_CONNECTION_INVALID; + + ib_qp_state_t state = + m_pParent->m_Ifc.user_verbs.nd_get_qp_state( m_pEndpoint->m_uQp ); + if( state != IB_QPS_RTS ) + return ND_CONNECTION_INVALID; + + HRESULT hr = m_pParent->GetLocalAddress( pAddress, pAddressLength ); + if( FAILED(hr) ) + return hr; + + // V4 and V6 addresses have the port number in the same place. + ((struct sockaddr_in*)pAddress)->sin_port = m_LocalPort; +#if DBG || defined(EVENT_TRACING) + struct sockaddr_in*pAddrV4 = (struct sockaddr_in*)pAddress; +#endif + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Local address: IP %#x, port %#hx\n", + cl_hton32(pAddrV4->sin_addr.S_un.S_addr), cl_hton16(pAddrV4->sin_port) ) ); + + return S_OK; +} + +HRESULT CConnector::GetAddressFromPdata( + __out_bcount_part(*pAddressLength, *pAddressLength) struct sockaddr* pAddress, + __inout SIZE_T* pAddressLength + ) +{ + ND_ENTER( ND_DBG_NDI ); + + IO_STATUS_BLOCK IoStatus; + ual_cep_get_pdata_ioctl_t IoctlBuf; + + IoctlBuf.in.cid = m_cid; + + HRESULT hr = NtDeviceIoControlFile( + m_pParent->m_hSync, + NULL, + NULL, + NULL, + &IoStatus, + UAL_CEP_GET_PDATA, + &IoctlBuf, + sizeof(IoctlBuf.in), + &IoctlBuf, + sizeof(IoctlBuf.out) ); + + // UAL_CEP_GET_PDATA never returns pending. + if( FAILED( hr ) ) + { + CL_ASSERT( hr != ND_PENDING ); + return hr; + } + + if( IoctlBuf.out.pdata_len != IB_REQ_PDATA_SIZE ) + return ND_CONNECTION_ABORTED; + + ib_cm_rdma_req_t* pIpData = (ib_cm_rdma_req_t*)&IoctlBuf.out.pdata; + CL_ASSERT( pIpData->maj_min_ver == 0 ); + + SIZE_T len; + switch( pIpData->ipv ) + { + case 0x40: + len = 4; + break; + case 0x60: + len = 16; + break; + default: + CL_ASSERT( pIpData->ipv == 0x40 || pIpData->ipv == 0x60 ); + len = 0; + break; + } + + if( len > *pAddressLength ) + { + *pAddressLength = len; + return ND_BUFFER_OVERFLOW; + } + + ((struct sockaddr_in*)pAddress)->sin_port = + _byteswap_ushort( pIpData->src_port ); + + switch( pIpData->ipv ) + { + case 0x40: + ((struct sockaddr_in*)pAddress)->sin_family = AF_INET; + ((struct sockaddr_in*)pAddress)->sin_addr.s_addr = pIpData->src_ip_addr[3]; + ZeroMemory( ((struct sockaddr_in*)pAddress)->sin_zero, + sizeof( ((struct sockaddr_in*)pAddress)->sin_zero ) ); + break; + + case 0x60: + ((struct sockaddr_in6*)pAddress)->sin6_family = AF_INET6; + ((struct sockaddr_in6*)pAddress)->sin6_flowinfo = 0; + RtlCopyMemory( (char*)((struct sockaddr_in6*)pAddress)->sin6_addr.s6_bytes, + (char *const)pIpData->src_ip_addr, sizeof(pIpData->src_ip_addr) ); + ((struct sockaddr_in6*)pAddress)->sin6_scope_id = 0; + break; + } + + *pAddressLength = len; + return hr; +} + +HRESULT CConnector::GetPeerAddress( + __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress, + __inout SIZE_T* pAddressLength + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( !m_fActive ) + return GetAddressFromPdata( pAddress, pAddressLength ); + + if( m_pEndpoint == NULL ) + return ND_CONNECTION_INVALID; + + ib_qp_state_t state = + m_pParent->m_Ifc.user_verbs.nd_get_qp_state( m_pEndpoint->m_uQp ); + if( state != IB_QPS_RTS ) + return ND_CONNECTION_INVALID; + + switch( m_PeerAddr.v4.sin_family ) + { + case AF_INET: + if( *pAddressLength < sizeof(struct sockaddr_in) ) + { + *pAddressLength = sizeof(struct sockaddr_in); + return ND_BUFFER_OVERFLOW; + } + *(struct sockaddr_in*)pAddress = m_PeerAddr.v4; + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Peer address: IP %#x, port %#hx\n", + cl_hton32(m_PeerAddr.v4.sin_addr.S_un.S_addr), cl_hton16(m_PeerAddr.v4.sin_port) ) ); + break; + + case AF_INET6: + if( *pAddressLength < sizeof(struct sockaddr_in6) ) + { + *pAddressLength = sizeof(struct sockaddr_in6); + return ND_BUFFER_OVERFLOW; + } + *(struct sockaddr_in6*)pAddress = m_PeerAddr.v6; + break; + + default: + return ND_CONNECTION_INVALID; + } + + return S_OK; +} + +HRESULT CConnector::NotifyDisconnect( + __inout OVERLAPPED* pOverlapped + ) +{ + ND_ENTER( ND_DBG_NDI ); + + pOverlapped->Internal = ND_PENDING; + return NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_NOTIFY_DREQ, + &m_cid, + sizeof(m_cid), + NULL, + 0 ); +} + +HRESULT CConnector::Disconnect( + __inout OVERLAPPED* pOverlapped + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( m_pEndpoint == NULL ) + return ND_CONNECTION_INVALID; + + ib_qp_state_t state = + m_pParent->m_Ifc.user_verbs.nd_get_qp_state( m_pEndpoint->m_uQp ); + if( state != IB_QPS_RTS ) + return ND_CONNECTION_INVALID; + + // + // Get the UVP's buffer for modify operations. + // + void* pOutbuf; + DWORD szOutbuf; + + m_pParent->m_Ifc.user_verbs.nd_modify_qp( + m_pEndpoint->m_uQp, + &pOutbuf, + &szOutbuf + ); + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Disconnect QP %#I64x, QPn %#x\n", m_pEndpoint->m_hQp, m_pEndpoint->m_Qpn ) ); + + pOverlapped->Internal = ND_PENDING; + HRESULT hr = NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_DREQ_CM, + &m_cid, + sizeof(m_cid), + pOutbuf, + szOutbuf ); + + if( SUCCEEDED( hr ) ) + { + m_pEndpoint->Release(); + m_pEndpoint = NULL; + } + + return hr; +} + +} // namespace diff --git a/trunk/ulp/nd/user/NdConnector.h b/trunk/ulp/nd/user/NdConnector.h new file mode 100644 index 00000000..6f701a9e --- /dev/null +++ b/trunk/ulp/nd/user/NdConnector.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2008 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:$ + */ + +#pragma once + +#include "ndspi.h" +#include "nddebug.h" +#include +#include +#include +#include "ual_ci_ca.h" + + +namespace NetworkDirect +{ + +class CConnector : + public INDConnector +{ + friend class CListen; + +private: + CConnector(void); + ~CConnector(void); + void FreeCid(void); + +public: + static HRESULT Create( + __in CAdapter* pParent, + __deref_out INDConnector** ppConnector + ); + + // *** IUnknown methods *** + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + + ULONG STDMETHODCALLTYPE Release(void); + + // *** INDOverlapped methods *** + HRESULT STDMETHODCALLTYPE CancelOverlappedRequests(void); + + HRESULT STDMETHODCALLTYPE GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL 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 + ); + +private: + HRESULT GetAddressFromPdata( + __out_bcount_part(*pAddressLength, *pAddressLength) struct sockaddr* pAddress, + __inout SIZE_T* pAddressLength + ); + +protected: + volatile LONG m_nRef; + + CAdapter* m_pParent; + + CEndpoint* m_pEndpoint; + + UINT8 m_Protocol; + USHORT m_LocalPort; + net32_t m_cid; + bool m_fActive; + + union _addr + { + struct sockaddr_in v4; + struct sockaddr_in6 v6; + + } m_PeerAddr; +}; + +} diff --git a/trunk/ulp/nd/user/NdCq.cpp b/trunk/ulp/nd/user/NdCq.cpp new file mode 100644 index 00000000..94c71c3b --- /dev/null +++ b/trunk/ulp/nd/user/NdCq.cpp @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2008 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 "NdCq.h" +#include "NdAdapter.h" +#include "al_cq.h" +#include "al_dev.h" +#include "al.h" +#include "al_verbs.h" +#pragma warning( push, 3 ) +#include "winternl.h" +#pragma warning( pop ) +#include "limits.h" +#include "nddebug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdCq.tmh" +#endif + + +namespace NetworkDirect +{ + + CCq::CCq(void) : + m_nRef( 1 ), + m_pParent( NULL ), + m_hCq( 0 ), + m_uCq( NULL ) + { + } + + CCq::~CCq(void) + { + if( m_hCq ) + CloseCq(); + + if( m_pParent ) + m_pParent->Release(); + } + + HRESULT CCq::Initialize( + CAdapter* pParent, + SIZE_T nEntries ) + { + if( nEntries > UINT_MAX ) + return ND_INVALID_PARAMETER; + + m_pParent = pParent; + pParent->AddRef(); + + return CreateCq( (UINT32)nEntries ); + } + + HRESULT CCq::QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ) + { + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppvObj = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDCompletionQueue ) ) + { + *ppvObj = this; + return S_OK; + } + + return E_NOINTERFACE; + } + + ULONG CCq::AddRef(void) + { + return InterlockedIncrement( &m_nRef ); + } + + ULONG CCq::Release(void) + { + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; + } + + // *** INDOverlapped methods *** + HRESULT CCq::CancelOverlappedRequests(void) + { + ND_ENTER( ND_DBG_NDI ); + + DWORD BytesRet; + DeviceIoControl( + m_pParent->m_hSync, + UAL_NDI_CANCEL_CQ, + &m_hCq, + sizeof(m_hCq), + NULL, + 0, + &BytesRet, + NULL + ); + + return S_OK; + } + + HRESULT CCq::GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ) + { + ND_ENTER( ND_DBG_NDI ); + + *pNumberOfBytesTransferred = 0; + ::GetOverlappedResult( + m_pParent->GetFileHandle(), + pOverlapped, + (DWORD*)pNumberOfBytesTransferred, + bWait ); + ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI, + ("==> %s, result %#x, bytes %d\n", __FUNCTION__, (int)pOverlapped->Internal, (int)*pNumberOfBytesTransferred )); + return (HRESULT)pOverlapped->Internal; + } + + // *** INDCompletionQueue methods *** + HRESULT CCq::Resize( + __in SIZE_T nEntries + ) + { + ND_ENTER( ND_DBG_NDI ); + + if( nEntries > UINT_MAX ) + return ND_INVALID_PARAMETER; + + ib_api_status_t status; + + /* Clear the IOCTL buffer */ + ual_modify_cq_ioctl_t cq_ioctl; + cl_memclr( &cq_ioctl, sizeof(cq_ioctl) ); + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( m_uCq && m_pParent->m_Ifc.user_verbs.pre_resize_cq ) + { + /* Pre call to the UVP library */ + status = m_pParent->m_Ifc.user_verbs.pre_resize_cq( + m_uCq, (uint32_t*)&nEntries, &cq_ioctl.in.umv_buf ); + if( status != IB_SUCCESS ) + goto exit; + } + + cq_ioctl.in.h_cq = m_hCq; + cq_ioctl.in.size = (DWORD)nEntries; + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_MODIFY_CQ, + &cq_ioctl.in, + sizeof(cq_ioctl.in), + &cq_ioctl.out, + sizeof(cq_ioctl.out), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(cq_ioctl.out) ) + status = IB_ERROR; + else + status = cq_ioctl.out.status; + + /* Post uvp call */ + if( m_uCq && m_pParent->m_Ifc.user_verbs.post_resize_cq ) + { + m_pParent->m_Ifc.user_verbs.post_resize_cq( + m_uCq, status, cq_ioctl.out.size, &cq_ioctl.out.umv_buf ); + } + +exit: + switch( status ) + { + case IB_INVALID_CQ_SIZE: + return ND_INVALID_PARAMETER; + + case IB_SUCCESS: + return S_OK; + + case IB_INSUFFICIENT_RESOURCES: + return ND_INSUFFICIENT_RESOURCES; + + default: + return ND_UNSUCCESSFUL; + } + } + + HRESULT CCq::Notify( + __in DWORD Type, + __inout OVERLAPPED* pOverlapped + ) + { +// ND_ENTER( ND_DBG_NDI ); + + ual_ndi_notify_cq_ioctl_in_t ioctl; + ioctl.h_cq = m_hCq; + ioctl.notify_comps = (boolean_t)Type; + pOverlapped->Internal = ND_PENDING; + HRESULT hr = NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_NOTIFY_CQ, + &ioctl, + sizeof(ioctl), + NULL, + 0 ); + + if( hr == ND_PENDING && Type != ND_CQ_NOTIFY_ERRORS ) + { + m_pParent->m_Ifc.user_verbs.rearm_cq( + m_uCq, + (Type == ND_CQ_NOTIFY_SOLICITED) ? TRUE : FALSE + ); + ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI, + ("==> %s, rearming with Type %d\n", __FUNCTION__, Type)); + } + else + { + ND_PRINT( TRACE_LEVEL_ERROR, ND_DBG_NDI, + ("==> %s failed: hr %#x, notify_type %d \n", __FUNCTION__, hr, Type )); + } + return hr; + } + + SIZE_T CCq::GetResults( + __out_ecount(nResults) ND_RESULT* pResults[], + __in SIZE_T nResults + ) + { +#if DBG + if (!(++g.c_cnt % 100000000)) // || !(rcv_pkts % 1000) || !(snd_pkts % 1000) + ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI, + ("==> %s, cnt %I64d, rcv: %I64d:%I64d:%I64d, snd %I64d:%I64d:%I64d\n", + __FUNCTION__, g.c_cnt, + g.c_rcv_pkts, g.c_rcv_bytes, g.c_rcv_pkts_err, + g.c_snd_pkts, g.c_snd_bytes, g.c_snd_pkts_err)); +#endif + SIZE_T i = 0; + + while( nResults-- ) + { + ib_wc_t wc; + ib_wc_t* pWc = &wc; + ib_wc_t* pDoneWc; + wc.p_next = NULL; + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.poll_cq( m_uCq, &pWc, &pDoneWc ); + + if( status != IB_SUCCESS ) + break; + + pResults[i] = (ND_RESULT*)wc.wr_id; + if( wc.wc_type == IB_WC_RECV ) + pResults[i]->BytesTransferred = wc.length; + + if( wc.recv.conn.recv_opt & IB_RECV_OPT_IMMEDIATE ) + { + // Emulated receive with invalidate - the immediate + // data holds the RKey that is supposed to be invalidated. + + //TODO: We need the QP handle (or context) so we can force an + // error if we don't find a matching MW for the given RKEY. + // We also need to change the receive status in this case to + // ND_INVALIDATION_ERROR; + } + + switch( wc.status ) + { + case IB_WCS_SUCCESS: + pResults[i]->Status = ND_SUCCESS; + break; + case IB_WCS_LOCAL_LEN_ERR: + pResults[i]->Status = ND_LOCAL_LENGTH; + break; + case IB_WCS_LOCAL_OP_ERR: + case IB_WCS_LOCAL_ACCESS_ERR: + case IB_WCS_GENERAL_ERR: + default: + pResults[i]->Status = ND_INTERNAL_ERROR; + break; + case IB_WCS_LOCAL_PROTECTION_ERR: + case IB_WCS_MEM_WINDOW_BIND_ERR: + pResults[i]->Status = ND_ACCESS_VIOLATION; + break; + case IB_WCS_WR_FLUSHED_ERR: + pResults[i]->Status = ND_CANCELED; + break; + case IB_WCS_REM_INVALID_REQ_ERR: + pResults[i]->Status = ND_BUFFER_OVERFLOW; + break; + case IB_WCS_REM_ACCESS_ERR: + case IB_WCS_REM_OP_ERR: + case IB_WCS_BAD_RESP_ERR: + pResults[i]->Status = ND_REMOTE_ERROR; + break; + case IB_WCS_RNR_RETRY_ERR: + case IB_WCS_TIMEOUT_RETRY_ERR: + pResults[i]->Status = ND_TIMEOUT; + break; + } + i++; + // leo +#if DBG + { + if (wc.wc_type == IB_WC_RECV) + { + if (!wc.status) + { + ++g.c_rcv_pkts; + g.c_rcv_bytes += wc.length; + } + else + ++g.c_rcv_pkts_err; + } + else + { + if (!wc.status) + { + ++g.c_snd_pkts; + g.c_snd_bytes += wc.length; + } + else + ++g.c_snd_pkts_err; + } + } +#endif + continue; + } + return i; + } + + HRESULT CCq::CreateCq( + __in UINT32 nEntries ) + { + ND_ENTER( ND_DBG_NDI ); + + /* Clear the IOCTL buffer */ + ual_create_cq_ioctl_t cq_ioctl; + cl_memclr( &cq_ioctl, sizeof(cq_ioctl) ); + + /* Pre call to the UVP library */ + ib_api_status_t status; + if( m_pParent->m_uCa && m_pParent->m_Ifc.user_verbs.pre_create_cq ) + { + status = m_pParent->m_Ifc.user_verbs.pre_create_cq( + m_pParent->m_uCa, + &nEntries, + &cq_ioctl.in.umv_buf, + (ib_cq_handle_t*)(ULONG_PTR)&m_uCq + ); + if( status != IB_SUCCESS ) + goto done; + } + + cq_ioctl.in.h_ca = m_pParent->m_hCa; + cq_ioctl.in.size = nEntries; + cq_ioctl.in.h_wait_obj = NULL; + cq_ioctl.in.context = (ULONG_PTR)this; + cq_ioctl.in.ev_notify = FALSE; + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_NDI_CREATE_CQ, + &cq_ioctl.in, + sizeof(cq_ioctl.in), + &cq_ioctl.out, + sizeof(cq_ioctl.out), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(cq_ioctl.out) ) + status = IB_ERROR; + else + status = cq_ioctl.out.status; + + m_hCq = cq_ioctl.out.h_cq; + + /* Post uvp call */ + if( m_pParent->m_uCa && m_pParent->m_Ifc.user_verbs.post_create_cq ) + { + m_pParent->m_Ifc.user_verbs.post_create_cq( + m_pParent->m_uCa, + status, + cq_ioctl.out.size, + (ib_cq_handle_t*)(ULONG_PTR)&m_uCq, + &cq_ioctl.out.umv_buf ); + } + +done: + switch( status ) + { + case IB_INVALID_CQ_SIZE: + return ND_INVALID_PARAMETER; + + case IB_INSUFFICIENT_RESOURCES: + return ND_INSUFFICIENT_RESOURCES; + + case IB_INSUFFICIENT_MEMORY: + return ND_NO_MEMORY; + + case IB_SUCCESS: + return S_OK; + + default: + return ND_UNSUCCESSFUL; + } + } + + void CCq::CloseCq(void) + { + ND_ENTER( ND_DBG_NDI ); + + ib_api_status_t status; + + if( m_uCq && m_pParent->m_Ifc.user_verbs.pre_destroy_cq ) + { + /* Pre call to the UVP library */ + status = m_pParent->m_Ifc.user_verbs.pre_destroy_cq( m_uCq ); + if( status != IB_SUCCESS ) + return; + } + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_DESTROY_CQ, + &m_hCq, + sizeof(m_hCq), + &status, + sizeof(status), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(status) ) + status = IB_ERROR; + + if( m_uCq && m_pParent->m_Ifc.user_verbs.post_destroy_cq ) + m_pParent->m_Ifc.user_verbs.post_destroy_cq( m_uCq, status ); + } + +} // namespace diff --git a/trunk/ulp/nd/user/NdCq.h b/trunk/ulp/nd/user/NdCq.h new file mode 100644 index 00000000..f4bdb79a --- /dev/null +++ b/trunk/ulp/nd/user/NdCq.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2008 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:$ + */ + +#pragma once +#include "ndspi.h" +#include +#include "al_cq.h" + + +namespace NetworkDirect +{ + class CAdapter; + + class CCq : + public INDCompletionQueue + { + friend class CEndpoint; + public: + CCq(void); + ~CCq(void); + + HRESULT Initialize( + CAdapter* pParent, + SIZE_T nEntries ); + + // *** IUnknown methods *** + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + + ULONG STDMETHODCALLTYPE Release(void); + + // *** INDOverlapped methods *** + HRESULT STDMETHODCALLTYPE CancelOverlappedRequests(void); + + HRESULT STDMETHODCALLTYPE GetOverlappedResult( + __inout_opt OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ); + + // *** INDCompletionQueue methods *** + HANDLE STDMETHODCALLTYPE GetAdapterFileHandle(void); + + HRESULT STDMETHODCALLTYPE Close(void); + + HRESULT STDMETHODCALLTYPE Resize( + __in SIZE_T nEntries + ); + + HRESULT STDMETHODCALLTYPE Notify( + __in DWORD Type, + __inout_opt OVERLAPPED* pOverlapped + ); + + SIZE_T STDMETHODCALLTYPE GetResults( + __out_ecount(nResults) ND_RESULT* pResults[], + __in SIZE_T nResults + ); + + private: + HRESULT CreateCq( + __in UINT32 nEntries ); + + HRESULT Complete( + __in HRESULT Status ); + + HRESULT ModifyCq( + __in SIZE_T nEntries ); + + void CloseCq(void); + + private: + volatile LONG m_nRef; + + CAdapter* m_pParent; + + UINT64 m_hCq; + ib_cq_handle_t m_uCq; + }; + +} // namespace diff --git a/trunk/ulp/nd/user/NdEndpoint.cpp b/trunk/ulp/nd/user/NdEndpoint.cpp new file mode 100644 index 00000000..3325477a --- /dev/null +++ b/trunk/ulp/nd/user/NdEndpoint.cpp @@ -0,0 +1,944 @@ +/* + * Copyright (c) 2008 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 "NdEndpoint.h" +#include "NdCq.h" +#include "NdAdapter.h" +#include "NdMr.h" +#include "NdListen.h" +#include "limits.h" +#include "al_dev.h" +#pragma warning( push, 3 ) +#include "winternl.h" +#pragma warning( pop ) +#include "nddebug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdEndpoint.tmh" +#endif + +#if DBG +dbg_data g = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; +#endif + +#ifndef SIZE_MAX +#ifdef _WIN64 +#define SIZE_MAX _UI64_MAX +#else +#define SIZE_MAX UINT_MAX +#endif +#endif + +namespace NetworkDirect +{ + +/////////////////////////////////////////////////////////////////////////////// +// +// HPC Pack 2008 Beta 2 SPI +// +/////////////////////////////////////////////////////////////////////////////// + + +CEndpoint::CEndpoint(void) : + m_nRef( 1 ), + m_pParent( NULL ), + m_hQp( 0 ) +{ +} + +CEndpoint::~CEndpoint(void) +{ + if( m_hQp ) + DestroyQp(); + + if( m_pParent ) + m_pParent->Release(); +} + +HRESULT CEndpoint::Initialize( + __in CAdapter* pParent, + __in CCq* pInboundCq, + __in CCq* 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 + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( InboundReadLimit > UCHAR_MAX ) + return ND_INVALID_PARAMETER_8; + + if( OutboundReadLimit > UCHAR_MAX ) + return ND_INVALID_PARAMETER_9; + + m_pParent = pParent; + m_pParent->AddRef(); + + CL_ASSERT( + m_pParent->m_Ifc.user_verbs.pre_create_qp != NULL || + m_pParent->m_Ifc.user_verbs.post_create_qp != NULL || + m_pParent->m_Ifc.user_verbs.nd_modify_qp != NULL || + m_pParent->m_Ifc.user_verbs.nd_get_qp_state != NULL || + m_pParent->m_Ifc.user_verbs.pre_destroy_qp != NULL || + m_pParent->m_Ifc.user_verbs.post_destroy_qp != NULL || + m_pParent->m_Ifc.user_verbs.post_send != NULL || + m_pParent->m_Ifc.user_verbs.post_recv != NULL /*|| + m_pParent->m_Ifc.user_verbs.bind_mw != NULL*/ ); + + HRESULT hr = CreateQp( + pInboundCq, + pOutboundCq, + nInboundEntries, + nOutboundEntries, + nInboundSge, + nOutboundSge, + InboundReadLimit, + OutboundReadLimit ); + + if( FAILED( hr ) ) + return hr; + + m_Ird = (UINT8)InboundReadLimit; + m_Ord = (UINT8)OutboundReadLimit; + + // Move the QP to the INIT state so users can post receives. + hr = ModifyQp( IB_QPS_INIT ); + if( FAILED( hr ) ) + DestroyQp(); + + if( SUCCEEDED( hr ) && pMaxInlineData != NULL ) + { + // Worst case. + *pMaxInlineData = nOutboundSge * 12; + } + + return hr; +} + +HRESULT CEndpoint::Create( + __in CAdapter* pParent, + __in CCq* pInboundCq, + __in CCq* 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, + __out INDEndpoint** ppEndpoint + ) +{ + CEndpoint* pEp = new CEndpoint(); + if( pEp == NULL ) + return ND_NO_MEMORY; + + HRESULT hr = pEp->Initialize( + pParent, + pInboundCq, + pOutboundCq, + nInboundEntries, + nOutboundEntries, + nInboundSge, + nOutboundSge, + InboundReadLimit, + OutboundReadLimit, + pMaxInlineData + ); + + if( FAILED( hr ) ) + { + pEp->Release(); + return hr; + } + + *ppEndpoint = pEp; + return ND_SUCCESS; +} + +HRESULT CEndpoint::QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ) +{ + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppvObj = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDEndpoint ) ) + { + *ppvObj = this; + return S_OK; + } + + return E_NOINTERFACE; +} + +ULONG CEndpoint::AddRef(void) +{ + return InterlockedIncrement( &m_nRef ); +} + +ULONG CEndpoint::Release(void) +{ + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; +} + +// *** INDEndpoint methods *** +HRESULT CEndpoint::Flush(void) +{ + return ModifyQp( IB_QPS_ERROR ); +} + +void CEndpoint::StartRequestBatch(void) +{ + return; +} + +void CEndpoint::SubmitRequestBatch(void) +{ + return; +} + +HRESULT CEndpoint::Send( + __out ND_RESULT* pResult, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge, + __in DWORD Flags + ) +{ + ib_send_wr_t wr; + ib_local_ds_t* pDs; + ib_local_ds_t ds[4]; + + if( nSge > UINT_MAX ) + return ND_DATA_OVERRUN; + else if( nSge <= 4 ) + pDs = ds; + else + { + pDs = new ib_local_ds_t[nSge]; + if( !pDs ) + return ND_NO_MEMORY; + } + + pResult->BytesTransferred = 0; + for( SIZE_T i = 0; i < nSge; i++ ) + { + pDs[i].vaddr = (ULONG_PTR)pSgl[i].pAddr; + if( pSgl[i].Length > UINT_MAX ) + { + if( nSge > 4 ) + delete[] pDs; + return ND_BUFFER_OVERFLOW; + } + pDs[i].length = (uint32_t)pSgl[i].Length; + pDs[i].lkey = ((CMr*)pSgl[i].hMr)->mr_ioctl.out.lkey; + + // 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; + } + + wr.p_next = NULL; + wr.wr_id = (ULONG_PTR)pResult; + wr.wr_type = WR_SEND; + wr.send_opt = 0; + if( !(Flags & ND_OP_FLAG_SILENT_SUCCESS) ) + wr.send_opt |= IB_SEND_OPT_SIGNALED; + if( Flags & ND_OP_FLAG_READ_FENCE ) + wr.send_opt |= IB_SEND_OPT_FENCE; + if( Flags & ND_OP_FLAG_SEND_AND_SOLICIT_EVENT ) + wr.send_opt |= IB_SEND_OPT_SOLICITED; + wr.num_ds = (uint32_t)nSge; + wr.ds_array = pDs; + + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL ); + if( nSge > 4 ) + delete[] pDs; + + // leo + CL_ASSERT( nSge || pSgl == NULL ); +#if DBG + if (!status ) + { + if (pSgl) + { + ++g.snd_pkts; + g.snd_bytes += pSgl[0].Length; + } + else + ++g.snd_pkts_zero; + } + else + ++g.snd_pkts_err; +#endif + + switch( status ) + { + 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 CEndpoint::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 + ) +{ + ND_ENTER( ND_DBG_NDI ); + + ib_send_wr_t wr; + ib_local_ds_t* pDs; + + if( nSge > UINT_MAX ) + return ND_DATA_OVERRUN; + + pDs = new ib_local_ds_t[nSge]; + if( !pDs ) + return ND_NO_MEMORY; + + pResult->BytesTransferred = 0; + for( SIZE_T i = 0; i < nSge; i++ ) + { + pDs[i].vaddr = (ULONG_PTR)pSgl[i].pAddr; + if( pSgl[i].Length > UINT_MAX ) + { + delete[] pDs; + return ND_BUFFER_OVERFLOW; + } + pDs[i].length = (uint32_t)pSgl[i].Length; + pDs[i].lkey = ((CMr*)pSgl[i].hMr)->mr_ioctl.out.lkey; + + // 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; + } + + wr.p_next = NULL; + wr.wr_id = (ULONG_PTR)pResult; + wr.wr_type = WR_SEND; + // We simulate invalidate operations (since we simulate MW use). We + // put the RKey in the immediate data, the recipient will do the + // lookup of the MW based on that (as they would with a regular + // invalidate request). + wr.send_opt = IB_SEND_OPT_IMMEDIATE; + if( !(Flags & ND_OP_FLAG_SILENT_SUCCESS) ) + wr.send_opt |= IB_SEND_OPT_SIGNALED; + if( Flags & ND_OP_FLAG_READ_FENCE ) + wr.send_opt |= IB_SEND_OPT_FENCE; + if( Flags & ND_OP_FLAG_SEND_AND_SOLICIT_EVENT ) + wr.send_opt |= IB_SEND_OPT_SOLICITED; + wr.num_ds = (uint32_t)nSge; + wr.ds_array = pDs; + // Put the RKey in the immeditate data. + wr.immediate_data = pRemoteMwDescriptor->Token; + + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL ); + delete[] pDs; + + switch( status ) + { + 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 CEndpoint::Receive( + __out ND_RESULT* pResult, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge + ) +{ +#if DBG + if (!(++g.rcv_cnt % 1000)) + ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI, + ("==> %s, cnt %I64d, rcv %I64d:%I64d:%I64d:%I64d\n", + __FUNCTION__, g.rcv_cnt, g.rcv_pkts, g.rcv_bytes, g.rcv_pkts_err, g.rcv_pkts_zero )); +#endif + ib_recv_wr_t wr; + ib_local_ds_t* pDs; + ib_local_ds_t ds[4]; + + if( nSge > UINT_MAX ) + return ND_DATA_OVERRUN; + else if( nSge <= 4 ) + pDs = ds; + else + { + pDs = new ib_local_ds_t[nSge]; + if( !pDs ) + return ND_NO_MEMORY; + } + + for( SIZE_T i = 0; i < nSge; i++ ) + { + pDs[i].vaddr = (ULONG_PTR)pSgl[i].pAddr; + if( pSgl[i].Length > UINT_MAX ) + { + if( nSge > 4 ) + delete[] pDs; + return ND_BUFFER_OVERFLOW; + } + pDs[i].length = (uint32_t)pSgl[i].Length; + pDs[i].lkey = ((CMr*)pSgl[i].hMr)->mr_ioctl.out.lkey; + } + + wr.p_next = NULL; + wr.wr_id = (ULONG_PTR)pResult; + wr.num_ds = (uint32_t)nSge; + wr.ds_array = pDs; + + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.post_recv( m_uQp, &wr, NULL ); + + if( nSge > 4 ) + delete[] pDs; + + // leo + CL_ASSERT( nSge || pSgl == NULL ); +#if DBG + if (!status) + { + if (pSgl) + { + ++g.rcv_pkts; + g.rcv_bytes += pSgl[0].Length; + } + else + ++g.rcv_pkts_zero; + } + else + ++g.rcv_pkts_err; +#endif + + switch( status ) + { + 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 CEndpoint::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 + ) +{ + ND_ENTER( ND_DBG_NDI ); + + UNREFERENCED_PARAMETER( pMw ); + UNREFERENCED_PARAMETER( Flags ); + + CMr* pMr = ((CMr*)hMr); + + if( pBuffer < pMr->pBase || + pBuffer > pMr->pBase + pMr->Length ) + { + return ND_INVALID_PARAMETER_4; + } + + if( ((const char*)pBuffer + BufferSize) > (pMr->pBase + pMr->Length) ) + { + return ND_INVALID_PARAMETER_5; + } + + // Ok, this here is a workaround since the Mellanox HCA driver doesn't + // support MWs. This should be pushed into the HCA driver. + pMwDescriptor->Base = _byteswap_uint64( (UINT64)(ULONG_PTR)pBuffer ); + pMwDescriptor->Length = _byteswap_uint64( BufferSize ); + pMwDescriptor->Token = pMr->mr_ioctl.out.rkey; + + // Zero-byte RDMA write. Could also be a no-op on the send queue + // which would be better, but requires changing the HCA driver. + ib_send_wr_t wr; + wr.p_next = NULL; + wr.wr_id = (ULONG_PTR)pResult; + wr.wr_type = WR_RDMA_WRITE; + wr.send_opt = IB_SEND_OPT_SIGNALED; + wr.num_ds = 0; + wr.ds_array = NULL; + + wr.remote_ops.vaddr = 0; + wr.remote_ops.rkey = 0; + + pResult->BytesTransferred = 0; + + // TODO: Track the MW by rkey, so we can unbind it. + + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL ); + + switch( status ) + { + case IB_SUCCESS: + return S_OK; + case IB_INSUFFICIENT_RESOURCES: + return ND_NO_MORE_ENTRIES; + case IB_INVALID_QP_STATE: + return ND_CONNECTION_INVALID; + default: + return ND_UNSUCCESSFUL; + } +} + +HRESULT CEndpoint::Invalidate( + __out ND_RESULT* pResult, + __in INDMemoryWindow* pMw, + __in DWORD Flags + ) +{ + ND_ENTER( ND_DBG_NDI ); + + UNREFERENCED_PARAMETER( pMw ); + UNREFERENCED_PARAMETER( Flags ); + + // Zero-byte RDMA write. Could also be a no-op on the send queue + // which would be better, but requires changing the HCA driver. + ib_send_wr_t wr; + wr.p_next = NULL; + wr.wr_id = (ULONG_PTR)pResult; + wr.wr_type = WR_RDMA_WRITE; + wr.send_opt = IB_SEND_OPT_SIGNALED; + wr.num_ds = 0; + wr.ds_array = NULL; + + wr.remote_ops.vaddr = 0; + wr.remote_ops.rkey = 0; + + pResult->BytesTransferred = 0; + + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL ); + + switch( status ) + { + case IB_SUCCESS: + // TODO: Stop trackign MW + return S_OK; + case IB_INSUFFICIENT_RESOURCES: + return ND_NO_MORE_ENTRIES; + case IB_INVALID_QP_STATE: + return ND_CONNECTION_INVALID; + default: + return ND_UNSUCCESSFUL; + } +} + +HRESULT CEndpoint::Rdma( + __out ND_RESULT* pResult, + __in ib_wr_type_t Type, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge, + __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, + __in ULONGLONG Offset, + __in DWORD Flags + ) +{ +// ND_ENTER( ND_DBG_NDI ); + + ib_send_wr_t wr; + ib_local_ds_t* pDs; + ib_local_ds_t ds[4]; + + if( nSge > UINT_MAX ) + return ND_DATA_OVERRUN; + else if( nSge <= 4 ) + pDs = ds; + else + { + pDs = new ib_local_ds_t[nSge]; + if( !pDs ) + return ND_NO_MEMORY; + } + + pResult->BytesTransferred = 0; + for( SIZE_T i = 0; i < nSge; i++ ) + { + pDs[i].vaddr = (ULONG_PTR)pSgl[i].pAddr; + if( pSgl[i].Length > UINT_MAX ) + { + if( nSge > 4 ) + delete[] pDs; + return ND_BUFFER_OVERFLOW; + } + pDs[i].length = (uint32_t)pSgl[i].Length; + pDs[i].lkey = ((CMr*)pSgl[i].hMr)->mr_ioctl.out.lkey; + + //TODO: temporary - a workaround of test bug + //leo + if( (int)pSgl[i].Length < 0 ) + { + pDs[i].length = 0 - (int)pSgl[i].Length; +#if DBG + ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI, + ("nSge %d, i %d, Length %#x\n", nSge, i, pSgl[i].Length )); + if( nSge > 4 ) + delete[] pDs; + return ND_BUFFER_OVERFLOW; +#endif + } + + // 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; + } + + wr.p_next = NULL; + wr.wr_id = (ULONG_PTR)pResult; + wr.wr_type = Type; + wr.send_opt = 0; + if( !(Flags & ND_OP_FLAG_SILENT_SUCCESS) ) + wr.send_opt |= IB_SEND_OPT_SIGNALED; + if( Flags & ND_OP_FLAG_READ_FENCE ) + wr.send_opt |= IB_SEND_OPT_FENCE; + wr.num_ds = (uint32_t)nSge; + wr.ds_array = pDs; + + UINT64 vaddr = _byteswap_uint64( pRemoteMwDescriptor->Base ); + vaddr += Offset; + wr.remote_ops.vaddr = vaddr; + wr.remote_ops.rkey = pRemoteMwDescriptor->Token; + + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL ); + + if( nSge > 4 ) + delete[] pDs; + + switch( status ) + { + 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 CEndpoint::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 + ) +{ +// ND_ENTER( ND_DBG_NDI ); + + return Rdma( pResult, WR_RDMA_READ, pSgl, nSge, + pRemoteMwDescriptor, Offset, Flags ); +} + +HRESULT CEndpoint::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 + ) +{ +// ND_ENTER( ND_DBG_NDI ); + + return Rdma( pResult, WR_RDMA_WRITE, pSgl, nSge, + pRemoteMwDescriptor, Offset, Flags ); +} + +HRESULT CEndpoint::CreateQp( + __in CCq* pInboundCq, + __in CCq* 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 + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( nInboundEntries > UINT_MAX ) + return ND_INVALID_PARAMETER_4; + if( nOutboundEntries > UINT_MAX ) + return ND_INVALID_PARAMETER_5; + if( nInboundSge > UINT_MAX ) + return ND_INVALID_PARAMETER_6; + if( nOutboundSge > UINT_MAX ) + return ND_INVALID_PARAMETER_7; + if( InboundReadLimit > UCHAR_MAX ) + return ND_INVALID_PARAMETER_9; + if( OutboundReadLimit > UCHAR_MAX ) + return ND_INVALID_PARAMETER_10; + + /* Setup the qp_ioctl */ + ual_create_qp_ioctl_t qp_ioctl; + cl_memclr( &qp_ioctl, sizeof(qp_ioctl) ); + + qp_ioctl.in.qp_create.qp_type = IB_QPT_RELIABLE_CONN; + qp_ioctl.in.qp_create.sq_depth = (uint32_t)nOutboundEntries; + qp_ioctl.in.qp_create.rq_depth = (uint32_t)nInboundEntries; + qp_ioctl.in.qp_create.sq_sge = (uint32_t)nOutboundSge; + qp_ioctl.in.qp_create.rq_sge = (uint32_t)nInboundSge; + qp_ioctl.in.qp_create.h_srq = NULL; + qp_ioctl.in.qp_create.sq_signaled = FALSE; + + /* Pre call to the UVP library */ + CL_ASSERT( m_pParent->m_Ifc.user_verbs.pre_create_qp ); + qp_ioctl.in.qp_create.h_sq_cq = pOutboundCq->m_uCq; + qp_ioctl.in.qp_create.h_rq_cq = pInboundCq->m_uCq; + ib_api_status_t status = m_pParent->m_Ifc.user_verbs.pre_create_qp( + m_pParent->m_uPd, + &qp_ioctl.in.qp_create, + &qp_ioctl.in.umv_buf, + (ib_qp_handle_t*)(ULONG_PTR)&m_uQp + ); + if( status != IB_SUCCESS ) + return ND_INSUFFICIENT_RESOURCES; + + /* + * Convert the handles to KAL handles once again starting + * from the input qp attribute + */ + qp_ioctl.in.h_pd = m_pParent->m_hPd; + qp_ioctl.in.qp_create.h_sq_cq = (ib_cq_handle_t)pOutboundCq->m_hCq; + qp_ioctl.in.qp_create.h_rq_cq = (ib_cq_handle_t)pInboundCq->m_hCq; + qp_ioctl.in.context = (ULONG_PTR)this; + qp_ioctl.in.ev_notify = FALSE; + + DWORD bytes_ret; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_CREATE_QP, + &qp_ioctl.in, + sizeof(qp_ioctl.in), + &qp_ioctl.out, + sizeof(qp_ioctl.out), + &bytes_ret, + NULL ); + + if( fSuccess != TRUE || bytes_ret != sizeof(qp_ioctl.out) ) + qp_ioctl.out.status = IB_ERROR; + + /* Post uvp call */ + CL_ASSERT( m_pParent->m_Ifc.user_verbs.post_create_qp ); + m_pParent->m_Ifc.user_verbs.post_create_qp( + m_pParent->m_uPd, + qp_ioctl.out.status, + (ib_qp_handle_t*)(ULONG_PTR)&m_uQp, + &qp_ioctl.out.umv_buf + ); + + + switch( qp_ioctl.out.status ) + { + case IB_SUCCESS: + m_hQp = qp_ioctl.out.h_qp; + m_Qpn = qp_ioctl.out.attr.num; + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Created QP %#I64x, QPn %#x, pd %#I64x, context %p \n", + m_hQp, m_Qpn, m_pParent->m_hPd, this ) ); + return S_OK; + + case IB_INVALID_MAX_WRS: + if( nInboundEntries > nOutboundEntries ) + return ND_INVALID_PARAMETER_4; + else + return ND_INVALID_PARAMETER_5; + + case IB_INVALID_MAX_SGE: + if( nInboundSge > nOutboundSge ) + return ND_INVALID_PARAMETER_6; + else + return ND_INVALID_PARAMETER_7; + + case IB_INSUFFICIENT_MEMORY: + return ND_NO_MEMORY; + + default: + return ND_INSUFFICIENT_RESOURCES; + } +} + +void CEndpoint::DestroyQp() +{ + ND_ENTER( ND_DBG_NDI ); + + /* Call the uvp pre call if the vendor library provided a valid QP handle */ + CL_ASSERT( m_pParent->m_Ifc.user_verbs.pre_destroy_qp ); + m_pParent->m_Ifc.user_verbs.pre_destroy_qp( m_uQp ); + + ual_destroy_qp_ioctl_t qp_ioctl; + cl_memclr( &qp_ioctl, sizeof(qp_ioctl) ); + qp_ioctl.in.h_qp = m_hQp; + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Destroy QP %I64x\n", m_hQp) ); + + DWORD bytes_ret; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_DESTROY_QP, + &qp_ioctl.in, + sizeof(qp_ioctl.in), + &qp_ioctl.out, + sizeof(qp_ioctl.out), + &bytes_ret, + NULL + ); + + if( fSuccess != TRUE || bytes_ret != sizeof(qp_ioctl.out) ) + qp_ioctl.out.status = IB_ERROR; + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Destroyed QP %#I64x, QPn %#x, pd %#I64x, context %p \n", + m_hQp, m_Qpn, m_pParent->m_hPd, this ) ); + + /* Call vendor's post_destroy_qp */ + CL_ASSERT( m_pParent->m_Ifc.user_verbs.post_destroy_qp ); + m_pParent->m_Ifc.user_verbs.post_destroy_qp( + m_uQp, + qp_ioctl.out.status + ); + m_hQp = NULL; +} + +HRESULT CEndpoint::ModifyQp( + __in ib_qp_state_t NewState ) +{ + ND_ENTER( ND_DBG_NDI ); + + /* Setup the qp_ioctl */ + ual_ndi_modify_qp_ioctl_in_t qp_ioctl; + cl_memclr( &qp_ioctl, sizeof(qp_ioctl) ); + + switch( NewState ) + { + case IB_QPS_INIT: + qp_ioctl.qp_mod.state.init.primary_port = m_pParent->m_PortNum; + qp_ioctl.qp_mod.state.init.qkey = 0; + qp_ioctl.qp_mod.state.init.pkey_index = 0; + qp_ioctl.qp_mod.state.init.access_ctrl = + IB_AC_LOCAL_WRITE | IB_AC_RDMA_READ | IB_AC_RDMA_WRITE; + + // Fall through. + case IB_QPS_RESET: + case IB_QPS_ERROR: + qp_ioctl.qp_mod.req_state = NewState; + } + + /* Call the uvp ND modify verb */ + CL_ASSERT( m_pParent->m_Ifc.user_verbs.nd_modify_qp ); + void* pOutbuf; + DWORD szOutbuf; + + m_pParent->m_Ifc.user_verbs.nd_modify_qp( + m_uQp, + &pOutbuf, + &szOutbuf + ); + + qp_ioctl.h_qp = m_hQp; + + DWORD bytes_ret; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_NDI_MODIFY_QP, + &qp_ioctl, + sizeof(qp_ioctl), + pOutbuf, + szOutbuf, + &bytes_ret, + NULL ); + + if( fSuccess != TRUE ) + return ND_UNSUCCESSFUL; + + return S_OK; +} + +} // namespace diff --git a/trunk/ulp/nd/user/NdEndpoint.h b/trunk/ulp/nd/user/NdEndpoint.h new file mode 100644 index 00000000..f47a6c34 --- /dev/null +++ b/trunk/ulp/nd/user/NdEndpoint.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2008 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:$ + */ + +#pragma once +#include "ndspi.h" +#include +#include + + +namespace NetworkDirect +{ + + +/////////////////////////////////////////////////////////////////////////////// +// +// HPC Pack 2008 Beta 2 SPI +// +/////////////////////////////////////////////////////////////////////////////// + +class CAdapter; +class CCq; + +class CEndpoint : + public INDEndpoint +{ + friend class CConnector; + +private: + CEndpoint(void); + ~CEndpoint(void); + + HRESULT Initialize( + __in CAdapter* pParent, + __in CCq* pInboundCq, + __in CCq* 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 + ); + +public: + static HRESULT Create( + __in CAdapter* pParent, + __in CCq* pInboundCq, + __in CCq* 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, + __out INDEndpoint** ppEndpoint + ); + + // *** IUnknown methods *** + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + + ULONG STDMETHODCALLTYPE Release(void); + + // *** 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 Rdma( + __out ND_RESULT* pResult, + __in ib_wr_type_t Type, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge, + __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, + __in ULONGLONG Offset, + __in DWORD Flags + ); + + HRESULT CreateQp( + __in CCq* pInboundCq, + __in CCq* 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 + ); + + void DestroyQp(); + + HRESULT ModifyQp( + __in ib_qp_state_t NewState + ); + +protected: + volatile LONG m_nRef; + + CAdapter* m_pParent; + + uint64_t m_hQp; + ib_qp_handle_t m_uQp; + + net32_t m_Qpn; + + UINT8 m_Ird; + UINT8 m_Ord; +}; + +} // namespace diff --git a/trunk/ulp/nd/user/NdListen.cpp b/trunk/ulp/nd/user/NdListen.cpp new file mode 100644 index 00000000..82f01110 --- /dev/null +++ b/trunk/ulp/nd/user/NdListen.cpp @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2008 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 "NdListen.h" +#include "NdAdapter.h" +#include "NdEndpoint.h" +#include "NdConnector.h" +#include "al_dev.h" +#pragma warning( push, 3 ) +#include "winternl.h" +#pragma warning( pop ) +#include +#include +#include "nddebug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdListen.tmh" +#endif + +namespace NetworkDirect +{ + +HRESULT GetPdataForPassive( + __in UINT8* pSrc, + __in SIZE_T SrcLength, + __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData, + __inout SIZE_T* pPrivateDataLength + ) +{ + if( SrcLength != IB_REQ_PDATA_SIZE ) + { + ND_PRINT( TRACE_LEVEL_ERROR, ND_DBG_NDI, + ("Connection aborted: incorrect pdata_len %d \n", (int)SrcLength )); + return ND_CONNECTION_ABORTED; + } + + if( pPrivateDataLength == NULL ) + return S_OK; + + ib_cm_rdma_req_t* pIpData = (ib_cm_rdma_req_t*)pSrc; + CL_ASSERT( pIpData->maj_min_ver == 0 ); + CL_ASSERT( pIpData->ipv == 0x40 || pIpData->ipv == 0x60 ); + + if( *pPrivateDataLength == 0 ) + { + *pPrivateDataLength = sizeof(pIpData->pdata); + return ND_BUFFER_OVERFLOW; + } + + CopyMemory( + pPrivateData, + pIpData->pdata, + min( *pPrivateDataLength, sizeof(pIpData->pdata) ) + ); + + HRESULT hr; + if( *pPrivateDataLength < sizeof(pIpData->pdata) ) + { + hr = ND_BUFFER_OVERFLOW; + } + else + { + hr = S_OK; + } + + *pPrivateDataLength = sizeof(pIpData->pdata); + return hr; +} + +HRESULT GetPdataForActive( + __in UINT8* pSrc, + __in SIZE_T SrcLength, + __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData, + __inout SIZE_T* pPrivateDataLength + ) +{ + if( pPrivateDataLength == NULL ) + return S_OK; + + if( *pPrivateDataLength == 0 ) + { + *pPrivateDataLength = SrcLength; + return ND_BUFFER_OVERFLOW; + } + + CopyMemory( + pPrivateData, + pSrc, + min( *pPrivateDataLength, SrcLength ) ); + + HRESULT hr; + if( *pPrivateDataLength < IB_REJ_PDATA_SIZE ) + { + hr = ND_BUFFER_OVERFLOW; + } + else + { + hr = S_OK; + } + + *pPrivateDataLength = SrcLength; + return hr; +} + + CListen::CListen(void) : + m_nRef( 1 ), + m_pParent( NULL ), + m_cid( 0 ) + { + } + + CListen::~CListen(void) + { + if( m_cid != 0 ) + { + DWORD bytes_ret; + DeviceIoControl( + m_pParent->m_hSync, + UAL_DESTROY_CEP, + &m_cid, + sizeof(m_cid), + NULL, + 0, + &bytes_ret, + NULL ); + } + + if( m_pParent ) + m_pParent->Release(); + } + + HRESULT CListen::Initialize( + __in CAdapter* pParent, + __in SIZE_T Backlog, + __in INT Protocol, + __in USHORT Port, + __out_opt USHORT* pAssignedPort + ) + { + ND_ENTER( ND_DBG_NDI ); + + m_pParent = pParent; + m_pParent->AddRef(); + + UNREFERENCED_PARAMETER( Backlog ); + + if( Port == 0 && pAssignedPort == NULL ) + return ND_INVALID_PARAMETER_MIX; + + // + // IP Addressing Annex only supports a single byte for protocol. + // + if( Protocol > UCHAR_MAX || Protocol < 0 ) + return ND_INVALID_PARAMETER_3; + + ual_cep_listen_ioctl_t listen; + listen.cid = 0; + + listen.cep_listen.svc_id = + 0x0000000001000000 | Protocol << 16 | Port; + + listen.cep_listen.port_guid = m_pParent->m_PortGuid; + + switch( m_pParent->m_Addr.v4.sin_family ) + { + case AF_INET: + ZeroMemory( listen.compare, ATS_IPV4_OFFSET ); + CopyMemory( &listen.compare[ATS_IPV4_OFFSET], + (uint8_t*)&m_pParent->m_Addr.v4.sin_addr, + sizeof(m_pParent->m_Addr.v4.sin_addr) ); + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Listen for: IP %#x, port %#hx\n", + cl_hton32(m_pParent->m_Addr.v4.sin_addr.S_un.S_addr), cl_hton16(m_pParent->m_Addr.v4.sin_port) ) ); + break; + case AF_INET6: + CopyMemory( listen.compare, + (uint8_t*)&m_pParent->m_Addr.v6.sin6_addr, + sizeof(m_pParent->m_Addr.v6.sin6_addr) ); + break; + } + listen.cep_listen.p_cmp_buf = listen.compare; + listen.cep_listen.cmp_len = 16; + listen.cep_listen.cmp_offset = FIELD_OFFSET( ib_cm_rdma_req_t, dst_ip_addr ); + + IO_STATUS_BLOCK IoStatus; + IoStatus.Status = NtDeviceIoControlFile( + m_pParent->m_hSync, + NULL, + NULL, + NULL, + &IoStatus, + UAL_NDI_LISTEN_CM, + &listen, + sizeof(listen), + &m_cid, + sizeof(m_cid) ); + + switch( IoStatus.Status ) + { + case ND_SUCCESS: + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Listen for: Guid %#I64x, sid %#I64x\n", + m_pParent->m_PortGuid, listen.cep_listen.svc_id ) ); + break; + + case IB_INVALID_SETTING: + return ND_ADDRESS_ALREADY_EXISTS; + + default: + return IoStatus.Status; + } + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Created listen CEP with cid %d \n", m_cid ) ); + + // TODO: Come up with something better for port number. + if( Port == 0 ) + Port = (USHORT)m_cid | (USHORT)(m_cid >> 16); + + if( pAssignedPort ) + *pAssignedPort = Port; + + m_Protocol = (UINT8)Protocol; + return S_OK; + } + + HRESULT CListen::Create( + __in CAdapter* pParent, + __in SIZE_T Backlog, + __in INT Protocol, + __in USHORT Port, + __out_opt USHORT* pAssignedPort, + __deref_out INDListen** ppListen + ) + { + CListen* pListen = new CListen(); + if( pListen == NULL ) + return ND_NO_MEMORY; + + HRESULT hr = pListen->Initialize( + pParent, + Backlog, + Protocol, + Port, + pAssignedPort ); + if( FAILED( hr ) ) + { + delete pListen; + return hr; + } + + *ppListen = pListen; + return S_OK; + } + + // *** IUnknown methods *** + HRESULT CListen::QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ) + { + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppvObj = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDListen ) ) + { + *ppvObj = this; + return S_OK; + } + + return E_NOINTERFACE; + } + + ULONG CListen::AddRef(void) + { + return InterlockedIncrement( &m_nRef ); + } + + ULONG CListen::Release(void) + { + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; + } + + // *** INDOverlapped methods *** + HRESULT CListen::CancelOverlappedRequests(void) + { + ND_ENTER( ND_DBG_NDI ); + + DWORD bytes_ret; + BOOL ret = DeviceIoControl( + m_pParent->m_hSync, + UAL_NDI_CANCEL_CM_IRPS, + &m_cid, + sizeof(m_cid), + NULL, + 0, + &bytes_ret, + NULL ); + + if( ret ) + return S_OK; + else + return ND_UNSUCCESSFUL; + } + + HRESULT CListen::GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ) + { + ND_ENTER( ND_DBG_NDI ); + + *pNumberOfBytesTransferred = 0; + ::GetOverlappedResult( + m_pParent->GetFileHandle(), + pOverlapped, + (DWORD*)pNumberOfBytesTransferred, + bWait ); + return (HRESULT)pOverlapped->Internal; + } + + // *** INDListen methods *** + HRESULT CListen::GetConnectionRequest( + __inout INDConnector* pConnector, + __inout OVERLAPPED* pOverlapped + ) + { + ND_ENTER( ND_DBG_NDI ); + + static_cast(pConnector)->m_Protocol = m_Protocol; + + pOverlapped->Internal = ND_PENDING; + return NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_GET_REQ_CM, + &m_cid, + sizeof(m_cid), + &static_cast(pConnector)->m_cid, + sizeof(static_cast(pConnector)->m_cid) ); + } + +} // namespace diff --git a/trunk/ulp/nd/user/NdListen.h b/trunk/ulp/nd/user/NdListen.h new file mode 100644 index 00000000..3372fbf8 --- /dev/null +++ b/trunk/ulp/nd/user/NdListen.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2008 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:$ + */ + +#pragma once +#include "ndspi.h" +#include + + +namespace NetworkDirect +{ + +HRESULT GetPdataForPassive( + __in UINT8* pSrc, + __in SIZE_T SrcLength, + __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData, + __inout SIZE_T* pPrivateDataLength + ); + +HRESULT GetPdataForActive( + __in UINT8* pSrc, + __in SIZE_T SrcLength, + __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData, + __inout SIZE_T* pPrivateDataLength + ); + +class CAdapter; + +class CListen : + public INDListen +{ +private: + CListen(void); + ~CListen(void); + + HRESULT Initialize( + __in CAdapter* pParent, + __in SIZE_T Backlog, + __in INT Protocol, + __in USHORT Port, + __out_opt USHORT* pAssignedPort + ); + +public: + static HRESULT Create( + __in CAdapter* pParent, + __in SIZE_T Backlog, + __in INT Protocol, + __in USHORT Port, + __out_opt USHORT* pAssignedPort, + __deref_out INDListen** ppListen + ); + + // *** IUnknown methods *** + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + + ULONG STDMETHODCALLTYPE Release(void); + + // *** INDOverlapped methods *** + HRESULT STDMETHODCALLTYPE CancelOverlappedRequests(void); + + HRESULT STDMETHODCALLTYPE GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ); + + // *** INDListen methods *** + HRESULT STDMETHODCALLTYPE GetConnectionRequest( + __inout INDConnector* pConnector, + __inout OVERLAPPED* pOverlapped + ); + +private: + volatile LONG m_nRef; + + CAdapter* m_pParent; + + UINT8 m_Protocol; + net32_t m_cid; +}; + +} // namespace diff --git a/trunk/ulp/nd/user/NdMr.cpp b/trunk/ulp/nd/user/NdMr.cpp new file mode 100644 index 00000000..2216e63f --- /dev/null +++ b/trunk/ulp/nd/user/NdMr.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008 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 +#include "ndspi.h" +#include "NdMr.h" + + +namespace NetworkDirect +{ + + CMr::CMr(void) + { + } + + CMr::~CMr(void) + { + } + +} // namespace diff --git a/trunk/ulp/nd/user/NdMr.h b/trunk/ulp/nd/user/NdMr.h new file mode 100644 index 00000000..c0eb4058 --- /dev/null +++ b/trunk/ulp/nd/user/NdMr.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008 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:$ + */ + +#pragma once + +#include "iba/ib_al_ioctl.h" + + +namespace NetworkDirect +{ + + class CMr + { + friend class CAdapter; + friend class CEndpoint; + + friend class CAdapter_Beta1; + friend class CEndpoint_Beta1; + public: + CMr(void); + ~CMr(void); + + protected: + const char* pBase; + uint32_t Length; + ual_reg_mem_ioctl_t mr_ioctl; + }; + +} // namespace diff --git a/trunk/ulp/nd/user/NdMw.cpp b/trunk/ulp/nd/user/NdMw.cpp new file mode 100644 index 00000000..cc10eb04 --- /dev/null +++ b/trunk/ulp/nd/user/NdMw.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008 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 "NdMw.h" +#include "NdAdapter.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdMw.tmh" +#endif + + +namespace NetworkDirect +{ + + CMw::CMw(void) : + m_nRef( 1 ), + m_pParent( NULL ) + { + } + + CMw::~CMw(void) + { + if( m_pParent ) + m_pParent->Release(); + } + + HRESULT CMw::Initialize( + CAdapter* pParent, + ND_RESULT* pInvalidateResult + ) + { + m_pParent = pParent; + m_pParent->AddRef(); + + m_pInvalidateResult = pInvalidateResult; + return S_OK; + } + + HRESULT CMw::QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ) + { + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppvObj = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDMemoryWindow ) ) + { + *ppvObj = this; + return S_OK; + } + + return E_NOINTERFACE; + } + + ULONG CMw::AddRef(void) + { + return InterlockedIncrement( &m_nRef ); + } + + ULONG CMw::Release(void) + { + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; + } + + HRESULT CMw::Close(void) + { + Release(); + return S_OK; + } + +} // namespace diff --git a/trunk/ulp/nd/user/NdMw.h b/trunk/ulp/nd/user/NdMw.h new file mode 100644 index 00000000..c3589c56 --- /dev/null +++ b/trunk/ulp/nd/user/NdMw.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2008 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:$ + */ + +#pragma once +#include "ndspi.h" + + +namespace NetworkDirect +{ + + class CAdapter; + + class CMw : + public INDMemoryWindow + { + public: + CMw(void); + ~CMw(void); + + HRESULT Initialize( + CAdapter* pParent, + ND_RESULT* pInvalidateResult ); + + // *** IUnknown methods *** + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + + ULONG STDMETHODCALLTYPE Release(void); + + // *** INDMemoryWindow methods *** + HRESULT STDMETHODCALLTYPE Close(void); + + //operator ND_RESULT*(){ return m_pInvalidateResult; }; + + private: + volatile LONG m_nRef; + + CAdapter* m_pParent; + + ND_RESULT* m_pInvalidateResult; + }; + +/////////////////////////////////////////////////////////////////////////////// +// +// HPC Pack 2008 Beta 1 SPI +// +/////////////////////////////////////////////////////////////////////////////// + + class CAdapter_Beta1; + + class CMw_Beta1 : + public INDMemoryWindow + { + public: + CMw_Beta1(void); + ~CMw_Beta1(void); + + HRESULT Initialize( + CAdapter_Beta1* pParent, + ND_RESULT* pInvalidateResult ); + + // *** IUnknown methods *** + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + + ULONG STDMETHODCALLTYPE Release(void); + + // *** INDMemoryWindow methods *** + HRESULT STDMETHODCALLTYPE Close(void); + + //operator ND_RESULT*(){ return m_pInvalidateResult; }; + + private: + volatile LONG m_nRef; + + CAdapter_Beta1* m_pParent; + + ND_RESULT* m_pInvalidateResult; + }; + +} // namespace \ No newline at end of file diff --git a/trunk/ulp/nd/user/NdProv.cpp b/trunk/ulp/nd/user/NdProv.cpp new file mode 100644 index 00000000..e2428773 --- /dev/null +++ b/trunk/ulp/nd/user/NdProv.cpp @@ -0,0 +1,561 @@ +/* + * Copyright (c) 2008 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 +#include +#include +#include +#include +#pragma warning( push, 3 ) +#include +#include +#include +#include +#include +#include +#pragma warning( pop ) +#include "ndprov.h" +#include "ndadapter.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdProv.tmh" +#endif + +#include "nddebug.h" + +uint32_t g_nd_dbg_level = TRACE_LEVEL_ERROR; +/* WPP doesn't want here literals! */ +uint32_t g_nd_dbg_flags = 0x80000001; /* ND_DBG_ERROR | ND_DBG_NDI; */ + +namespace NetworkDirect +{ + + static LONG gnRef = 0; + + CProvider::CProvider() : + m_nRef( 1 ) + { + InterlockedIncrement( &gnRef ); + } + + CProvider::~CProvider() + { + InterlockedDecrement( &gnRef ); + } + + HRESULT CProvider::QueryInterface( + const IID &riid, + void **ppObject ) + { + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppObject = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDProvider ) ) + { + *ppObject = this; + return S_OK; + } + + return E_NOINTERFACE; + } + + ULONG CProvider::AddRef() + { + return InterlockedIncrement( &m_nRef ); + } + + ULONG CProvider::Release() + { + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; + } + + HRESULT CProvider::QueryAddressList( + __out_bcount_part_opt(*pBufferSize, *pBufferSize) SOCKET_ADDRESS_LIST* pAddressList, + __inout SIZE_T* pBufferSize ) + { + ND_ENTER( ND_DBG_NDI ); + + HANDLE hIbatDev = CreateFileW( IBAT_WIN32_NAME, + MAXIMUM_ALLOWED, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if( hIbatDev == INVALID_HANDLE_VALUE ) + return ND_NO_MEMORY; + + IOCTL_IBAT_IP_ADDRESSES_IN addrIn; + + addrIn.Version = IBAT_IOCTL_VERSION; + addrIn.PortGuid = 0; + + DWORD size = sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT); + IOCTL_IBAT_IP_ADDRESSES_OUT *pAddrOut; + do + { + pAddrOut = (IOCTL_IBAT_IP_ADDRESSES_OUT*)HeapAlloc( + GetProcessHeap(), + 0, + size ); + if( !pAddrOut ) + { + //AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + // ("Failed to allocate output buffer.\n") ); + return ND_NO_MEMORY; + } + + if( !DeviceIoControl( hIbatDev, IOCTL_IBAT_IP_ADDRESSES, + &addrIn, sizeof(addrIn), pAddrOut, size, &size, NULL ) ) + { + HeapFree( GetProcessHeap(), 0, pAddrOut ); + //AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + // ("IOCTL_IBAT_IP_ADDRESSES failed (%x).\n", GetLastError()) ); + return ND_UNSUCCESSFUL; + } + + if( pAddrOut->Size > size ) + { + size = pAddrOut->Size; + HeapFree( GetProcessHeap(), 0, pAddrOut ); + pAddrOut = NULL; + } + + } while( !pAddrOut ); + + CloseHandle( hIbatDev ); + + // + // Note: the required size computed is a few bytes larger than necessary, + // but that keeps the code clean. + // + SIZE_T size_req = sizeof(SOCKET_ADDRESS_LIST); + + switch( pAddrOut->AddressCount ) + { + case 0: + break; + + default: + size_req += (pAddrOut->AddressCount - 1) * + (sizeof(SOCKET_ADDRESS) + sizeof(SOCKADDR)); + /* Fall through. */ + __fallthrough; + + case 1: + /* Add the space for the first address. */ + size_req += sizeof(SOCKADDR); + break; + } + + if( size_req > *pBufferSize ) + { + HeapFree( GetProcessHeap(), 0, pAddrOut ); + *pBufferSize = size_req; + return ND_BUFFER_OVERFLOW; + } + + ZeroMemory( pAddressList, *pBufferSize ); + + /* We store the array of addresses after the last address pointer: + * iAddressCount + * Address[0]; <-- points to sockaddr[0] + * Address[1]; <-- points to sockaddr[1] + * ... + * Address[n-1]; <-- points to sockaddr[n-1] + * sockaddr[0]; + * sockaddr[1]; + * ... + * sockaddr[n-1] + */ + BYTE* pBuf = (BYTE*)(&(pAddressList->Address[pAddrOut->AddressCount])); + *pBufferSize = size_req; + + pAddressList->iAddressCount = 0; + for( LONG i = 0; i < pAddrOut->AddressCount; i++ ) + { + pAddressList->Address[pAddressList->iAddressCount].lpSockaddr = + (LPSOCKADDR)pBuf; + + switch( pAddrOut->Address[i].IpVersion ) + { + case 4: + { + struct sockaddr_in* pAddr4 = ((struct sockaddr_in*)pBuf); + pAddr4->sin_family = AF_INET; + pAddr4->sin_addr.s_addr = + *((u_long*)&pAddrOut->Address[i].Address[12]); + pAddressList->Address[pAddressList->iAddressCount].iSockaddrLength = + sizeof(struct sockaddr_in); + } + break; + + case 6: + { + struct sockaddr_in6* pAddr6 = ((struct sockaddr_in6*)pBuf); + pAddr6->sin6_family = AF_INET6; + CopyMemory( + &pAddr6->sin6_addr, + pAddrOut->Address[i].Address, + sizeof(pAddr6->sin6_addr) ); + pAddressList->Address[pAddressList->iAddressCount].iSockaddrLength = + sizeof(struct sockaddr_in6); + } + break; + + default: + continue; + } + + pBuf += pAddressList->Address[pAddressList->iAddressCount++].iSockaddrLength; + } + + HeapFree( GetProcessHeap(), 0, pAddrOut ); + + return S_OK; + } + + HRESULT CProvider::OpenAdapter( + __in_bcount(AddressLength) const struct sockaddr* pAddress, + __in SIZE_T AddressLength, + __deref_out INDAdapter** ppAdapter ) + { + ND_ENTER( ND_DBG_NDI ); + + if( AddressLength < sizeof(struct sockaddr) ) + return ND_INVALID_ADDRESS; + + IOCTL_IBAT_IP_TO_PORT_IN in; + in.Version = IBAT_IOCTL_VERSION; + + switch( pAddress->sa_family ) + { + case AF_INET: + if( AddressLength < sizeof(struct sockaddr_in) ) + return ND_INVALID_ADDRESS; + in.Address.IpVersion = 4; + RtlCopyMemory( + &in.Address.Address[12], + &((struct sockaddr_in*)pAddress)->sin_addr, + sizeof( ((struct sockaddr_in*)pAddress)->sin_addr ) ); + break; + + case AF_INET6: + if( AddressLength < sizeof(struct sockaddr_in6) ) + return ND_INVALID_ADDRESS; + in.Address.IpVersion = 6; + RtlCopyMemory( + in.Address.Address, + &((struct sockaddr_in6*)pAddress)->sin6_addr, + sizeof(in.Address.Address) ); + break; + + default: + return ND_INVALID_ADDRESS; + } + + HANDLE hIbatDev = CreateFileW( IBAT_WIN32_NAME, + MAXIMUM_ALLOWED, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if( hIbatDev == INVALID_HANDLE_VALUE ) + return ND_NO_MEMORY; + + IBAT_PORT_RECORD out; + DWORD size; + BOOL fSuccess = DeviceIoControl( hIbatDev, IOCTL_IBAT_IP_TO_PORT, + &in, sizeof(in), &out, sizeof(out), &size, NULL ); + + CloseHandle( hIbatDev ); + if( !fSuccess || size == 0 ) + return ND_INVALID_ADDRESS; + + return CAdapter::Create( this, pAddress, &out, ppAdapter ); + } + + CClassFactory::CClassFactory(void) : + m_nRef( 1 ) + { + InterlockedIncrement( &gnRef ); + } + + CClassFactory::~CClassFactory(void) + { + InterlockedDecrement( &gnRef ); + } + + HRESULT CClassFactory::QueryInterface( + REFIID riid, + void** ppObject ) + { + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppObject = this; + return S_OK; + } + if( IsEqualIID( riid, IID_IClassFactory ) ) + { + *ppObject = this; + return S_OK; + } + + return E_NOINTERFACE; + } + + ULONG CClassFactory::AddRef() + { + return InterlockedIncrement( &m_nRef ); + } + + ULONG CClassFactory::Release() + { + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; + } + + HRESULT CClassFactory::CreateInstance( + IUnknown* pUnkOuter, + REFIID riid, + void** ppObject ) + { + if( pUnkOuter != NULL ) + return CLASS_E_NOAGGREGATION; + + if( IsEqualIID( riid, IID_INDProvider ) ) + { + *ppObject = new CProvider(); + if( !*ppObject ) + return E_OUTOFMEMORY; + + return S_OK; + } + + return E_NOINTERFACE; + } + + HRESULT CClassFactory::LockServer( BOOL fLock ) + { + UNREFERENCED_PARAMETER( fLock ); + return S_OK; + } + +} // namespace + +void* __cdecl operator new( + size_t count + ) +{ + return HeapAlloc( GetProcessHeap(), 0, count ); +} + + +void __cdecl operator delete( + void* object + ) +{ + HeapFree( GetProcessHeap(), 0, object ); +} + +extern "C" { +STDAPI DllGetClassObject( + REFCLSID rclsid, + REFIID riid, + LPVOID * ppv + ) +{ + ND_ENTER( ND_DBG_NDI ); + + UNREFERENCED_PARAMETER( rclsid ); + + if( IsEqualIID( riid, IID_IClassFactory ) ) + { + NetworkDirect::CClassFactory* pFactory = new NetworkDirect::CClassFactory(); + if( pFactory == NULL ) + return E_OUTOFMEMORY; + + *ppv = pFactory; + return S_OK; + } + + return E_NOINTERFACE; +} + +STDAPI DllCanUnloadNow(void) +{ + ND_ENTER( ND_DBG_NDI ); + + if( InterlockedCompareExchange( &NetworkDirect::gnRef, 0, 0 ) != 0 ) + return S_FALSE; + + return S_OK; +} + +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 hinstDll, + IN DWORD dwReason, + IN LPVOID lpvReserved ) +{ + + ND_ENTER( ND_DBG_NDI ); + + UNUSED_PARAM( hinstDll ); + UNUSED_PARAM( lpvReserved ); + + switch( dwReason ) + { + case DLL_PROCESS_ATTACH: + + +#if defined(EVENT_TRACING) +#if DBG + WPP_INIT_TRACING(L"ibndprov.dll"); +#else + WPP_INIT_TRACING(L"ibndprov.dll"); +#endif +#endif + + +#if !defined(EVENT_TRACING) +#if DBG + TCHAR env_var[16]; + DWORD i; + + i = GetEnvironmentVariable( "IBNDPROV_DBG_LEVEL", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + { + g_nd_dbg_level = _tcstoul( env_var, NULL, 16 ); + } + + i = GetEnvironmentVariable( "IBNDPROV_DBG_FLAGS", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + { + g_nd_dbg_flags = _tcstoul( env_var, NULL, 16 ); + } + + if( g_nd_dbg_flags & ND_DBG_ERR ) + g_nd_dbg_flags |= CL_DBG_ERROR; + + ND_PRINT( TRACE_LEVEL_ERROR, ND_DBG_ERR , + ("(pcs %#x) IbNdProv: Debug print: level:%d, flags 0x%x\n", + GetCurrentProcessId(), g_nd_dbg_level ,g_nd_dbg_flags) ); + +#endif +#endif + + ND_PRINT(TRACE_LEVEL_INFORMATION, ND_DBG_NDI, ("DllMain: DLL_PROCESS_ATTACH\n") ); + break; + + case DLL_PROCESS_DETACH: + ND_PRINT(TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("DllMain: DLL_PROCESS_DETACH, ref count %d\n", NetworkDirect::gnRef) ); + +#if defined(EVENT_TRACING) + WPP_CLEANUP(); +#endif + break; + } + + ND_EXIT( ND_DBG_NDI ); + + return TRUE; +} + + +extern BOOL APIENTRY +_DllMainCRTStartupForGS( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ); + + +BOOL APIENTRY +DllMain( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ) +{ + switch( ul_reason_for_call ) + { + case DLL_PROCESS_ATTACH: + if( !_DllMainCRTStartupForGS( + h_module, ul_reason_for_call, lp_reserved ) ) + { + return FALSE; + } + + return _DllMain( h_module, ul_reason_for_call, lp_reserved ); + + case DLL_THREAD_ATTACH: + ND_PRINT(TRACE_LEVEL_INFORMATION, ND_DBG_NDI, ("DllMain: DLL_THREAD_ATTACH\n") ); + break; + + case DLL_THREAD_DETACH: + ND_PRINT(TRACE_LEVEL_INFORMATION, ND_DBG_NDI, ("DllMain: DLL_THREAD_DETACH\n") ); + break; + + case DLL_PROCESS_DETACH: + _DllMain( h_module, ul_reason_for_call, lp_reserved ); + + return _DllMainCRTStartupForGS( + h_module, ul_reason_for_call, lp_reserved ); + } + return TRUE; +} + +} // extern "C" + diff --git a/trunk/ulp/nd/user/NdProv.def b/trunk/ulp/nd/user/NdProv.def new file mode 100644 index 00000000..f2fb99c5 --- /dev/null +++ b/trunk/ulp/nd/user/NdProv.def @@ -0,0 +1,6 @@ +LIBRARY IbNdProv.dll + +EXPORTS + DllGetClassObject private + WSPStartup + DllCanUnloadNow private \ No newline at end of file diff --git a/trunk/ulp/nd/user/NdProv.h b/trunk/ulp/nd/user/NdProv.h new file mode 100644 index 00000000..21de4a70 --- /dev/null +++ b/trunk/ulp/nd/user/NdProv.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008 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:$ + */ + +#pragma once +#include + +#ifdef __cplusplus +namespace NetworkDirect +{ + + +/////////////////////////////////////////////////////////////////////////////// +// +// HPC Pack 2008 Beta 2 SPI +// +/////////////////////////////////////////////////////////////////////////////// + +class CProvider : + public INDProvider +{ + friend class CClassFactory; + +public: + CProvider(void); + ~CProvider(void); + + // IUnknown Methods + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppObject + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + ULONG STDMETHODCALLTYPE Release(void); + + // 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 + ); + +private: + volatile LONG m_nRef; +}; + + +class CClassFactory : public IClassFactory +{ +public: + CClassFactory(void); + ~CClassFactory(void); + + // IUnknown Methods. + HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void** ppObject ); + ULONG STDMETHODCALLTYPE AddRef(void); + ULONG STDMETHODCALLTYPE Release(void); + + // IClassFactory Methods. + HRESULT STDMETHODCALLTYPE CreateInstance( IUnknown* pUnkOuter, REFIID riid, void** ppObject ); + HRESULT STDMETHODCALLTYPE LockServer( BOOL fLock ); + +private: + volatile LONG m_nRef; +}; + +} // namespace + +void* __cdecl operator new( + size_t count + ); + +void __cdecl operator delete( + void* object + ); + +#endif // __cplusplus diff --git a/trunk/ulp/nd/user/NdProv.rc b/trunk/ulp/nd/user/NdProv.rc new file mode 100644 index 00000000..6f5908b1 --- /dev/null +++ b/trunk/ulp/nd/user/NdProv.rc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2008 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 + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "OpenFabrics Network Direct Provider (Debug)" +#define VER_INTERNALNAME_STR "ibndprov.dll" +#define VER_ORIGINALFILENAME_STR "ibndprov.dll" +#else +#define VER_FILEDESCRIPTION_STR "OpenFabrics Network Direct Provider" +#define VER_INTERNALNAME_STR "ibndprov.dll" +#define VER_ORIGINALFILENAME_STR "ibndprov.dll" +#endif + +#include + diff --git a/trunk/ulp/nd/user/SOURCES b/trunk/ulp/nd/user/SOURCES index 75d006a0..67f80f7d 100644 --- a/trunk/ulp/nd/user/SOURCES +++ b/trunk/ulp/nd/user/SOURCES @@ -1,15 +1,62 @@ -TARGETNAME=fake +TARGETNAME=ibndprov + TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) -TARGETTYPE=PROGRAM -UMTYPE=console -USE_MSVCRT=1 +TARGETTYPE=DYNLINK +DLLDEF=NdProv.def +DLLENTRY=DllMain + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +#!else +#ENABLE_EVENT_TRACING=1 +!endif + +USE_NTDLL=1 + +SOURCES=\ + NdProv.rc \ + NdAdapter.cpp \ + NdCq.cpp \ + NdEndpoint.cpp \ + NdListen.cpp \ + NdMr.cpp \ + NdMw.cpp \ + NdProv.cpp \ + NdConnector.cpp + + +INCLUDES=$(SDK_INC_PATH);..;..\..\..\inc;..\..\..\inc\user;..\..\..\core\al;..\..\..\core\al\user;$(ND_INC);$(PLATFORM_SDK_PATH)\Include + +USER_C_FLAGS=$(USER_C_FLAGS) -DEXPORT_AL_SYMBOLS -DCL_NO_TRACK_MEM -DWPP_OLDCC + +#/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)\iphlpapi.lib \ + $(TARGETPATH)\*\ibat.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ +!else + $(TARGETPATH)\*\complibd.lib\ +!endif + $(SDK_LIB_PATH)\uuid.lib + -SOURCES=fake.c +!IFDEF ENABLE_EVENT_TRACING -INCLUDES=..;..\..\..\inc;..\..\..\inc\kernel; +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING -ND_TARGET1=..\..\..\bin\user\$(O)\ibndprov.dll -ND_TARGET2=..\..\..\bin\user\$(O)\ndinstall.exe +RUN_WPP = $(SOURCES) -ext: .c .h .C .H \ + -scan:nddebug.h \ + -func:ND_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:ND_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) \ + -dll +!ENDIF -NTTARGETFILES=$(ND_TARGET1) $(ND_TARGET2) +BUILD_PRODUCES=NetworkDirect +MSC_WARNING_LEVEL= /W4 diff --git a/trunk/ulp/nd/user/makefile b/trunk/ulp/nd/user/makefile index d3662669..bffacaa7 100644 --- a/trunk/ulp/nd/user/makefile +++ b/trunk/ulp/nd/user/makefile @@ -3,4 +3,5 @@ # 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. # + !INCLUDE ..\..\..\inc\openib.def diff --git a/trunk/ulp/nd/user/nddebug.h b/trunk/ulp/nd/user/nddebug.h new file mode 100644 index 00000000..ab5607b4 --- /dev/null +++ b/trunk/ulp/nd/user/nddebug.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2008 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:$ + */ + +#pragma once + +#ifdef __MODULE__ +#undef __MODULE__ +#endif +#define __MODULE__ "[ND]" + + +#include + +extern uint32_t g_nd_dbg_level; +extern uint32_t g_nd_dbg_flags; + +#if defined(EVENT_TRACING) +// +// Software Tracing Definitions +// + + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(NDCtlGuid1,(1463B4CE,7A66,47a4,ABDB,09EE7AD9E698), \ + WPP_DEFINE_BIT( ND_DBG_ERROR)\ + WPP_DEFINE_BIT( ND_DBG_NDI)) + + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags)(WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + + +// begin_wpp config +// ND_ENTER( FLAG ); +// ND_EXIT( FLAG ); +// USEPREFIX(ND_PRINT, "%!STDPREFIX! [ND] :%!FUNC!() :"); +// USESUFFIX(ND_ENTER, " [ND] :%!FUNC!():["); +// USESUFFIX(ND_EXIT, " [ND] :%!FUNC!():]"); +// end_wpp + + + +#else + +#include +#include + +/* + * Debug macros + */ + + +/* Debug message source */ +#define ND_DBG_ERR (1 << 0) +#define ND_DBG_NDI (1 << 1) + +#define ND_DBG_ERROR (CL_DBG_ERROR | ND_DBG_ERR) + +#if DBG + +// assignment of _level_ is need to to overcome warning C4127 +#define ND_PRINT( _level_,_flag_,_msg_) \ + { \ + if( g_nd_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_nd_dbg_flags, _msg_ ); \ + } + + +#define ND_PRINT_EXIT( _level_,_flag_,_msg_) \ + { \ + if( g_nd_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_nd_dbg_flags, _msg_ );\ + ND_EXIT( _flag_ );\ + } + +#define ND_ENTER( _flag_) \ + { \ + if( g_nd_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_ENTER( _flag_, g_nd_dbg_flags ); \ + } + +#define ND_EXIT( _flag_)\ + { \ + if( g_nd_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_EXIT( _flag_, g_nd_dbg_flags ); \ + } + + +#else + +#define ND_PRINT( lvl, flags, msg) + +#define ND_PRINT_EXIT( _level_,_flag_,_msg_) + +#define ND_ENTER( _flag_) + +#define ND_EXIT( _flag_) + + +#endif + +#endif //EVENT_TRACING + + +#if DBG +struct dbg_data +{ + int64_t rcv_cnt; + int64_t rcv_pkts; + int64_t rcv_bytes; + int64_t rcv_pkts_err; + int64_t rcv_pkts_zero; + int64_t snd_cnt; + int64_t snd_pkts; + int64_t snd_bytes; + int64_t snd_pkts_err; + int64_t snd_pkts_zero; + int64_t c_cnt; + int64_t c_rcv_pkts; + int64_t c_rcv_bytes; + int64_t c_rcv_pkts_err; + int64_t c_snd_pkts; + int64_t c_snd_bytes; + int64_t c_snd_pkts_err; +}; + +extern dbg_data g; + +#endif