Remove stale HPC Pack 2008 Beta 1 objects
[mirror/winof/.git] / ulp / nd / user / NdCq.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 "al_cq.h"\r
35 #include "al_dev.h"\r
36 #include "al.h"\r
37 #include "al_verbs.h"\r
38 #pragma warning( push, 3 )\r
39 #include "winternl.h"\r
40 #pragma warning( pop )\r
41 #include "limits.h"\r
42 #include "nddebug.h"\r
43 \r
44 #if defined(EVENT_TRACING)\r
45 #ifdef offsetof\r
46 #undef offsetof\r
47 #endif\r
48 #include "NdCq.tmh"\r
49 #endif\r
50 \r
51 \r
52 namespace NetworkDirect\r
53 {\r
54 \r
55     CCq::CCq(void) :\r
56         m_nRef( 1 ),\r
57         m_pParent( NULL ),\r
58         m_hCq( 0 ),\r
59         m_uCq( NULL )\r
60     {\r
61     }\r
62 \r
63     CCq::~CCq(void)\r
64     {\r
65         if( m_hCq )\r
66             CloseCq();\r
67 \r
68         if( m_pParent )\r
69             m_pParent->Release();\r
70     }\r
71 \r
72     HRESULT CCq::Initialize(\r
73         CAdapter* pParent,\r
74         SIZE_T nEntries )\r
75     {\r
76         if( nEntries > UINT_MAX )\r
77             return ND_INVALID_PARAMETER;\r
78 \r
79         m_pParent = pParent;\r
80         pParent->AddRef();\r
81 \r
82         return CreateCq( (UINT32)nEntries );\r
83     }\r
84 \r
85     HRESULT CCq::QueryInterface(\r
86         REFIID riid,\r
87         LPVOID FAR* ppvObj\r
88         )\r
89     {\r
90         if( IsEqualIID( riid, IID_IUnknown ) )\r
91         {\r
92             *ppvObj = this;\r
93             return S_OK;\r
94         }\r
95 \r
96         if( IsEqualIID( riid, IID_INDCompletionQueue ) )\r
97         {\r
98             *ppvObj = this;\r
99             return S_OK;\r
100         }\r
101 \r
102         return E_NOINTERFACE;\r
103     }\r
104 \r
105     ULONG CCq::AddRef(void)\r
106     {\r
107         return InterlockedIncrement( &m_nRef );\r
108     }\r
109 \r
110     ULONG CCq::Release(void)\r
111     {\r
112         ULONG ref = InterlockedDecrement( &m_nRef );\r
113         if( ref == 0 )\r
114             delete this;\r
115 \r
116         return ref;\r
117     }\r
118 \r
119     // *** INDOverlapped methods ***\r
120     HRESULT CCq::CancelOverlappedRequests(void)\r
121     {\r
122         ND_ENTER( ND_DBG_NDI );\r
123 \r
124         DWORD BytesRet;\r
125         DeviceIoControl(\r
126             m_pParent->m_hSync,\r
127             UAL_NDI_CANCEL_CQ,\r
128             &m_hCq,\r
129             sizeof(m_hCq),\r
130             NULL,\r
131             0,\r
132             &BytesRet,\r
133             NULL\r
134             );\r
135 \r
136         return S_OK;\r
137     }\r
138 \r
139     HRESULT CCq::GetOverlappedResult(\r
140         __inout OVERLAPPED *pOverlapped,\r
141         __out SIZE_T *pNumberOfBytesTransferred,\r
142         __in BOOL bWait\r
143         )\r
144     {\r
145         ND_ENTER( ND_DBG_NDI );\r
146 \r
147         *pNumberOfBytesTransferred = 0;\r
148         ::GetOverlappedResult(\r
149             m_pParent->GetFileHandle(),\r
150             pOverlapped,\r
151             (DWORD*)pNumberOfBytesTransferred,\r
152             bWait );\r
153         ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI,\r
154             ("==> %s, result %#x, bytes %d\n", __FUNCTION__, (int)pOverlapped->Internal, (int)*pNumberOfBytesTransferred ));\r
155         return (HRESULT)pOverlapped->Internal;\r
156     }\r
157 \r
158     // *** INDCompletionQueue methods ***\r
159     HRESULT CCq::Resize(\r
160         __in SIZE_T nEntries\r
161         )\r
162     {\r
163         ND_ENTER( ND_DBG_NDI );\r
164 \r
165         if( nEntries > UINT_MAX )\r
166             return ND_INVALID_PARAMETER;\r
167 \r
168         ib_api_status_t                 status;\r
169 \r
170         /* Clear the IOCTL buffer */\r
171         ual_modify_cq_ioctl_t   cq_ioctl;\r
172         cl_memclr( &cq_ioctl, sizeof(cq_ioctl) );\r
173 \r
174         /* Call the uvp pre call if the vendor library provided a valid ca handle */\r
175         if( m_uCq && m_pParent->m_Ifc.user_verbs.pre_resize_cq )\r
176         {\r
177             /* Pre call to the UVP library */\r
178             status = m_pParent->m_Ifc.user_verbs.pre_resize_cq(\r
179                 m_uCq, (uint32_t*)&nEntries, &cq_ioctl.in.umv_buf );\r
180             if( status != IB_SUCCESS )\r
181                 goto exit;\r
182         }\r
183 \r
184         cq_ioctl.in.h_cq = m_hCq;\r
185         cq_ioctl.in.size = (DWORD)nEntries;\r
186 \r
187         DWORD BytesRet;\r
188         BOOL fSuccess = DeviceIoControl(\r
189             m_pParent->m_hSync,\r
190             UAL_MODIFY_CQ,\r
191             &cq_ioctl.in,\r
192             sizeof(cq_ioctl.in),\r
193             &cq_ioctl.out,\r
194             sizeof(cq_ioctl.out),\r
195             &BytesRet,\r
196             NULL\r
197             );\r
198 \r
199         if( fSuccess != TRUE || BytesRet != sizeof(cq_ioctl.out) )\r
200             status = IB_ERROR;\r
201         else\r
202             status = cq_ioctl.out.status;\r
203 \r
204         /* Post uvp call */\r
205         if( m_uCq && m_pParent->m_Ifc.user_verbs.post_resize_cq )\r
206         {\r
207             m_pParent->m_Ifc.user_verbs.post_resize_cq(\r
208                 m_uCq, status, cq_ioctl.out.size, &cq_ioctl.out.umv_buf );\r
209         }\r
210 \r
211 exit:\r
212         switch( status )\r
213         {\r
214         case IB_INVALID_CQ_SIZE:\r
215             return ND_INVALID_PARAMETER;\r
216 \r
217         case IB_SUCCESS:\r
218             return S_OK;\r
219 \r
220         case IB_INSUFFICIENT_RESOURCES:\r
221             return ND_INSUFFICIENT_RESOURCES;\r
222 \r
223         default:\r
224             return ND_UNSUCCESSFUL;\r
225         }\r
226     }\r
227 \r
228     HRESULT CCq::Notify(\r
229         __in DWORD Type,\r
230         __inout OVERLAPPED* pOverlapped\r
231         )\r
232     {\r
233 //        ND_ENTER( ND_DBG_NDI );\r
234 \r
235         ual_ndi_notify_cq_ioctl_in_t ioctl;\r
236         ioctl.h_cq = m_hCq;\r
237         ioctl.notify_comps = (boolean_t)Type;\r
238         pOverlapped->Internal = ND_PENDING;\r
239         HRESULT hr = NtDeviceIoControlFile(\r
240             m_pParent->GetFileHandle(),\r
241             pOverlapped->hEvent,\r
242             NULL,\r
243             (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped,\r
244             (IO_STATUS_BLOCK*)&pOverlapped->Internal,\r
245             UAL_NDI_NOTIFY_CQ,\r
246             &ioctl,\r
247             sizeof(ioctl),\r
248             NULL,\r
249             0 );\r
250 \r
251         if( hr == ND_PENDING && Type != ND_CQ_NOTIFY_ERRORS )\r
252         {\r
253             m_pParent->m_Ifc.user_verbs.rearm_cq(\r
254                 m_uCq,\r
255                 (Type == ND_CQ_NOTIFY_SOLICITED) ? TRUE : FALSE\r
256                 );\r
257             ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI,\r
258                 ("==> %s, rearming with Type %d\n", __FUNCTION__, Type));\r
259         }\r
260         else\r
261         {\r
262             ND_PRINT( TRACE_LEVEL_ERROR, ND_DBG_NDI,\r
263                 ("==> %s failed: hr %#x, notify_type %d \n", __FUNCTION__, hr, Type ));\r
264         }\r
265         return hr;\r
266     }\r
267 \r
268     SIZE_T CCq::GetResults(\r
269         __out_ecount(nResults) ND_RESULT* pResults[],\r
270         __in SIZE_T nResults\r
271         )\r
272     {\r
273 #if DBG    \r
274         if (!(++g.c_cnt % 100000000))        //  || !(rcv_pkts % 1000) || !(snd_pkts % 1000)\r
275             ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI,\r
276                 ("==> %s, cnt %I64d, rcv: %I64d:%I64d:%I64d, snd %I64d:%I64d:%I64d\n", \r
277                 __FUNCTION__, g.c_cnt, \r
278                 g.c_rcv_pkts, g.c_rcv_bytes, g.c_rcv_pkts_err,\r
279                 g.c_snd_pkts, g.c_snd_bytes, g.c_snd_pkts_err));\r
280 #endif                \r
281         SIZE_T i = 0;\r
282 \r
283         while( nResults-- )\r
284         {\r
285             ib_wc_t wc;\r
286             ib_wc_t* pWc = &wc;\r
287             ib_wc_t* pDoneWc;\r
288             wc.p_next = NULL;\r
289             ib_api_status_t status =\r
290                 m_pParent->m_Ifc.user_verbs.poll_cq( m_uCq, &pWc, &pDoneWc );\r
291 \r
292             if( status != IB_SUCCESS )\r
293                 break;\r
294 \r
295             pResults[i] = (ND_RESULT*)wc.wr_id;\r
296             if( wc.wc_type == IB_WC_RECV )\r
297                 pResults[i]->BytesTransferred = wc.length;\r
298 \r
299             if( wc.recv.conn.recv_opt & IB_RECV_OPT_IMMEDIATE )\r
300             {\r
301                 // Emulated receive with invalidate - the immediate\r
302                 // data holds the RKey that is supposed to be invalidated.\r
303 \r
304                 //TODO: We need the QP handle (or context) so we can force an\r
305                 // error if we don't find a matching MW for the given RKEY.\r
306                 // We also need to change the receive status in this case to\r
307                 // ND_INVALIDATION_ERROR;\r
308             }\r
309 \r
310             switch( wc.status )\r
311             {\r
312             case IB_WCS_SUCCESS:\r
313                 pResults[i]->Status = ND_SUCCESS;\r
314                 break;\r
315             case IB_WCS_LOCAL_LEN_ERR:\r
316                 pResults[i]->Status = ND_LOCAL_LENGTH;\r
317                 break;\r
318             case IB_WCS_LOCAL_OP_ERR:\r
319             case IB_WCS_LOCAL_ACCESS_ERR:\r
320             case IB_WCS_GENERAL_ERR:\r
321             default:\r
322                 pResults[i]->Status = ND_INTERNAL_ERROR;\r
323                 break;\r
324             case IB_WCS_LOCAL_PROTECTION_ERR:\r
325             case IB_WCS_MEM_WINDOW_BIND_ERR:\r
326                 pResults[i]->Status = ND_ACCESS_VIOLATION;\r
327                 break;\r
328             case IB_WCS_WR_FLUSHED_ERR:\r
329                 pResults[i]->Status = ND_CANCELED;\r
330                 break;\r
331             case IB_WCS_REM_INVALID_REQ_ERR:\r
332                 pResults[i]->Status = ND_BUFFER_OVERFLOW;\r
333                 break;\r
334             case IB_WCS_REM_ACCESS_ERR:\r
335             case IB_WCS_REM_OP_ERR:\r
336             case IB_WCS_BAD_RESP_ERR:\r
337                 pResults[i]->Status = ND_REMOTE_ERROR;\r
338                 break;\r
339             case IB_WCS_RNR_RETRY_ERR:\r
340             case IB_WCS_TIMEOUT_RETRY_ERR:\r
341                 pResults[i]->Status = ND_TIMEOUT;\r
342                 break;\r
343             }\r
344             i++;\r
345             // leo\r
346 #if DBG\r
347             {\r
348                 if (wc.wc_type == IB_WC_RECV)\r
349                 {    \r
350                     if (!wc.status)\r
351                     {\r
352                         ++g.c_rcv_pkts;\r
353                         g.c_rcv_bytes += wc.length;\r
354                     }\r
355                     else\r
356                         ++g.c_rcv_pkts_err;\r
357                 }\r
358                 else\r
359                 {    \r
360                     if (!wc.status)\r
361                     {\r
362                         ++g.c_snd_pkts;\r
363                         g.c_snd_bytes += wc.length;\r
364                     }\r
365                     else\r
366                         ++g.c_snd_pkts_err;\r
367                 }\r
368             }\r
369 #endif\r
370             continue;\r
371         }\r
372         return i;\r
373     }\r
374 \r
375     HRESULT CCq::CreateCq(\r
376         __in UINT32 nEntries )\r
377     {\r
378         ND_ENTER( ND_DBG_NDI );\r
379 \r
380         /* Clear the IOCTL buffer */\r
381         ual_create_cq_ioctl_t cq_ioctl;\r
382         cl_memclr( &cq_ioctl, sizeof(cq_ioctl) );\r
383 \r
384         /* Pre call to the UVP library */\r
385         ib_api_status_t status;\r
386         if( m_pParent->m_uCa && m_pParent->m_Ifc.user_verbs.pre_create_cq )\r
387         {\r
388             status = m_pParent->m_Ifc.user_verbs.pre_create_cq(\r
389                 m_pParent->m_uCa,\r
390                 &nEntries,\r
391                 &cq_ioctl.in.umv_buf,\r
392                 (ib_cq_handle_t*)(ULONG_PTR)&m_uCq\r
393                 );\r
394             if( status != IB_SUCCESS )\r
395                 goto done;\r
396         }\r
397 \r
398         cq_ioctl.in.h_ca = m_pParent->m_hCa;\r
399         cq_ioctl.in.size = nEntries;\r
400         cq_ioctl.in.h_wait_obj = NULL;\r
401         cq_ioctl.in.context = (ULONG_PTR)this;\r
402         cq_ioctl.in.ev_notify = FALSE;\r
403 \r
404         DWORD BytesRet;\r
405         BOOL fSuccess = DeviceIoControl(\r
406             m_pParent->m_hSync,\r
407             UAL_NDI_CREATE_CQ,\r
408             &cq_ioctl.in,\r
409             sizeof(cq_ioctl.in),\r
410             &cq_ioctl.out,\r
411             sizeof(cq_ioctl.out),\r
412             &BytesRet,\r
413             NULL\r
414             );\r
415 \r
416         if( fSuccess != TRUE || BytesRet != sizeof(cq_ioctl.out) )\r
417             status = IB_ERROR;\r
418         else\r
419             status = cq_ioctl.out.status;\r
420 \r
421         m_hCq = cq_ioctl.out.h_cq;\r
422 \r
423         /* Post uvp call */\r
424         if( m_pParent->m_uCa && m_pParent->m_Ifc.user_verbs.post_create_cq )\r
425         {\r
426             m_pParent->m_Ifc.user_verbs.post_create_cq(\r
427                 m_pParent->m_uCa,\r
428                 status,\r
429                 cq_ioctl.out.size,\r
430                 (ib_cq_handle_t*)(ULONG_PTR)&m_uCq,\r
431                 &cq_ioctl.out.umv_buf );\r
432         }\r
433 \r
434 done:\r
435         switch( status )\r
436         {\r
437         case IB_INVALID_CQ_SIZE:\r
438             return ND_INVALID_PARAMETER;\r
439 \r
440         case IB_INSUFFICIENT_RESOURCES:\r
441             return ND_INSUFFICIENT_RESOURCES;\r
442 \r
443         case IB_INSUFFICIENT_MEMORY:\r
444             return ND_NO_MEMORY;\r
445 \r
446         case IB_SUCCESS:\r
447             return S_OK;\r
448 \r
449         default:\r
450             return ND_UNSUCCESSFUL;\r
451         }\r
452     }\r
453 \r
454     void CCq::CloseCq(void)\r
455     {\r
456         ND_ENTER( ND_DBG_NDI );\r
457 \r
458         ib_api_status_t                 status;\r
459 \r
460         if( m_uCq && m_pParent->m_Ifc.user_verbs.pre_destroy_cq )\r
461         {\r
462             /* Pre call to the UVP library */\r
463             status = m_pParent->m_Ifc.user_verbs.pre_destroy_cq( m_uCq );\r
464             if( status != IB_SUCCESS )\r
465                 return;\r
466         }\r
467 \r
468         DWORD BytesRet;\r
469         BOOL fSuccess = DeviceIoControl(\r
470             m_pParent->m_hSync,\r
471             UAL_DESTROY_CQ,\r
472             &m_hCq,\r
473             sizeof(m_hCq),\r
474             &status,\r
475             sizeof(status),\r
476             &BytesRet,\r
477             NULL\r
478             );\r
479 \r
480         if( fSuccess != TRUE || BytesRet != sizeof(status) )\r
481             status = IB_ERROR;\r
482 \r
483         if( m_uCq && m_pParent->m_Ifc.user_verbs.post_destroy_cq )\r
484             m_pParent->m_Ifc.user_verbs.post_destroy_cq( m_uCq, status );\r
485     }\r
486 \r
487 } // namespace\r