[nd] Don't use inline for RDMA reads. (mlnx 5666)
[mirror/winof/.git] / ulp / nd / user / NdEndpoint.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 "NdEndpoint.h"\r
33 #include "NdCq.h"\r
34 #include "NdAdapter.h"\r
35 #include "NdMr.h"\r
36 #include "NdListen.h"\r
37 #include "limits.h"\r
38 #include "al_dev.h"\r
39 #pragma warning( push, 3 )\r
40 #include "winternl.h"\r
41 #pragma warning( pop )\r
42 #include "nddebug.h"\r
43 \r
44 extern uint32_t                 g_nd_max_inline_size;\r
45 \r
46 #if defined(EVENT_TRACING)\r
47 #ifdef offsetof\r
48 #undef offsetof\r
49 #endif\r
50 #include "NdEndpoint.tmh"\r
51 #endif\r
52 \r
53 #if DBG\r
54 dbg_data g = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };\r
55 #endif\r
56 \r
57 #ifndef SIZE_MAX\r
58 #ifdef _WIN64\r
59 #define SIZE_MAX _UI64_MAX\r
60 #else\r
61 #define SIZE_MAX UINT_MAX\r
62 #endif\r
63 #endif\r
64 \r
65 namespace NetworkDirect\r
66 {\r
67 \r
68 ///////////////////////////////////////////////////////////////////////////////\r
69 //\r
70 // HPC Pack 2008 Beta 2 SPI\r
71 //\r
72 ///////////////////////////////////////////////////////////////////////////////\r
73 \r
74 \r
75 CEndpoint::CEndpoint(void) :\r
76     m_nRef( 1 ),\r
77     m_pParent( NULL ),\r
78     m_hQp( 0 )\r
79 {\r
80 }\r
81 \r
82 CEndpoint::~CEndpoint(void)\r
83 {\r
84     if( m_hQp )\r
85         DestroyQp();\r
86 \r
87     if( m_pParent )\r
88         m_pParent->Release();\r
89 }\r
90 \r
91 HRESULT CEndpoint::Initialize(\r
92     __in CAdapter* pParent,\r
93     __in CCq* pInboundCq,\r
94     __in CCq* pOutboundCq,\r
95     __in SIZE_T nInboundEntries,\r
96     __in SIZE_T nOutboundEntries,\r
97     __in SIZE_T nInboundSge,\r
98     __in SIZE_T nOutboundSge,\r
99     __in SIZE_T InboundReadLimit,\r
100     __in SIZE_T OutboundReadLimit,\r
101     __out_opt SIZE_T* pMaxInlineData\r
102     )\r
103 {\r
104     ND_ENTER( ND_DBG_NDI );\r
105 \r
106     if( InboundReadLimit > UCHAR_MAX )\r
107         return ND_INVALID_PARAMETER_8;\r
108 \r
109     if( OutboundReadLimit > UCHAR_MAX )\r
110         return ND_INVALID_PARAMETER_9;\r
111 \r
112     m_pParent = pParent;\r
113     m_pParent->AddRef();\r
114 \r
115     CL_ASSERT(\r
116         m_pParent->m_Ifc.user_verbs.pre_create_qp != NULL ||\r
117         m_pParent->m_Ifc.user_verbs.post_create_qp != NULL ||\r
118         m_pParent->m_Ifc.user_verbs.nd_modify_qp != NULL ||\r
119         m_pParent->m_Ifc.user_verbs.nd_get_qp_state != NULL ||\r
120         m_pParent->m_Ifc.user_verbs.pre_destroy_qp != NULL ||\r
121         m_pParent->m_Ifc.user_verbs.post_destroy_qp != NULL ||\r
122         m_pParent->m_Ifc.user_verbs.post_query_qp != NULL ||\r
123         m_pParent->m_Ifc.user_verbs.post_send != NULL ||\r
124         m_pParent->m_Ifc.user_verbs.post_recv != NULL /*||\r
125         m_pParent->m_Ifc.user_verbs.bind_mw != NULL*/ );\r
126 \r
127         m_MaxInlineSize = g_nd_max_inline_size;\r
128                 \r
129     HRESULT hr = CreateQp(\r
130         pInboundCq,\r
131         pOutboundCq,\r
132         nInboundEntries,\r
133         nOutboundEntries,\r
134         nInboundSge,\r
135         nOutboundSge,\r
136         InboundReadLimit,\r
137         OutboundReadLimit,\r
138         m_MaxInlineSize );\r
139 \r
140     if( FAILED( hr ) )\r
141         return hr;\r
142 \r
143         ib_qp_attr_t qp_attr;\r
144         hr = QueryQp(&qp_attr);\r
145         if( FAILED( hr ) ) {\r
146                 DestroyQp();\r
147                 return hr;\r
148         }\r
149         else\r
150                 m_MaxInlineSize = (UINT32)qp_attr.sq_max_inline;\r
151         \r
152         \r
153     m_Ird = (UINT8)InboundReadLimit;\r
154     m_Ord = (UINT8)OutboundReadLimit;\r
155 \r
156     // Move the QP to the INIT state so users can post receives.\r
157     hr = ModifyQp( IB_QPS_INIT );\r
158     if( FAILED( hr ) )\r
159         DestroyQp();\r
160 \r
161     if( SUCCEEDED( hr ) && pMaxInlineData != NULL )\r
162         *pMaxInlineData = m_MaxInlineSize;\r
163 \r
164     return hr;\r
165 }\r
166 \r
167 HRESULT CEndpoint::Create(\r
168     __in CAdapter* pParent,\r
169     __in CCq* pInboundCq,\r
170     __in CCq* pOutboundCq,\r
171     __in SIZE_T nInboundEntries,\r
172     __in SIZE_T nOutboundEntries,\r
173     __in SIZE_T nInboundSge,\r
174     __in SIZE_T nOutboundSge,\r
175     __in SIZE_T InboundReadLimit,\r
176     __in SIZE_T OutboundReadLimit,\r
177     __out_opt SIZE_T* pMaxInlineData,\r
178     __out INDEndpoint** ppEndpoint\r
179     )\r
180 {\r
181     CEndpoint* pEp = new CEndpoint();\r
182     if( pEp == NULL )\r
183         return ND_NO_MEMORY;\r
184 \r
185     HRESULT hr = pEp->Initialize(\r
186         pParent,\r
187         pInboundCq,\r
188         pOutboundCq,\r
189         nInboundEntries,\r
190         nOutboundEntries,\r
191         nInboundSge,\r
192         nOutboundSge,\r
193         InboundReadLimit,\r
194         OutboundReadLimit,\r
195         pMaxInlineData\r
196         );\r
197 \r
198     if( FAILED( hr ) )\r
199     {\r
200         pEp->Release();\r
201         return hr;\r
202     }\r
203 \r
204     *ppEndpoint = pEp;\r
205     return ND_SUCCESS;\r
206 }\r
207 \r
208 HRESULT CEndpoint::QueryInterface(\r
209     REFIID riid,\r
210     LPVOID FAR* ppvObj\r
211     )\r
212 {\r
213     if( IsEqualIID( riid, IID_IUnknown ) )\r
214     {\r
215         *ppvObj = this;\r
216         return S_OK;\r
217     }\r
218 \r
219     if( IsEqualIID( riid, IID_INDEndpoint ) )\r
220     {\r
221         *ppvObj = this;\r
222         return S_OK;\r
223     }\r
224 \r
225     return E_NOINTERFACE;\r
226 }\r
227 \r
228 ULONG CEndpoint::AddRef(void)\r
229 {\r
230     return InterlockedIncrement( &m_nRef );\r
231 }\r
232 \r
233 ULONG CEndpoint::Release(void)\r
234 {\r
235     ULONG ref = InterlockedDecrement( &m_nRef );\r
236     if( ref == 0 )\r
237         delete this;\r
238 \r
239     return ref;\r
240 }\r
241 \r
242 // *** INDEndpoint methods ***\r
243 HRESULT CEndpoint::Flush(void)\r
244 {\r
245     return ModifyQp( IB_QPS_ERROR );\r
246 }\r
247 \r
248 void CEndpoint::StartRequestBatch(void)\r
249 {\r
250     return;\r
251 }\r
252 \r
253 void CEndpoint::SubmitRequestBatch(void)\r
254 {\r
255     return;\r
256 }\r
257 \r
258 HRESULT CEndpoint::Send(\r
259     __out ND_RESULT* pResult,\r
260     __in_ecount(nSge) const ND_SGE* pSgl,\r
261     __in SIZE_T nSge,\r
262     __in DWORD Flags\r
263     )\r
264 {\r
265     ib_send_wr_t wr;\r
266     ib_local_ds_t* pDs;\r
267     ib_local_ds_t ds[4];\r
268 \r
269     if( nSge > UINT_MAX )\r
270         return ND_DATA_OVERRUN;\r
271     else if( nSge <= 4 )\r
272         pDs = ds;\r
273     else\r
274     {\r
275         pDs = new ib_local_ds_t[nSge];\r
276         if( !pDs )\r
277             return ND_NO_MEMORY;\r
278     }\r
279 \r
280     pResult->BytesTransferred = 0;\r
281     for( SIZE_T i = 0; i < nSge; i++ )\r
282     {\r
283         pDs[i].vaddr = (ULONG_PTR)pSgl[i].pAddr;\r
284         if( pSgl[i].Length > UINT_MAX )\r
285         {\r
286             if( nSge > 4 )\r
287                 delete[] pDs;\r
288             return ND_BUFFER_OVERFLOW;\r
289         }\r
290         pDs[i].length = (uint32_t)pSgl[i].Length;\r
291         pDs[i].lkey = ((CMr*)pSgl[i].hMr)->mr_ioctl.out.lkey;\r
292 \r
293         // Send completions don't include the length.  It's going to\r
294         // be all or nothing, so store it now and we can reset if the\r
295         // request fails.\r
296         pResult->BytesTransferred += pSgl[i].Length;\r
297     }\r
298 \r
299     wr.p_next = NULL;\r
300     wr.wr_id = (ULONG_PTR)pResult;\r
301     wr.wr_type = WR_SEND;\r
302     if ( pResult->BytesTransferred <= m_MaxInlineSize )\r
303             wr.send_opt = IB_SEND_OPT_INLINE; \r
304         else\r
305             wr.send_opt = 0;\r
306     \r
307     if( !(Flags & ND_OP_FLAG_SILENT_SUCCESS) )\r
308         wr.send_opt |= IB_SEND_OPT_SIGNALED;\r
309     if( Flags & ND_OP_FLAG_READ_FENCE )\r
310         wr.send_opt |= IB_SEND_OPT_FENCE;\r
311     if( Flags & ND_OP_FLAG_SEND_AND_SOLICIT_EVENT )\r
312         wr.send_opt |= IB_SEND_OPT_SOLICITED;\r
313     wr.num_ds = (uint32_t)nSge;\r
314     wr.ds_array = pDs;\r
315 \r
316     ib_api_status_t status =\r
317         m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL );\r
318     if( nSge > 4 )\r
319         delete[] pDs;\r
320 \r
321     // leo\r
322     CL_ASSERT( nSge || pSgl == NULL );\r
323 #if DBG\r
324     if (!status )\r
325     {\r
326         if (pSgl)\r
327         {\r
328             ++g.snd_pkts;\r
329             g.snd_bytes += pSgl[0].Length;\r
330         }\r
331         else\r
332             ++g.snd_pkts_zero;\r
333     }\r
334     else\r
335         ++g.snd_pkts_err;\r
336 #endif\r
337 \r
338     switch( status )\r
339     {\r
340     case IB_SUCCESS:\r
341         return S_OK;\r
342     case IB_INSUFFICIENT_RESOURCES:\r
343         return ND_NO_MORE_ENTRIES;\r
344     case IB_INVALID_MAX_SGE:\r
345         return ND_DATA_OVERRUN;\r
346     case IB_INVALID_QP_STATE:\r
347         return ND_CONNECTION_INVALID;\r
348     default:\r
349         return ND_UNSUCCESSFUL;\r
350     }\r
351 }\r
352 \r
353 HRESULT CEndpoint::SendAndInvalidate(\r
354     __out ND_RESULT* pResult,\r
355     __in_ecount(nSge) const ND_SGE* pSgl,\r
356     __in SIZE_T nSge,\r
357     __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor,\r
358     __in DWORD Flags\r
359     )\r
360 {\r
361     ND_ENTER( ND_DBG_NDI );\r
362 \r
363     ib_send_wr_t wr;\r
364     ib_local_ds_t* pDs;\r
365 \r
366     if( nSge > UINT_MAX )\r
367         return ND_DATA_OVERRUN;\r
368 \r
369     pDs = new ib_local_ds_t[nSge];\r
370     if( !pDs )\r
371         return ND_NO_MEMORY;\r
372 \r
373     pResult->BytesTransferred = 0;\r
374     for( SIZE_T i = 0; i < nSge; i++ )\r
375     {\r
376         pDs[i].vaddr = (ULONG_PTR)pSgl[i].pAddr;\r
377         if( pSgl[i].Length > UINT_MAX )\r
378         {\r
379             delete[] pDs;\r
380             return ND_BUFFER_OVERFLOW;\r
381         }\r
382         pDs[i].length = (uint32_t)pSgl[i].Length;\r
383         pDs[i].lkey = ((CMr*)pSgl[i].hMr)->mr_ioctl.out.lkey;\r
384 \r
385         // Send completions don't include the length.  It's going to\r
386         // be all or nothing, so store it now and we can reset if the\r
387         // request fails.\r
388         pResult->BytesTransferred += pSgl[i].Length;\r
389     }\r
390 \r
391     wr.p_next = NULL;\r
392     wr.wr_id = (ULONG_PTR)pResult;\r
393     wr.wr_type = WR_SEND;\r
394     if ( pResult->BytesTransferred <= m_MaxInlineSize )\r
395             wr.send_opt = IB_SEND_OPT_INLINE; \r
396         else\r
397             wr.send_opt = 0;\r
398     // We simulate invalidate operations (since we simulate MW use).  We\r
399     // put the RKey in the immediate data, the recipient will do the\r
400     // lookup of the MW based on that (as they would with a regular\r
401     // invalidate request).\r
402     wr.send_opt |= IB_SEND_OPT_IMMEDIATE;\r
403     if( !(Flags & ND_OP_FLAG_SILENT_SUCCESS) )\r
404         wr.send_opt |= IB_SEND_OPT_SIGNALED;\r
405     if( Flags & ND_OP_FLAG_READ_FENCE )\r
406         wr.send_opt |= IB_SEND_OPT_FENCE;\r
407     if( Flags & ND_OP_FLAG_SEND_AND_SOLICIT_EVENT )\r
408         wr.send_opt |= IB_SEND_OPT_SOLICITED;\r
409     wr.num_ds = (uint32_t)nSge;\r
410     wr.ds_array = pDs;\r
411     // Put the RKey in the immeditate data.\r
412     wr.immediate_data = pRemoteMwDescriptor->Token;\r
413 \r
414     ib_api_status_t status =\r
415         m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL );\r
416     delete[] pDs;\r
417 \r
418     switch( status )\r
419     {\r
420     case IB_SUCCESS:\r
421         return S_OK;\r
422     case IB_INSUFFICIENT_RESOURCES:\r
423         return ND_NO_MORE_ENTRIES;\r
424     case IB_INVALID_MAX_SGE:\r
425         return ND_DATA_OVERRUN;\r
426     case IB_INVALID_QP_STATE:\r
427         return ND_CONNECTION_INVALID;\r
428     default:\r
429         return ND_UNSUCCESSFUL;\r
430     }\r
431 }\r
432 \r
433 HRESULT CEndpoint::Receive(\r
434     __out ND_RESULT* pResult,\r
435     __in_ecount(nSge) const ND_SGE* pSgl,\r
436     __in SIZE_T nSge\r
437     )\r
438 {\r
439 #if DBG    \r
440     if (!(++g.rcv_cnt % 1000))\r
441         ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI,\r
442             ("==> %s, cnt %I64d, rcv %I64d:%I64d:%I64d:%I64d\n",\r
443             __FUNCTION__, g.rcv_cnt, g.rcv_pkts, g.rcv_bytes, g.rcv_pkts_err, g.rcv_pkts_zero ));\r
444 #endif\r
445     ib_recv_wr_t wr;\r
446     ib_local_ds_t* pDs;\r
447     ib_local_ds_t ds[4];\r
448 \r
449     if( nSge > UINT_MAX )\r
450         return ND_DATA_OVERRUN;\r
451     else if( nSge <= 4 )\r
452         pDs = ds;\r
453     else\r
454     {\r
455         pDs = new ib_local_ds_t[nSge];\r
456         if( !pDs )\r
457             return ND_NO_MEMORY;\r
458     }\r
459 \r
460     for( SIZE_T i = 0; i < nSge; i++ )\r
461     {\r
462         pDs[i].vaddr = (ULONG_PTR)pSgl[i].pAddr;\r
463         if( pSgl[i].Length > UINT_MAX )\r
464         {\r
465             if( nSge > 4 )\r
466                 delete[] pDs;\r
467             return ND_BUFFER_OVERFLOW;\r
468         }\r
469         pDs[i].length = (uint32_t)pSgl[i].Length;\r
470         pDs[i].lkey = ((CMr*)pSgl[i].hMr)->mr_ioctl.out.lkey;\r
471     }\r
472 \r
473     wr.p_next = NULL;\r
474     wr.wr_id = (ULONG_PTR)pResult;\r
475     wr.num_ds = (uint32_t)nSge;\r
476     wr.ds_array = pDs;\r
477 \r
478     ib_api_status_t status =\r
479         m_pParent->m_Ifc.user_verbs.post_recv( m_uQp, &wr, NULL );\r
480 \r
481     if( nSge > 4 )\r
482         delete[] pDs;\r
483 \r
484     // leo\r
485     CL_ASSERT( nSge || pSgl == NULL );\r
486 #if DBG\r
487     if (!status)\r
488     {\r
489         if (pSgl)\r
490         {\r
491             ++g.rcv_pkts;\r
492             g.rcv_bytes += pSgl[0].Length;\r
493         }\r
494         else\r
495             ++g.rcv_pkts_zero;\r
496     }\r
497     else\r
498         ++g.rcv_pkts_err;\r
499 #endif\r
500 \r
501     switch( status )\r
502     {\r
503     case IB_SUCCESS:\r
504         return S_OK;\r
505     case IB_INSUFFICIENT_RESOURCES:\r
506         return ND_NO_MORE_ENTRIES;\r
507     case IB_INVALID_MAX_SGE:\r
508         return ND_DATA_OVERRUN;\r
509     case IB_INVALID_QP_STATE:\r
510         return ND_CONNECTION_INVALID;\r
511     default:\r
512         return ND_UNSUCCESSFUL;\r
513     }\r
514 }\r
515 \r
516 HRESULT CEndpoint::Bind(\r
517     __out ND_RESULT* pResult,\r
518     __in ND_MR_HANDLE hMr,\r
519     __in INDMemoryWindow* pMw,\r
520     __in_bcount(BufferSize) const void* pBuffer,\r
521     __in SIZE_T BufferSize,\r
522     __in DWORD Flags,\r
523     __out ND_MW_DESCRIPTOR* pMwDescriptor\r
524     )\r
525 {\r
526     ND_ENTER( ND_DBG_NDI );\r
527 \r
528     UNREFERENCED_PARAMETER( pMw );\r
529     UNREFERENCED_PARAMETER( Flags );\r
530 \r
531     CMr* pMr = ((CMr*)hMr);\r
532 \r
533     if( pBuffer < pMr->pBase ||\r
534         pBuffer > pMr->pBase + pMr->Length )\r
535     {\r
536         return ND_INVALID_PARAMETER_4;\r
537     }\r
538 \r
539     if( ((const char*)pBuffer + BufferSize) > (pMr->pBase + pMr->Length) )\r
540     {\r
541         return ND_INVALID_PARAMETER_5;\r
542     }\r
543 \r
544     // Ok, this here is a workaround since the Mellanox HCA driver doesn't\r
545     // support MWs.  This should be pushed into the HCA driver.\r
546     pMwDescriptor->Base = _byteswap_uint64( (UINT64)(ULONG_PTR)pBuffer );\r
547     pMwDescriptor->Length = _byteswap_uint64( BufferSize );\r
548     pMwDescriptor->Token = pMr->mr_ioctl.out.rkey;\r
549 \r
550     // Zero-byte RDMA write.  Could also be a no-op on the send queue\r
551     // which would be better, but requires changing the HCA driver.\r
552     ib_send_wr_t wr;\r
553     wr.p_next = NULL;\r
554     wr.wr_id = (ULONG_PTR)pResult;\r
555     wr.wr_type = WR_RDMA_WRITE;\r
556     wr.send_opt = IB_SEND_OPT_SIGNALED;\r
557     wr.num_ds = 0;\r
558     wr.ds_array = NULL;\r
559 \r
560     wr.remote_ops.vaddr = 0;\r
561     wr.remote_ops.rkey = 0;\r
562 \r
563     pResult->BytesTransferred = 0;\r
564 \r
565     // TODO: Track the MW by rkey, so we can unbind it.\r
566 \r
567     ib_api_status_t status =\r
568         m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL );\r
569 \r
570     switch( status )\r
571     {\r
572     case IB_SUCCESS:\r
573         return S_OK;\r
574     case IB_INSUFFICIENT_RESOURCES:\r
575         return ND_NO_MORE_ENTRIES;\r
576     case IB_INVALID_QP_STATE:\r
577         return ND_CONNECTION_INVALID;\r
578     default:\r
579         return ND_UNSUCCESSFUL;\r
580     }\r
581 }\r
582 \r
583 HRESULT CEndpoint::Invalidate(\r
584     __out ND_RESULT* pResult,\r
585     __in INDMemoryWindow* pMw,\r
586     __in DWORD Flags\r
587     )\r
588 {\r
589     ND_ENTER( ND_DBG_NDI );\r
590 \r
591     UNREFERENCED_PARAMETER( pMw );\r
592     UNREFERENCED_PARAMETER( Flags );\r
593 \r
594     // Zero-byte RDMA write.  Could also be a no-op on the send queue\r
595     // which would be better, but requires changing the HCA driver.\r
596     ib_send_wr_t wr;\r
597     wr.p_next = NULL;\r
598     wr.wr_id = (ULONG_PTR)pResult;\r
599     wr.wr_type = WR_RDMA_WRITE;\r
600     wr.send_opt = IB_SEND_OPT_SIGNALED;\r
601     wr.num_ds = 0;\r
602     wr.ds_array = NULL;\r
603 \r
604     wr.remote_ops.vaddr = 0;\r
605     wr.remote_ops.rkey = 0;\r
606 \r
607     pResult->BytesTransferred = 0;\r
608 \r
609     ib_api_status_t status =\r
610         m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL );\r
611 \r
612     switch( status )\r
613     {\r
614     case IB_SUCCESS:\r
615         // TODO: Stop trackign MW\r
616         return S_OK;\r
617     case IB_INSUFFICIENT_RESOURCES:\r
618         return ND_NO_MORE_ENTRIES;\r
619     case IB_INVALID_QP_STATE:\r
620         return ND_CONNECTION_INVALID;\r
621     default:\r
622         return ND_UNSUCCESSFUL;\r
623     }\r
624 }\r
625 \r
626 HRESULT CEndpoint::Rdma(\r
627     __out ND_RESULT* pResult,\r
628     __in ib_wr_type_t Type,\r
629     __in_ecount(nSge) const ND_SGE* pSgl,\r
630     __in SIZE_T nSge,\r
631     __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor,\r
632     __in ULONGLONG Offset,\r
633     __in DWORD Flags\r
634     )\r
635 {\r
636 //        ND_ENTER( ND_DBG_NDI );\r
637 \r
638     ib_send_wr_t wr;\r
639     ib_local_ds_t* pDs;\r
640     ib_local_ds_t ds[4];\r
641 \r
642     if( nSge > UINT_MAX )\r
643         return ND_DATA_OVERRUN;\r
644     else if( nSge <= 4 )\r
645         pDs = ds;\r
646     else\r
647     {\r
648         pDs = new ib_local_ds_t[nSge];\r
649         if( !pDs )\r
650             return ND_NO_MEMORY;\r
651     }\r
652 \r
653     pResult->BytesTransferred = 0;\r
654     for( SIZE_T i = 0; i < nSge; i++ )\r
655     {\r
656         pDs[i].vaddr = (ULONG_PTR)pSgl[i].pAddr;\r
657         if( pSgl[i].Length > UINT_MAX )\r
658         {\r
659             if( nSge > 4 )\r
660                 delete[] pDs;\r
661             return ND_BUFFER_OVERFLOW;\r
662         }\r
663         pDs[i].length = (uint32_t)pSgl[i].Length;\r
664         pDs[i].lkey = ((CMr*)pSgl[i].hMr)->mr_ioctl.out.lkey;\r
665 \r
666         //TODO: temporary - a workaround of test bug\r
667         //leo\r
668         if( (int)pSgl[i].Length < 0 )\r
669         {\r
670             pDs[i].length = 0 - (int)pSgl[i].Length;\r
671 #if DBG                \r
672             ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI,\r
673                 ("nSge %d, i %d, Length %#x\n", nSge, i, pSgl[i].Length ));\r
674             if( nSge > 4 )\r
675                 delete[] pDs;\r
676             return ND_BUFFER_OVERFLOW;\r
677 #endif                \r
678         }\r
679 \r
680         // Send completions don't include the length.  It's going to\r
681         // be all or nothing, so store it now and we can reset if the\r
682         // request fails.\r
683         pResult->BytesTransferred += pSgl[i].Length;\r
684     }\r
685 \r
686     wr.p_next = NULL;\r
687     wr.wr_id = (ULONG_PTR)pResult;\r
688     wr.wr_type = Type;\r
689     if ( (pResult->BytesTransferred <= m_MaxInlineSize) && Type != WR_RDMA_READ)\r
690         wr.send_opt = IB_SEND_OPT_INLINE; \r
691     else\r
692         wr.send_opt = 0;\r
693     if( !(Flags & ND_OP_FLAG_SILENT_SUCCESS) )\r
694         wr.send_opt |= IB_SEND_OPT_SIGNALED;\r
695     if( Flags & ND_OP_FLAG_READ_FENCE )\r
696         wr.send_opt |= IB_SEND_OPT_FENCE;\r
697     wr.num_ds = (uint32_t)nSge;\r
698     wr.ds_array = pDs;\r
699 \r
700     UINT64 vaddr = _byteswap_uint64( pRemoteMwDescriptor->Base );\r
701     vaddr += Offset;\r
702     wr.remote_ops.vaddr = vaddr;\r
703     wr.remote_ops.rkey = pRemoteMwDescriptor->Token;\r
704 \r
705     ib_api_status_t status =\r
706         m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL );\r
707 \r
708     if( nSge > 4 )\r
709         delete[] pDs;\r
710 \r
711     switch( status )\r
712     {\r
713     case IB_SUCCESS:\r
714         return S_OK;\r
715     case IB_INSUFFICIENT_RESOURCES:\r
716         return ND_NO_MORE_ENTRIES;\r
717     case IB_INVALID_MAX_SGE:\r
718         return ND_DATA_OVERRUN;\r
719     case IB_INVALID_QP_STATE:\r
720         return ND_CONNECTION_INVALID;\r
721     default:\r
722         return ND_UNSUCCESSFUL;\r
723     }\r
724 }\r
725 \r
726 HRESULT CEndpoint::Read(\r
727     __out ND_RESULT* pResult,\r
728     __in_ecount(nSge) const ND_SGE* pSgl,\r
729     __in SIZE_T nSge,\r
730     __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor,\r
731     __in ULONGLONG Offset,\r
732     __in DWORD Flags\r
733     )\r
734 {\r
735 //        ND_ENTER( ND_DBG_NDI );\r
736 \r
737     return Rdma( pResult, WR_RDMA_READ, pSgl, nSge,\r
738         pRemoteMwDescriptor, Offset, Flags );\r
739 }\r
740 \r
741 HRESULT CEndpoint::Write(\r
742     __out ND_RESULT* pResult,\r
743     __in_ecount(nSge) const ND_SGE* pSgl,\r
744     __in SIZE_T nSge,\r
745     __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor,\r
746     __in ULONGLONG Offset,\r
747     __in DWORD Flags\r
748     )\r
749 {\r
750 //        ND_ENTER( ND_DBG_NDI );\r
751 \r
752     return Rdma( pResult, WR_RDMA_WRITE, pSgl, nSge,\r
753         pRemoteMwDescriptor, Offset, Flags );\r
754 }\r
755 \r
756 HRESULT CEndpoint::CreateQp(\r
757     __in CCq* pInboundCq,\r
758     __in CCq* pOutboundCq,\r
759     __in SIZE_T nInboundEntries,\r
760     __in SIZE_T nOutboundEntries,\r
761     __in SIZE_T nInboundSge,\r
762     __in SIZE_T nOutboundSge,\r
763     __in SIZE_T InboundReadLimit,\r
764     __in SIZE_T OutboundReadLimit,\r
765     __in SIZE_T MaxInlineData\r
766     )\r
767 {\r
768     ND_ENTER( ND_DBG_NDI );\r
769 \r
770     if( MaxInlineData > UINT_MAX )\r
771         return ND_INVALID_PARAMETER_3;\r
772     if( nInboundEntries > UINT_MAX )\r
773         return ND_INVALID_PARAMETER_4;\r
774     if( nOutboundEntries > UINT_MAX )\r
775         return ND_INVALID_PARAMETER_5;\r
776     if( nInboundSge > UINT_MAX )\r
777         return ND_INVALID_PARAMETER_6;\r
778     if( nOutboundSge > UINT_MAX )\r
779         return ND_INVALID_PARAMETER_7;\r
780     if( InboundReadLimit > UCHAR_MAX )\r
781         return ND_INVALID_PARAMETER_9;\r
782     if( OutboundReadLimit > UCHAR_MAX )\r
783         return ND_INVALID_PARAMETER_10;\r
784 \r
785     /* Setup the qp_ioctl */\r
786     ual_create_qp_ioctl_t qp_ioctl;\r
787     cl_memclr( &qp_ioctl, sizeof(qp_ioctl) );\r
788 \r
789     qp_ioctl.in.qp_create.qp_type = IB_QPT_RELIABLE_CONN;\r
790     qp_ioctl.in.qp_create.sq_depth = (uint32_t)nOutboundEntries;\r
791     qp_ioctl.in.qp_create.rq_depth = (uint32_t)nInboundEntries;\r
792     qp_ioctl.in.qp_create.sq_sge = (uint32_t)nOutboundSge;\r
793     qp_ioctl.in.qp_create.rq_sge = (uint32_t)nInboundSge;\r
794     qp_ioctl.in.qp_create.sq_max_inline = (uint32_t)MaxInlineData;\r
795     qp_ioctl.in.qp_create.h_srq = NULL;\r
796     qp_ioctl.in.qp_create.sq_signaled = FALSE;\r
797 \r
798     /* Pre call to the UVP library */\r
799     CL_ASSERT( m_pParent->m_Ifc.user_verbs.pre_create_qp );\r
800     qp_ioctl.in.qp_create.h_sq_cq = pOutboundCq->m_uCq;\r
801     qp_ioctl.in.qp_create.h_rq_cq = pInboundCq->m_uCq;\r
802     ib_api_status_t status = m_pParent->m_Ifc.user_verbs.pre_create_qp(\r
803         m_pParent->m_uPd,\r
804         &qp_ioctl.in.qp_create,\r
805         &qp_ioctl.in.umv_buf,\r
806         (ib_qp_handle_t*)(ULONG_PTR)&m_uQp\r
807         );\r
808     if( status != IB_SUCCESS )\r
809         return ND_INSUFFICIENT_RESOURCES;\r
810 \r
811     /*\r
812     * Convert the handles to KAL handles once again starting\r
813     * from the input qp attribute\r
814     */\r
815     qp_ioctl.in.h_pd = m_pParent->m_hPd;\r
816     qp_ioctl.in.qp_create.h_sq_cq = (ib_cq_handle_t)pOutboundCq->m_hCq;\r
817     qp_ioctl.in.qp_create.h_rq_cq = (ib_cq_handle_t)pInboundCq->m_hCq;\r
818     qp_ioctl.in.context = (ULONG_PTR)this;\r
819     qp_ioctl.in.ev_notify = FALSE;\r
820 \r
821     DWORD bytes_ret;\r
822     BOOL fSuccess = DeviceIoControl(\r
823         m_pParent->m_hSync,\r
824         UAL_CREATE_QP,\r
825         &qp_ioctl.in,\r
826         sizeof(qp_ioctl.in),\r
827         &qp_ioctl.out,\r
828         sizeof(qp_ioctl.out),\r
829         &bytes_ret,\r
830         NULL );\r
831 \r
832     if( fSuccess != TRUE || bytes_ret != sizeof(qp_ioctl.out) )\r
833         qp_ioctl.out.status = IB_ERROR;\r
834 \r
835     /* Post uvp call */\r
836     CL_ASSERT( m_pParent->m_Ifc.user_verbs.post_create_qp );\r
837     m_pParent->m_Ifc.user_verbs.post_create_qp(\r
838         m_pParent->m_uPd,\r
839         qp_ioctl.out.status,\r
840         (ib_qp_handle_t*)(ULONG_PTR)&m_uQp,\r
841         &qp_ioctl.out.umv_buf\r
842         );\r
843 \r
844 \r
845     switch( qp_ioctl.out.status )\r
846     {\r
847     case IB_SUCCESS:\r
848         m_hQp = qp_ioctl.out.h_qp;\r
849         m_Qpn = qp_ioctl.out.attr.num;\r
850         ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI,\r
851             ("Created QP %#I64x, QPn %#x, pd %#I64x, context %p \n", \r
852             m_hQp, m_Qpn, m_pParent->m_hPd, this ) );\r
853         return S_OK;\r
854 \r
855     case IB_INVALID_MAX_WRS:\r
856         if( nInboundEntries > nOutboundEntries )\r
857             return ND_INVALID_PARAMETER_4;\r
858         else\r
859             return ND_INVALID_PARAMETER_5;\r
860 \r
861     case IB_INVALID_MAX_SGE:\r
862         if( nInboundSge > nOutboundSge )\r
863             return ND_INVALID_PARAMETER_6;\r
864         else\r
865             return ND_INVALID_PARAMETER_7;\r
866 \r
867     case IB_INSUFFICIENT_MEMORY:\r
868         return ND_NO_MEMORY;\r
869 \r
870     default:\r
871         return ND_INSUFFICIENT_RESOURCES;\r
872     }\r
873 }\r
874 \r
875 void CEndpoint::DestroyQp()\r
876 {\r
877     ND_ENTER( ND_DBG_NDI );\r
878 \r
879     /* Call the uvp pre call if the vendor library provided a valid QP handle */\r
880     CL_ASSERT( m_pParent->m_Ifc.user_verbs.pre_destroy_qp );\r
881     m_pParent->m_Ifc.user_verbs.pre_destroy_qp( m_uQp );\r
882 \r
883     ual_destroy_qp_ioctl_t qp_ioctl;\r
884     cl_memclr( &qp_ioctl, sizeof(qp_ioctl) );\r
885     qp_ioctl.in.h_qp = m_hQp;\r
886 \r
887     ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI,\r
888         ("Destroy QP %I64x\n", m_hQp) );\r
889 \r
890     DWORD bytes_ret;\r
891     BOOL fSuccess = DeviceIoControl(\r
892         m_pParent->m_hSync,\r
893         UAL_DESTROY_QP,\r
894         &qp_ioctl.in,\r
895         sizeof(qp_ioctl.in),\r
896         &qp_ioctl.out,\r
897         sizeof(qp_ioctl.out),\r
898         &bytes_ret,\r
899         NULL\r
900         );\r
901 \r
902     if( fSuccess != TRUE || bytes_ret != sizeof(qp_ioctl.out) )\r
903         qp_ioctl.out.status = IB_ERROR;\r
904 \r
905     ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI,\r
906         ("Destroyed QP %#I64x, QPn %#x, pd %#I64x, context %p \n", \r
907         m_hQp, m_Qpn, m_pParent->m_hPd, this ) );\r
908         \r
909     /* Call vendor's post_destroy_qp */\r
910     CL_ASSERT( m_pParent->m_Ifc.user_verbs.post_destroy_qp );\r
911     m_pParent->m_Ifc.user_verbs.post_destroy_qp(\r
912         m_uQp,\r
913         qp_ioctl.out.status\r
914         );\r
915     m_hQp = NULL;\r
916 }\r
917 \r
918 HRESULT CEndpoint::ModifyQp(\r
919     __in ib_qp_state_t NewState )\r
920 {\r
921     ND_ENTER( ND_DBG_NDI );\r
922 \r
923     /* Setup the qp_ioctl */\r
924     ual_ndi_modify_qp_ioctl_in_t qp_ioctl;\r
925     cl_memclr( &qp_ioctl, sizeof(qp_ioctl) );\r
926 \r
927     switch( NewState )\r
928     {\r
929     case IB_QPS_INIT:\r
930         qp_ioctl.qp_mod.state.init.primary_port = m_pParent->m_PortNum;\r
931         qp_ioctl.qp_mod.state.init.qkey = 0;\r
932         qp_ioctl.qp_mod.state.init.pkey_index = 0;\r
933         qp_ioctl.qp_mod.state.init.access_ctrl =\r
934             IB_AC_LOCAL_WRITE | IB_AC_RDMA_READ | IB_AC_RDMA_WRITE;\r
935 \r
936         // Fall through.\r
937     case IB_QPS_RESET:\r
938     case IB_QPS_ERROR:\r
939         qp_ioctl.qp_mod.req_state = NewState;\r
940     }\r
941 \r
942     /* Call the uvp ND modify verb */\r
943     CL_ASSERT( m_pParent->m_Ifc.user_verbs.nd_modify_qp );\r
944     void* pOutbuf;\r
945     DWORD szOutbuf;\r
946 \r
947     m_pParent->m_Ifc.user_verbs.nd_modify_qp(\r
948         m_uQp,\r
949         &pOutbuf,\r
950         &szOutbuf\r
951         );\r
952 \r
953     qp_ioctl.h_qp = m_hQp;\r
954 \r
955     DWORD bytes_ret;\r
956     BOOL fSuccess = DeviceIoControl(\r
957         m_pParent->m_hSync,\r
958         UAL_NDI_MODIFY_QP,\r
959         &qp_ioctl,\r
960         sizeof(qp_ioctl),\r
961         pOutbuf,\r
962         szOutbuf,\r
963         &bytes_ret,\r
964         NULL );\r
965 \r
966     if( fSuccess != TRUE )\r
967         return ND_UNSUCCESSFUL;\r
968 \r
969     return S_OK;\r
970 }\r
971 \r
972 HRESULT CEndpoint::QueryQp(\r
973         __out ib_qp_attr_t *qp_attr\r
974         )\r
975 {\r
976         ib_api_status_t status;\r
977         \r
978         ND_ENTER( ND_DBG_NDI );\r
979 \r
980         ual_query_qp_ioctl_t qp_ioctl;\r
981         cl_memclr( &qp_ioctl, sizeof(qp_ioctl) );\r
982         qp_ioctl.in.h_qp = m_hQp;\r
983 \r
984         /* Call the uvp pre call if the vendor library provided a valid ca handle */\r
985         if( m_pParent->m_Ifc.user_verbs.pre_query_qp )\r
986         {\r
987                 /* Pre call to the UVP library */\r
988                 status = m_pParent->m_Ifc.user_verbs.pre_query_qp( m_uQp, &qp_ioctl.in.umv_buf );\r
989                 if( status != IB_SUCCESS )\r
990                         goto done;\r
991         }\r
992 \r
993         DWORD bytes_ret;\r
994         BOOL fSuccess = DeviceIoControl(\r
995                 m_pParent->m_hSync,\r
996                 UAL_QUERY_QP,\r
997                 &qp_ioctl.in,\r
998                 sizeof(qp_ioctl.in),\r
999                 &qp_ioctl.out,\r
1000                 sizeof(qp_ioctl.out),\r
1001                 &bytes_ret,\r
1002                 NULL\r
1003                 );\r
1004 \r
1005         if( fSuccess != TRUE || bytes_ret != sizeof(qp_ioctl.out) )\r
1006                 status = IB_ERROR;\r
1007         else\r
1008                 status = qp_ioctl.out.status;\r
1009 \r
1010         /* Call vendor's post_query_qp */\r
1011         CL_ASSERT( m_pParent->m_Ifc.user_verbs.post_query_qp );\r
1012         if( m_pParent->m_Ifc.user_verbs.post_query_qp )\r
1013         {\r
1014                 m_pParent->m_Ifc.user_verbs.post_query_qp( m_uQp, status,\r
1015                         &qp_ioctl.out.attr, &qp_ioctl.out.umv_buf );\r
1016         }\r
1017 \r
1018 done:\r
1019         ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI,\r
1020                 ("Queried QP %#I64x, QPn %#x, pd %#I64x, context %p, status %#x \n", \r
1021                 m_hQp, m_Qpn, m_pParent->m_hPd, this, status ) );\r
1022 \r
1023         switch( status )\r
1024         {\r
1025         case IB_SUCCESS:\r
1026                 *qp_attr = qp_ioctl.out.attr;\r
1027                 return S_OK;\r
1028 \r
1029         default:\r
1030                 return ND_UNSUCCESSFUL;\r
1031         }\r
1032         \r
1033 }\r
1034 \r
1035 } // namespace\r