[IBAL] This patch adds a missing reference taken on a QP when delaying the QP modific...
[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     deref_al_obj( &p_async_dreq->cm.h_qp->obj );\r
712         cl_free( p_async_dreq );\r
713         AL_EXIT( AL_DBG_NDI );\r
714 }\r
715 \r
716 static void\r
717 __ndi_proc_dreq(\r
718         IN                              ib_cm_handle_t* const           p_cm,\r
719         IN                              mad_cm_dreq_t* const            p_dreq )\r
720 {\r
721         ndi_async_dreq_t *p_async_dreq;\r
722         UNUSED_PARAM(p_dreq);\r
723 \r
724         AL_ENTER( AL_DBG_NDI );\r
725 \r
726         AL_PRINT(TRACE_LEVEL_INFORMATION ,AL_DBG_NDI ,("h_qp = 0x%p\n", p_cm->h_qp));\r
727 \r
728         p_async_dreq = (ndi_async_dreq_t*)cl_zalloc( sizeof(ndi_async_dreq_t) );\r
729         if( !p_async_dreq )\r
730         {\r
731                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
732                         ("failed to cl_zalloc ndi_async_dreq_t (%d bytes)\n",\r
733                         sizeof(ndi_async_dreq_t)) );\r
734                 ASSERT(FALSE);\r
735                 goto exit;\r
736         }\r
737 \r
738     ref_al_obj( &p_cm->h_qp->obj );\r
739         p_async_dreq->cm = *p_cm;\r
740         p_async_dreq->item.pfn_callback = __ndi_proc_dreq_async;\r
741 \r
742         /* Queue the MAD for asynchronous processing. */\r
743         cl_async_proc_queue( gp_async_proc_mgr, &p_async_dreq->item );\r
744 \r
745 exit:   \r
746         AL_EXIT( AL_DBG_NDI );\r
747 }\r
748 \r
749 static void\r
750 __ndi_cm_handler(\r
751         IN              const   ib_al_handle_t FUNC_PTR64                               h_al,\r
752         IN              const   net32_t                                         cid )\r
753 {\r
754         void* VOID_PTR64                context;\r
755         net32_t                         new_cid;\r
756         ib_mad_element_t        *p_mad_el;\r
757         ib_cm_handle_t          h_cm;\r
758 \r
759         AL_ENTER( AL_DBG_NDI );\r
760 \r
761         while( al_cep_poll( h_al, cid, &context, &new_cid, &p_mad_el ) == IB_SUCCESS )\r
762         {\r
763                 ib_mad_t*p_mad = ib_get_mad_buf( p_mad_el );\r
764                 ib_qp_handle_t VOID_PTR64 h_qp = (ib_qp_handle_t VOID_PTR64)context;\r
765 \r
766                 if( p_mad_el->status != IB_SUCCESS )\r
767                 {\r
768                         switch( p_mad->attr_id )\r
769                         {\r
770                         case CM_REQ_ATTR_ID:\r
771                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
772                                         ("REQ timeouted for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
773                                         cid, h_al, h_qp, new_cid ) );\r
774                                 __ndi_complete_irp_ex( h_qp, STATUS_TIMEOUT, NDI_CM_IDLE );\r
775                                 break;\r
776 \r
777                         case CM_REP_ATTR_ID:\r
778                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
779                                         ("REP timeouted for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
780                                         cid, h_al, h_qp, new_cid ) );\r
781                                 __ndi_complete_irp_ex( h_qp, STATUS_CONNECTION_ABORTED, NDI_CM_IDLE );\r
782                                 break;\r
783 \r
784                         case CM_DREQ_ATTR_ID:\r
785                         default:\r
786                                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
787                                         ("Unhandled MAD attr ID %d for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
788                                         p_mad->attr_id, cid, h_al, h_qp, new_cid ) );\r
789                                 break;\r
790                         }\r
791                 }\r
792                 else\r
793                 {\r
794                         h_cm.h_al = h_al;\r
795                         h_cm.h_qp = h_qp;\r
796                         h_cm.cid = cid;\r
797                         \r
798                         switch( p_mad->attr_id )\r
799                         {\r
800                         case CM_REP_ATTR_ID:\r
801                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
802                                         ("REP received for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
803                                         cid, h_al, h_qp, new_cid ) );\r
804                                 CL_ASSERT( ((al_conn_qp_t*)h_qp)->cid == (int32_t)cid || \r
805                                         ((al_conn_qp_t*)h_qp)->cid == AL_INVALID_CID ||\r
806                                         ((al_conn_qp_t*)h_qp)->cid == AL_RESERVED_CID );\r
807                                 __ndi_proc_rep( &h_cm, (mad_cm_rep_t*)p_mad );\r
808                                 break;\r
809                         \r
810                         case CM_REJ_ATTR_ID:\r
811                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
812                                         ("REJ received for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
813                                         cid, h_al, h_qp, new_cid ) );\r
814                                 __ndi_proc_rej( &h_cm, (mad_cm_rej_t*)p_mad );\r
815                                 break;\r
816                 \r
817                         case CM_DREQ_ATTR_ID:\r
818                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
819                                         ("DREQ received for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
820                                         cid, h_al, h_qp, new_cid ) );\r
821                                 CL_ASSERT( ((al_conn_qp_t*)h_qp)->cid == (int32_t)cid || \r
822                                 ((al_conn_qp_t*)h_qp)->cid == AL_INVALID_CID ||\r
823                                 ((al_conn_qp_t*)h_qp)->cid == AL_RESERVED_CID );\r
824                                 __ndi_proc_dreq( &h_cm, (mad_cm_dreq_t*)p_mad );\r
825                                 break;\r
826                 \r
827                         default:\r
828                                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
829                                         ("Invalid CM recv MAD attribute ID %d.\n", p_mad->attr_id) );\r
830                         }\r
831                 }\r
832 \r
833                 ib_put_mad( p_mad_el );\r
834         }\r
835 \r
836         AL_EXIT( AL_DBG_NDI );\r
837 }\r
838 \r
839 static void\r
840 __ndi_fill_cm_req(\r
841         IN              ib_qp_handle_t  const                           h_qp,\r
842         IN              ual_ndi_req_cm_ioctl_in_t                       *p_req,\r
843         IN              ib_path_rec_t                                           *p_path_rec,\r
844                 OUT     ib_cm_req_t                                                     *p_cm_req)\r
845 {\r
846         AL_ENTER( AL_DBG_NDI );\r
847 \r
848         memset( p_cm_req, 0, sizeof(ib_cm_req_t) );\r
849 \r
850         p_cm_req->svc_id = IB_REQ_CM_RDMA_SID_PREFIX | (p_req->prot << 16) | p_req->dst_port;\r
851         p_cm_req->max_cm_retries = g_max_cm_retries;\r
852         p_cm_req->p_primary_path = p_path_rec;  \r
853 \r
854         p_cm_req->p_req_pdata = (uint8_t *)&p_req->pdata;\r
855         p_cm_req->req_length = sizeof(p_req->pdata);\r
856 \r
857         p_cm_req->qp_type = IB_QPT_RELIABLE_CONN;\r
858         p_cm_req->h_qp = h_qp;\r
859         p_cm_req->resp_res = 0;\r
860         p_cm_req->init_depth = 0;\r
861 \r
862         p_cm_req->remote_resp_timeout =\r
863                 ib_path_rec_pkt_life( p_path_rec ) + CM_REMOTE_TIMEOUT;\r
864         if( p_cm_req->remote_resp_timeout > 0x1F )\r
865                 p_cm_req->remote_resp_timeout = 0x1F;\r
866         else if( p_cm_req->remote_resp_timeout < CM_MIN_REMOTE_TIMEOUT )\r
867                 p_cm_req->remote_resp_timeout = CM_MIN_REMOTE_TIMEOUT;\r
868 \r
869         p_cm_req->flow_ctrl = TRUE;     /* HCAs must support end-to-end flow control. */\r
870 \r
871         p_cm_req->local_resp_timeout =\r
872                 ib_path_rec_pkt_life( p_path_rec ) + CM_LOCAL_TIMEOUT;\r
873         if( p_cm_req->local_resp_timeout > 0x1F )\r
874                 p_cm_req->local_resp_timeout = 0x1F;\r
875         else if( p_cm_req->local_resp_timeout < CM_MIN_LOCAL_TIMEOUT )\r
876                 p_cm_req->local_resp_timeout = CM_MIN_LOCAL_TIMEOUT;\r
877 \r
878         p_cm_req->rnr_nak_timeout = QP_ATTRIB_RNR_NAK_TIMEOUT;\r
879         p_cm_req->rnr_retry_cnt = QP_ATTRIB_RNR_RETRY;\r
880         p_cm_req->retry_cnt = g_qp_retries;\r
881         p_cm_req->p_alt_path = NULL;\r
882 \r
883         AL_EXIT( AL_DBG_NDI );\r
884 }\r
885 \r
886 static void AL_API\r
887 __ndi_pr_query_cb(\r
888                                         ib_query_rec_t                          *p_query_rec )\r
889 {\r
890         ib_api_status_t status;\r
891         cl_ioctl_handle_t h_ioctl;\r
892         ib_cm_req_t cm_req;\r
893         uint8_t pkt_life;\r
894         ib_qp_mod_t qp_mod;\r
895         ib_path_rec_t *p_path_rec;\r
896         ual_ndi_req_cm_ioctl_in_t *p_req = (ual_ndi_req_cm_ioctl_in_t* VOID_PTR64)p_query_rec->query_context;\r
897         ib_qp_handle_t VOID_PTR64 h_qp = (ib_qp_handle_t VOID_PTR64)HDL_TO_PTR(p_req->h_qp);\r
898         net32_t cid, old_cid;\r
899 \r
900         AL_ENTER( AL_DBG_NDI );\r
901 \r
902         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
903                 ("status is %d, count is %d, context %p\n", p_query_rec->status,\r
904                 p_query_rec->result_cnt, p_query_rec->query_context) );\r
905 \r
906         h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
907         if( !h_ioctl || p_query_rec->status != IB_SUCCESS || !p_query_rec->result_cnt )\r
908                 goto err_irp_complete;\r
909 \r
910         /* Path Record has been received ! */\r
911         p_path_rec = ib_get_query_path_rec( p_query_rec->p_result_mad, 0 );\r
912 \r
913         /* fix packet life */\r
914         CL_ASSERT( p_path_rec );\r
915         pkt_life = ib_path_rec_pkt_life( p_path_rec ) + g_pkt_life_modifier;\r
916         if( pkt_life > 0x1F )\r
917                 pkt_life = 0x1F;\r
918 \r
919         p_path_rec->pkt_life &= IB_PATH_REC_SELECTOR_MASK;\r
920         p_path_rec->pkt_life |= pkt_life;\r
921 \r
922         /* Get a CEP and bind it to the QP. */\r
923         status = al_create_cep( qp_get_al( h_qp ), __ndi_cm_handler, h_qp, &cid );\r
924         if( status != IB_SUCCESS )\r
925         {\r
926                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
927                         ("al_create_cep returned %s.\n", ib_get_err_str( status )) );\r
928                 goto err_irp_complete;\r
929         }\r
930         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
931                 ("Created Active CEP with cid %d, h_al %p, context %p\n",\r
932                 cid, qp_get_al( h_qp ), h_qp ) );\r
933 \r
934         /* See if this QP has already been connected. */\r
935         old_cid = cl_atomic_comp_xchg( &((al_conn_qp_t*)h_qp)->cid, AL_INVALID_CID, cid );\r
936         if( old_cid != AL_INVALID_CID || h_qp->obj.state == CL_DESTROYING )\r
937                 goto err_cep_destroy;\r
938 \r
939         /* Format ib_cm_req_t structure */\r
940         __ndi_fill_cm_req( h_qp, p_req, p_path_rec, &cm_req );\r
941 \r
942         /* prepare CEP for connection */\r
943         status = al_cep_pre_req( qp_get_al( h_qp ),\r
944                 ((al_conn_qp_t*)h_qp)->cid, &cm_req, &qp_mod );\r
945         if( status != IB_SUCCESS )\r
946         {\r
947                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
948                         ("al_cep_pre_req returned %s.\n", ib_get_err_str( status )) );\r
949                 goto err_cep_destroy;\r
950         }\r
951 \r
952         /* insert IRP in the queue */\r
953         h_qp->p_irp_que->state = NDI_CM_CONNECTING_REQ_SENT;\r
954         IoCsqInsertIrp( &h_qp->p_irp_que->csq, h_ioctl, NULL );\r
955 \r
956         /* send CM REQ */\r
957         status = al_cep_send_req( qp_get_al( h_qp ), cid );\r
958         if( status != IB_SUCCESS )\r
959                 goto err_irp_remove;\r
960 \r
961         /* we can release it now. In case of QP destroy __destroying_qp will remove CEP */\r
962         deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
963 \r
964         /* SUCCESS ! */\r
965         goto exit;\r
966 \r
967 err_irp_remove:\r
968         h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
969 \r
970 err_cep_destroy:\r
971         al_destroy_cep( qp_get_al( h_qp ), cid, NULL );\r
972         \r
973 err_irp_complete:\r
974         h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
975         /* the IRP "has" 2 QP references, taken in __ndi_ats_query */\r
976         if ( h_ioctl )\r
977                 __ndi_complete_irp( h_qp, h_ioctl, STATUS_HOST_UNREACHABLE );\r
978         deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
979 \r
980 exit:   \r
981         cl_free( p_req );\r
982         if( p_query_rec->p_result_mad )\r
983                 ib_put_mad( p_query_rec->p_result_mad );\r
984 \r
985         AL_EXIT( AL_DBG_NDI );\r
986 }\r
987 \r
988 \r
989 \r
990 /* Synchronously query the SA for a GUID. Return 0 on success. */\r
991 void\r
992 __ndi_pr_query(\r
993         IN              cl_ioctl_handle_t                                       h_ioctl,\r
994         IN              ual_ndi_req_cm_ioctl_in_t                       *p_req,\r
995         IN              ib_gid_t                                                        *p_dest_gid )\r
996 {\r
997         ib_gid_pair_t user_query;\r
998         ib_query_req_t query_req;\r
999         ib_api_status_t status;\r
1000         ib_qp_handle_t VOID_PTR64 h_qp = (ib_qp_handle_t VOID_PTR64)HDL_TO_PTR(p_req->h_qp);\r
1001 \r
1002         AL_ENTER( AL_DBG_NDI );\r
1003 \r
1004         query_req.query_type = IB_QUERY_PATH_REC_BY_GIDS;\r
1005         query_req.p_query_input = &user_query;\r
1006         query_req.port_guid = p_req->guid;\r
1007         query_req.timeout_ms = g_sa_timeout;\r
1008         query_req.retry_cnt = g_sa_retries;\r
1009         query_req.flags = 0;    /* IB_FLAGS_SYNC */\r
1010         query_req.query_context = p_req;\r
1011         query_req.pfn_query_cb = __ndi_pr_query_cb;\r
1012 \r
1013         user_query.src_gid.unicast.prefix = p_dest_gid->unicast.prefix;\r
1014         user_query.src_gid.unicast.interface_id = p_req->guid;\r
1015         user_query.dest_gid = *p_dest_gid;\r
1016 \r
1017         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
1018                 ("Query for path from %I64x to %I64x\n",\r
1019                 p_req->guid, ib_gid_get_guid( p_dest_gid )) );\r
1020 \r
1021         /* insert IRP in the queue */\r
1022         h_qp->p_irp_que->state = NDI_CM_CONNECTING_QPR_SENT;\r
1023         IoCsqInsertIrp( &h_qp->p_irp_que->csq, h_ioctl, NULL );\r
1024 \r
1025         status = ib_query( qp_get_al( h_qp ), &query_req, &h_qp->p_irp_que->h_query );\r
1026 \r
1027         if( status != IB_SUCCESS )\r
1028         {\r
1029                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("ib_query failed (%d)\n", status) );\r
1030                 cl_free( p_req );\r
1031                 __ndi_complete_irp_ex( h_qp, CL_ERROR, NDI_CM_IDLE );\r
1032                 /* relase additional reference, taken in __ndi_ats_query */\r
1033                 deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
1034         }\r
1035 \r
1036         AL_EXIT( AL_DBG_NDI );\r
1037 }\r
1038 \r
1039 \r
1040 static void AL_API\r
1041 __ndi_ats_query_cb(\r
1042         IN                              ib_query_rec_t                          *p_query_rec )\r
1043 {\r
1044         cl_ioctl_handle_t h_ioctl;\r
1045         ib_service_record_t *service_record;\r
1046         ual_ndi_req_cm_ioctl_in_t *p_req = (ual_ndi_req_cm_ioctl_in_t* VOID_PTR64)p_query_rec->query_context;\r
1047         ib_qp_handle_t VOID_PTR64 h_qp = (ib_qp_handle_t VOID_PTR64)HDL_TO_PTR(p_req->h_qp);\r
1048 \r
1049         AL_ENTER( AL_DBG_NDI );\r
1050 \r
1051         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1052                 ("status is %d, count is %d, context %p\n", p_query_rec->status,\r
1053                 p_query_rec->result_cnt, p_query_rec->query_context) );\r
1054 \r
1055         h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
1056         if( !h_ioctl || p_query_rec->status != IB_SUCCESS || !p_query_rec->result_cnt )\r
1057         {\r
1058                 h_qp->p_irp_que->state = NDI_CM_IDLE; \r
1059                 if ( h_ioctl )\r
1060                         __ndi_complete_irp( h_qp, h_ioctl, STATUS_HOST_UNREACHABLE );\r
1061                 deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
1062                 cl_free( p_req );\r
1063                 goto exit;              /* ATS request failed */\r
1064         }\r
1065 \r
1066         /* send Path Request */\r
1067         service_record = ib_get_query_svc_rec( p_query_rec->p_result_mad, 0 );\r
1068         __ndi_pr_query( h_ioctl, p_req, &service_record->service_gid );\r
1069 \r
1070 exit:   \r
1071         if( p_query_rec->p_result_mad )\r
1072                 ib_put_mad( p_query_rec->p_result_mad );\r
1073 \r
1074         AL_EXIT( AL_DBG_NDI );\r
1075 }\r
1076 \r
1077 /* Send asynchronous query to SA for a GUID. Return STATUS_PENDING on success. */\r
1078 NTSTATUS\r
1079 __ndi_ats_query(\r
1080         IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
1081         IN              cl_ioctl_handle_t                                       h_ioctl,\r
1082         IN              ual_ndi_req_cm_ioctl_in_t                       *p_req )\r
1083 {\r
1084         ib_user_query_t user_query;\r
1085         ib_service_record_t service_record;\r
1086         ib_query_req_t query_req;\r
1087         ib_api_status_t status;\r
1088         NTSTATUS nt_status = STATUS_PENDING;\r
1089 \r
1090         AL_ENTER( AL_DBG_NDI );\r
1091 \r
1092         query_req.query_type = IB_QUERY_USER_DEFINED;\r
1093         query_req.p_query_input = &user_query;\r
1094         query_req.port_guid = p_req->guid;\r
1095         query_req.timeout_ms = g_sa_timeout;\r
1096         query_req.retry_cnt = g_sa_retries;\r
1097         query_req.flags = 0;    /* IB_FLAGS_SYNC */\r
1098         query_req.query_context = p_req;\r
1099         query_req.pfn_query_cb = __ndi_ats_query_cb;\r
1100 \r
1101         /* TODO: which method one is correct? */\r
1102         user_query.method = IB_MAD_METHOD_GETTABLE;\r
1103         //user_query.method = IB_MAD_METHOD_GET;\r
1104         user_query.attr_id = IB_MAD_ATTR_SERVICE_RECORD;\r
1105         user_query.attr_size = sizeof(ib_service_record_t);\r
1106         user_query.comp_mask =\r
1107                 IB_SR_COMPMASK_SPKEY |\r
1108                 IB_SR_COMPMASK_SLEASE |\r
1109                 IB_SR_COMPMASK_SNAME |\r
1110                 IB_SR_COMPMASK_SDATA8_12 |\r
1111                 IB_SR_COMPMASK_SDATA8_13 | IB_SR_COMPMASK_SDATA8_14 | IB_SR_COMPMASK_SDATA8_15;\r
1112 \r
1113         user_query.p_attr = &service_record;\r
1114 \r
1115         memset( &service_record, 0, sizeof(service_record) );\r
1116         service_record.service_pkey = cl_hton16( IB_DEFAULT_PKEY );\r
1117         service_record.service_data8[12] = (uint8_t) (p_req->pdata.dst_ip_addr[3] >> 0);\r
1118         service_record.service_data8[13] = (uint8_t) (p_req->pdata.dst_ip_addr[3] >> 8);\r
1119         service_record.service_data8[14] = (uint8_t) (p_req->pdata.dst_ip_addr[3] >> 16);\r
1120         service_record.service_data8[15] = (uint8_t) (p_req->pdata.dst_ip_addr[3] >> 24);\r
1121         service_record.service_lease = 0xFFFFFFFF;\r
1122         strcpy( (void*)service_record.service_name, ATS_NAME );\r
1123         \r
1124         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
1125                 ("ATS:: MAD: method %#x, attr_id %#hx, Service: comp_mask %#I64x, IP %d.%d.%d.%d \n", \r
1126                 user_query.method,\r
1127                 CL_NTOH16(user_query.attr_id),\r
1128                 user_query.comp_mask,\r
1129                 service_record.service_data8[12],\r
1130                 service_record.service_data8[13],\r
1131                 service_record.service_data8[14],\r
1132                 service_record.service_data8[15]\r
1133                 ) );\r
1134 \r
1135         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, \r
1136                 ("h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n", \r
1137                 (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
1138 \r
1139         // preserve QP for the life of this IOCTL\r
1140         ref_al_obj( &h_qp->obj );               /* take IRP life reference */\r
1141 \r
1142         /* insert IRP in the queue */\r
1143         IoCsqInsertIrp( &h_qp->p_irp_que->csq, h_ioctl, NULL );\r
1144 \r
1145         /* prevent destroying QP after cancelling of the IRP and before ib_query calback*/\r
1146         ref_al_obj( &h_qp->obj );               /* take IRP SA reference */\r
1147 \r
1148         /* query SA */\r
1149         status = ib_query( qp_get_al( h_qp ), &query_req, &h_qp->p_irp_que->h_query );\r
1150         if( status != IB_SUCCESS )\r
1151         {\r
1152                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("ib_query failed (%d)\n", status) );\r
1153                 deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
1154                 h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
1155                 if ( h_ioctl )\r
1156                 { /* IOCTL should be released in the caller */\r
1157                         deref_al_obj( &h_qp->obj );             /* release IRP life reference */\r
1158                         nt_status = STATUS_DRIVER_INTERNAL_ERROR;\r
1159                 }\r
1160         }\r
1161 \r
1162         AL_EXIT( AL_DBG_NDI );\r
1163         return nt_status;\r
1164 }\r
1165 \r
1166 NTSTATUS\r
1167 ndi_req_cm(\r
1168         IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
1169         IN              cl_ioctl_handle_t                                       h_ioctl,\r
1170         IN              ual_ndi_req_cm_ioctl_in_t                       *p_req\r
1171         )\r
1172 {\r
1173         NTSTATUS nt_status;\r
1174 \r
1175         AL_ENTER( AL_DBG_NDI );\r
1176 \r
1177         /* check outstanding request */\r
1178         __ndi_acquire_lock( &h_qp->p_irp_que->csq, NULL);\r
1179         if ( h_qp->p_irp_que->h_ioctl )\r
1180         {\r
1181                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
1182                         ("STATUS_CONNECTION_ACTIVE: h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n",\r
1183                         (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
1184                 nt_status = STATUS_CONNECTION_ACTIVE;\r
1185                 __ndi_release_lock( &h_qp->p_irp_que->csq, 0 );\r
1186                 goto exit;\r
1187         }\r
1188         if ( h_qp->p_irp_que->state != NDI_CM_IDLE )\r
1189         {\r
1190                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
1191                         ("STATUS_INVALID_DEVICE_STATE: h_qp %I64x, ref_cnt %d, state %d\n",\r
1192                         (uint64_t)h_qp, h_qp->obj.ref_cnt, h_qp->p_irp_que->state ) );\r
1193                 nt_status = STATUS_INVALID_DEVICE_STATE;\r
1194                 __ndi_release_lock( &h_qp->p_irp_que->csq, 0 );\r
1195                 goto exit;\r
1196         }\r
1197         h_qp->p_irp_que->h_ioctl = h_ioctl;     /* mark IRP as present */\r
1198         h_qp->p_irp_que->state = NDI_CM_CONNECTING_ATS_SENT;\r
1199         __ndi_release_lock( &h_qp->p_irp_que->csq, 0 );\r
1200 \r
1201         /* send ATS request */\r
1202         nt_status = __ndi_ats_query( h_qp, h_ioctl, p_req );\r
1203 \r
1204 exit:\r
1205         if ( nt_status != STATUS_PENDING )\r
1206         {\r
1207                 cl_free( p_req );\r
1208                 h_qp->p_irp_que->state = NDI_CM_IDLE; \r
1209                 h_qp->p_irp_que->h_ioctl = NULL; /* mark IRP as present */\r
1210                 cl_ioctl_complete( h_ioctl, nt_status, 0 );\r
1211         }\r
1212         AL_EXIT( AL_DBG_NDI );\r
1213         return STATUS_PENDING;\r
1214 }\r
1215 \r
1216 \r
1217 /*******************************************************************\r
1218  *\r
1219  * RTU CM request\r
1220  *\r
1221  ******************************************************************/\r
1222 \r
1223 static void\r
1224 __ndi_rtu_cm(\r
1225         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1226         IN                              PIRP                                            p_irp )\r
1227 {\r
1228         NTSTATUS nt_status;\r
1229         ib_qp_mod_t qp_mod;\r
1230         ib_api_status_t status;\r
1231         ib_qp_handle_t VOID_PTR64 h_qp = p_irp->Tail.Overlay.DriverContext[0];\r
1232         ual_ndi_rtu_cm_ioctl_in_t *p_rtu = \r
1233                 (ual_ndi_rtu_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
1234         uint8_t pdata[IB_REJ_PDATA_SIZE];\r
1235         uint8_t psize = sizeof(pdata);\r
1236 \r
1237         UNUSED_PARAM(p_dev_obj);\r
1238 \r
1239         AL_ENTER( AL_DBG_NDI );\r
1240 \r
1241         /* free the work item if any */\r
1242         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1243                 IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
1244 \r
1245         /* change the QP state to RTS */\r
1246         status = __ndi_qp2rts( h_qp, p_rtu->init_depth, \r
1247                 p_rtu->resp_res, p_irp, &qp_mod );\r
1248         if ( status != IB_SUCCESS )\r
1249         {\r
1250                 goto err;\r
1251         }\r
1252         \r
1253         /* send RTU */\r
1254         al_cep_get_pdata( qp_get_al( h_qp ), ((al_conn_qp_t*)h_qp)->cid, &psize, pdata );\r
1255         status = al_cep_rtu( qp_get_al( h_qp ), ((al_conn_qp_t*)h_qp)->cid, pdata, psize );\r
1256         if( status != IB_SUCCESS && status != IB_INVALID_STATE )\r
1257         {\r
1258                 net32_t                         cid;\r
1259 err:\r
1260                 /* Reject and abort the connection. */\r
1261                 al_cep_rej(\r
1262                         qp_get_al( h_qp ), ((al_conn_qp_t*)h_qp)->cid, \r
1263                         IB_REJ_INSUF_QP, NULL, 0, NULL, 0 );\r
1264 \r
1265                 __cep_timewait_qp( h_qp );\r
1266 \r
1267                 cid = cl_atomic_xchg( &((al_conn_qp_t*)h_qp)->cid, AL_INVALID_CID );\r
1268 \r
1269                 if( cid != AL_INVALID_CID )\r
1270                 {\r
1271                         ref_al_obj( &h_qp->obj );\r
1272                         if( al_destroy_cep( qp_get_al( h_qp ), cid, deref_al_obj ) != IB_SUCCESS )\r
1273                         {\r
1274                                 deref_al_obj( &h_qp->obj );\r
1275                         }\r
1276                 }\r
1277 \r
1278                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
1279                         ("al_cep_rtu returned %s.\n", ib_get_err_str( status )) );\r
1280                 h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
1281                 nt_status = STATUS_DRIVER_INTERNAL_ERROR;\r
1282                 p_irp->IoStatus.Information = 0;\r
1283                 goto exit;\r
1284         }\r
1285 \r
1286         p_irp->IoStatus.Information = sizeof(uint32_t);;\r
1287         h_qp->p_irp_que->state = NDI_CM_CONNECTED;\r
1288         nt_status = STATUS_SUCCESS;\r
1289 \r
1290 exit:   \r
1291         /* release the reference only for async case */\r
1292         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1293                 deref_al_obj( &h_qp->obj );\r
1294 \r
1295         p_irp->IoStatus.Status = nt_status;\r
1296         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1297         AL_EXIT( AL_DBG_NDI );\r
1298 }\r
1299 \r
1300 cl_status_t\r
1301 ndi_rtu_cm(\r
1302         IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
1303         IN              PIRP                                                            p_irp\r
1304         )\r
1305 {\r
1306         IO_STACK_LOCATION       *p_io_stack;\r
1307 \r
1308         AL_ENTER( AL_DBG_NDI );\r
1309 \r
1310         p_irp->Tail.Overlay.DriverContext[0] = h_qp;\r
1311         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1312         p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject );\r
1313         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1314         { /* asyncronous performing */\r
1315                 /* take a ref to prevent QP destroy before calling work item */\r
1316                 ref_al_obj( &h_qp->obj );\r
1317                 IoMarkIrpPending( p_irp );\r
1318                 IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1],\r
1319                         __ndi_rtu_cm, DelayedWorkQueue, p_irp );\r
1320         }\r
1321         else\r
1322         { /* syncronous performing */\r
1323                 p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
1324                 __ndi_rtu_cm( p_io_stack->DeviceObject, p_irp );\r
1325         }\r
1326 \r
1327         AL_EXIT( AL_DBG_NDI );\r
1328         return CL_PENDING;\r
1329 }\r
1330 \r
1331 \r
1332 /*******************************************************************\r
1333  *\r
1334  * REP CM request\r
1335  *\r
1336  ******************************************************************/\r
1337 \r
1338 static void\r
1339 __ndi_rep_cm(\r
1340         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1341         IN                              PIRP                                            p_irp )\r
1342 {\r
1343         NTSTATUS nt_status;\r
1344         ib_qp_mod_t qp_mod;\r
1345         ib_api_status_t status;\r
1346         ib_qp_handle_t VOID_PTR64 h_qp = p_irp->Tail.Overlay.DriverContext[0];\r
1347         ual_ndi_rep_cm_ioctl_in_t *p_rep = \r
1348                 (ual_ndi_rep_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
1349 \r
1350         UNUSED_PARAM(p_dev_obj);\r
1351 \r
1352         AL_ENTER( AL_DBG_NDI );\r
1353 \r
1354         /* free the work item if any */\r
1355         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1356                 IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
1357 \r
1358         /* change the QP state to RTS */\r
1359         status = __ndi_qp2rts( h_qp, p_rep->init_depth, \r
1360                 p_rep->resp_res, p_irp, &qp_mod );\r
1361         if ( status != IB_SUCCESS )\r
1362         {\r
1363                 nt_status = STATUS_CONNECTION_ABORTED;\r
1364                 goto err;\r
1365         }\r
1366         \r
1367         /* send REP */\r
1368         status = al_cep_send_rep ( qp_get_al( h_qp ), p_rep->cid );\r
1369         if( status != IB_SUCCESS )\r
1370         {\r
1371                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1372                         ("al_cep_send_rep returned %s\n", ib_get_err_str(status)) );\r
1373                 if (status == IB_INSUFFICIENT_RESOURCES)\r
1374                         nt_status = STATUS_INSUFFICIENT_RESOURCES;\r
1375                 else\r
1376                         nt_status = STATUS_CONNECTION_ABORTED;\r
1377 err:\r
1378                 cl_atomic_xchg( &((al_conn_qp_t*)h_qp)->cid, AL_INVALID_CID );\r
1379 \r
1380                 /* Reject and abort the connection. */\r
1381                 al_cep_rej( qp_get_al( h_qp ), p_rep->cid, IB_REJ_INSUF_QP, NULL, 0, NULL, 0 );\r
1382 \r
1383                 /* transit QP to error state */\r
1384                 __cep_timewait_qp( h_qp );\r
1385 \r
1386                 ref_al_obj( &h_qp->obj );\r
1387                 if( al_destroy_cep( qp_get_al( h_qp ), p_rep->cid, deref_al_obj ) != IB_SUCCESS )\r
1388                         deref_al_obj( &h_qp->obj );\r
1389 \r
1390                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1391                         ("al_cep_rtu returned %s.\n", ib_get_err_str( status )) );\r
1392                 h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
1393                 p_irp->IoStatus.Information = 0;\r
1394                 goto exit;\r
1395         }\r
1396 \r
1397         p_irp->IoStatus.Information = cl_ioctl_out_size( p_irp );\r
1398         h_qp->p_irp_que->state = NDI_CM_CONNECTED;\r
1399         nt_status = STATUS_SUCCESS;\r
1400 \r
1401 exit:   \r
1402         /* release the reference only for async case */\r
1403         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1404                 deref_al_obj( &h_qp->obj );\r
1405 \r
1406         p_irp->IoStatus.Status = nt_status;\r
1407         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1408         AL_EXIT( AL_DBG_NDI );\r
1409 }\r
1410 \r
1411 static void\r
1412 __ndi_fill_cm_rep(\r
1413         IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
1414         IN              ual_ndi_rep_cm_ioctl_in_t                       *p_rep,\r
1415                 OUT     ib_cm_rep_t                                                     *p_cm_rep)\r
1416 {\r
1417         AL_ENTER( AL_DBG_NDI );\r
1418 \r
1419         memset( p_cm_rep, 0, sizeof(ib_cm_rep_t) );\r
1420 \r
1421         p_cm_rep->p_rep_pdata = p_rep->pdata;\r
1422         p_cm_rep->rep_length = sizeof(p_rep->pdata);\r
1423 \r
1424         p_cm_rep->qp_type = IB_QPT_RELIABLE_CONN;\r
1425         p_cm_rep->h_qp = h_qp;\r
1426 \r
1427         p_cm_rep->access_ctrl = IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE;\r
1428         p_cm_rep->init_depth = 0;\r
1429         p_cm_rep->target_ack_delay = 10;\r
1430         p_cm_rep->failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED;\r
1431         p_cm_rep->flow_ctrl = TRUE;     /* HCAs must support end-to-end flow control. */\r
1432         p_cm_rep->rnr_nak_timeout = QP_ATTRIB_RNR_NAK_TIMEOUT;\r
1433         p_cm_rep->rnr_retry_cnt = QP_ATTRIB_RNR_RETRY;\r
1434 \r
1435         AL_EXIT( AL_DBG_NDI );\r
1436 }\r
1437 \r
1438 NTSTATUS\r
1439 ndi_rep_cm(\r
1440         IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
1441         IN              net32_t                 const                           cid,\r
1442         IN              PIRP                                                            p_irp,\r
1443         IN              ual_ndi_rep_cm_ioctl_in_t                       *p_rep\r
1444         )\r
1445 {\r
1446         IO_STACK_LOCATION       *p_io_stack;\r
1447         ib_cm_rep_t cm_rep;\r
1448         ib_qp_mod_t qp_mod;\r
1449         net32_t old_cid;\r
1450         ib_api_status_t status;\r
1451         NTSTATUS nt_status;\r
1452 \r
1453         AL_ENTER( AL_DBG_NDI );\r
1454 \r
1455         /* Format ib_cm_req_t structure */\r
1456         __ndi_fill_cm_rep( h_qp, p_rep, &cm_rep );\r
1457 \r
1458         /* prepare Passive CEP for connection */\r
1459         status = al_cep_pre_rep_ex( qp_get_al( h_qp ), cid, __ndi_cm_handler, h_qp, &cm_rep, &qp_mod );\r
1460         if( status != IB_SUCCESS )\r
1461         {\r
1462                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1463                         ("al_cep_pre_rep_ex returned %s.\n", ib_get_err_str( status )) );\r
1464                 switch (status)\r
1465                 {\r
1466                         case IB_INVALID_HANDLE:\r
1467                                 nt_status = STATUS_CANCELLED;\r
1468                                 break;\r
1469                         case IB_INVALID_STATE:\r
1470                                 nt_status = STATUS_CONNECTION_ABORTED;\r
1471                                 break;\r
1472                         default:\r
1473                                 nt_status = STATUS_INSUFFICIENT_RESOURCES;\r
1474                                 break;\r
1475                 }\r
1476                 goto err_cep_destroy;\r
1477         }\r
1478 \r
1479         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
1480                 ("Prepared Passive CEP with cid %d, h_al %p, context %p\n",\r
1481                 cid, qp_get_al( h_qp ), h_qp ) );\r
1482 \r
1483         /* See if this QP has already been connected. */\r
1484         old_cid = cl_atomic_comp_xchg( &((al_conn_qp_t*)h_qp)->cid, AL_INVALID_CID, cid );\r
1485         if( old_cid != AL_INVALID_CID )\r
1486         {\r
1487                 nt_status = STATUS_CONNECTION_ACTIVE;\r
1488                 goto err_cep_destroy;\r
1489         }\r
1490 \r
1491         /* transfer work to a work the thread */\r
1492         p_irp->Tail.Overlay.DriverContext[0] = h_qp;\r
1493         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1494         p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject );\r
1495         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1496         { /* asyncronous performing */\r
1497                 /* take a ref to prevent QP destroy before calling work item */\r
1498                 ref_al_obj( &h_qp->obj );\r
1499                 IoMarkIrpPending( p_irp );\r
1500                 IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1],\r
1501                         __ndi_rep_cm, DelayedWorkQueue, p_irp );\r
1502         }\r
1503         else\r
1504         { /* syncronous performing */\r
1505                 __ndi_rep_cm( p_io_stack->DeviceObject, p_irp );\r
1506         }\r
1507         goto exit;\r
1508 \r
1509 err_cep_destroy:\r
1510         al_destroy_cep( qp_get_al( h_qp ), cid, NULL );\r
1511         \r
1512         h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
1513         cl_ioctl_complete( p_irp, nt_status, 0 );\r
1514 \r
1515 exit:\r
1516         AL_EXIT( AL_DBG_NDI );\r
1517         return CL_PENDING;\r
1518 }\r
1519 \r
1520 \r
1521 /*******************************************************************\r
1522  *\r
1523  * DREQ CM request\r
1524  *\r
1525  ******************************************************************/\r
1526 \r
1527 NTSTATUS\r
1528 ndi_dreq_cm(\r
1529         IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
1530         IN              PIRP                                                            p_irp\r
1531         )\r
1532 {\r
1533         ib_qp_mod_t qp_mod;\r
1534         net32_t cid;\r
1535         ib_api_status_t status;\r
1536         NTSTATUS nt_status;\r
1537         uint64_t timewait_us;\r
1538 \r
1539         AL_ENTER( AL_DBG_NDI );\r
1540 \r
1541         status = al_cep_get_timewait( qp_get_al( h_qp ), \r
1542                 ((al_conn_qp_t*)h_qp)->cid, &timewait_us );\r
1543 \r
1544         if (status != IB_SUCCESS)\r
1545         {\r
1546                 nt_status = STATUS_CONNECTION_INVALID;\r
1547                 goto exit;\r
1548         }\r
1549 \r
1550         /* bring QP to error state */\r
1551         cl_memclr( &qp_mod, sizeof(qp_mod) );\r
1552         qp_mod.req_state = IB_QPS_ERROR;\r
1553         \r
1554         status = ndi_modify_qp( h_qp, &qp_mod, \r
1555                 cl_ioctl_out_size( p_irp ), cl_ioctl_out_buf( p_irp ) );\r
1556         if ( status != IB_SUCCESS )\r
1557         {\r
1558                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1559                         ("ndi_modify_qp to ERROR returned %s.\n", ib_get_err_str(status) ) );\r
1560                 nt_status = STATUS_CONNECTION_INVALID;\r
1561                 goto exit;\r
1562         }\r
1563 \r
1564         /* Store the timestamp after which the QP exits timewait. */\r
1565         h_qp->timewait = cl_get_time_stamp() + timewait_us;\r
1566 \r
1567         cid = cl_atomic_xchg( &((al_conn_qp_t*)h_qp)->cid, AL_INVALID_CID );\r
1568 \r
1569         if( cid != AL_INVALID_CID )\r
1570         {\r
1571                 ref_al_obj( &h_qp->obj );\r
1572                 if( al_destroy_cep( qp_get_al( h_qp ), cid, deref_al_obj ) != IB_SUCCESS )\r
1573                 {\r
1574                         deref_al_obj( &h_qp->obj );\r
1575                 }\r
1576         }\r
1577 \r
1578         nt_status = STATUS_SUCCESS;\r
1579 \r
1580 exit:\r
1581         h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
1582         cl_ioctl_complete( p_irp, nt_status, cl_ioctl_out_size( p_irp ) );\r
1583 \r
1584         AL_EXIT( AL_DBG_NDI );\r
1585         return STATUS_EVENT_DONE;       /* CL_COMPLETED */\r
1586 }\r
1587 \r
1588 \r
1589 \r