964f003f93237032702a9d72e2343b78a77ab5b5
[mirror/winof/.git] / core / al / kernel / al_ndi_cm.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. \r
4  * Portions Copyright (c) 2008 Microsoft Corporation.  All rights reserved.\r
5  *\r
6  * This software is available to you under the OpenIB.org BSD license\r
7  * below:\r
8  *\r
9  *     Redistribution and use in source and binary forms, with or\r
10  *     without modification, are permitted provided that the following\r
11  *     conditions are met:\r
12  *\r
13  *      - Redistributions of source code must retain the above\r
14  *        copyright notice, this list of conditions and the following\r
15  *        disclaimer.\r
16  *\r
17  *      - Redistributions in binary form must reproduce the above\r
18  *        copyright notice, this list of conditions and the following\r
19  *        disclaimer in the documentation and/or other materials\r
20  *        provided with the distribution.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
29  * SOFTWARE.\r
30  *\r
31  * $Id: al_proxy_verbs.c 548 2006-11-27 20:03:51Z leonidk $\r
32  */\r
33 \r
34 \r
35 #include <complib/comp_lib.h>\r
36 #include <iba/ib_al.h>\r
37 #include <iba/ib_al_ioctl.h>\r
38 #include "al.h"\r
39 #include "al_mgr.h"\r
40 #include "al_debug.h"\r
41 \r
42 #if defined(EVENT_TRACING)\r
43 #ifdef offsetof\r
44 #undef offsetof\r
45 #endif\r
46 #include "al_ndi_cm.tmh"\r
47 #endif\r
48 \r
49 #include "al_dev.h"\r
50 /* Get the internal definitions of apis for the proxy */\r
51 #include "al_ca.h"\r
52 #include "ib_common.h"\r
53 #include "al_qp.h"\r
54 #include "al_cm_conn.h"\r
55 #include "al_cm_cep.h"\r
56 #include "al_ndi_cm.h"\r
57 \r
58 uint32_t                g_sa_timeout = 500;\r
59 uint32_t                g_sa_retries = 4;\r
60 uint8_t                 g_qp_retries = QP_ATTRIB_RETRY_COUNT;\r
61 uint8_t                 g_pkt_life_modifier = 0;\r
62 uint8_t                 g_max_cm_retries = CM_RETRIES;\r
63 \r
64 /*******************************************************************\r
65  *\r
66  * Helpers\r
67  *\r
68  ******************************************************************/\r
69 \r
70 static char * State2String(ndi_cm_state_t state) \r
71 {\r
72         switch (state) \r
73         {\r
74                 case NDI_CM_IDLE                                        : return "NDI_CM_IDLE";\r
75                 case NDI_CM_CONNECTING_ATS_SENT         : return "NDI_CM_CONNECTING_ATS_SENT";\r
76                 case NDI_CM_CONNECTING_QPR_SENT         : return "NDI_CM_CONNECTING_QPR_SENT";\r
77                 case NDI_CM_CONNECTING_REQ_SENT         : return "NDI_CM_CONNECTING_REQ_SENT";\r
78                 case NDI_CM_CONNECTING_REP_RCVD         : return "NDI_CM_CONNECTING_REP_RCVD";\r
79                 case NDI_CM_CONNECTING_REJ_RCVD         : return "NDI_CM_CONNECTING_REJ_RCVD";\r
80                 case NDI_CM_CONNECTED                           : return "NDI_CM_CONNECTED";\r
81                 case NDI_CM_BOUND                                       : return "NDI_CM_BOUND";\r
82                 case NDI_CM_LISTENING                           : return "NDI_CM_LISTENING";\r
83                 case NDI_CM_REP_SENT                            : return "NDI_CM_REP_SENT";\r
84                 case NDI_CM_CONNECTED_DREP_SENT         : return "NDI_CM_CONNECTED_DREP_SENT";\r
85                 case NDI_CM_CONNECTED_DREQ_SENT         : return "NDI_CM_CONNECTED_DREQ_SENT";\r
86                 default : \r
87                         ASSERT(FALSE);\r
88         }\r
89         return "Unknown state";\r
90 }\r
91 \r
92 static inline void\r
93 __ndi_complete_irp(\r
94         IN      ib_qp_handle_t FUNC_PTR64                                                       h_qp,\r
95         IN      PIRP                                                                    Irp,\r
96         IN      NTSTATUS                                                                code\r
97         )\r
98 {\r
99         AL_ENTER( AL_DBG_NDI );\r
100 \r
101         CL_ASSERT( Irp );\r
102 \r
103         cl_ioctl_complete( Irp, code, 0 );\r
104         deref_al_obj( &h_qp->obj );                     /* release IRP life reference */\r
105         h_qp->p_irp_que->h_ioctl = NULL;        /* mark IRP as cancelled */\r
106 \r
107         AL_EXIT( AL_DBG_NDI );\r
108 }\r
109 \r
110 static inline void\r
111 __ndi_complete_irp_ex(\r
112         IN      ib_qp_handle_t FUNC_PTR64                                                       h_qp,\r
113         IN      NTSTATUS                                                                code,\r
114         IN      ndi_cm_state_t                                                  new_state\r
115         )\r
116 {\r
117         PIRP Irp;\r
118 \r
119         AL_ENTER( AL_DBG_NDI );\r
120         h_qp->p_irp_que->state = new_state;     \r
121         Irp = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
122         if ( Irp )\r
123                 __ndi_complete_irp( h_qp, Irp, code );\r
124         AL_EXIT( AL_DBG_NDI );\r
125 }\r
126 \r
127 /*\r
128  * Transition the QP to the error state to flush all oustanding work\r
129  * requests and sets the timewait time.  This function may be called\r
130  * when destroying the QP in order to flush all work requests, so we\r
131  * cannot call through the main API, or the call will fail since the\r
132  * QP is no longer in the initialize state.\r
133  */\r
134 static void\r
135 __cep_timewait_qp(\r
136         IN              const   ib_qp_handle_t                          h_qp )\r
137 {\r
138         uint64_t                        timewait = 0;\r
139         ib_qp_mod_t                     qp_mod;\r
140         ib_api_status_t         status;\r
141 \r
142         AL_ENTER( AL_DBG_CM );\r
143 \r
144         CL_ASSERT( h_qp );\r
145 \r
146         /*\r
147          * The CM should have set the proper timewait time-out value.  Reset\r
148          * the QP and let it enter the timewait state.\r
149          */\r
150         if( al_cep_get_timewait( h_qp->obj.h_al,\r
151                 ((al_conn_qp_t*)h_qp)->cid, &timewait ) == IB_SUCCESS )\r
152         {\r
153                 /* Special checks on the QP state for error handling - see above. */\r
154                 if( !h_qp || !AL_OBJ_IS_TYPE( h_qp, AL_OBJ_TYPE_H_QP ) ||\r
155                         ( (h_qp->obj.state != CL_INITIALIZED) && \r
156                         (h_qp->obj.state != CL_DESTROYING) ) )\r
157                 {\r
158                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
159                         return;\r
160                 }\r
161 \r
162                 cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) );\r
163                 qp_mod.req_state = IB_QPS_ERROR;\r
164 \r
165                 /* Modify to error state using function pointers - see above. */\r
166                 status = h_qp->pfn_modify_qp( h_qp, &qp_mod, NULL );\r
167                 if( status != IB_SUCCESS )\r
168                 {\r
169                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
170                                 ("pfn_modify_qp to IB_QPS_ERROR returned %s\n",\r
171                                 ib_get_err_str( status )) );\r
172                         return;\r
173                 }\r
174 \r
175 #ifdef CL_KERNEL\r
176                 /* Store the timestamp after which the QP exits timewait. */\r
177                 h_qp->timewait = cl_get_time_stamp() + timewait;\r
178 #endif  /* CL_KERNEL */\r
179         }\r
180 \r
181         AL_EXIT( AL_DBG_CM );\r
182 }\r
183 \r
184 static ib_api_status_t\r
185 __ndi_qp2rts(\r
186         IN              ib_qp_handle_t  const                           h_qp,\r
187         IN              uint8_t                                                         init_depth,\r
188         IN              uint8_t                                                         resp_res,\r
189         IN              PIRP                                                            p_irp,\r
190         IN      OUT     ib_qp_mod_t                                                     *p_qp_mod\r
191         )\r
192 {\r
193         ib_api_status_t status;\r
194 \r
195         AL_ENTER( AL_DBG_NDI );\r
196 \r
197         /* fill required qp attributes */\r
198         status = al_cep_get_rtr_attr( qp_get_al( h_qp ), \r
199                 ((al_conn_qp_t*)h_qp)->cid, p_qp_mod );\r
200         if ( status != IB_SUCCESS )\r
201         {\r
202                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
203                         ("al_cep_get_rtr_attr returned %s\n", ib_get_err_str( status )) );\r
204                 goto exit;\r
205         }\r
206         p_qp_mod->state.rtr.resp_res = resp_res;\r
207 \r
208         /* perform the request: INIT->RTR */\r
209         status = ndi_modify_qp( h_qp, p_qp_mod, \r
210                 cl_ioctl_out_size( p_irp ), cl_ioctl_out_buf( p_irp ) );\r
211         if ( status != IB_SUCCESS )\r
212         {\r
213                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
214                         ("ndi_modify_qp to RTR returned %s.\n", ib_get_err_str(status) ) );\r
215                 goto exit;\r
216         }\r
217 \r
218         /* fill required qp attributes */\r
219         status = al_cep_get_rts_attr( qp_get_al( h_qp ), \r
220                 ((al_conn_qp_t*)h_qp)->cid, p_qp_mod );\r
221         if ( status != IB_SUCCESS )\r
222         {\r
223                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
224                         ("al_cep_get_rts_attr returned %s\n", ib_get_err_str( status )) );\r
225                 goto exit;\r
226         }\r
227         p_qp_mod->state.rts.init_depth = init_depth;\r
228 \r
229         /* perform the request: RTR->RTS */\r
230         status = ndi_modify_qp( h_qp, p_qp_mod, \r
231                 cl_ioctl_out_size( p_irp ), cl_ioctl_out_buf( p_irp ) );\r
232         if ( status != IB_SUCCESS )\r
233         {\r
234                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
235                         ("ndi_modify_qp to RTS returned %s.\n", ib_get_err_str(status) ) );\r
236         }\r
237 \r
238 exit:\r
239         AL_EXIT( AL_DBG_NDI );\r
240         return status;\r
241 }\r
242 \r
243 \r
244 /*******************************************************************\r
245  *\r
246  * CSQ\r
247  *\r
248  ******************************************************************/\r
249 \r
250 static VOID __ndi_insert_irp(\r
251         IN      PIO_CSQ                                                                 Csq,\r
252         IN      PIRP                                                                    Irp\r
253         )\r
254 {\r
255         ndi_qp_csq_t *p_ndi_csq = (ndi_qp_csq_t*)Csq;\r
256 \r
257         AL_ENTER( AL_DBG_NDI );\r
258         InsertTailList( &p_ndi_csq->que, &Irp->Tail.Overlay.ListEntry );\r
259         AL_EXIT( AL_DBG_NDI );\r
260 }\r
261 \r
262 static VOID __ndi_remove_irp(\r
263         IN      PIO_CSQ                                                                 Csq,\r
264         IN      PIRP                                                                    Irp\r
265         )\r
266 {\r
267         UNUSED_PARAM( Csq );\r
268 \r
269         AL_ENTER( AL_DBG_NDI );\r
270         RemoveEntryList( &Irp->Tail.Overlay.ListEntry );\r
271         AL_EXIT( AL_DBG_NDI );\r
272 }\r
273 \r
274 static PIRP __ndi_peek_next_irp(\r
275         IN      PIO_CSQ                                                                 Csq,\r
276         IN      PIRP                                                                    Irp,\r
277         IN      PVOID                                                                   PeekContext\r
278         )\r
279 {\r
280         PIRP nextIrp = NULL;\r
281         PLIST_ENTRY nextEntry;\r
282         PLIST_ENTRY listHead;\r
283         ndi_qp_csq_t *p_ndi_csq = (ndi_qp_csq_t*)Csq;\r
284 \r
285         AL_ENTER( AL_DBG_NDI );\r
286 \r
287         listHead = &p_ndi_csq->que;\r
288 \r
289         // \r
290         // If the IRP is NULL, we will start peeking from the listhead, else\r
291         // we will start from that IRP onwards. This is done under the\r
292         // assumption that new IRPs are always inserted at the tail.\r
293         //\r
294 \r
295         if(Irp == NULL)\r
296                 nextEntry = listHead->Flink;\r
297         else\r
298                 nextEntry = Irp->Tail.Overlay.ListEntry.Flink;\r
299 \r
300         while(nextEntry != listHead) {\r
301                 nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry);\r
302 \r
303                 //\r
304                 // If context is present, continue until you find a matching one.\r
305                 // Else you break out as you got next one.\r
306                 //\r
307 \r
308                 if(PeekContext) \r
309                 {\r
310                         /* for now PeekContext is not used */\r
311                 } \r
312                 else\r
313                 {\r
314                         break;\r
315                 }\r
316 \r
317                 nextIrp = NULL;\r
318                 nextEntry = nextEntry->Flink;\r
319         }\r
320 \r
321         AL_EXIT( AL_DBG_NDI );\r
322         return nextIrp;\r
323 }\r
324 \r
325 static VOID __ndi_acquire_lock(\r
326         IN      PIO_CSQ                                                                 Csq,\r
327         OUT     PKIRQL                                                                  Irql\r
328         )\r
329 {\r
330         ndi_qp_csq_t *p_ndi_csq = (ndi_qp_csq_t*)Csq;\r
331         ib_qp_handle_t h_qp = p_ndi_csq->h_qp;\r
332         UNUSED_PARAM( Irql );\r
333 \r
334         AL_ENTER( AL_DBG_NDI );\r
335         cl_spinlock_acquire( &h_qp->obj.lock );\r
336         AL_EXIT( AL_DBG_NDI );\r
337 }\r
338 \r
339 static VOID __ndi_release_lock(\r
340         IN      PIO_CSQ                                                                 Csq,\r
341         IN      KIRQL                                                                   Irql\r
342         )\r
343 {\r
344         ndi_qp_csq_t *p_ndi_csq = (ndi_qp_csq_t*)Csq;\r
345         ib_qp_handle_t h_qp = p_ndi_csq->h_qp;\r
346         UNUSED_PARAM( Irql );\r
347 \r
348         AL_ENTER( AL_DBG_NDI );\r
349         cl_spinlock_release( &h_qp->obj.lock );\r
350         AL_EXIT( AL_DBG_NDI );\r
351 }\r
352 \r
353 static VOID __ndi_complete_cancelled_irp(\r
354         IN      PIO_CSQ                                                                 Csq,\r
355         IN      PIRP                                                                    Irp\r
356         )\r
357 {\r
358         ndi_qp_csq_t *p_ndi_csq = (ndi_qp_csq_t*)Csq;\r
359         ib_qp_handle_t VOID_PTR64 h_qp = p_ndi_csq->h_qp;\r
360         net32_t cid;\r
361 \r
362         AL_ENTER( AL_DBG_NDI );\r
363 \r
364         switch (p_ndi_csq->state)\r
365         {\r
366         case NDI_CM_CONNECTING_REQ_SENT:\r
367                 /* Cleanup from issuing CM REQ. */\r
368                 ref_al_obj( &h_qp->obj );\r
369                 cid = cl_atomic_xchg( &((al_conn_qp_t*)h_qp)->cid, AL_INVALID_CID );\r
370                 if( cid == AL_INVALID_CID || al_destroy_cep( qp_get_al( h_qp ), cid, deref_al_obj ) != IB_SUCCESS )\r
371                 {\r
372                         deref_al_obj( &h_qp->obj );\r
373                 }\r
374                 break;\r
375 \r
376         case NDI_CM_CONNECTING_ATS_SENT:\r
377         case NDI_CM_CONNECTING_QPR_SENT:\r
378                 al_cancel_sa_req( &h_qp->p_irp_que->h_query->sa_req );\r
379                 break;\r
380 \r
381         default:\r
382                 /* fall through */\r
383                 break;\r
384         }\r
385 \r
386         //TODO: is it always true ?\r
387         p_ndi_csq->state = NDI_CM_IDLE;\r
388         __ndi_complete_irp( h_qp, Irp, CL_CANCELED );\r
389 \r
390         AL_EXIT( AL_DBG_NDI );\r
391 }\r
392 \r
393 /* flush a queue of pending requests */\r
394 \r
395 #pragma warning(disable:4706)\r
396 static inline void __ndi_flush_que(\r
397         IN      ndi_qp_csq_t*                                                   p_ndi_csq,\r
398         IN      NTSTATUS                                                                completion_code\r
399         )\r
400 {\r
401         PIRP Irp;\r
402         while( Irp = IoCsqRemoveNextIrp( &p_ndi_csq->csq, NULL ) )\r
403         {\r
404                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, \r
405                         ("h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n", \r
406                         (uint64_t)p_ndi_csq->h_qp, p_ndi_csq->h_qp->obj.hdl, \r
407                         p_ndi_csq->h_qp->obj.ref_cnt ) );\r
408                 cl_ioctl_complete( Irp, completion_code, 0 );\r
409                 deref_al_obj( &p_ndi_csq->h_qp->obj );          /* release IRP life reference */\r
410         }\r
411 }\r
412 #pragma warning(default:4706)\r
413 \r
414 void\r
415 ndi_qp_flush_ques(\r
416         IN      ib_qp_handle_t FUNC_PTR64                                                       h_qp\r
417         )\r
418 {\r
419         AL_ENTER( AL_DBG_NDI );\r
420         __ndi_flush_que( h_qp->p_irp_que, STATUS_CANCELLED );\r
421         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, \r
422                 ("h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n", \r
423                 (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
424         AL_EXIT( AL_DBG_NDI );\r
425 }\r
426 \r
427 \r
428 \r
429 NTSTATUS\r
430 ndi_qp_init(\r
431         IN                              ib_qp_handle_t                          h_qp )\r
432 {\r
433 \r
434         NTSTATUS status;\r
435 \r
436         AL_ENTER( AL_DBG_NDI );\r
437 \r
438         if ( h_qp->type != IB_QPT_RELIABLE_CONN )\r
439         {\r
440                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
441                         ("Only RC QP type is supported \n"));\r
442                 status = STATUS_SUCCESS;\r
443                 goto exit;\r
444         }\r
445         \r
446         h_qp->p_irp_que = (ndi_qp_csq_t*)cl_zalloc(sizeof(ndi_qp_csq_t));\r
447         if (!h_qp->p_irp_que)\r
448         {\r
449                 status = STATUS_NO_MEMORY;\r
450                 goto exit;\r
451         }\r
452 \r
453         status = IoCsqInitialize( &h_qp->p_irp_que->csq, \r
454                 __ndi_insert_irp, __ndi_remove_irp,\r
455                 __ndi_peek_next_irp, __ndi_acquire_lock,\r
456                 __ndi_release_lock, __ndi_complete_cancelled_irp );\r
457         if ( !NT_SUCCESS( status ) )\r
458                 goto exit;\r
459 \r
460         InitializeListHead( &h_qp->p_irp_que->que );\r
461         h_qp->p_irp_que->h_qp = h_qp;\r
462         h_qp->p_irp_que->h_query = NULL;\r
463         h_qp->p_irp_que->state = NDI_CM_IDLE;\r
464         status = STATUS_SUCCESS;\r
465 \r
466 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
467         ("Creating h_qp %#I64x, uhdl %#I64x \n", \r
468         (uint64_t)h_qp, h_qp->obj.hdl ) );\r
469 \r
470 exit:\r
471         AL_EXIT( AL_DBG_NDI );\r
472         return status;\r
473 }\r
474 \r
475 void\r
476 ndi_qp_destroy(\r
477         IN              ib_qp_handle_t FUNC_PTR64                                       h_qp )\r
478 {\r
479         AL_ENTER( AL_DBG_NDI );\r
480 \r
481         if (h_qp->type == IB_QPT_RELIABLE_CONN && h_qp->p_irp_que)\r
482         {\r
483                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
484                         ("Destroying h_qp %#I64x, uhdl %#I64x, h_ioctl %p, cid %d\n", \r
485                         (uint64_t)h_qp, h_qp->obj.hdl, h_qp->p_irp_que->h_ioctl, ((al_conn_qp_t*)h_qp)->cid ) );\r
486 \r
487                 /* cancel pending IRPS for NDI type CQ */\r
488                 ndi_qp_flush_ques( h_qp );\r
489         }\r
490 \r
491         AL_EXIT( AL_DBG_NDI );\r
492 }\r
493 \r
494 void\r
495 ndi_qp_free(\r
496         IN              ib_qp_handle_t FUNC_PTR64                                       h_qp )\r
497 {\r
498         AL_ENTER( AL_DBG_NDI );\r
499 \r
500         if (h_qp->type == IB_QPT_RELIABLE_CONN && h_qp->p_irp_que)\r
501         {\r
502                 /* free NDI context */\r
503                 cl_free( h_qp->p_irp_que );\r
504                 h_qp->p_irp_que = NULL;\r
505         }\r
506 \r
507         AL_EXIT( AL_DBG_NDI );\r
508 }\r
509 \r
510 \r
511 /*******************************************************************\r
512  *\r
513  * REQ CM request\r
514  *\r
515  ******************************************************************/\r
516 \r
517 static void\r
518 __ndi_req_cm_wi(\r
519         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
520         IN                              void*                                           context )\r
521 {\r
522         NTSTATUS status;\r
523         ib_qp_handle_t VOID_PTR64       h_qp = (ib_qp_handle_t VOID_PTR64)context;\r
524         UNUSED_PARAM(p_dev_obj);\r
525 \r
526         AL_ENTER( AL_DBG_NDI );\r
527 \r
528         IoFreeWorkItem( h_qp->p_irp_que->p_workitem );\r
529 \r
530         __cep_timewait_qp( h_qp );\r
531         \r
532         h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
533         status = (h_qp->p_irp_que->state == NDI_CM_CONNECTED) ? STATUS_CONNECTION_DISCONNECTED : STATUS_CONNECTION_REFUSED;\r
534         __ndi_complete_irp( h_qp, h_qp->p_irp_que->h_ioctl, status );\r
535         deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
536 \r
537         AL_EXIT( AL_DBG_NDI );\r
538 }\r
539 \r
540 /*\r
541  * A user-specified callback that is invoked after receiving a connection\r
542  * rejection message (REJ).\r
543  */\r
544         \r
545         \r
546 static void\r
547 __ndi_proc_rej(\r
548         IN              const   ib_cm_handle_t* const           p_cm,\r
549         IN              const   mad_cm_rej_t* const             p_rej )\r
550 {\r
551         net32_t cid;\r
552         NTSTATUS status;\r
553         ib_qp_handle_t VOID_PTR64       h_qp = p_cm->h_qp;\r
554         ndi_qp_csq_t *p_ndi_csq = h_qp->p_irp_que;\r
555 \r
556         AL_ENTER( AL_DBG_NDI );\r
557 \r
558         AL_PRINT(TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
559                 ("p_rej %p, h_qp %#I64x, uhdl %#I64x, connect reject, reason=%hd\n", \r
560                 p_rej, (uint64_t)h_qp, h_qp->obj.hdl, cl_ntoh16(p_rej->reason) ) );\r
561 \r
562         ref_al_obj( &h_qp->obj );\r
563         cid = cl_atomic_xchg( &((al_conn_qp_t*)h_qp)->cid, AL_INVALID_CID );\r
564         CL_ASSERT( cid == p_cm->cid || cid == AL_RESERVED_CID || cid == AL_INVALID_CID );\r
565         if( cid == AL_INVALID_CID ||\r
566                 al_destroy_cep( p_cm->h_al, cid, deref_al_obj ) != IB_SUCCESS )\r
567         {\r
568                 deref_al_obj( &h_qp->obj );\r
569         }\r
570 \r
571         switch (p_ndi_csq->state)\r
572         {\r
573         case NDI_CM_CONNECTING_REQ_SENT:\r
574                 al_cep_set_pdata( p_cm->h_al, p_cm->cid, IB_REJ_PDATA_SIZE, (uint8_t*)p_rej->pdata );\r
575                 AL_PRINT(TRACE_LEVEL_INFORMATION, AL_DBG_NDI ,\r
576                         ("set %d of REQ pdata to CEP with cid %d, h_al %p\n", \r
577                         IB_REJ_PDATA_SIZE, p_cm->cid, p_cm->h_al ));\r
578                 status = (p_rej->reason == IB_REJ_TIMEOUT) ? STATUS_TIMEOUT : STATUS_CONNECTION_REFUSED;\r
579                 __ndi_complete_irp_ex( h_qp, status, NDI_CM_CONNECTING_REJ_RCVD );\r
580                 break;\r
581 \r
582         case NDI_CM_CONNECTED:\r
583         case NDI_CM_REP_SENT:\r
584                 /* a race: the passive side\92s REP times out, but active side has sent the RTU.  \r
585                    We are treating this case it like a DREQ */\r
586                 {\r
587                         IO_STACK_LOCATION *p_io_stack;\r
588                         cl_ioctl_handle_t h_ioctl;\r
589 \r
590                         h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
591                         if (!h_ioctl)\r
592                         { /* IRP has been cancelled */\r
593                                 // TODO: no QP flash\r
594                                 AL_PRINT(TRACE_LEVEL_INFORMATION, AL_DBG_NDI ,\r
595                                         ( "IRP cancelled: Can't flush the QP %p, ndi_state %d\n",\r
596                                         h_qp, p_ndi_csq->state ) );\r
597                                 h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
598 //                              ASSERT(FALSE);\r
599                         }\r
600                         else\r
601                         {\r
602                                 p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );\r
603                                 h_qp->p_irp_que->p_workitem = IoAllocateWorkItem( p_io_stack->DeviceObject );\r
604                                 if ( h_qp->p_irp_que->p_workitem )\r
605                                 { /* asyncronous performing */\r
606                                         IoQueueWorkItem( h_qp->p_irp_que->p_workitem,\r
607                                                 __ndi_req_cm_wi, DelayedWorkQueue, h_qp );\r
608                                 }\r
609                                 else\r
610                                 { /* syncronous performing */\r
611                                         // TODO: no QP flash\r
612                                         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
613                                                 ( "Can't flush the QP %p, ndi_state %d\n",\r
614                                                 h_qp, p_ndi_csq->state ) );\r
615                                         h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
616                                         status = (h_qp->p_irp_que->state == NDI_CM_CONNECTED) ? STATUS_CONNECTION_DISCONNECTED : STATUS_CONNECTION_REFUSED;\r
617                                         __ndi_complete_irp( h_qp, h_ioctl, status );\r
618                                         deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
619                                         h_qp->p_irp_que->h_ioctl = NULL;\r
620                                 }\r
621                         }\r
622                         break;\r
623                 }\r
624                 \r
625         default:        \r
626                 // This is not the state that we waited for, not much that we can\r
627                 // do. (This might happen in shutdown)\r
628                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
629                         ("Not the expected state %s\n", State2String( p_ndi_csq->state )));\r
630                 ASSERT(FALSE);\r
631                 break;\r
632         }\r
633         \r
634         AL_EXIT( AL_DBG_NDI );\r
635 }\r
636 \r
637 static void\r
638 __ndi_proc_rep(\r
639         IN                              ib_cm_handle_t* const           p_cm,\r
640         IN                              mad_cm_rep_t* const                     p_rep )\r
641 {\r
642         ndi_qp_csq_t *p_ndi_csq = p_cm->h_qp->p_irp_que;\r
643 \r
644         AL_ENTER( AL_DBG_NDI );\r
645 \r
646         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI ,("h_qp = 0x%p\n", p_cm->h_qp));\r
647 \r
648         if ( p_ndi_csq->state  != NDI_CM_CONNECTING_REQ_SENT) \r
649         {\r
650                 // This is not the state that we waited for, not much that we can do\r
651                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
652                         ("Not the expected state %s\n", State2String( p_ndi_csq->state )));\r
653                 ASSERT(FALSE);\r
654                 goto exit;\r
655         }\r
656 \r
657         /* fill the rej data */\r
658         al_cep_set_pdata( p_cm->h_al, p_cm->cid, IB_REJ_PDATA_SIZE, p_rep->pdata );\r
659         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
660                 ("set %d of REQ pdata to CEP with cid %d, h_al %p\n", \r
661                 IB_REJ_PDATA_SIZE, p_cm->cid, p_cm->h_al ));\r
662 \r
663         __ndi_complete_irp_ex( p_cm->h_qp, STATUS_SUCCESS, NDI_CM_CONNECTING_REP_RCVD );\r
664 \r
665 exit:   \r
666         AL_EXIT( AL_DBG_NDI );\r
667 }\r
668 \r
669 typedef struct _ndi_async_dreq\r
670 {\r
671         cl_async_proc_item_t    item;\r
672         ib_cm_handle_t                  cm;\r
673 \r
674 }       ndi_async_dreq_t;\r
675 \r
676 static void\r
677 __ndi_proc_dreq_async(\r
678         IN                              cl_async_proc_item_t            *p_item )\r
679 {\r
680         ib_qp_mod_t qp_mod;\r
681         ib_api_status_t status;\r
682         ib_cm_drep_t cm_drep = { NULL, 0 };\r
683         ndi_async_dreq_t *p_async_dreq = PARENT_STRUCT( p_item, ndi_async_dreq_t, item );\r
684 \r
685         AL_ENTER( AL_DBG_NDI );\r
686 \r
687         /* bring QP to error state */\r
688         cl_memclr( &qp_mod, sizeof(qp_mod) );\r
689         qp_mod.req_state = IB_QPS_ERROR;\r
690 \r
691         status = modify_qp( p_async_dreq->cm.h_qp, &qp_mod, NULL );\r
692         if ( status != IB_SUCCESS )\r
693         {\r
694                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
695                         ("al_modify_qp to ERROR returned %s.\n", ib_get_err_str(status) ) );\r
696                 goto exit;\r
697         }\r
698 \r
699         status = al_cep_drep( p_async_dreq->cm.h_al,\r
700                 ((al_conn_qp_t*)p_async_dreq->cm.h_qp)->cid, &cm_drep);\r
701 \r
702         if ( status != IB_SUCCESS )\r
703         {\r
704                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
705                         ("al_cep_drep returned %s.\n", ib_get_err_str(status) ) );\r
706         }\r
707         //TODO: what state is to be set here ?\r
708         //p_async_dreq->cm.h_qp->p_irp_que->state = NDI_CM_IDLE;        \r
709 \r
710 exit:\r
711         cl_free( p_async_dreq );\r
712         AL_EXIT( AL_DBG_NDI );\r
713 }\r
714 \r
715 static void\r
716 __ndi_proc_dreq(\r
717         IN                              ib_cm_handle_t* const           p_cm,\r
718         IN                              mad_cm_dreq_t* const            p_dreq )\r
719 {\r
720         ndi_async_dreq_t *p_async_dreq;\r
721         UNUSED_PARAM(p_dreq);\r
722 \r
723         AL_ENTER( AL_DBG_NDI );\r
724 \r
725         AL_PRINT(TRACE_LEVEL_INFORMATION ,AL_DBG_NDI ,("h_qp = 0x%p\n", p_cm->h_qp));\r
726 \r
727         p_async_dreq = (ndi_async_dreq_t*)cl_zalloc( sizeof(ndi_async_dreq_t) );\r
728         if( !p_async_dreq )\r
729         {\r
730                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
731                         ("failed to cl_zalloc ndi_async_dreq_t (%d bytes)\n",\r
732                         sizeof(ndi_async_dreq_t)) );\r
733                 ASSERT(FALSE);\r
734                 goto exit;\r
735         }\r
736 \r
737         p_async_dreq->cm = *p_cm;\r
738         p_async_dreq->item.pfn_callback = __ndi_proc_dreq_async;\r
739 \r
740         /* Queue the MAD for asynchronous processing. */\r
741         cl_async_proc_queue( gp_async_proc_mgr, &p_async_dreq->item );\r
742 \r
743 exit:   \r
744         AL_EXIT( AL_DBG_NDI );\r
745 }\r
746 \r
747 static void\r
748 __ndi_cm_handler(\r
749         IN              const   ib_al_handle_t FUNC_PTR64                               h_al,\r
750         IN              const   net32_t                                         cid )\r
751 {\r
752         void* VOID_PTR64                context;\r
753         net32_t                         new_cid;\r
754         ib_mad_element_t        *p_mad_el;\r
755         ib_cm_handle_t          h_cm;\r
756 \r
757         AL_ENTER( AL_DBG_NDI );\r
758 \r
759         while( al_cep_poll( h_al, cid, &context, &new_cid, &p_mad_el ) == IB_SUCCESS )\r
760         {\r
761                 ib_mad_t*p_mad = ib_get_mad_buf( p_mad_el );\r
762                 ib_qp_handle_t VOID_PTR64 h_qp = (ib_qp_handle_t VOID_PTR64)context;\r
763 \r
764                 if( p_mad_el->status != IB_SUCCESS )\r
765                 {\r
766                         switch( p_mad->attr_id )\r
767                         {\r
768                         case CM_REQ_ATTR_ID:\r
769                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
770                                         ("REQ timeouted for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
771                                         cid, h_al, h_qp, new_cid ) );\r
772                                 __ndi_complete_irp_ex( h_qp, STATUS_TIMEOUT, NDI_CM_IDLE );\r
773                                 break;\r
774 \r
775                         case CM_REP_ATTR_ID:\r
776                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
777                                         ("REP timeouted for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
778                                         cid, h_al, h_qp, new_cid ) );\r
779                                 __ndi_complete_irp_ex( h_qp, STATUS_CONNECTION_ABORTED, NDI_CM_IDLE );\r
780                                 break;\r
781 \r
782                         case CM_DREQ_ATTR_ID:\r
783                         default:\r
784                                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
785                                         ("Unhandled MAD attr ID %d for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
786                                         p_mad->attr_id, cid, h_al, h_qp, new_cid ) );\r
787                                 break;\r
788                         }\r
789                 }\r
790                 else\r
791                 {\r
792                         h_cm.h_al = h_al;\r
793                         h_cm.h_qp = h_qp;\r
794                         h_cm.cid = cid;\r
795                         \r
796                         switch( p_mad->attr_id )\r
797                         {\r
798                         case CM_REP_ATTR_ID:\r
799                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
800                                         ("REP received for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
801                                         cid, h_al, h_qp, new_cid ) );\r
802                                 CL_ASSERT( ((al_conn_qp_t*)h_qp)->cid == (int32_t)cid || \r
803                                         ((al_conn_qp_t*)h_qp)->cid == AL_INVALID_CID ||\r
804                                         ((al_conn_qp_t*)h_qp)->cid == AL_RESERVED_CID );\r
805                                 __ndi_proc_rep( &h_cm, (mad_cm_rep_t*)p_mad );\r
806                                 break;\r
807                         \r
808                         case CM_REJ_ATTR_ID:\r
809                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
810                                         ("REJ received for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
811                                         cid, h_al, h_qp, new_cid ) );\r
812                                 __ndi_proc_rej( &h_cm, (mad_cm_rej_t*)p_mad );\r
813                                 break;\r
814                 \r
815                         case CM_DREQ_ATTR_ID:\r
816                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
817                                         ("DREQ received for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
818                                         cid, h_al, h_qp, new_cid ) );\r
819                                 CL_ASSERT( ((al_conn_qp_t*)h_qp)->cid == (int32_t)cid || \r
820                                 ((al_conn_qp_t*)h_qp)->cid == AL_INVALID_CID ||\r
821                                 ((al_conn_qp_t*)h_qp)->cid == AL_RESERVED_CID );\r
822                                 __ndi_proc_dreq( &h_cm, (mad_cm_dreq_t*)p_mad );\r
823                                 break;\r
824                 \r
825                         default:\r
826                                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
827                                         ("Invalid CM recv MAD attribute ID %d.\n", p_mad->attr_id) );\r
828                         }\r
829                 }\r
830 \r
831                 ib_put_mad( p_mad_el );\r
832         }\r
833 \r
834         AL_EXIT( AL_DBG_NDI );\r
835 }\r
836 \r
837 static void\r
838 __ndi_fill_cm_req(\r
839         IN              ib_qp_handle_t  const                           h_qp,\r
840         IN              ual_ndi_req_cm_ioctl_in_t                       *p_req,\r
841         IN              ib_path_rec_t                                           *p_path_rec,\r
842                 OUT     ib_cm_req_t                                                     *p_cm_req)\r
843 {\r
844         AL_ENTER( AL_DBG_NDI );\r
845 \r
846         memset( p_cm_req, 0, sizeof(ib_cm_req_t) );\r
847 \r
848         p_cm_req->svc_id = IB_REQ_CM_RDMA_SID_PREFIX | (p_req->prot << 16) | p_req->dst_port;\r
849         p_cm_req->max_cm_retries = g_max_cm_retries;\r
850         p_cm_req->p_primary_path = p_path_rec;  \r
851 \r
852         p_cm_req->p_req_pdata = (uint8_t *)&p_req->pdata;\r
853         p_cm_req->req_length = sizeof(p_req->pdata);\r
854 \r
855         p_cm_req->qp_type = IB_QPT_RELIABLE_CONN;\r
856         p_cm_req->h_qp = h_qp;\r
857         p_cm_req->resp_res = 0;\r
858         p_cm_req->init_depth = 0;\r
859 \r
860         p_cm_req->remote_resp_timeout =\r
861                 ib_path_rec_pkt_life( p_path_rec ) + CM_REMOTE_TIMEOUT;\r
862         if( p_cm_req->remote_resp_timeout > 0x1F )\r
863                 p_cm_req->remote_resp_timeout = 0x1F;\r
864         else if( p_cm_req->remote_resp_timeout < CM_MIN_REMOTE_TIMEOUT )\r
865                 p_cm_req->remote_resp_timeout = CM_MIN_REMOTE_TIMEOUT;\r
866 \r
867         p_cm_req->flow_ctrl = TRUE;     /* HCAs must support end-to-end flow control. */\r
868 \r
869         p_cm_req->local_resp_timeout =\r
870                 ib_path_rec_pkt_life( p_path_rec ) + CM_LOCAL_TIMEOUT;\r
871         if( p_cm_req->local_resp_timeout > 0x1F )\r
872                 p_cm_req->local_resp_timeout = 0x1F;\r
873         else if( p_cm_req->local_resp_timeout < CM_MIN_LOCAL_TIMEOUT )\r
874                 p_cm_req->local_resp_timeout = CM_MIN_LOCAL_TIMEOUT;\r
875 \r
876         p_cm_req->rnr_nak_timeout = QP_ATTRIB_RNR_NAK_TIMEOUT;\r
877         p_cm_req->rnr_retry_cnt = QP_ATTRIB_RNR_RETRY;\r
878         p_cm_req->retry_cnt = g_qp_retries;\r
879         p_cm_req->p_alt_path = NULL;\r
880 \r
881         AL_EXIT( AL_DBG_NDI );\r
882 }\r
883 \r
884 static void AL_API\r
885 __ndi_pr_query_cb(\r
886                                         ib_query_rec_t                          *p_query_rec )\r
887 {\r
888         ib_api_status_t status;\r
889         cl_ioctl_handle_t h_ioctl;\r
890         ib_cm_req_t cm_req;\r
891         uint8_t pkt_life;\r
892         ib_qp_mod_t qp_mod;\r
893         ib_path_rec_t *p_path_rec;\r
894         ual_ndi_req_cm_ioctl_in_t *p_req = (ual_ndi_req_cm_ioctl_in_t* VOID_PTR64)p_query_rec->query_context;\r
895         ib_qp_handle_t VOID_PTR64 h_qp = (ib_qp_handle_t VOID_PTR64)HDL_TO_PTR(p_req->h_qp);\r
896         net32_t cid, old_cid;\r
897 \r
898         AL_ENTER( AL_DBG_NDI );\r
899 \r
900         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
901                 ("status is %d, count is %d, context %p\n", p_query_rec->status,\r
902                 p_query_rec->result_cnt, p_query_rec->query_context) );\r
903 \r
904         h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
905         if( !h_ioctl || p_query_rec->status != IB_SUCCESS || !p_query_rec->result_cnt )\r
906                 goto err_irp_complete;\r
907 \r
908         /* Path Record has been received ! */\r
909         p_path_rec = ib_get_query_path_rec( p_query_rec->p_result_mad, 0 );\r
910 \r
911         /* fix packet life */\r
912         CL_ASSERT( p_path_rec );\r
913         pkt_life = ib_path_rec_pkt_life( p_path_rec ) + g_pkt_life_modifier;\r
914         if( pkt_life > 0x1F )\r
915                 pkt_life = 0x1F;\r
916 \r
917         p_path_rec->pkt_life &= IB_PATH_REC_SELECTOR_MASK;\r
918         p_path_rec->pkt_life |= pkt_life;\r
919 \r
920         /* Get a CEP and bind it to the QP. */\r
921         status = al_create_cep( qp_get_al( h_qp ), __ndi_cm_handler, h_qp, &cid );\r
922         if( status != IB_SUCCESS )\r
923         {\r
924                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
925                         ("al_create_cep returned %s.\n", ib_get_err_str( status )) );\r
926                 goto err_irp_complete;\r
927         }\r
928         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
929                 ("Created Active CEP with cid %d, h_al %p, context %p\n",\r
930                 cid, qp_get_al( h_qp ), h_qp ) );\r
931 \r
932         /* See if this QP has already been connected. */\r
933         old_cid = cl_atomic_comp_xchg( &((al_conn_qp_t*)h_qp)->cid, AL_INVALID_CID, cid );\r
934         if( old_cid != AL_INVALID_CID || h_qp->obj.state == CL_DESTROYING )\r
935                 goto err_cep_destroy;\r
936 \r
937         /* Format ib_cm_req_t structure */\r
938         __ndi_fill_cm_req( h_qp, p_req, p_path_rec, &cm_req );\r
939 \r
940         /* prepare CEP for connection */\r
941         status = al_cep_pre_req( qp_get_al( h_qp ),\r
942                 ((al_conn_qp_t*)h_qp)->cid, &cm_req, &qp_mod );\r
943         if( status != IB_SUCCESS )\r
944         {\r
945                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
946                         ("al_cep_pre_req returned %s.\n", ib_get_err_str( status )) );\r
947                 goto err_cep_destroy;\r
948         }\r
949 \r
950         /* insert IRP in the queue */\r
951         h_qp->p_irp_que->state = NDI_CM_CONNECTING_REQ_SENT;\r
952         IoCsqInsertIrp( &h_qp->p_irp_que->csq, h_ioctl, NULL );\r
953 \r
954         /* send CM REQ */\r
955         status = al_cep_send_req( qp_get_al( h_qp ), cid );\r
956         if( status != IB_SUCCESS )\r
957                 goto err_irp_remove;\r
958 \r
959         /* we can release it now. In case of QP destroy __destroying_qp will remove CEP */\r
960         deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
961 \r
962         /* SUCCESS ! */\r
963         goto exit;\r
964 \r
965 err_irp_remove:\r
966         h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
967 \r
968 err_cep_destroy:\r
969         al_destroy_cep( qp_get_al( h_qp ), cid, NULL );\r
970         \r
971 err_irp_complete:\r
972         h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
973         /* the IRP "has" 2 QP references, taken in __ndi_ats_query */\r
974         if ( h_ioctl )\r
975                 __ndi_complete_irp( h_qp, h_ioctl, STATUS_HOST_UNREACHABLE );\r
976         deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
977 \r
978 exit:   \r
979         cl_free( p_req );\r
980         if( p_query_rec->p_result_mad )\r
981                 ib_put_mad( p_query_rec->p_result_mad );\r
982 \r
983         AL_EXIT( AL_DBG_NDI );\r
984 }\r
985 \r
986 \r
987 \r
988 /* Synchronously query the SA for a GUID. Return 0 on success. */\r
989 void\r
990 __ndi_pr_query(\r
991         IN              cl_ioctl_handle_t                                       h_ioctl,\r
992         IN              ual_ndi_req_cm_ioctl_in_t                       *p_req,\r
993         IN              ib_gid_t                                                        *p_dest_gid )\r
994 {\r
995         ib_gid_pair_t user_query;\r
996         ib_query_req_t query_req;\r
997         ib_api_status_t status;\r
998         ib_qp_handle_t VOID_PTR64 h_qp = (ib_qp_handle_t VOID_PTR64)HDL_TO_PTR(p_req->h_qp);\r
999 \r
1000         AL_ENTER( AL_DBG_NDI );\r
1001 \r
1002         query_req.query_type = IB_QUERY_PATH_REC_BY_GIDS;\r
1003         query_req.p_query_input = &user_query;\r
1004         query_req.port_guid = p_req->guid;\r
1005         query_req.timeout_ms = g_sa_timeout;\r
1006         query_req.retry_cnt = g_sa_retries;\r
1007         query_req.flags = 0;    /* IB_FLAGS_SYNC */\r
1008         query_req.query_context = p_req;\r
1009         query_req.pfn_query_cb = __ndi_pr_query_cb;\r
1010 \r
1011         user_query.src_gid.unicast.prefix = p_dest_gid->unicast.prefix;\r
1012         user_query.src_gid.unicast.interface_id = p_req->guid;\r
1013         user_query.dest_gid = *p_dest_gid;\r
1014 \r
1015         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
1016                 ("Query for path from %I64x to %I64x\n",\r
1017                 p_req->guid, ib_gid_get_guid( p_dest_gid )) );\r
1018 \r
1019         /* insert IRP in the queue */\r
1020         h_qp->p_irp_que->state = NDI_CM_CONNECTING_QPR_SENT;\r
1021         IoCsqInsertIrp( &h_qp->p_irp_que->csq, h_ioctl, NULL );\r
1022 \r
1023         status = ib_query( qp_get_al( h_qp ), &query_req, &h_qp->p_irp_que->h_query );\r
1024 \r
1025         if( status != IB_SUCCESS )\r
1026         {\r
1027                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("ib_query failed (%d)\n", status) );\r
1028                 cl_free( p_req );\r
1029                 __ndi_complete_irp_ex( h_qp, CL_ERROR, NDI_CM_IDLE );\r
1030                 /* relase additional reference, taken in __ndi_ats_query */\r
1031                 deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
1032         }\r
1033 \r
1034         AL_EXIT( AL_DBG_NDI );\r
1035 }\r
1036 \r
1037 \r
1038 static void AL_API\r
1039 __ndi_ats_query_cb(\r
1040         IN                              ib_query_rec_t                          *p_query_rec )\r
1041 {\r
1042         cl_ioctl_handle_t h_ioctl;\r
1043         ib_service_record_t *service_record;\r
1044         ual_ndi_req_cm_ioctl_in_t *p_req = (ual_ndi_req_cm_ioctl_in_t* VOID_PTR64)p_query_rec->query_context;\r
1045         ib_qp_handle_t VOID_PTR64 h_qp = (ib_qp_handle_t VOID_PTR64)HDL_TO_PTR(p_req->h_qp);\r
1046 \r
1047         AL_ENTER( AL_DBG_NDI );\r
1048 \r
1049         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1050                 ("status is %d, count is %d, context %p\n", p_query_rec->status,\r
1051                 p_query_rec->result_cnt, p_query_rec->query_context) );\r
1052 \r
1053         h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
1054         if( !h_ioctl || p_query_rec->status != IB_SUCCESS || !p_query_rec->result_cnt )\r
1055         {\r
1056                 h_qp->p_irp_que->state = NDI_CM_IDLE; \r
1057                 if ( h_ioctl )\r
1058                         __ndi_complete_irp( h_qp, h_ioctl, STATUS_HOST_UNREACHABLE );\r
1059                 deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
1060                 cl_free( p_req );\r
1061                 goto exit;              /* ATS request failed */\r
1062         }\r
1063 \r
1064         /* send Path Request */\r
1065         service_record = ib_get_query_svc_rec( p_query_rec->p_result_mad, 0 );\r
1066         __ndi_pr_query( h_ioctl, p_req, &service_record->service_gid );\r
1067 \r
1068 exit:   \r
1069         if( p_query_rec->p_result_mad )\r
1070                 ib_put_mad( p_query_rec->p_result_mad );\r
1071 \r
1072         AL_EXIT( AL_DBG_NDI );\r
1073 }\r
1074 \r
1075 /* Send asynchronous query to SA for a GUID. Return STATUS_PENDING on success. */\r
1076 NTSTATUS\r
1077 __ndi_ats_query(\r
1078         IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
1079         IN              cl_ioctl_handle_t                                       h_ioctl,\r
1080         IN              ual_ndi_req_cm_ioctl_in_t                       *p_req )\r
1081 {\r
1082         ib_user_query_t user_query;\r
1083         ib_service_record_t service_record;\r
1084         ib_query_req_t query_req;\r
1085         ib_api_status_t status;\r
1086         NTSTATUS nt_status = STATUS_PENDING;\r
1087 \r
1088         AL_ENTER( AL_DBG_NDI );\r
1089 \r
1090         query_req.query_type = IB_QUERY_USER_DEFINED;\r
1091         query_req.p_query_input = &user_query;\r
1092         query_req.port_guid = p_req->guid;\r
1093         query_req.timeout_ms = g_sa_timeout;\r
1094         query_req.retry_cnt = g_sa_retries;\r
1095         query_req.flags = 0;    /* IB_FLAGS_SYNC */\r
1096         query_req.query_context = p_req;\r
1097         query_req.pfn_query_cb = __ndi_ats_query_cb;\r
1098 \r
1099         /* TODO: which method one is correct? */\r
1100         user_query.method = IB_MAD_METHOD_GETTABLE;\r
1101         //user_query.method = IB_MAD_METHOD_GET;\r
1102         user_query.attr_id = IB_MAD_ATTR_SERVICE_RECORD;\r
1103         user_query.attr_size = sizeof(ib_service_record_t);\r
1104         user_query.comp_mask =\r
1105                 IB_SR_COMPMASK_SPKEY |\r
1106                 IB_SR_COMPMASK_SLEASE |\r
1107                 IB_SR_COMPMASK_SNAME |\r
1108                 IB_SR_COMPMASK_SDATA8_12 |\r
1109                 IB_SR_COMPMASK_SDATA8_13 | IB_SR_COMPMASK_SDATA8_14 | IB_SR_COMPMASK_SDATA8_15;\r
1110 \r
1111         user_query.p_attr = &service_record;\r
1112 \r
1113         memset( &service_record, 0, sizeof(service_record) );\r
1114         service_record.service_pkey = cl_hton16( IB_DEFAULT_PKEY );\r
1115         service_record.service_data8[12] = (uint8_t) (p_req->pdata.dst_ip_addr[3] >> 0);\r
1116         service_record.service_data8[13] = (uint8_t) (p_req->pdata.dst_ip_addr[3] >> 8);\r
1117         service_record.service_data8[14] = (uint8_t) (p_req->pdata.dst_ip_addr[3] >> 16);\r
1118         service_record.service_data8[15] = (uint8_t) (p_req->pdata.dst_ip_addr[3] >> 24);\r
1119         service_record.service_lease = 0xFFFFFFFF;\r
1120         strcpy( (void*)service_record.service_name, ATS_NAME );\r
1121         \r
1122         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
1123                 ("ATS:: MAD: method %#x, attr_id %#hx, Service: comp_mask %#I64x, IP %d.%d.%d.%d \n", \r
1124                 user_query.method,\r
1125                 CL_NTOH16(user_query.attr_id),\r
1126                 user_query.comp_mask,\r
1127                 service_record.service_data8[12],\r
1128                 service_record.service_data8[13],\r
1129                 service_record.service_data8[14],\r
1130                 service_record.service_data8[15]\r
1131                 ) );\r
1132 \r
1133         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, \r
1134                 ("h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n", \r
1135                 (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
1136 \r
1137         // preserve QP for the life of this IOCTL\r
1138         ref_al_obj( &h_qp->obj );               /* take IRP life reference */\r
1139 \r
1140         /* insert IRP in the queue */\r
1141         IoCsqInsertIrp( &h_qp->p_irp_que->csq, h_ioctl, NULL );\r
1142 \r
1143         /* prevent destroying QP after cancelling of the IRP and before ib_query calback*/\r
1144         ref_al_obj( &h_qp->obj );               /* take IRP SA reference */\r
1145 \r
1146         /* query SA */\r
1147         status = ib_query( qp_get_al( h_qp ), &query_req, &h_qp->p_irp_que->h_query );\r
1148         if( status != IB_SUCCESS )\r
1149         {\r
1150                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("ib_query failed (%d)\n", status) );\r
1151                 deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
1152                 h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
1153                 if ( h_ioctl )\r
1154                 { /* IOCTL should be released in the caller */\r
1155                         deref_al_obj( &h_qp->obj );             /* release IRP life reference */\r
1156                         nt_status = STATUS_DRIVER_INTERNAL_ERROR;\r
1157                 }\r
1158         }\r
1159 \r
1160         AL_EXIT( AL_DBG_NDI );\r
1161         return nt_status;\r
1162 }\r
1163 \r
1164 NTSTATUS\r
1165 ndi_req_cm(\r
1166         IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
1167         IN              cl_ioctl_handle_t                                       h_ioctl,\r
1168         IN              ual_ndi_req_cm_ioctl_in_t                       *p_req\r
1169         )\r
1170 {\r
1171         NTSTATUS nt_status;\r
1172 \r
1173         AL_ENTER( AL_DBG_NDI );\r
1174 \r
1175         /* check outstanding request */\r
1176         __ndi_acquire_lock( &h_qp->p_irp_que->csq, NULL);\r
1177         if ( h_qp->p_irp_que->h_ioctl )\r
1178         {\r
1179                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
1180                         ("STATUS_CONNECTION_ACTIVE: h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n",\r
1181                         (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
1182                 nt_status = STATUS_CONNECTION_ACTIVE;\r
1183                 __ndi_release_lock( &h_qp->p_irp_que->csq, 0 );\r
1184                 goto exit;\r
1185         }\r
1186         if ( h_qp->p_irp_que->state != NDI_CM_IDLE )\r
1187         {\r
1188                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
1189                         ("STATUS_INVALID_DEVICE_STATE: h_qp %I64x, ref_cnt %d, state %d\n",\r
1190                         (uint64_t)h_qp, h_qp->obj.ref_cnt, h_qp->p_irp_que->state ) );\r
1191                 nt_status = STATUS_INVALID_DEVICE_STATE;\r
1192                 __ndi_release_lock( &h_qp->p_irp_que->csq, 0 );\r
1193                 goto exit;\r
1194         }\r
1195         h_qp->p_irp_que->h_ioctl = h_ioctl;     /* mark IRP as present */\r
1196         h_qp->p_irp_que->state = NDI_CM_CONNECTING_ATS_SENT;\r
1197         __ndi_release_lock( &h_qp->p_irp_que->csq, 0 );\r
1198 \r
1199         /* send ATS request */\r
1200         nt_status = __ndi_ats_query( h_qp, h_ioctl, p_req );\r
1201 \r
1202 exit:\r
1203         if ( nt_status != STATUS_PENDING )\r
1204         {\r
1205                 cl_free( p_req );\r
1206                 h_qp->p_irp_que->state = NDI_CM_IDLE; \r
1207                 h_qp->p_irp_que->h_ioctl = NULL; /* mark IRP as present */\r
1208                 cl_ioctl_complete( h_ioctl, nt_status, 0 );\r
1209         }\r
1210         AL_EXIT( AL_DBG_NDI );\r
1211         return STATUS_PENDING;\r
1212 }\r
1213 \r
1214 \r
1215 /*******************************************************************\r
1216  *\r
1217  * RTU CM request\r
1218  *\r
1219  ******************************************************************/\r
1220 \r
1221 static void\r
1222 __ndi_rtu_cm(\r
1223         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1224         IN                              PIRP                                            p_irp )\r
1225 {\r
1226         NTSTATUS nt_status;\r
1227         ib_qp_mod_t qp_mod;\r
1228         ib_api_status_t status;\r
1229         ib_qp_handle_t VOID_PTR64 h_qp = p_irp->Tail.Overlay.DriverContext[0];\r
1230         ual_ndi_rtu_cm_ioctl_in_t *p_rtu = \r
1231                 (ual_ndi_rtu_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
1232         uint8_t pdata[IB_REJ_PDATA_SIZE];\r
1233         uint8_t psize = sizeof(pdata);\r
1234 \r
1235         UNUSED_PARAM(p_dev_obj);\r
1236 \r
1237         AL_ENTER( AL_DBG_NDI );\r
1238 \r
1239         /* free the work item if any */\r
1240         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1241                 IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
1242 \r
1243         /* change the QP state to RTS */\r
1244         status = __ndi_qp2rts( h_qp, p_rtu->init_depth, \r
1245                 p_rtu->resp_res, p_irp, &qp_mod );\r
1246         if ( status != IB_SUCCESS )\r
1247         {\r
1248                 goto err;\r
1249         }\r
1250         \r
1251         /* send RTU */\r
1252         al_cep_get_pdata( qp_get_al( h_qp ), ((al_conn_qp_t*)h_qp)->cid, &psize, pdata );\r
1253         status = al_cep_rtu( qp_get_al( h_qp ), ((al_conn_qp_t*)h_qp)->cid, pdata, psize );\r
1254         if( status != IB_SUCCESS && status != IB_INVALID_STATE )\r
1255         {\r
1256                 net32_t                         cid;\r
1257 err:\r
1258                 /* Reject and abort the connection. */\r
1259                 al_cep_rej(\r
1260                         qp_get_al( h_qp ), ((al_conn_qp_t*)h_qp)->cid, \r
1261                         IB_REJ_INSUF_QP, NULL, 0, NULL, 0 );\r
1262 \r
1263                 __cep_timewait_qp( h_qp );\r
1264 \r
1265                 cid = cl_atomic_xchg( &((al_conn_qp_t*)h_qp)->cid, AL_INVALID_CID );\r
1266 \r
1267                 if( cid != AL_INVALID_CID )\r
1268                 {\r
1269                         ref_al_obj( &h_qp->obj );\r
1270                         if( al_destroy_cep( qp_get_al( h_qp ), cid, deref_al_obj ) != IB_SUCCESS )\r
1271                         {\r
1272                                 deref_al_obj( &h_qp->obj );\r
1273                         }\r
1274                 }\r
1275 \r
1276                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
1277                         ("al_cep_rtu returned %s.\n", ib_get_err_str( status )) );\r
1278                 h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
1279                 nt_status = STATUS_DRIVER_INTERNAL_ERROR;\r
1280                 p_irp->IoStatus.Information = 0;\r
1281                 goto exit;\r
1282         }\r
1283 \r
1284         p_irp->IoStatus.Information = sizeof(uint32_t);;\r
1285         h_qp->p_irp_que->state = NDI_CM_CONNECTED;\r
1286         nt_status = STATUS_SUCCESS;\r
1287 \r
1288 exit:   \r
1289         /* release the reference only for async case */\r
1290         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1291                 deref_al_obj( &h_qp->obj );\r
1292 \r
1293         p_irp->IoStatus.Status = nt_status;\r
1294         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1295         AL_EXIT( AL_DBG_NDI );\r
1296 }\r
1297 \r
1298 cl_status_t\r
1299 ndi_rtu_cm(\r
1300         IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
1301         IN              PIRP                                                            p_irp\r
1302         )\r
1303 {\r
1304         IO_STACK_LOCATION       *p_io_stack;\r
1305 \r
1306         AL_ENTER( AL_DBG_NDI );\r
1307 \r
1308         p_irp->Tail.Overlay.DriverContext[0] = h_qp;\r
1309         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1310         p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject );\r
1311         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1312         { /* asyncronous performing */\r
1313                 /* take a ref to prevent QP destroy before calling work item */\r
1314                 ref_al_obj( &h_qp->obj );\r
1315                 IoMarkIrpPending( p_irp );\r
1316                 IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1],\r
1317                         __ndi_rtu_cm, DelayedWorkQueue, p_irp );\r
1318         }\r
1319         else\r
1320         { /* syncronous performing */\r
1321                 p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
1322                 __ndi_rtu_cm( p_io_stack->DeviceObject, p_irp );\r
1323         }\r
1324 \r
1325         AL_EXIT( AL_DBG_NDI );\r
1326         return CL_PENDING;\r
1327 }\r
1328 \r
1329 \r
1330 /*******************************************************************\r
1331  *\r
1332  * REP CM request\r
1333  *\r
1334  ******************************************************************/\r
1335 \r
1336 static void\r
1337 __ndi_rep_cm(\r
1338         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1339         IN                              PIRP                                            p_irp )\r
1340 {\r
1341         NTSTATUS nt_status;\r
1342         ib_qp_mod_t qp_mod;\r
1343         ib_api_status_t status;\r
1344         ib_qp_handle_t VOID_PTR64 h_qp = p_irp->Tail.Overlay.DriverContext[0];\r
1345         ual_ndi_rep_cm_ioctl_in_t *p_rep = \r
1346                 (ual_ndi_rep_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
1347 \r
1348         UNUSED_PARAM(p_dev_obj);\r
1349 \r
1350         AL_ENTER( AL_DBG_NDI );\r
1351 \r
1352         /* free the work item if any */\r
1353         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1354                 IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
1355 \r
1356         /* change the QP state to RTS */\r
1357         status = __ndi_qp2rts( h_qp, p_rep->init_depth, \r
1358                 p_rep->resp_res, p_irp, &qp_mod );\r
1359         if ( status != IB_SUCCESS )\r
1360         {\r
1361                 nt_status = STATUS_CONNECTION_ABORTED;\r
1362                 goto err;\r
1363         }\r
1364         \r
1365         /* send REP */\r
1366         status = al_cep_send_rep ( qp_get_al( h_qp ), p_rep->cid );\r
1367         if( status != IB_SUCCESS )\r
1368         {\r
1369                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1370                         ("al_cep_send_rep returned %s\n", ib_get_err_str(status)) );\r
1371                 if (status == IB_INSUFFICIENT_RESOURCES)\r
1372                         nt_status = STATUS_INSUFFICIENT_RESOURCES;\r
1373                 else\r
1374                         nt_status = STATUS_CONNECTION_ABORTED;\r
1375 err:\r
1376                 cl_atomic_xchg( &((al_conn_qp_t*)h_qp)->cid, AL_INVALID_CID );\r
1377 \r
1378                 /* Reject and abort the connection. */\r
1379                 al_cep_rej( qp_get_al( h_qp ), p_rep->cid, IB_REJ_INSUF_QP, NULL, 0, NULL, 0 );\r
1380 \r
1381                 /* transit QP to error state */\r
1382                 __cep_timewait_qp( h_qp );\r
1383 \r
1384                 ref_al_obj( &h_qp->obj );\r
1385                 if( al_destroy_cep( qp_get_al( h_qp ), p_rep->cid, deref_al_obj ) != IB_SUCCESS )\r
1386                         deref_al_obj( &h_qp->obj );\r
1387 \r
1388                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1389                         ("al_cep_rtu returned %s.\n", ib_get_err_str( status )) );\r
1390                 h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
1391                 p_irp->IoStatus.Information = 0;\r
1392                 goto exit;\r
1393         }\r
1394 \r
1395         p_irp->IoStatus.Information = cl_ioctl_out_size( p_irp );\r
1396         h_qp->p_irp_que->state = NDI_CM_CONNECTED;\r
1397         nt_status = STATUS_SUCCESS;\r
1398 \r
1399 exit:   \r
1400         /* release the reference only for async case */\r
1401         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1402                 deref_al_obj( &h_qp->obj );\r
1403 \r
1404         p_irp->IoStatus.Status = nt_status;\r
1405         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1406         AL_EXIT( AL_DBG_NDI );\r
1407 }\r
1408 \r
1409 static void\r
1410 __ndi_fill_cm_rep(\r
1411         IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
1412         IN              ual_ndi_rep_cm_ioctl_in_t                       *p_rep,\r
1413                 OUT     ib_cm_rep_t                                                     *p_cm_rep)\r
1414 {\r
1415         AL_ENTER( AL_DBG_NDI );\r
1416 \r
1417         memset( p_cm_rep, 0, sizeof(ib_cm_rep_t) );\r
1418 \r
1419         p_cm_rep->p_rep_pdata = p_rep->pdata;\r
1420         p_cm_rep->rep_length = sizeof(p_rep->pdata);\r
1421 \r
1422         p_cm_rep->qp_type = IB_QPT_RELIABLE_CONN;\r
1423         p_cm_rep->h_qp = h_qp;\r
1424 \r
1425         p_cm_rep->access_ctrl = IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE;\r
1426         p_cm_rep->init_depth = 0;\r
1427         p_cm_rep->target_ack_delay = 10;\r
1428         p_cm_rep->failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED;\r
1429         p_cm_rep->flow_ctrl = TRUE;     /* HCAs must support end-to-end flow control. */\r
1430         p_cm_rep->rnr_nak_timeout = QP_ATTRIB_RNR_NAK_TIMEOUT;\r
1431         p_cm_rep->rnr_retry_cnt = QP_ATTRIB_RNR_RETRY;\r
1432 \r
1433         AL_EXIT( AL_DBG_NDI );\r
1434 }\r
1435 \r
1436 NTSTATUS\r
1437 ndi_rep_cm(\r
1438         IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
1439         IN              net32_t                 const                           cid,\r
1440         IN              PIRP                                                            p_irp,\r
1441         IN              ual_ndi_rep_cm_ioctl_in_t                       *p_rep\r
1442         )\r
1443 {\r
1444         IO_STACK_LOCATION       *p_io_stack;\r
1445         ib_cm_rep_t cm_rep;\r
1446         ib_qp_mod_t qp_mod;\r
1447         net32_t old_cid;\r
1448         ib_api_status_t status;\r
1449         NTSTATUS nt_status;\r
1450 \r
1451         AL_ENTER( AL_DBG_NDI );\r
1452 \r
1453         /* Format ib_cm_req_t structure */\r
1454         __ndi_fill_cm_rep( h_qp, p_rep, &cm_rep );\r
1455 \r
1456         /* prepare Passive CEP for connection */\r
1457         status = al_cep_pre_rep_ex( qp_get_al( h_qp ), cid, __ndi_cm_handler, h_qp, &cm_rep, &qp_mod );\r
1458         if( status != IB_SUCCESS )\r
1459         {\r
1460                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1461                         ("al_cep_pre_rep_ex returned %s.\n", ib_get_err_str( status )) );\r
1462                 switch (status)\r
1463                 {\r
1464                         case IB_INVALID_HANDLE:\r
1465                                 nt_status = STATUS_CANCELLED;\r
1466                                 break;\r
1467                         case IB_INVALID_STATE:\r
1468                                 nt_status = STATUS_CONNECTION_ABORTED;\r
1469                                 break;\r
1470                         default:\r
1471                                 nt_status = STATUS_INSUFFICIENT_RESOURCES;\r
1472                                 break;\r
1473                 }\r
1474                 goto err_cep_destroy;\r
1475         }\r
1476 \r
1477         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
1478                 ("Prepared Passive CEP with cid %d, h_al %p, context %p\n",\r
1479                 cid, qp_get_al( h_qp ), h_qp ) );\r
1480 \r
1481         /* See if this QP has already been connected. */\r
1482         old_cid = cl_atomic_comp_xchg( &((al_conn_qp_t*)h_qp)->cid, AL_INVALID_CID, cid );\r
1483         if( old_cid != AL_INVALID_CID )\r
1484         {\r
1485                 nt_status = STATUS_CONNECTION_ACTIVE;\r
1486                 goto err_cep_destroy;\r
1487         }\r
1488 \r
1489         /* transfer work to a work the thread */\r
1490         p_irp->Tail.Overlay.DriverContext[0] = h_qp;\r
1491         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1492         p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject );\r
1493         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1494         { /* asyncronous performing */\r
1495                 /* take a ref to prevent QP destroy before calling work item */\r
1496                 ref_al_obj( &h_qp->obj );\r
1497                 IoMarkIrpPending( p_irp );\r
1498                 IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1],\r
1499                         __ndi_rep_cm, DelayedWorkQueue, p_irp );\r
1500         }\r
1501         else\r
1502         { /* syncronous performing */\r
1503                 __ndi_rep_cm( p_io_stack->DeviceObject, p_irp );\r
1504         }\r
1505         goto exit;\r
1506 \r
1507 err_cep_destroy:\r
1508         al_destroy_cep( qp_get_al( h_qp ), cid, NULL );\r
1509         \r
1510         h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
1511         cl_ioctl_complete( p_irp, nt_status, 0 );\r
1512 \r
1513 exit:\r
1514         AL_EXIT( AL_DBG_NDI );\r
1515         return CL_PENDING;\r
1516 }\r
1517 \r
1518 \r
1519 /*******************************************************************\r
1520  *\r
1521  * DREQ CM request\r
1522  *\r
1523  ******************************************************************/\r
1524 \r
1525 NTSTATUS\r
1526 ndi_dreq_cm(\r
1527         IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
1528         IN              PIRP                                                            p_irp\r
1529         )\r
1530 {\r
1531         ib_qp_mod_t qp_mod;\r
1532         net32_t cid;\r
1533         ib_api_status_t status;\r
1534         NTSTATUS nt_status;\r
1535         uint64_t timewait_us;\r
1536 \r
1537         AL_ENTER( AL_DBG_NDI );\r
1538 \r
1539         status = al_cep_get_timewait( qp_get_al( h_qp ), \r
1540                 ((al_conn_qp_t*)h_qp)->cid, &timewait_us );\r
1541 \r
1542         if (status != IB_SUCCESS)\r
1543         {\r
1544                 nt_status = STATUS_CONNECTION_INVALID;\r
1545                 goto exit;\r
1546         }\r
1547 \r
1548         /* bring QP to error state */\r
1549         cl_memclr( &qp_mod, sizeof(qp_mod) );\r
1550         qp_mod.req_state = IB_QPS_ERROR;\r
1551         \r
1552         status = ndi_modify_qp( h_qp, &qp_mod, \r
1553                 cl_ioctl_out_size( p_irp ), cl_ioctl_out_buf( p_irp ) );\r
1554         if ( status != IB_SUCCESS )\r
1555         {\r
1556                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1557                         ("ndi_modify_qp to ERROR returned %s.\n", ib_get_err_str(status) ) );\r
1558                 nt_status = STATUS_CONNECTION_INVALID;\r
1559                 goto exit;\r
1560         }\r
1561 \r
1562         /* Store the timestamp after which the QP exits timewait. */\r
1563         h_qp->timewait = cl_get_time_stamp() + timewait_us;\r
1564 \r
1565         cid = cl_atomic_xchg( &((al_conn_qp_t*)h_qp)->cid, AL_INVALID_CID );\r
1566 \r
1567         if( cid != AL_INVALID_CID )\r
1568         {\r
1569                 ref_al_obj( &h_qp->obj );\r
1570                 if( al_destroy_cep( qp_get_al( h_qp ), cid, deref_al_obj ) != IB_SUCCESS )\r
1571                 {\r
1572                         deref_al_obj( &h_qp->obj );\r
1573                 }\r
1574         }\r
1575 \r
1576         nt_status = STATUS_SUCCESS;\r
1577 \r
1578 exit:\r
1579         h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
1580         cl_ioctl_complete( p_irp, nt_status, cl_ioctl_out_size( p_irp ) );\r
1581 \r
1582         AL_EXIT( AL_DBG_NDI );\r
1583         return STATUS_EVENT_DONE;       /* CL_COMPLETED */\r
1584 }\r
1585 \r
1586 \r
1587 \r