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