Remove stale HPC Pack 2008 Beta 1 objects
[mirror/winof/.git] / ulp / nd / user / NdAdapter.cpp
1 /*\r
2  * Copyright (c) 2008 Microsoft Corporation.  All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.org BSD license\r
5  * below:\r
6  *\r
7  *     Redistribution and use in source and binary forms, with or\r
8  *     without modification, are permitted provided that the following\r
9  *     conditions are met:\r
10  *\r
11  *      - Redistributions of source code must retain the above\r
12  *        copyright notice, this list of conditions and the following\r
13  *        disclaimer.\r
14  *\r
15  *      - Redistributions in binary form must reproduce the above\r
16  *        copyright notice, this list of conditions and the following\r
17  *        disclaimer in the documentation and/or other materials\r
18  *        provided with the distribution.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
27  * SOFTWARE.\r
28  *\r
29  * $Id:$\r
30  */\r
31 \r
32 #include "NdCq.h"\r
33 #include "NdAdapter.h"\r
34 #include "NdMw.h"\r
35 #include "NdEndpoint.h"\r
36 #include "NdProv.h"\r
37 #include "NdMr.h"\r
38 #include "NdListen.h"\r
39 #include "NdConnector.h"\r
40 \r
41 #include "al_dev.h"\r
42 #pragma warning( push, 3 )\r
43 #include "winternl.h"\r
44 #pragma warning( pop )\r
45 \r
46 #include <assert.h>\r
47 #include <limits.h>\r
48 #include <strsafe.h>\r
49 \r
50 #if defined(EVENT_TRACING)\r
51 #ifdef offsetof\r
52 #undef offsetof\r
53 #endif\r
54 #include "NdAdapter.tmh"\r
55 #endif\r
56 \r
57 \r
58 namespace NetworkDirect\r
59 {\r
60 \r
61 ///////////////////////////////////////////////////////////////////////////////\r
62 //\r
63 // HPC Pack 2008 Beta 2 SPI\r
64 //\r
65 ///////////////////////////////////////////////////////////////////////////////\r
66 \r
67 \r
68 CAdapter::CAdapter(void) :\r
69     m_nRef( 1 ),\r
70     m_hSync( INVALID_HANDLE_VALUE ),\r
71     m_hAsync( INVALID_HANDLE_VALUE ),\r
72     m_hCa( 0 ),\r
73     m_hPd( 0 ),\r
74     m_uCa( NULL ),\r
75     m_uPd( NULL ),\r
76     m_pParent( NULL )\r
77 {\r
78     m_Ifc.h_uvp_lib = NULL;\r
79 }\r
80 \r
81 CAdapter::~CAdapter(void)\r
82 {\r
83     if( m_hPd )\r
84         DeallocPd();\r
85 \r
86     if( m_hCa )\r
87         CloseCa();\r
88 \r
89     if( m_hSync != INVALID_HANDLE_VALUE )\r
90         CloseHandle( m_hSync );\r
91 \r
92     if( m_hAsync != INVALID_HANDLE_VALUE )\r
93         CloseHandle( m_hAsync );\r
94 \r
95     if( m_pParent )\r
96         m_pParent->Release();\r
97 }\r
98 \r
99 HRESULT CAdapter::Initialize(\r
100     CProvider* pParent,\r
101     const struct sockaddr* pAddr,\r
102     const IBAT_PORT_RECORD* pPortRecord )\r
103 {\r
104     m_pParent = pParent;\r
105     m_pParent->AddRef();\r
106 \r
107     HRESULT hr = OpenFiles();\r
108     if( FAILED( hr ) )\r
109         return hr;\r
110 \r
111     hr = OpenCa( pPortRecord->CaGuid );\r
112     if( FAILED( hr ) )\r
113         return hr;\r
114 \r
115     hr = AllocPd();\r
116     if( FAILED( hr ) )\r
117         return hr;\r
118 \r
119     m_PortNum = pPortRecord->PortNum;\r
120     m_PortGuid = pPortRecord->PortGuid;\r
121 \r
122     switch( pAddr->sa_family )\r
123     {\r
124     case AF_INET:\r
125         RtlCopyMemory( &m_Addr.v4, pAddr, sizeof(m_Addr.v4) );\r
126         ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI,\r
127             ("Local address: IP %#x, port %#hx\n", \r
128             cl_hton32(m_Addr.v4.sin_addr.S_un.S_addr), cl_hton16(m_Addr.v4.sin_port) ) );\r
129         break;\r
130     case AF_INET6:\r
131         RtlCopyMemory( &m_Addr.v6, pAddr, sizeof(m_Addr.v6) );\r
132         break;\r
133     default:\r
134         return ND_INVALID_ADDRESS;\r
135     }\r
136     return S_OK;\r
137 }\r
138 \r
139 HRESULT CAdapter::Create(\r
140     CProvider* pParent,\r
141     const struct sockaddr* pAddr,\r
142     const IBAT_PORT_RECORD* pPortRecord,\r
143     __out INDAdapter** ppAdapter\r
144     )\r
145 {\r
146     CAdapter* pAdapter = new CAdapter();\r
147     if( pAdapter == NULL )\r
148         return ND_NO_MEMORY;\r
149 \r
150     HRESULT hr = pAdapter->Initialize( pParent, pAddr, pPortRecord );\r
151     if( FAILED( hr ) )\r
152     {\r
153         delete pAdapter;\r
154         return hr;\r
155     }\r
156 \r
157     *ppAdapter = pAdapter;\r
158     return ND_SUCCESS;\r
159 }\r
160 \r
161 // IUnknown overrides.\r
162 HRESULT CAdapter::QueryInterface(\r
163     const IID &riid,\r
164     LPVOID FAR *ppvObj )\r
165 {\r
166     if( IsEqualIID( riid, IID_IUnknown ) )\r
167     {\r
168         *ppvObj = this;\r
169         return S_OK;\r
170     }\r
171 \r
172     if( IsEqualIID( riid, IID_INDAdapter ) )\r
173     {\r
174         *ppvObj = this;\r
175         return S_OK;\r
176     }\r
177 \r
178     return E_NOINTERFACE;\r
179 }\r
180 \r
181 ULONG CAdapter::AddRef(void)\r
182 {\r
183     return InterlockedIncrement( &m_nRef );\r
184 }\r
185 \r
186 ULONG CAdapter::Release(void)\r
187 {\r
188     ULONG ref = InterlockedDecrement( &m_nRef );\r
189     if( ref == 0 )\r
190         delete this;\r
191 \r
192     return ref;\r
193 }\r
194 \r
195 // *** INDOverlapped methods ***\r
196 HRESULT CAdapter::CancelOverlappedRequests(void)\r
197 {\r
198     // Memory registration IOCTLs can't be cancelled.\r
199     return S_OK;\r
200 }\r
201 \r
202 HRESULT CAdapter::GetOverlappedResult(\r
203     __inout OVERLAPPED *pOverlapped,\r
204     __out SIZE_T *pNumberOfBytesTransferred,\r
205     __in BOOL bWait\r
206     )\r
207 {\r
208     ND_ENTER( ND_DBG_NDI );\r
209 \r
210     *pNumberOfBytesTransferred = 0;\r
211     ::GetOverlappedResult(\r
212         m_hAsync,\r
213         pOverlapped,\r
214         (DWORD*)pNumberOfBytesTransferred,\r
215         bWait );\r
216     return (HRESULT)pOverlapped->Internal;\r
217 }\r
218 \r
219 // INDAdapter overrides.\r
220 HANDLE CAdapter::GetFileHandle(void)\r
221 {\r
222     return m_hAsync;\r
223 }\r
224 \r
225 HRESULT CAdapter::Query(\r
226     __in DWORD VersionRequested,\r
227     __out_bcount_part_opt(*pBufferSize, *pBufferSize) ND_ADAPTER_INFO* pInfo,\r
228     __inout_opt SIZE_T* pBufferSize\r
229     )\r
230 {\r
231     ND_ENTER( ND_DBG_NDI );\r
232 \r
233     if( VersionRequested != 1 )\r
234         return ND_NOT_SUPPORTED;\r
235 \r
236     if( *pBufferSize < sizeof(ND_ADAPTER_INFO1) )\r
237     {\r
238         *pBufferSize = sizeof(ND_ADAPTER_INFO1);\r
239         return ND_BUFFER_OVERFLOW;\r
240     }\r
241 \r
242     ib_ca_attr_t* pAttr = NULL;\r
243     DWORD size = 0;\r
244     HRESULT hr = QueryCa( pAttr, &size );\r
245     if( hr != ND_BUFFER_OVERFLOW )\r
246         return hr;\r
247 \r
248     pAttr = (ib_ca_attr_t*)HeapAlloc( GetProcessHeap(), 0, size );\r
249     if( !pAttr )\r
250         return ND_UNSUCCESSFUL;\r
251 \r
252     hr = QueryCa( pAttr, &size );\r
253     if( FAILED( hr ) )\r
254     {\r
255         HeapFree( GetProcessHeap(), 0, pAttr );\r
256         return hr;\r
257     }\r
258 \r
259     pInfo->MaxInboundSge = pAttr->max_sges;\r
260     pInfo->MaxInboundRequests = pAttr->max_wrs;\r
261     pInfo->MaxInboundLength = INT_MAX;\r
262     pInfo->MaxOutboundSge = pAttr->max_sges;\r
263     pInfo->MaxOutboundRequests = pAttr->max_wrs;\r
264     pInfo->MaxOutboundLength = INT_MAX;\r
265     pInfo->MaxInboundReadLimit = pAttr->max_qp_resp_res;\r
266     pInfo->MaxOutboundReadLimit = pAttr->max_qp_init_depth;\r
267     pInfo->MaxCqEntries = pAttr->max_cqes;\r
268 #ifndef SIZE_MAX\r
269 #ifdef _WIN64\r
270 #define SIZE_MAX _UI64_MAX\r
271 #else\r
272 #define SIZE_MAX UINT_MAX\r
273 #endif\r
274 #endif\r
275     if( pAttr->init_region_size > SIZE_MAX )\r
276         pInfo->MaxRegistrationSize = SIZE_MAX;\r
277     else\r
278         pInfo->MaxRegistrationSize = (SIZE_T)pAttr->init_region_size;\r
279     pInfo->MaxWindowSize = pInfo->MaxRegistrationSize;\r
280     pInfo->LargeRequestThreshold = 16 * 1024;\r
281     pInfo->MaxCallerData = 56;\r
282     pInfo->MaxCalleeData = 148;\r
283     *pBufferSize = sizeof(ND_ADAPTER_INFO1);\r
284     return S_OK;\r
285 }\r
286 \r
287 HRESULT CAdapter::Control(\r
288     __in DWORD IoControlCode,\r
289     __in_bcount_opt(InBufferSize) const void* pInBuffer,\r
290     __in SIZE_T InBufferSize,\r
291     __out_bcount_opt(OutBufferSize) void* pOutBuffer,\r
292     __in SIZE_T OutBufferSize,\r
293     __out SIZE_T* pBytesReturned,\r
294     __inout OVERLAPPED* pOverlapped\r
295     )\r
296 {\r
297     UNREFERENCED_PARAMETER( IoControlCode );\r
298     UNREFERENCED_PARAMETER( pInBuffer );\r
299     UNREFERENCED_PARAMETER( InBufferSize );\r
300     UNREFERENCED_PARAMETER( pOutBuffer );\r
301     UNREFERENCED_PARAMETER( OutBufferSize );\r
302     UNREFERENCED_PARAMETER( pBytesReturned );\r
303     UNREFERENCED_PARAMETER( pOverlapped );\r
304     \r
305     return ND_NOT_SUPPORTED;\r
306 }\r
307 \r
308 HRESULT CAdapter::CreateCompletionQueue(\r
309     __in SIZE_T nEntries,\r
310     __deref_out INDCompletionQueue** ppCq\r
311     )\r
312 {\r
313     ND_ENTER( ND_DBG_NDI );\r
314 \r
315     CCq* pCq = new CCq();\r
316     if( pCq == NULL )\r
317         return ND_NO_MEMORY;\r
318 \r
319     HRESULT hr = pCq->Initialize( this, nEntries );\r
320     if( FAILED(hr) )\r
321     {\r
322         delete pCq;\r
323         return hr;\r
324     }\r
325 \r
326     *ppCq = pCq;\r
327     return S_OK;\r
328 }\r
329 \r
330 \r
331 HRESULT CAdapter::RegisterMemory(\r
332     __in_bcount(BufferSize) const void* pBuffer,\r
333     __in SIZE_T BufferSize,\r
334     __inout OVERLAPPED* pOverlapped,\r
335     __deref_out ND_MR_HANDLE* phMr\r
336     )\r
337 {\r
338     ND_ENTER( ND_DBG_NDI );\r
339 \r
340     /* Get a MR tracking structure. */\r
341     CMr* pMr = new CMr();\r
342     if( pMr == NULL )\r
343         return ND_NO_MEMORY;\r
344 \r
345     pMr->pBase = (const char*)pBuffer;\r
346 \r
347     if( BufferSize > ULONG_MAX )\r
348         return ND_INVALID_PARAMETER_2;\r
349     pMr->Length = (uint32_t)BufferSize;\r
350 \r
351     /* Clear the mr_ioctl */\r
352     pMr->mr_ioctl.in.h_pd = m_hPd;\r
353     pMr->mr_ioctl.in.mem_create.vaddr_padding = (ULONG_PTR)pBuffer;\r
354     pMr->mr_ioctl.in.mem_create.length = BufferSize;\r
355     // No support for MWs yet, so simulate it.\r
356     pMr->mr_ioctl.in.mem_create.access_ctrl =\r
357         IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE;\r
358 \r
359     *phMr = (ND_MR_HANDLE)pMr;\r
360     //\r
361     // We must issue the IOCTL on the synchronous file handle.\r
362     // If the user bound the async file handle to an I/O completion port\r
363     // DeviceIoControl could succeed, but not return data, so the MR\r
364     // wouldn't be updated.\r
365     //\r
366     // We use a second IOCTL to complet the user's overlapped.\r
367     //\r
368     DWORD bytes_ret = 0;\r
369     BOOL ret = DeviceIoControl( m_hSync, UAL_REG_MR,\r
370         &pMr->mr_ioctl.in, sizeof(pMr->mr_ioctl.in),\r
371         &pMr->mr_ioctl.out, sizeof(pMr->mr_ioctl.out),\r
372         &bytes_ret, NULL );\r
373     if( !ret )\r
374     {\r
375         CL_ASSERT( GetLastError() != ERROR_IO_PENDING );\r
376 \r
377         delete pMr;\r
378         return ND_UNSUCCESSFUL;\r
379     }\r
380     if( bytes_ret != sizeof(pMr->mr_ioctl.out) || \r
381         pMr->mr_ioctl.out.status != IB_SUCCESS )\r
382     {\r
383         delete pMr;\r
384         return ND_UNSUCCESSFUL;\r
385     }\r
386 \r
387     //\r
388     // The registration succeeded.  Now issue the user's IOCTL.\r
389     //\r
390     pOverlapped->Internal = ND_PENDING;\r
391     HRESULT hr = NtDeviceIoControlFile(\r
392         m_hAsync,\r
393         pOverlapped->hEvent,\r
394         NULL,\r
395         (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped,\r
396         (IO_STATUS_BLOCK*)&pOverlapped->Internal,\r
397         UAL_NDI_NOOP,\r
398         NULL,\r
399         0,\r
400         NULL,\r
401         0 );\r
402 \r
403     if( hr != ND_PENDING && hr != ND_SUCCESS )\r
404     {\r
405         delete pMr;\r
406         return hr;\r
407     }\r
408 \r
409     AddRef();\r
410     return ND_SUCCESS;\r
411 }\r
412 \r
413 HRESULT CAdapter::DeregisterMemory(\r
414     __in ND_MR_HANDLE hMr,\r
415     __inout OVERLAPPED* pOverlapped\r
416     )\r
417 {\r
418     ND_ENTER( ND_DBG_NDI );\r
419 \r
420     CMr* pMr = (CMr*)hMr;\r
421 \r
422     //\r
423     // We must issue the IOCTL on the synchronous file handle.\r
424     // If the user bound the async file handle to an I/O completion port\r
425     // DeviceIoControl could succeed, but not return data, so the MR\r
426     // wouldn't be updated.\r
427     //\r
428     // We use a second IOCTL to complet the user's overlapped.\r
429     //\r
430     DWORD bytes_ret = 0;\r
431     BOOL ret = DeviceIoControl( m_hSync, UAL_DEREG_MR,\r
432         &pMr->mr_ioctl.out.h_mr, sizeof(pMr->mr_ioctl.out.h_mr),\r
433         &pMr->mr_ioctl.out.status, sizeof(pMr->mr_ioctl.out.status),\r
434         &bytes_ret, NULL );\r
435     if( !ret )\r
436     {\r
437         CL_ASSERT( GetLastError() != ERROR_IO_PENDING );\r
438         pMr->mr_ioctl.out.status = IB_ERROR;\r
439     }\r
440     if( bytes_ret != sizeof(pMr->mr_ioctl.out.status) )\r
441         return ND_UNSUCCESSFUL;\r
442 \r
443     switch( pMr->mr_ioctl.out.status )\r
444     {\r
445     case IB_SUCCESS:\r
446         {\r
447         delete pMr;\r
448         Release();\r
449 \r
450         //\r
451         // The deregistration succeeded.  Now issue the user's IOCTL.\r
452         //\r
453         pOverlapped->Internal = ND_PENDING;\r
454         HRESULT hr = NtDeviceIoControlFile(\r
455             m_hAsync,\r
456             pOverlapped->hEvent,\r
457             NULL,\r
458             (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped,\r
459             (IO_STATUS_BLOCK*)&pOverlapped->Internal,\r
460             UAL_NDI_NOOP,\r
461             NULL,\r
462             0,\r
463             NULL,\r
464             0 );\r
465         CL_ASSERT( SUCCEEDED( hr ) );\r
466         return hr;\r
467         }\r
468     case IB_RESOURCE_BUSY:\r
469         return ND_DEVICE_BUSY;\r
470 \r
471     default:\r
472         return ND_UNSUCCESSFUL;\r
473     }\r
474 }\r
475 \r
476 HRESULT CAdapter::CreateMemoryWindow(\r
477     __out ND_RESULT* pInvalidateResult,\r
478     __deref_out INDMemoryWindow** ppMw\r
479     )\r
480 {\r
481     ND_ENTER( ND_DBG_NDI );\r
482 \r
483     CMw* pMw = new CMw();\r
484     if( pMw == NULL )\r
485         return ND_NO_MEMORY;\r
486 \r
487     HRESULT hr = pMw->Initialize( this, pInvalidateResult );\r
488     if( FAILED(hr) )\r
489     {\r
490         delete pMw;\r
491         return hr;\r
492     }\r
493 \r
494     *ppMw = pMw;\r
495     return S_OK;\r
496 }\r
497 \r
498 HRESULT CAdapter::CreateConnector(\r
499     __deref_out INDConnector** ppConnector\r
500     )\r
501 {\r
502     ND_ENTER( ND_DBG_NDI );\r
503 \r
504     return CConnector::Create( this, ppConnector );\r
505 }\r
506 \r
507 HRESULT CAdapter::Listen(\r
508     __in SIZE_T Backlog,\r
509     __in INT Protocol,\r
510     __in USHORT Port,\r
511     __out_opt USHORT* pAssignedPort,\r
512     __deref_out INDListen** ppListen\r
513     )\r
514 {\r
515     ND_ENTER( ND_DBG_NDI );\r
516 \r
517     return CListen::Create(\r
518         this,\r
519         Backlog,\r
520         Protocol,\r
521         Port,\r
522         pAssignedPort,\r
523         ppListen\r
524         );\r
525 }\r
526 \r
527 HRESULT CAdapter::GetLocalAddress(\r
528     __out_bcount_part(*pAddressLength, *pAddressLength) struct sockaddr *pAddr,\r
529     __inout SIZE_T *pAddressLength )\r
530 {\r
531     ND_ENTER( ND_DBG_NDI );\r
532 \r
533     switch( m_Addr.v4.sin_family )\r
534     {\r
535     case AF_INET:\r
536         if( *pAddressLength < sizeof(struct sockaddr_in) )\r
537         {\r
538             *pAddressLength = sizeof(struct sockaddr_in);\r
539             return ND_BUFFER_OVERFLOW;\r
540         }\r
541         *(struct sockaddr_in*)pAddr = m_Addr.v4;\r
542         ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI,\r
543             ("Local address: IP %#x, port %#hx\n", \r
544             cl_hton32(m_Addr.v4.sin_addr.S_un.S_addr), cl_hton16(m_Addr.v4.sin_port) ) );\r
545         return S_OK;\r
546 \r
547     case AF_INET6:\r
548         if( *pAddressLength < sizeof(struct sockaddr_in6) )\r
549         {\r
550             *pAddressLength = sizeof(struct sockaddr_in6);\r
551             return ND_BUFFER_OVERFLOW;\r
552         }\r
553         *(struct sockaddr_in6*)pAddr = m_Addr.v6;\r
554         return S_OK;\r
555 \r
556     default:\r
557         return ND_INVALID_ADDRESS;\r
558     }\r
559 }\r
560 \r
561 HRESULT CAdapter::OpenFiles(void)\r
562 {\r
563     ND_ENTER( ND_DBG_NDI );\r
564 \r
565     /* First open the kernel device. */\r
566     CL_ASSERT( m_hSync == INVALID_HANDLE_VALUE );\r
567     m_hSync = CreateFile(\r
568         "\\\\.\\ibal",\r
569         GENERIC_READ | GENERIC_WRITE,\r
570         FILE_SHARE_READ | FILE_SHARE_WRITE,\r
571         NULL,\r
572         OPEN_EXISTING,\r
573         0,\r
574         NULL\r
575         );\r
576     if( m_hSync == INVALID_HANDLE_VALUE )\r
577         return ND_UNSUCCESSFUL;\r
578 \r
579     // Now issue the BIND IOCTL which associates us as a client.\r
580     ULONG ver = AL_IOCTL_VERSION;\r
581     DWORD BytesRet;\r
582     BOOL fSuccess = DeviceIoControl(\r
583         m_hSync,\r
584         UAL_BIND,\r
585         &ver,\r
586         sizeof(ver),\r
587         NULL,\r
588         0,\r
589         &BytesRet,\r
590         NULL\r
591         );\r
592     if( fSuccess != TRUE )\r
593         return ND_UNSUCCESSFUL;\r
594 \r
595     // Now create the async file.\r
596     m_hAsync = CreateFile(\r
597         "\\\\.\\ibal",\r
598         GENERIC_READ | GENERIC_WRITE,\r
599         FILE_SHARE_READ | FILE_SHARE_WRITE,\r
600         NULL,\r
601         OPEN_EXISTING,\r
602         FILE_FLAG_OVERLAPPED,\r
603         NULL\r
604         );\r
605     if( m_hAsync == INVALID_HANDLE_VALUE )\r
606         return ND_UNSUCCESSFUL;\r
607 \r
608     /*\r
609      * Send an IOCTL down on the main file handle to bind this file\r
610      * handle with our proxy context.\r
611      */\r
612     UINT64 hFile = (ULONG_PTR)m_hAsync;\r
613     fSuccess = DeviceIoControl(\r
614         m_hSync,\r
615         UAL_BIND_ND,\r
616         &hFile,\r
617         sizeof(hFile),\r
618         NULL,\r
619         0,\r
620         &BytesRet,\r
621         NULL\r
622         );\r
623     if( fSuccess != TRUE )\r
624         return ND_UNSUCCESSFUL;\r
625 \r
626     return S_OK;\r
627 }\r
628 \r
629 HRESULT CAdapter::OpenCa(\r
630     __in UINT64 CaGuid )\r
631 {\r
632     ND_ENTER( ND_DBG_NDI );\r
633 \r
634     ual_get_uvp_name_ioctl_t    al_ioctl;\r
635 \r
636     /* Initialize assuming no user-mode support */\r
637     cl_memclr( &al_ioctl, sizeof(al_ioctl) );\r
638     cl_memclr( &m_Ifc, sizeof(m_Ifc) );\r
639 \r
640     /* init with the guid */\r
641     m_Ifc.guid = CaGuid;\r
642 \r
643     DWORD BytesRet;\r
644     BOOL fSuccess = DeviceIoControl(\r
645         m_hSync,\r
646         UAL_GET_VENDOR_LIBCFG,\r
647         &CaGuid, sizeof(CaGuid),\r
648         &al_ioctl.out, sizeof(al_ioctl.out),\r
649         &BytesRet,\r
650         NULL\r
651         );\r
652 \r
653     if( fSuccess != TRUE || BytesRet != sizeof(al_ioctl.out) )\r
654         return ND_INSUFFICIENT_RESOURCES;\r
655 \r
656     if( !strlen( al_ioctl.out.uvp_lib_name ) )\r
657     {\r
658         /* Vendor does not implement user-mode library */\r
659         return ND_NOT_SUPPORTED;\r
660     }\r
661 \r
662     /*\r
663      * The vendor supports a user-mode library\r
664      * open the library and get the interfaces supported\r
665      */\r
666 #if DBG\r
667     HRESULT hr = StringCbCatA( al_ioctl.out.uvp_lib_name, 32, "d.dll" );\r
668 #else\r
669     HRESULT hr = StringCbCatA( al_ioctl.out.uvp_lib_name, 32, ".dll" );\r
670 #endif\r
671     if( FAILED( hr ) )\r
672         return ND_NOT_SUPPORTED;\r
673 \r
674     m_Ifc.h_uvp_lib = LoadLibrary( al_ioctl.out.uvp_lib_name );\r
675     if( m_Ifc.h_uvp_lib == NULL )\r
676         return ND_NOT_SUPPORTED;\r
677 \r
678     uvp_get_interface_t pfn_uvp_ifc = (uvp_get_interface_t)GetProcAddress(\r
679         m_Ifc.h_uvp_lib,\r
680         "uvp_get_interface"\r
681         );\r
682 \r
683     if( pfn_uvp_ifc == NULL )\r
684         return ND_NOT_SUPPORTED;\r
685 \r
686     /* Query the vendor-supported user-mode functions */\r
687     pfn_uvp_ifc( IID_UVP, &m_Ifc.user_verbs );\r
688 \r
689     ual_open_ca_ioctl_t ca_ioctl;\r
690     cl_memclr( &ca_ioctl, sizeof(ca_ioctl) );\r
691 \r
692     /* Pre call to the UVP library */\r
693     ib_api_status_t status = IB_ERROR;\r
694     if( m_Ifc.user_verbs.pre_open_ca )\r
695     {\r
696         status = m_Ifc.user_verbs.pre_open_ca(\r
697             CaGuid,\r
698             &ca_ioctl.in.umv_buf,\r
699             (ib_ca_handle_t*)(ULONG_PTR)&m_uCa\r
700             );\r
701         if( status != IB_SUCCESS )\r
702         {\r
703             CL_ASSERT( status != IB_VERBS_PROCESSING_DONE );\r
704             return ND_INSUFFICIENT_RESOURCES;\r
705         }\r
706     }\r
707 \r
708     ca_ioctl.in.guid = CaGuid;\r
709     ca_ioctl.in.context = (ULONG_PTR)this;\r
710 \r
711     fSuccess = DeviceIoControl(\r
712         m_hSync,\r
713         UAL_OPEN_CA,\r
714         &ca_ioctl.in,\r
715         sizeof(ca_ioctl.in),\r
716         &ca_ioctl.out,\r
717         sizeof(ca_ioctl.out),\r
718         &BytesRet,\r
719         NULL\r
720         );\r
721 \r
722     if( fSuccess != TRUE || BytesRet != sizeof(ca_ioctl.out) )\r
723     {\r
724         status = IB_ERROR;\r
725     }\r
726     else\r
727     {\r
728         status = ca_ioctl.out.status;\r
729         m_hCa = ca_ioctl.out.h_ca;\r
730     }\r
731 \r
732     /* Post uvp call */\r
733     if( m_Ifc.user_verbs.post_open_ca )\r
734     {\r
735         status = m_Ifc.user_verbs.post_open_ca(\r
736             CaGuid,\r
737             status,\r
738             (ib_ca_handle_t*)(ULONG_PTR)&m_uCa,\r
739             &ca_ioctl.out.umv_buf );\r
740     }\r
741 \r
742     // TODO: Does the UVP need a query call to succeed?\r
743     // IBAL always does this internally.\r
744 \r
745     return (status == IB_SUCCESS? S_OK : ND_INSUFFICIENT_RESOURCES );\r
746 }\r
747 \r
748 HRESULT CAdapter::QueryCa(\r
749         __out_bcount(*pSize) ib_ca_attr_t* pAttr,\r
750         __inout DWORD* pSize )\r
751 {\r
752     ND_ENTER( ND_DBG_NDI );\r
753 \r
754     ual_query_ca_ioctl_t ca_ioctl;\r
755 \r
756     cl_memclr( &ca_ioctl, sizeof(ca_ioctl) );\r
757 \r
758     ca_ioctl.in.h_ca = m_hCa;\r
759     ca_ioctl.in.p_ca_attr = (ULONG_PTR)pAttr;\r
760     ca_ioctl.in.byte_cnt = *pSize;\r
761 \r
762     /* Call the uvp pre call if the vendor library provided a valid ca handle */\r
763     ib_api_status_t status;\r
764     if( m_uCa && m_Ifc.user_verbs.pre_query_ca )\r
765     {\r
766         /* Pre call to the UVP library */\r
767         status = m_Ifc.user_verbs.pre_query_ca(\r
768             m_uCa, pAttr, *pSize, &ca_ioctl.in.umv_buf );\r
769         if( status != IB_SUCCESS )\r
770             return ND_UNSUCCESSFUL;\r
771     }\r
772 \r
773     DWORD BytesRet;\r
774     BOOL fSuccess = DeviceIoControl(\r
775         m_hSync,\r
776         UAL_QUERY_CA,\r
777         &ca_ioctl.in,\r
778         sizeof(ca_ioctl.in),\r
779         &ca_ioctl.out,\r
780         sizeof(ca_ioctl.out),\r
781         &BytesRet,\r
782         NULL\r
783         );\r
784     if( fSuccess != TRUE || BytesRet != sizeof(ca_ioctl.out) )\r
785     {\r
786         status = IB_ERROR;\r
787     }\r
788     else\r
789     {\r
790         *pSize = ca_ioctl.out.byte_cnt;\r
791         status = ca_ioctl.out.status;\r
792     }\r
793 \r
794     /* The attributes, if any, will be directly copied by proxy */\r
795     /* Post uvp call */\r
796     if( m_uCa && m_Ifc.user_verbs.post_query_ca )\r
797     {\r
798         m_Ifc.user_verbs.post_query_ca( m_uCa,\r
799             status, pAttr, ca_ioctl.out.byte_cnt, &ca_ioctl.out.umv_buf );\r
800     }\r
801 \r
802     switch( status )\r
803     {\r
804     case IB_SUCCESS:\r
805         return S_OK;\r
806     case IB_INSUFFICIENT_MEMORY:\r
807         return ND_BUFFER_OVERFLOW;\r
808     default:\r
809         return ND_INSUFFICIENT_RESOURCES;\r
810     }\r
811 }\r
812 \r
813 void CAdapter::CloseCa(void)\r
814 {\r
815     ND_ENTER( ND_DBG_NDI );\r
816 \r
817     ib_api_status_t status;\r
818 \r
819     /* Call the uvp pre call if the vendor library provided a valid ca handle */\r
820     if( m_uCa && m_Ifc.user_verbs.pre_close_ca )\r
821     {\r
822         /* Pre call to the UVP library */\r
823         status = m_Ifc.user_verbs.pre_close_ca( m_uCa );\r
824         if( status != IB_SUCCESS )\r
825             return;\r
826     }\r
827 \r
828     DWORD BytesRet;\r
829     BOOL fSuccess = DeviceIoControl(\r
830         m_hSync,\r
831         UAL_CLOSE_CA,\r
832         &m_hCa,\r
833         sizeof(m_hCa),\r
834         &status,\r
835         sizeof(status),\r
836         &BytesRet,\r
837         NULL\r
838         );\r
839 \r
840     if( fSuccess != TRUE || BytesRet != sizeof(status) )\r
841         status = IB_ERROR;\r
842 \r
843     if( m_uCa && m_Ifc.user_verbs.post_close_ca )\r
844         m_Ifc.user_verbs.post_close_ca( m_uCa, status );\r
845 \r
846     if( m_Ifc.h_uvp_lib )\r
847         FreeLibrary( m_Ifc.h_uvp_lib );\r
848 \r
849     m_hCa = 0;\r
850 }\r
851 \r
852 HRESULT CAdapter::AllocPd(void)\r
853 {\r
854     ND_ENTER( ND_DBG_NDI );\r
855 \r
856     /* Clear the pd_ioctl */\r
857     ual_alloc_pd_ioctl_t pd_ioctl;\r
858     cl_memclr( &pd_ioctl, sizeof(pd_ioctl) );\r
859 \r
860     /* Pre call to the UVP library */\r
861     ib_api_status_t status;\r
862     if( m_uCa && m_Ifc.user_verbs.pre_allocate_pd )\r
863     {\r
864         status = m_Ifc.user_verbs.pre_allocate_pd(\r
865             m_uCa,\r
866             &pd_ioctl.in.umv_buf,\r
867             (ib_pd_handle_t*)(ULONG_PTR)&m_uPd\r
868             );\r
869         if( status != IB_SUCCESS )\r
870             return ND_INSUFFICIENT_RESOURCES;\r
871     }\r
872 \r
873     pd_ioctl.in.h_ca = m_hCa;\r
874     pd_ioctl.in.type = IB_PDT_NORMAL;\r
875     pd_ioctl.in.context = (ULONG_PTR)this;\r
876 \r
877     DWORD BytesRet;\r
878     BOOL fSuccess = DeviceIoControl(\r
879         m_hSync,\r
880         UAL_ALLOC_PD,\r
881         &pd_ioctl.in,\r
882         sizeof(pd_ioctl.in),\r
883         &pd_ioctl.out,\r
884         sizeof(pd_ioctl.out),\r
885         &BytesRet,\r
886         NULL\r
887         );\r
888 \r
889     if( fSuccess != TRUE || BytesRet != sizeof(pd_ioctl.out) )\r
890     {\r
891         status = IB_ERROR;\r
892     }\r
893     else\r
894     {\r
895         status = pd_ioctl.out.status;\r
896         if( pd_ioctl.out.status == IB_SUCCESS )\r
897             m_hPd = pd_ioctl.out.h_pd;\r
898     }\r
899 \r
900     /* Post uvp call */\r
901     if( m_uCa && m_Ifc.user_verbs.post_allocate_pd )\r
902     {\r
903         m_Ifc.user_verbs.post_allocate_pd(\r
904             m_uCa,\r
905             status,\r
906             (ib_pd_handle_t*)(ULONG_PTR)&m_uPd,\r
907             &pd_ioctl.out.umv_buf );\r
908     }\r
909 \r
910     return (status == IB_SUCCESS? S_OK : ND_INSUFFICIENT_RESOURCES);\r
911 }\r
912 \r
913 void CAdapter::DeallocPd(void)\r
914 {\r
915     ND_ENTER( ND_DBG_NDI );\r
916 \r
917     ib_api_status_t                     status;\r
918 \r
919     /* Call the uvp pre call if the vendor library provided a valid ca handle */\r
920     if( m_uPd && m_Ifc.user_verbs.pre_deallocate_pd )\r
921     {\r
922         /* Pre call to the UVP library */\r
923         status = m_Ifc.user_verbs.pre_deallocate_pd( m_uPd );\r
924         if( status != IB_SUCCESS )\r
925             return;\r
926     }\r
927 \r
928     DWORD BytesRet;\r
929     BOOL fSuccess = DeviceIoControl(\r
930         m_hSync,\r
931         UAL_DEALLOC_PD,\r
932         &m_hPd,\r
933         sizeof(m_hPd),\r
934         &status,\r
935         sizeof(status),\r
936         &BytesRet,\r
937         NULL\r
938         );\r
939 \r
940     if( fSuccess == FALSE || BytesRet != sizeof(status) )\r
941         status = IB_ERROR;\r
942 \r
943     /* Call vendor's post_close ca */\r
944     if( m_uPd && m_Ifc.user_verbs.post_deallocate_pd )\r
945         m_Ifc.user_verbs.post_deallocate_pd( m_uPd, status );\r
946 \r
947     m_hPd = 0;\r
948 }\r
949 \r
950 } // namespace\r