[IBAL] This patch removes ATS queries from the ND proxy, with the anticipation that...
[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 NTSTATUS\r
65 __ndi_ats_query(\r
66         IN              IRP*                                                            p_irp\r
67         );\r
68 \r
69 NTSTATUS\r
70 __ndi_pr_query(\r
71         IN              IRP*                                                            p_irp\r
72         );\r
73 \r
74 NTSTATUS\r
75 __ndi_send_req(\r
76         IN              IRP*                                                            p_irp\r
77         );\r
78 \r
79 NTSTATUS\r
80 __ndi_send_rep(\r
81         IN              ib_qp_handle_t                                          h_qp,\r
82         IN              PIRP                                                            p_irp\r
83         );\r
84 \r
85 NTSTATUS\r
86 __ndi_send_dreq(\r
87         IN              IRP*                                                            p_irp\r
88         );\r
89 \r
90 static void\r
91 __ndi_queue_drep(\r
92         IN                              IRP                                                     *p_irp\r
93         );\r
94 \r
95 /*******************************************************************\r
96  *\r
97  * Helpers\r
98  *\r
99  ******************************************************************/\r
100 \r
101 static char * State2String(ndi_cm_state_t state) \r
102 {\r
103         switch (state) \r
104         {\r
105                 case NDI_CM_IDLE                                        : return "NDI_CM_IDLE";\r
106                 case NDI_CM_CONNECTING_QPR_SENT         : return "NDI_CM_CONNECTING_QPR_SENT";\r
107                 case NDI_CM_CONNECTING_REQ_SENT         : return "NDI_CM_CONNECTING_REQ_SENT";\r
108                 case NDI_CM_CONNECTING_REP_SENT         : return "NDI_CM_CONNECTING_REP_SENT";\r
109                 case NDI_CM_CONNECTING_REP_RCVD         : return "NDI_CM_CONNECTING_REP_RCVD";\r
110                 case NDI_CM_CONNECTED                           : return "NDI_CM_CONNECTED";\r
111                 case NDI_CM_DISCONNECTING                       : return "NDI_CM_DISCONNECTING";\r
112                 case NDI_CM_CONNECTED_DREQ_RCVD         : return "NDI_CM_CONNECTED_DREQ_RCVD";\r
113                 case NDI_CM_INVALID                                     : return "NDI_CM_CONNECTING_REP_SENT";\r
114                 default : \r
115                         ASSERT(FALSE);\r
116         }\r
117         return "Unknown state";\r
118 }\r
119 \r
120 \r
121 static inline void\r
122 __ndi_complete_irp(\r
123         IN      ib_qp_handle_t                                                  h_qp,\r
124         IN      PIRP                                                                    p_irp,\r
125         IN      NTSTATUS                                                                status\r
126         )\r
127 {\r
128         AL_ENTER( AL_DBG_NDI );\r
129 \r
130         CL_ASSERT( p_irp );\r
131         CL_ASSERT( p_irp->Tail.Overlay.DriverContext[1] == NULL );\r
132 \r
133         p_irp->IoStatus.Status = status;\r
134         if( status == STATUS_SUCCESS )\r
135         {\r
136                 p_irp->IoStatus.Information = cl_ioctl_out_size( p_irp );\r
137                 IoCompleteRequest( p_irp, IO_NETWORK_INCREMENT );\r
138         }\r
139         else\r
140         {\r
141                 p_irp->IoStatus.Information = 0;\r
142                 IoCompleteRequest( p_irp, 0 );\r
143         }\r
144         deref_al_obj( &h_qp->obj ); /* Release IRP reference */\r
145 \r
146         AL_EXIT( AL_DBG_NDI );\r
147 }\r
148 \r
149 \r
150 /*\r
151  * Transition the QP to the error state to flush all oustanding work\r
152  * requests and sets the timewait time.  This function may be called\r
153  * when destroying the QP in order to flush all work requests, so we\r
154  * cannot call through the main API, or the call will fail since the\r
155  * QP is no longer in the initialize state.\r
156  */\r
157 static void\r
158 __cep_timewait_qp(\r
159         IN              const   ib_qp_handle_t                          h_qp )\r
160 {\r
161         uint64_t                        timewait = 0;\r
162         ib_qp_mod_t                     qp_mod;\r
163         ib_api_status_t         status;\r
164 \r
165         AL_ENTER( AL_DBG_CM );\r
166 \r
167         CL_ASSERT( h_qp );\r
168 \r
169         /*\r
170          * The CM should have set the proper timewait time-out value.  Reset\r
171          * the QP and let it enter the timewait state.\r
172          */\r
173         if( al_cep_get_timewait( h_qp->obj.h_al,\r
174                 ((al_conn_qp_t*)h_qp)->cid, &timewait ) == IB_SUCCESS )\r
175         {\r
176                 /* Special checks on the QP state for error handling - see above. */\r
177                 if( !h_qp || !AL_OBJ_IS_TYPE( h_qp, AL_OBJ_TYPE_H_QP ) ||\r
178                         ( (h_qp->obj.state != CL_INITIALIZED) && \r
179                         (h_qp->obj.state != CL_DESTROYING) ) )\r
180                 {\r
181                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
182                         return;\r
183                 }\r
184 \r
185                 cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) );\r
186                 qp_mod.req_state = IB_QPS_ERROR;\r
187 \r
188                 /* Modify to error state using function pointers - see above. */\r
189                 status = h_qp->pfn_modify_qp( h_qp, &qp_mod, NULL );\r
190                 if( status != IB_SUCCESS )\r
191                 {\r
192                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
193                                 ("pfn_modify_qp to IB_QPS_ERROR returned %s\n",\r
194                                 ib_get_err_str( status )) );\r
195                         return;\r
196                 }\r
197 \r
198 #ifdef CL_KERNEL\r
199                 /* Store the timestamp after which the QP exits timewait. */\r
200                 h_qp->timewait = cl_get_time_stamp() + timewait;\r
201 #endif  /* CL_KERNEL */\r
202         }\r
203 \r
204         AL_EXIT( AL_DBG_CM );\r
205 }\r
206 \r
207 static ib_api_status_t\r
208 __ndi_qp2rts(\r
209         IN              ib_qp_handle_t  const                           h_qp,\r
210         IN              PIRP                                                            p_irp\r
211         )\r
212 {\r
213         ib_api_status_t status;\r
214         ib_qp_mod_t qp_mod;\r
215 \r
216         AL_ENTER( AL_DBG_NDI );\r
217 \r
218         /* fill required qp attributes */\r
219         status = al_cep_get_rtr_attr( qp_get_al( h_qp ), \r
220                 ((al_conn_qp_t*)h_qp)->cid, &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_rtr_attr returned %s\n", ib_get_err_str( status )) );\r
225                 goto exit;\r
226         }\r
227 \r
228         /* perform the request: INIT->RTR */\r
229         status = ndi_modify_qp( h_qp, &qp_mod, \r
230                 cl_ioctl_out_size( p_irp ), cl_ioctl_out_buf( p_irp ) );\r
231         if ( status != IB_SUCCESS )\r
232         {\r
233                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
234                         ("ndi_modify_qp to RTR returned %s.\n", ib_get_err_str(status) ) );\r
235                 goto exit;\r
236         }\r
237 \r
238         /* fill required qp attributes */\r
239         status = al_cep_get_rts_attr( qp_get_al( h_qp ), \r
240                 ((al_conn_qp_t*)h_qp)->cid, &qp_mod );\r
241         if ( status != IB_SUCCESS )\r
242         {\r
243                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
244                         ("al_cep_get_rts_attr returned %s\n", ib_get_err_str( status )) );\r
245                 goto exit;\r
246         }\r
247 \r
248         /* perform the request: RTR->RTS */\r
249         status = ndi_modify_qp( h_qp, &qp_mod, \r
250                 cl_ioctl_out_size( p_irp ), cl_ioctl_out_buf( p_irp ) );\r
251         if ( status != IB_SUCCESS )\r
252         {\r
253                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
254                         ("ndi_modify_qp to RTS returned %s.\n", ib_get_err_str(status) ) );\r
255         }\r
256 \r
257 exit:\r
258         AL_EXIT( AL_DBG_NDI );\r
259         return status;\r
260 }\r
261 \r
262 \r
263 /*******************************************************************\r
264  *\r
265  * CSQ\r
266  *\r
267  ******************************************************************/\r
268 \r
269 \r
270 static NTSTATUS __ndi_insert_irp_ex(\r
271         IN      PIO_CSQ                                                                 pCsq,\r
272         IN      PIRP                                                                    pIrp,\r
273         IN      VOID                                                                    *Context\r
274         )\r
275 {\r
276         NTSTATUS status;\r
277         ndi_qp_csq_t *p_ndi_csq = (ndi_qp_csq_t*)pCsq;\r
278 \r
279         AL_ENTER( AL_DBG_NDI );\r
280         switch( (ULONG_PTR)Context )\r
281         {\r
282         case NDI_CM_CONNECTING_QPR_SENT:\r
283                 status = __ndi_pr_query( pIrp );\r
284                 break;\r
285 \r
286         case NDI_CM_CONNECTING_REQ_SENT:\r
287                 status = __ndi_send_req( pIrp );\r
288                 break;\r
289 \r
290         case NDI_CM_CONNECTING_REP_SENT:\r
291                 status = __ndi_send_rep( p_ndi_csq->h_qp, pIrp );\r
292                 break;\r
293 \r
294         case NDI_CM_DISCONNECTING:\r
295                 status = __ndi_send_dreq( pIrp );\r
296                 break;\r
297 \r
298         default:\r
299                 status = STATUS_INVALID_DEVICE_REQUEST;\r
300                 ASSERT( FALSE );\r
301         }\r
302 \r
303         if( status == STATUS_SUCCESS )\r
304         {\r
305                 p_ndi_csq->state = (ndi_cm_state_t)(ULONG_PTR)Context;\r
306                 InsertTailList( &p_ndi_csq->queue, &pIrp->Tail.Overlay.ListEntry );\r
307                 ref_al_obj( &p_ndi_csq->h_qp->obj ); /* Take IRP reference. */\r
308         }\r
309         AL_EXIT( AL_DBG_NDI );\r
310         return status;\r
311 }\r
312 \r
313 static VOID __ndi_remove_irp(\r
314         IN      PIO_CSQ                                                                 Csq,\r
315         IN      PIRP                                                                    Irp\r
316         )\r
317 {\r
318         UNUSED_PARAM( Csq );\r
319 \r
320         AL_ENTER( AL_DBG_NDI );\r
321         RemoveEntryList( &Irp->Tail.Overlay.ListEntry );\r
322         AL_EXIT( AL_DBG_NDI );\r
323 }\r
324 \r
325 static PIRP __ndi_peek_next_irp(\r
326         IN      PIO_CSQ                                                                 Csq,\r
327         IN      PIRP                                                                    Irp,\r
328         IN      PVOID                                                                   PeekContext\r
329         )\r
330 {\r
331         PIRP nextIrp = NULL;\r
332         PLIST_ENTRY nextEntry;\r
333         PLIST_ENTRY listHead;\r
334         ndi_qp_csq_t *p_ndi_csq = (ndi_qp_csq_t*)Csq;\r
335 \r
336         AL_ENTER( AL_DBG_NDI );\r
337 \r
338         listHead = &p_ndi_csq->queue;\r
339 \r
340         // \r
341         // If the IRP is NULL, we will start peeking from the listhead, else\r
342         // we will start from that IRP onwards. This is done under the\r
343         // assumption that new IRPs are always inserted at the tail.\r
344         //\r
345 \r
346         if(Irp == NULL)\r
347                 nextEntry = listHead->Flink;\r
348         else\r
349                 nextEntry = Irp->Tail.Overlay.ListEntry.Flink;\r
350 \r
351         while(nextEntry != listHead) {\r
352                 nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry);\r
353 \r
354                 //\r
355                 // If context is present, continue until you find a matching one.\r
356                 // Else you break out as you got next one.\r
357                 //\r
358 \r
359                 if(PeekContext) \r
360                 {\r
361                         if( cl_ioctl_ctl_code( nextIrp ) == (ULONG_PTR)PeekContext )\r
362                                 break;\r
363                 }\r
364                 else\r
365                 {\r
366                         if( cl_ioctl_ctl_code( nextIrp ) != UAL_NDI_NOTIFY_DREQ )\r
367                                 break;\r
368                 }\r
369 \r
370                 nextIrp = NULL;\r
371                 nextEntry = nextEntry->Flink;\r
372         }\r
373 \r
374         AL_EXIT( AL_DBG_NDI );\r
375         return nextIrp;\r
376 }\r
377 \r
378 static VOID __ndi_acquire_lock(\r
379         IN      PIO_CSQ                                                                 Csq,\r
380         OUT     PKIRQL                                                                  Irql\r
381         )\r
382 {\r
383         ndi_qp_csq_t *p_ndi_csq = (ndi_qp_csq_t*)Csq;\r
384         ib_qp_handle_t h_qp = p_ndi_csq->h_qp;\r
385         UNUSED_PARAM( Irql );\r
386 \r
387         AL_ENTER( AL_DBG_NDI );\r
388         cl_spinlock_acquire( &h_qp->obj.lock );\r
389         AL_EXIT( AL_DBG_NDI );\r
390 }\r
391 \r
392 static VOID __ndi_release_lock(\r
393         IN      PIO_CSQ                                                                 Csq,\r
394         IN      KIRQL                                                                   Irql\r
395         )\r
396 {\r
397         ndi_qp_csq_t *p_ndi_csq = (ndi_qp_csq_t*)Csq;\r
398         ib_qp_handle_t h_qp = p_ndi_csq->h_qp;\r
399         UNUSED_PARAM( Irql );\r
400 \r
401         AL_ENTER( AL_DBG_NDI );\r
402         cl_spinlock_release( &h_qp->obj.lock );\r
403         AL_EXIT( AL_DBG_NDI );\r
404 }\r
405 \r
406 static VOID __ndi_complete_cancelled_irp(\r
407         IN      PIO_CSQ                                                                 Csq,\r
408         IN      PIRP                                                                    p_irp\r
409         )\r
410 {\r
411         ndi_qp_csq_t *p_ndi_csq = (ndi_qp_csq_t*)Csq;\r
412         ib_qp_handle_t h_qp = p_ndi_csq->h_qp;\r
413         KIRQL irql;\r
414         ib_query_handle_t h_query;\r
415 \r
416         AL_ENTER( AL_DBG_NDI );\r
417 \r
418         switch( cl_ioctl_ctl_code( p_irp ) )\r
419         {\r
420         case UAL_NDI_REQ_CM:\r
421                 __ndi_acquire_lock( Csq, &irql );\r
422                 /*\r
423                  * Note that al_cancel_sa_req is synchronized with any potential\r
424                  * SA callback by the CSQ lock.\r
425                  */\r
426 #pragma warning( disable:4305 )\r
427                 h_query = InterlockedExchangePointer( &h_qp->p_irp_queue->h_query, NULL );\r
428 #pragma warning( default:4305 )\r
429                 if( h_query != NULL )\r
430                         al_cancel_sa_req( &h_query->sa_req );\r
431 \r
432                 /* Always try to destroy the CEP.  The CEP manager handles invalid CIDs. */\r
433                 al_destroy_cep( qp_get_al( h_qp ), &((al_conn_qp_t*)h_qp)->cid, TRUE );\r
434 \r
435                 if( p_ndi_csq->state != NDI_CM_INVALID )\r
436                         p_ndi_csq->state = NDI_CM_IDLE;\r
437 \r
438                 __ndi_release_lock( Csq, irql );\r
439 \r
440                 __fallthrough;\r
441 \r
442         case UAL_NDI_NOTIFY_DREQ:\r
443                 __ndi_complete_irp( h_qp, p_irp, STATUS_CANCELLED );\r
444                 break;\r
445 \r
446         case UAL_NDI_DREQ_CM:\r
447                 __ndi_queue_drep( p_irp );\r
448                 break;\r
449         }\r
450 \r
451         AL_EXIT( AL_DBG_NDI );\r
452 }\r
453 \r
454 \r
455 \r
456 NTSTATUS\r
457 ndi_qp_init(\r
458         IN                              ib_qp_handle_t                          h_qp )\r
459 {\r
460 \r
461         NTSTATUS status;\r
462 \r
463         AL_ENTER( AL_DBG_NDI );\r
464 \r
465         if ( h_qp->type != IB_QPT_RELIABLE_CONN )\r
466         {\r
467                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
468                         ("Only RC QP type is supported \n"));\r
469                 status = STATUS_SUCCESS;\r
470                 goto exit;\r
471         }\r
472         \r
473         h_qp->p_irp_queue = (ndi_qp_csq_t*)cl_zalloc(sizeof(ndi_qp_csq_t));\r
474         if (!h_qp->p_irp_queue)\r
475         {\r
476                 status = STATUS_NO_MEMORY;\r
477                 goto exit;\r
478         }\r
479 \r
480         status = IoCsqInitializeEx( &h_qp->p_irp_queue->csq, \r
481                 __ndi_insert_irp_ex, __ndi_remove_irp,\r
482                 __ndi_peek_next_irp, __ndi_acquire_lock,\r
483                 __ndi_release_lock, __ndi_complete_cancelled_irp );\r
484         if ( !NT_SUCCESS( status ) )\r
485                 goto exit;\r
486 \r
487         InitializeListHead( &h_qp->p_irp_queue->queue );\r
488         h_qp->p_irp_queue->h_qp = h_qp;\r
489         h_qp->p_irp_queue->h_query = NULL;\r
490         h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
491         status = STATUS_SUCCESS;\r
492 \r
493 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
494         ("Creating h_qp %#I64x, uhdl %#I64x \n", \r
495         (uint64_t)h_qp, h_qp->obj.hdl ) );\r
496 \r
497 exit:\r
498         AL_EXIT( AL_DBG_NDI );\r
499         return status;\r
500 }\r
501 \r
502 #pragma warning(disable:4706)\r
503 void\r
504 ndi_qp_destroy(\r
505         IN              ib_qp_handle_t                                  h_qp )\r
506 {\r
507         KIRQL irql;\r
508         PIRP Irp;\r
509 \r
510         AL_ENTER( AL_DBG_NDI );\r
511 \r
512         if (h_qp->type == IB_QPT_RELIABLE_CONN && h_qp->p_irp_queue)\r
513         {\r
514                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
515                         ("Destroying h_qp %#I64x, uhdl %#I64x, cid %d\n", \r
516                         (uint64_t)h_qp, h_qp->obj.hdl, ((al_conn_qp_t*)h_qp)->cid ) );\r
517 \r
518                 /* Move the state before flushing, so that all new IRPs fail to queue. */\r
519                 __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
520                 h_qp->p_irp_queue->state = NDI_CM_INVALID;\r
521                 __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
522 \r
523                 /* cancel pending IRPS for NDI type CQ */\r
524                 AL_ENTER( AL_DBG_NDI );\r
525                 while( Irp = IoCsqRemoveNextIrp( &h_qp->p_irp_queue->csq, NULL ) )\r
526                 {\r
527                         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, \r
528                                 ("h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n", \r
529                                 (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
530 \r
531                         __ndi_complete_cancelled_irp( &h_qp->p_irp_queue->csq, Irp );\r
532                 }\r
533                 while( Irp = IoCsqRemoveNextIrp(\r
534                         &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_NOTIFY_DREQ ) )\r
535                 {\r
536                         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, \r
537                                 ("h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n", \r
538                                 (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
539 \r
540                         __ndi_complete_cancelled_irp( &h_qp->p_irp_queue->csq, Irp );\r
541                 }\r
542                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, \r
543                         ("h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n", \r
544                         (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
545         }\r
546 \r
547         AL_EXIT( AL_DBG_NDI );\r
548 }\r
549 #pragma warning(default:4706)\r
550 \r
551 \r
552 void\r
553 ndi_qp_free(\r
554         IN              ib_qp_handle_t                                  h_qp )\r
555 {\r
556         AL_ENTER( AL_DBG_NDI );\r
557 \r
558         if (h_qp->type == IB_QPT_RELIABLE_CONN && h_qp->p_irp_queue)\r
559         {\r
560                 /* free NDI context */\r
561                 cl_free( h_qp->p_irp_queue );\r
562                 h_qp->p_irp_queue = NULL;\r
563         }\r
564 \r
565         AL_EXIT( AL_DBG_NDI );\r
566 }\r
567 \r
568 \r
569 static inline void\r
570 __ndi_complete_req_irp(\r
571         IN      ib_qp_handle_t                                                  h_qp,\r
572         IN      NTSTATUS                                                                code\r
573         )\r
574 {\r
575         PIRP Irp;\r
576         KIRQL irql;\r
577 \r
578         AL_ENTER( AL_DBG_NDI );\r
579         Irp = IoCsqRemoveNextIrp( &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_REQ_CM );\r
580         if ( Irp )\r
581         {\r
582                 __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
583                 if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
584                         h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
585                 __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
586                 __ndi_complete_irp( h_qp, Irp, code );\r
587         }\r
588         AL_EXIT( AL_DBG_NDI );\r
589 }\r
590 \r
591 /*******************************************************************\r
592  *\r
593  * REQ CM request\r
594  *\r
595  ******************************************************************/\r
596 \r
597 static void\r
598 __ndi_notify_dreq(\r
599         IN                              ib_qp_handle_t const            h_qp )\r
600 {\r
601         IRP *p_irp = IoCsqRemoveNextIrp(\r
602                 &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_NOTIFY_DREQ );\r
603 \r
604         if( p_irp )\r
605         {\r
606                 __ndi_complete_irp( h_qp, p_irp, STATUS_SUCCESS );\r
607         }\r
608 }\r
609 \r
610 \r
611 static void\r
612 __ndi_proc_dreq(\r
613         IN                              ib_qp_handle_t const            h_qp )\r
614 {\r
615         IRP *p_irp;\r
616         KIRQL irql;\r
617         ndi_cm_state_t old_state;\r
618 \r
619         __ndi_notify_dreq( h_qp );\r
620 \r
621         __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
622         old_state = h_qp->p_irp_queue->state;\r
623         if( old_state == NDI_CM_CONNECTED )\r
624         {\r
625                 h_qp->p_irp_queue->state = NDI_CM_CONNECTED_DREQ_RCVD;\r
626         }\r
627         __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
628 \r
629         p_irp = IoCsqRemoveNextIrp(\r
630                 &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_DREQ_CM );\r
631         if( p_irp != NULL )\r
632         {\r
633                 __ndi_queue_drep( p_irp );\r
634         }\r
635 }\r
636 \r
637 \r
638 /*\r
639  * A user-specified callback that is invoked after receiving a connection\r
640  * rejection message (REJ).\r
641  */\r
642 static void\r
643 __ndi_proc_rej(\r
644         IN                              ib_qp_handle_t const            h_qp,\r
645         IN              const   mad_cm_rej_t* const             p_rej )\r
646 {\r
647         KIRQL irql;\r
648         IRP* p_irp;\r
649 \r
650         AL_ENTER( AL_DBG_NDI );\r
651 \r
652         AL_PRINT(TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
653                 ("p_rej %p, h_qp %#I64x, uhdl %#I64x, connect reject, reason=%hd\n", \r
654                 p_rej, (uint64_t)h_qp, h_qp->obj.hdl, cl_ntoh16(p_rej->reason) ) );\r
655 \r
656         p_irp = IoCsqRemoveNextIrp( &h_qp->p_irp_queue->csq, NULL );\r
657         __ndi_notify_dreq( h_qp );\r
658         __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
659         if( p_irp != NULL )\r
660         {\r
661                 switch( cl_ioctl_ctl_code( p_irp ) )\r
662                 {\r
663                 case UAL_NDI_REQ_CM:\r
664                         if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
665                                 h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
666                         if( p_rej->reason == IB_REJ_TIMEOUT )\r
667                                 __ndi_complete_irp( h_qp, p_irp, STATUS_TIMEOUT );\r
668                         else\r
669                                 __ndi_complete_irp( h_qp, p_irp, STATUS_CONNECTION_REFUSED );\r
670 \r
671                         al_destroy_cep(\r
672                                 qp_get_al( h_qp ), &((al_conn_qp_t*)h_qp)->cid, TRUE );\r
673                         break;\r
674 \r
675                 case UAL_NDI_DREQ_CM:\r
676                         __ndi_queue_drep( p_irp );\r
677                         break;\r
678                 }\r
679         }\r
680         else if( h_qp->p_irp_queue->state == NDI_CM_CONNECTED )\r
681         {\r
682                 if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
683                         h_qp->p_irp_queue->state = NDI_CM_CONNECTED_DREQ_RCVD;\r
684         }\r
685         __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
686 \r
687         AL_EXIT( AL_DBG_NDI );\r
688 }\r
689 \r
690 \r
691 static void\r
692 __ndi_proc_rep(\r
693         IN                              ib_qp_handle_t const            h_qp,\r
694         IN                              net32_t                                         cid )\r
695 {\r
696         ndi_qp_csq_t *p_ndi_csq = h_qp->p_irp_queue;\r
697         IRP* p_irp;\r
698         KIRQL irql;\r
699 \r
700         AL_ENTER( AL_DBG_NDI );\r
701 \r
702         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI ,("h_qp = 0x%p\n", h_qp));\r
703 \r
704         p_irp = IoCsqRemoveNextIrp( &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_REQ_CM );\r
705         __ndi_acquire_lock( &p_ndi_csq->csq, &irql );\r
706         if( p_irp == NULL )\r
707         {\r
708                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
709                         ("Not the expected state %s\n", State2String( p_ndi_csq->state )));\r
710                 CL_ASSERT( IsListEmpty( &h_qp->p_irp_queue->queue ) );\r
711                 al_cep_rej( qp_get_al( h_qp ), cid, IB_REJ_INVALID_COMM_INSTANCE, NULL, 0, NULL, 0 );\r
712         }\r
713         else\r
714         {\r
715                 p_ndi_csq->state = NDI_CM_CONNECTING_REP_RCVD;\r
716 \r
717                 __ndi_complete_irp( h_qp, p_irp, STATUS_SUCCESS );\r
718         }\r
719         __ndi_release_lock( &p_ndi_csq->csq, irql );\r
720 \r
721         AL_EXIT( AL_DBG_NDI );\r
722         return;\r
723 }\r
724 \r
725 \r
726 void\r
727 __ndi_do_drep(\r
728         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
729         IN                              PIRP                                            p_irp )\r
730 {\r
731         ib_qp_handle_t h_qp = p_irp->Tail.Overlay.DriverContext[0];\r
732         ib_qp_mod_t qp_mod;\r
733         ib_api_status_t status;\r
734         uint64_t timewait_us;\r
735         KIRQL irql;\r
736         NTSTATUS nt_status;\r
737 \r
738         UNREFERENCED_PARAMETER( p_dev_obj );\r
739 \r
740         AL_ENTER( AL_DBG_NDI );\r
741 \r
742         CL_ASSERT( p_irp->Tail.Overlay.DriverContext[1] );\r
743         IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
744         p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
745         deref_al_obj( &h_qp->obj ); /* Release work item reference. */\r
746 \r
747         status = al_cep_get_timewait( qp_get_al( h_qp ), \r
748                 ((al_conn_qp_t*)h_qp)->cid, &timewait_us );\r
749 \r
750         if (status != IB_SUCCESS)\r
751         {\r
752                 nt_status = STATUS_CONNECTION_INVALID;\r
753                 goto exit;\r
754         }\r
755 \r
756         /* Store the timestamp after which the QP exits timewait. */\r
757         h_qp->timewait = cl_get_time_stamp() + timewait_us;\r
758 \r
759         al_destroy_cep( qp_get_al( h_qp ), &((al_conn_qp_t*)h_qp)->cid, TRUE );\r
760 \r
761         /* bring QP to error state */\r
762         cl_memclr( &qp_mod, sizeof(qp_mod) );\r
763         qp_mod.req_state = IB_QPS_ERROR;\r
764         \r
765         status = ndi_modify_qp( h_qp, &qp_mod, \r
766                 cl_ioctl_out_size( p_irp ), cl_ioctl_out_buf( p_irp ) );\r
767         if ( status != IB_SUCCESS )\r
768         {\r
769                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
770                         ("ndi_modify_qp to ERROR returned %s.\n", ib_get_err_str(status) ) );\r
771         }\r
772 \r
773         nt_status = ib_to_ntstatus( status );\r
774 \r
775 exit:\r
776         __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
777         if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
778                 h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
779         __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
780 \r
781         __ndi_complete_irp( h_qp, p_irp, nt_status );\r
782         AL_EXIT( AL_DBG_NDI );\r
783 }\r
784 \r
785 \r
786 static void\r
787 __ndi_queue_drep(\r
788         IN                              IRP                                                     *p_irp )\r
789 {\r
790         CL_ASSERT( p_irp->Tail.Overlay.DriverContext[1] != NULL );\r
791         IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1],\r
792                 __ndi_do_drep, DelayedWorkQueue, p_irp );\r
793 }\r
794 \r
795 \r
796 static void\r
797 __ndi_proc_drep(\r
798         IN                              ib_qp_handle_t const            h_qp )\r
799 {\r
800         IRP* p_irp;\r
801 \r
802         AL_ENTER( AL_DBG_NDI );\r
803 \r
804         p_irp = IoCsqRemoveNextIrp(\r
805                 &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_DREQ_CM );\r
806         if( p_irp != NULL )\r
807         {\r
808                 __ndi_queue_drep( p_irp );\r
809         }\r
810 \r
811         AL_EXIT( AL_DBG_NDI );\r
812 }\r
813 \r
814 \r
815 static void\r
816 __ndi_cm_handler(\r
817         IN              const   ib_al_handle_t                          h_al,\r
818         IN              const   net32_t                                         cid )\r
819 {\r
820         void*                           context;\r
821         net32_t                         new_cid;\r
822         ib_mad_element_t        *p_mad_el;\r
823 \r
824         AL_ENTER( AL_DBG_NDI );\r
825 \r
826         while( al_cep_poll( h_al, cid, &context, &new_cid, &p_mad_el ) == IB_SUCCESS )\r
827         {\r
828                 ib_mad_t*p_mad = ib_get_mad_buf( p_mad_el );\r
829                 ib_qp_handle_t h_qp = (ib_qp_handle_t)context;\r
830 \r
831                 if( p_mad_el->status != IB_SUCCESS )\r
832                 {\r
833                         switch( p_mad->attr_id )\r
834                         {\r
835                         case CM_REQ_ATTR_ID:\r
836                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
837                                         ("REQ timeouted for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
838                                         cid, h_al, h_qp, new_cid ) );\r
839                                 __ndi_complete_req_irp( h_qp, STATUS_TIMEOUT );\r
840                                 break;\r
841 \r
842                         case CM_REP_ATTR_ID:\r
843                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
844                                         ("REP timeouted for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
845                                         cid, h_al, h_qp, new_cid ) );\r
846                                 break;\r
847 \r
848                         case CM_DREQ_ATTR_ID:\r
849                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
850                                         ("DREQ timeouted for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
851                                         cid, h_al, h_qp, new_cid ) );\r
852                                 __ndi_proc_drep( h_qp );\r
853                                 break;\r
854 \r
855                         default:\r
856                                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
857                                         ("Unhandled failed MAD attr ID %d for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
858                                         p_mad->attr_id, cid, h_al, h_qp, new_cid ) );\r
859                                 break;\r
860                         }\r
861                 }\r
862                 else\r
863                 {\r
864                         switch( p_mad->attr_id )\r
865                         {\r
866                         case CM_REP_ATTR_ID:\r
867                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
868                                         ("REP received for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
869                                         cid, h_al, h_qp, new_cid ) );\r
870                                 CL_ASSERT( ((al_conn_qp_t*)h_qp)->cid == (int32_t)cid || \r
871                                         ((al_conn_qp_t*)h_qp)->cid == AL_INVALID_CID ||\r
872                                         ((al_conn_qp_t*)h_qp)->cid == AL_RESERVED_CID );\r
873                                 __ndi_proc_rep( h_qp, cid );\r
874                                 break;\r
875                         \r
876                         case CM_REJ_ATTR_ID:\r
877                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
878                                         ("REJ received for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
879                                         cid, h_al, h_qp, new_cid ) );\r
880                                 __ndi_proc_rej( h_qp, (mad_cm_rej_t*)p_mad );\r
881                                 break;\r
882                 \r
883                         case CM_DREQ_ATTR_ID:\r
884                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
885                                         ("DREQ received for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
886                                         cid, h_al, h_qp, new_cid ) );\r
887                                 CL_ASSERT( ((al_conn_qp_t*)h_qp)->cid == (int32_t)cid || \r
888                                 ((al_conn_qp_t*)h_qp)->cid == AL_INVALID_CID ||\r
889                                 ((al_conn_qp_t*)h_qp)->cid == AL_RESERVED_CID );\r
890                                 __ndi_proc_dreq( h_qp );\r
891                                 break;\r
892 \r
893                         case CM_DREP_ATTR_ID:\r
894                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
895                                         ("DREP received for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
896                                         cid, h_al, h_qp, new_cid ) );\r
897                                 __ndi_proc_drep( h_qp );\r
898                                 break;\r
899 \r
900                         case CM_RTU_ATTR_ID:\r
901                                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
902                                         ("RTU received for CEP with cid %d, h_al %p, context %p, new_cid %d.\n",\r
903                                         cid, h_al, h_qp, new_cid ) );\r
904                                 break;\r
905 \r
906                         default:\r
907                                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
908                                         ("Unhandled MAD attr ID %d for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
909                                         p_mad->attr_id, cid, h_al, h_qp, new_cid ) );\r
910                         }\r
911                 }\r
912 \r
913                 ib_put_mad( p_mad_el );\r
914         }\r
915 \r
916         AL_EXIT( AL_DBG_NDI );\r
917 }\r
918 \r
919 static void\r
920 __ndi_fill_cm_req(\r
921         IN              ib_qp_handle_t  const                           h_qp,\r
922         IN              ual_ndi_req_cm_ioctl_in_t                       *p_req,\r
923         IN              ib_path_rec_t                                           *p_path_rec,\r
924                 OUT     ib_cm_req_t                                                     *p_cm_req)\r
925 {\r
926         AL_ENTER( AL_DBG_NDI );\r
927 \r
928         memset( p_cm_req, 0, sizeof(ib_cm_req_t) );\r
929 \r
930         p_cm_req->svc_id = IB_REQ_CM_RDMA_SID_PREFIX | (p_req->prot << 16) | p_req->dst_port;\r
931         p_cm_req->max_cm_retries = g_max_cm_retries;\r
932         p_cm_req->p_primary_path = p_path_rec;  \r
933 \r
934         p_cm_req->p_req_pdata = (uint8_t *)&p_req->pdata;\r
935         p_cm_req->req_length = sizeof(p_req->pdata);\r
936 \r
937         p_cm_req->qp_type = IB_QPT_RELIABLE_CONN;\r
938         p_cm_req->h_qp = h_qp;\r
939         p_cm_req->resp_res = p_req->resp_res;\r
940         p_cm_req->init_depth = p_req->init_depth;\r
941 \r
942         p_cm_req->remote_resp_timeout =\r
943                 ib_path_rec_pkt_life( p_path_rec ) + CM_REMOTE_TIMEOUT;\r
944         if( p_cm_req->remote_resp_timeout > 0x1F )\r
945                 p_cm_req->remote_resp_timeout = 0x1F;\r
946         else if( p_cm_req->remote_resp_timeout < CM_MIN_REMOTE_TIMEOUT )\r
947                 p_cm_req->remote_resp_timeout = CM_MIN_REMOTE_TIMEOUT;\r
948 \r
949         p_cm_req->flow_ctrl = TRUE;     /* HCAs must support end-to-end flow control. */\r
950 \r
951         p_cm_req->local_resp_timeout =\r
952                 ib_path_rec_pkt_life( p_path_rec ) + CM_LOCAL_TIMEOUT;\r
953         if( p_cm_req->local_resp_timeout > 0x1F )\r
954                 p_cm_req->local_resp_timeout = 0x1F;\r
955         else if( p_cm_req->local_resp_timeout < CM_MIN_LOCAL_TIMEOUT )\r
956                 p_cm_req->local_resp_timeout = CM_MIN_LOCAL_TIMEOUT;\r
957 \r
958         p_cm_req->rnr_nak_timeout = QP_ATTRIB_RNR_NAK_TIMEOUT;\r
959         p_cm_req->rnr_retry_cnt = QP_ATTRIB_RNR_RETRY;\r
960         p_cm_req->retry_cnt = g_qp_retries;\r
961         p_cm_req->p_alt_path = NULL;\r
962 \r
963         AL_EXIT( AL_DBG_NDI );\r
964 }\r
965 \r
966 \r
967 NTSTATUS\r
968 __ndi_send_req(\r
969         IN              IRP*                                                            p_irp\r
970         )\r
971 {\r
972         ib_api_status_t status;\r
973         ib_qp_handle_t h_qp = (ib_qp_handle_t)p_irp->Tail.Overlay.DriverContext[0];\r
974         ib_path_rec_t *p_path_rec = p_irp->Tail.Overlay.DriverContext[1];\r
975         ual_ndi_req_cm_ioctl_in_t *p_req = \r
976                 (ual_ndi_req_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
977         NTSTATUS nt_status;\r
978         ib_cm_req_t cm_req;\r
979         ib_qp_mod_t qp_mod;\r
980 \r
981         AL_ENTER( AL_DBG_NDI );\r
982 \r
983         p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
984 \r
985         if( h_qp->p_irp_queue->state != NDI_CM_CONNECTING_QPR_SENT )\r
986         {\r
987                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
988                         ("Unexpected state: %d\n", h_qp->p_irp_queue->state) );\r
989                 return STATUS_CONNECTION_ABORTED;\r
990         }\r
991 \r
992         /* Get a CEP and bind it to the QP. */\r
993         status = al_create_cep(\r
994                 qp_get_al( h_qp ), __ndi_cm_handler, h_qp, deref_al_obj,\r
995                 &((al_conn_qp_t*)h_qp)->cid );\r
996         if( status != IB_SUCCESS )\r
997         {\r
998                 h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
999                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1000                         ("al_create_cep returned %s.\n", ib_get_err_str( status )) );\r
1001                 return STATUS_INSUFFICIENT_RESOURCES;\r
1002         }\r
1003         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
1004                 ("Created Active CEP with cid %d, h_al %p, context %p\n",\r
1005                 ((al_conn_qp_t*)h_qp)->cid, qp_get_al( h_qp ), h_qp ) );\r
1006 \r
1007         ref_al_obj( &h_qp->obj ); /* Take CEP reference. */\r
1008 \r
1009         /* Format ib_cm_req_t structure */\r
1010         __ndi_fill_cm_req( h_qp, p_req, p_path_rec, &cm_req );\r
1011 \r
1012         /* prepare CEP for connection */\r
1013         status = al_cep_pre_req( qp_get_al( h_qp ),\r
1014                 ((al_conn_qp_t*)h_qp)->cid, &cm_req, &qp_mod );\r
1015         if( status != STATUS_SUCCESS )\r
1016         {\r
1017                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1018                         ("al_cep_pre_req returned %s.\n", ib_get_err_str( status )) );\r
1019                 goto error;\r
1020         }\r
1021 \r
1022         /* send CM REQ */\r
1023         status = al_cep_send_req( qp_get_al( h_qp ), ((al_conn_qp_t*)h_qp)->cid );\r
1024         if( status != IB_SUCCESS )\r
1025         {\r
1026                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1027                         ("al_cep_send_req returned %s.\n", ib_get_err_str( status )) );\r
1028                 goto error;\r
1029         }\r
1030 \r
1031         /* SUCCESS ! */\r
1032         AL_EXIT( AL_DBG_NDI );\r
1033         return STATUS_SUCCESS;\r
1034 \r
1035 error:\r
1036         al_destroy_cep( qp_get_al( h_qp ), &((al_conn_qp_t*)h_qp)->cid, TRUE );\r
1037         \r
1038         switch( status )\r
1039         {\r
1040         case IB_INVALID_HANDLE:\r
1041                 nt_status = STATUS_CANCELLED;\r
1042                 break;\r
1043 \r
1044         case IB_INVALID_STATE:\r
1045                 nt_status = STATUS_CONNECTION_ABORTED;\r
1046                 break;\r
1047 \r
1048         default:\r
1049                 nt_status = ib_to_ntstatus( status );\r
1050         }\r
1051 \r
1052         h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
1053         AL_EXIT( AL_DBG_NDI );\r
1054         return nt_status;\r
1055 }\r
1056 \r
1057 \r
1058 static void AL_API\r
1059 __ndi_pr_query_cb(\r
1060                                         ib_query_rec_t                          *p_query_rec )\r
1061 {\r
1062         cl_ioctl_handle_t p_irp;\r
1063         uint8_t pkt_life;\r
1064         ib_path_rec_t *p_path_rec;\r
1065         ib_qp_handle_t h_qp = (ib_qp_handle_t)p_query_rec->query_context;\r
1066         NTSTATUS status;\r
1067         KIRQL irql;\r
1068 \r
1069         AL_ENTER( AL_DBG_NDI );\r
1070 \r
1071         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
1072                 ("status is %d, count is %d, context %p\n", p_query_rec->status,\r
1073                 p_query_rec->result_cnt, p_query_rec->query_context) );\r
1074 \r
1075         p_irp = IoCsqRemoveNextIrp( &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_REQ_CM );\r
1076         if( p_irp == NULL )\r
1077         {\r
1078                 goto exit;\r
1079         }\r
1080 \r
1081 #pragma warning( disable:4305 )\r
1082         InterlockedExchangePointer( &h_qp->p_irp_queue->h_query, NULL );\r
1083 #pragma warning( default:4305 )\r
1084 \r
1085         if( p_query_rec->status != IB_SUCCESS || p_query_rec->result_cnt == 0 )\r
1086         {\r
1087                 __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
1088                 if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
1089                         h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
1090                 __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
1091                 switch( p_query_rec->status )\r
1092                 {\r
1093                 case IB_TIMEOUT:\r
1094                 case IB_CANCELED:\r
1095                         status = ib_to_ntstatus( p_query_rec->status );\r
1096                         break;\r
1097 \r
1098                 case IB_REMOTE_ERROR:\r
1099                         CL_ASSERT( p_query_rec->p_result_mad );\r
1100                         switch( p_query_rec->p_result_mad->p_mad_buf->status )\r
1101                         {\r
1102                         case IB_MAD_STATUS_BUSY:\r
1103                         case IB_SA_MAD_STATUS_NO_RESOURCES:\r
1104                                 status = STATUS_TIMEOUT;\r
1105                                 break;\r
1106 \r
1107                         default:\r
1108                                 status = STATUS_INVALID_PARAMETER_1 +\r
1109                                         (p_query_rec->p_result_mad->p_mad_buf->status & 0xFF);\r
1110                                 break;\r
1111                         }\r
1112                         break;\r
1113 \r
1114                 default:\r
1115                         status = STATUS_HOST_UNREACHABLE;\r
1116                         break;\r
1117                 }\r
1118                 __ndi_complete_irp( h_qp, p_irp, status );\r
1119                 goto exit;\r
1120         }\r
1121 \r
1122         /* Path Record has been received ! */\r
1123         p_path_rec = ib_get_query_path_rec( p_query_rec->p_result_mad, 0 );\r
1124 \r
1125         /* fix packet life */\r
1126         CL_ASSERT( p_path_rec );\r
1127         pkt_life = ib_path_rec_pkt_life( p_path_rec ) + g_pkt_life_modifier;\r
1128         if( pkt_life > 0x1F )\r
1129                 pkt_life = 0x1F;\r
1130 \r
1131         p_path_rec->pkt_life &= IB_PATH_REC_SELECTOR_MASK;\r
1132         p_path_rec->pkt_life |= pkt_life;\r
1133 \r
1134         p_irp->Tail.Overlay.DriverContext[1] = p_path_rec;\r
1135 \r
1136         status = IoCsqInsertIrpEx(\r
1137                 &h_qp->p_irp_queue->csq,\r
1138                 p_irp,\r
1139                 NULL,\r
1140                 (VOID*)(ULONG_PTR)NDI_CM_CONNECTING_REQ_SENT\r
1141                 );\r
1142         if( status != STATUS_SUCCESS )\r
1143         {\r
1144                 p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
1145                 __ndi_complete_irp( h_qp, p_irp, status );\r
1146         }\r
1147         else\r
1148         {\r
1149                 /*\r
1150                  * Release the previous reference because IoCsqInsertIrpEx\r
1151                  * took a new one.\r
1152                  */\r
1153                 deref_al_obj( &h_qp->obj ); /* Release IRP reference. */\r
1154         }\r
1155 \r
1156 exit:\r
1157         if( p_query_rec->p_result_mad )\r
1158                 ib_put_mad( p_query_rec->p_result_mad );\r
1159 \r
1160         deref_al_obj( &h_qp->obj );     /* release path query reference */\r
1161         AL_EXIT( AL_DBG_NDI );\r
1162 }\r
1163 \r
1164 \r
1165 /*\r
1166  * Send asynchronous query to the SA for a path record.\r
1167  *\r
1168  * Called from the __ndi_insert_irp_ex function, so the CSQ lock is held.\r
1169  */\r
1170 NTSTATUS\r
1171 __ndi_pr_query(\r
1172         IN              IRP*                                                            p_irp\r
1173         )\r
1174 {\r
1175         ib_query_req_t query_req;\r
1176         ib_api_status_t status;\r
1177         ual_ndi_req_cm_ioctl_in_t *p_req = \r
1178                 (ual_ndi_req_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
1179         ib_qp_handle_t h_qp = (ib_qp_handle_t)p_irp->Tail.Overlay.DriverContext[0];\r
1180 \r
1181         AL_ENTER( AL_DBG_NDI );\r
1182 \r
1183         if ( h_qp->p_irp_queue->state != NDI_CM_IDLE )\r
1184         {\r
1185                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
1186                         ("STATUS_CONNECTION_ACTIVE: h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n",\r
1187                         (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
1188                 return STATUS_CONNECTION_ACTIVE;\r
1189         }\r
1190 \r
1191         query_req.query_type = IB_QUERY_PATH_REC_BY_GIDS;\r
1192         query_req.p_query_input = &p_req->gids;\r
1193         query_req.port_guid = p_req->guid;\r
1194         query_req.timeout_ms = g_sa_timeout;\r
1195         query_req.retry_cnt = g_sa_retries;\r
1196         query_req.flags = 0;    /* IB_FLAGS_SYNC */\r
1197         query_req.query_context = h_qp;\r
1198         query_req.pfn_query_cb = __ndi_pr_query_cb;\r
1199 \r
1200         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
1201                 ("Query for path from %I64x to %I64x\n",\r
1202                 p_req->guid, ib_gid_get_guid( &p_req->gids.dest_gid )) );\r
1203 \r
1204         ref_al_obj( &h_qp->obj );               /* take path query reference */\r
1205         status = ib_query( qp_get_al( h_qp ), &query_req, &h_qp->p_irp_queue->h_query );\r
1206         if( status != IB_SUCCESS )\r
1207         {\r
1208                 h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
1209                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("ib_query failed (%d)\n", status) );\r
1210                 deref_al_obj( &h_qp->obj );     /* release path query reference */\r
1211                 return ib_to_ntstatus( status );\r
1212         }\r
1213 \r
1214         AL_EXIT( AL_DBG_NDI );\r
1215         return STATUS_SUCCESS;\r
1216 }\r
1217 \r
1218 \r
1219 NTSTATUS\r
1220 ndi_req_cm(\r
1221         IN              ib_qp_handle_t  const                           h_qp,\r
1222         IN              IRP                                                                     *p_irp\r
1223         )\r
1224 {\r
1225         NTSTATUS status;\r
1226 \r
1227         AL_ENTER( AL_DBG_NDI );\r
1228 \r
1229         p_irp->Tail.Overlay.DriverContext[0] = (ib_qp_t*)h_qp;\r
1230 \r
1231         status = IoCsqInsertIrpEx(\r
1232                 &h_qp->p_irp_queue->csq,\r
1233                 p_irp,\r
1234                 NULL,\r
1235                 (VOID*)(ULONG_PTR)NDI_CM_CONNECTING_QPR_SENT\r
1236                 );\r
1237         if( status == STATUS_SUCCESS )\r
1238                 status = STATUS_PENDING;\r
1239 \r
1240         AL_EXIT( AL_DBG_NDI );\r
1241         return status;\r
1242 }\r
1243 \r
1244 \r
1245 /*******************************************************************\r
1246  *\r
1247  * RTU CM request\r
1248  *\r
1249  ******************************************************************/\r
1250 \r
1251 static void\r
1252 __ndi_do_rtu(\r
1253         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1254         IN                              PIRP                                            p_irp )\r
1255 {\r
1256         ib_api_status_t status;\r
1257         ib_qp_handle_t h_qp = p_irp->Tail.Overlay.DriverContext[0];\r
1258         KIRQL irql;\r
1259         NTSTATUS nt_status;\r
1260 \r
1261         UNUSED_PARAM(p_dev_obj);\r
1262 \r
1263         AL_ENTER( AL_DBG_NDI );\r
1264 \r
1265         /* free the work item if any */\r
1266         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1267         {\r
1268                 IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
1269                 p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
1270                 deref_al_obj( &h_qp->obj ); /* Release work item reference. */\r
1271         }\r
1272 \r
1273         __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
1274         if( h_qp->p_irp_queue->state != NDI_CM_CONNECTING_REP_RCVD )\r
1275         {\r
1276                 nt_status = STATUS_CONNECTION_ABORTED;\r
1277                 goto exit;\r
1278         }\r
1279         __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
1280 \r
1281         /* change the QP state to RTS */\r
1282         status = __ndi_qp2rts( h_qp, p_irp );\r
1283 \r
1284         if ( status != IB_SUCCESS )\r
1285         {\r
1286                 goto err;\r
1287         }\r
1288         \r
1289         /* send RTU */\r
1290         status = al_cep_rtu( qp_get_al( h_qp ), ((al_conn_qp_t*)h_qp)->cid, NULL, 0 );\r
1291         if( status != IB_SUCCESS )\r
1292         {\r
1293 err:\r
1294                 /* Reject and abort the connection. */\r
1295                 al_cep_rej(\r
1296                         qp_get_al( h_qp ), ((al_conn_qp_t*)h_qp)->cid, \r
1297                         IB_REJ_INSUF_QP, NULL, 0, NULL, 0 );\r
1298 \r
1299                 __cep_timewait_qp( h_qp );\r
1300 \r
1301                 al_destroy_cep( qp_get_al( h_qp ), &((al_conn_qp_t*)h_qp)->cid, TRUE );\r
1302 \r
1303                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
1304                         ("al_cep_rtu returned %s.\n", ib_get_err_str( status )) );\r
1305 \r
1306                 __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
1307                 if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
1308                         h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
1309                 __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
1310 \r
1311                 nt_status = STATUS_CONNECTION_ABORTED;\r
1312                 goto exit;\r
1313         }\r
1314 \r
1315         __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
1316         if( h_qp->p_irp_queue->state == NDI_CM_CONNECTING_REP_RCVD )\r
1317                 h_qp->p_irp_queue->state = NDI_CM_CONNECTED;\r
1318         __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
1319 \r
1320         nt_status = STATUS_SUCCESS;\r
1321 \r
1322 exit:\r
1323         __ndi_complete_irp( h_qp, p_irp, nt_status );\r
1324         AL_EXIT( AL_DBG_NDI );\r
1325 }\r
1326 \r
1327 \r
1328 cl_status_t\r
1329 ndi_rtu_cm(\r
1330         IN              ib_qp_handle_t  const                           h_qp,\r
1331         IN              PIRP                                                            p_irp\r
1332         )\r
1333 {\r
1334         IO_STACK_LOCATION       *p_io_stack;\r
1335 \r
1336         AL_ENTER( AL_DBG_NDI );\r
1337 \r
1338         p_irp->Tail.Overlay.DriverContext[0] = h_qp;\r
1339         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1340         p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject );\r
1341         ref_al_obj( &h_qp->obj ); /* Take IRP reference. */\r
1342 \r
1343         if ( p_irp->Tail.Overlay.DriverContext[1] )\r
1344         { /* asyncronous performing */\r
1345                 /* take a ref to prevent QP destroy before calling work item */\r
1346                 ref_al_obj( &h_qp->obj ); /* Take work item reference. */\r
1347                 IoMarkIrpPending( p_irp );\r
1348                 IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1],\r
1349                         __ndi_do_rtu, DelayedWorkQueue, p_irp );\r
1350         }\r
1351         else\r
1352         { /* syncronous performing */\r
1353                 __ndi_do_rtu( p_io_stack->DeviceObject, p_irp );\r
1354         }\r
1355 \r
1356         AL_EXIT( AL_DBG_NDI );\r
1357         return CL_PENDING;\r
1358 }\r
1359 \r
1360 \r
1361 /*******************************************************************\r
1362  *\r
1363  * REP CM request\r
1364  *\r
1365  ******************************************************************/\r
1366 \r
1367 static void\r
1368 __ndi_do_rep(\r
1369         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1370         IN              PIRP                                                            p_irp )\r
1371 {\r
1372         ib_qp_handle_t h_qp = p_irp->Tail.Overlay.DriverContext[0];\r
1373         ib_api_status_t status;\r
1374         ual_ndi_rep_cm_ioctl_in_t *p_rep;\r
1375         KIRQL irql;\r
1376         NTSTATUS nt_status;\r
1377 \r
1378         UNUSED_PARAM(p_dev_obj);\r
1379 \r
1380         AL_ENTER( AL_DBG_NDI );\r
1381 \r
1382         /* free the work item if any */\r
1383         CL_ASSERT( p_irp->Tail.Overlay.DriverContext[1] != NULL );\r
1384         IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
1385         p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
1386         deref_al_obj( &h_qp->obj ); /* Release work item reference. */\r
1387 \r
1388         p_rep = (ual_ndi_rep_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
1389 \r
1390         /* change the QP state to RTS */\r
1391         status = __ndi_qp2rts( h_qp, p_irp );\r
1392         if ( status != IB_SUCCESS )\r
1393         {\r
1394                 goto err;\r
1395         }\r
1396         \r
1397         /* send REP */\r
1398         status = al_cep_send_rep ( qp_get_al( h_qp ), p_rep->cid );\r
1399         if( status != IB_SUCCESS )\r
1400         {\r
1401                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1402                         ("al_cep_send_rep returned %s\n", ib_get_err_str(status)) );\r
1403 err:\r
1404                 /* Reject and abort the connection. */\r
1405                 al_cep_rej( qp_get_al( h_qp ), p_rep->cid, IB_REJ_INSUF_QP, NULL, 0, NULL, 0 );\r
1406 \r
1407                 /* transit QP to error state */\r
1408                 __cep_timewait_qp( h_qp );\r
1409 \r
1410                 al_destroy_cep( qp_get_al( h_qp ), &((al_conn_qp_t*)h_qp)->cid, TRUE );\r
1411 \r
1412                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1413                         ("al_cep_rtu returned %s.\n", ib_get_err_str( status )) );\r
1414                 __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
1415                 if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
1416                         h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
1417                 __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
1418                 if (status == IB_INVALID_STATE)\r
1419                         nt_status = STATUS_CONNECTION_ABORTED;\r
1420                 else\r
1421                         nt_status =STATUS_INSUFFICIENT_RESOURCES;\r
1422                 goto exit;\r
1423         }\r
1424 \r
1425         __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
1426         if( h_qp->p_irp_queue->state == NDI_CM_CONNECTING_REP_SENT )\r
1427                 h_qp->p_irp_queue->state = NDI_CM_CONNECTED;\r
1428         __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
1429         nt_status = STATUS_SUCCESS;\r
1430 \r
1431 exit:\r
1432         __ndi_complete_irp( h_qp, p_irp, nt_status );\r
1433         AL_EXIT( AL_DBG_NDI );\r
1434 }\r
1435 \r
1436 static void\r
1437 __ndi_fill_cm_rep(\r
1438         IN              ib_qp_handle_t  const                           h_qp,\r
1439         IN              ual_ndi_rep_cm_ioctl_in_t                       *p_rep,\r
1440                 OUT     ib_cm_rep_t                                                     *p_cm_rep)\r
1441 {\r
1442         AL_ENTER( AL_DBG_NDI );\r
1443 \r
1444         memset( p_cm_rep, 0, sizeof(ib_cm_rep_t) );\r
1445 \r
1446         p_cm_rep->p_rep_pdata = p_rep->pdata;\r
1447         p_cm_rep->rep_length = sizeof(p_rep->pdata);\r
1448 \r
1449         p_cm_rep->qp_type = IB_QPT_RELIABLE_CONN;\r
1450         p_cm_rep->h_qp = h_qp;\r
1451 \r
1452         p_cm_rep->access_ctrl = IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE;\r
1453         p_cm_rep->init_depth = p_rep->init_depth;\r
1454         p_cm_rep->target_ack_delay = 10;\r
1455         p_cm_rep->failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED;\r
1456         p_cm_rep->flow_ctrl = TRUE;     /* HCAs must support end-to-end flow control. */\r
1457         p_cm_rep->rnr_nak_timeout = QP_ATTRIB_RNR_NAK_TIMEOUT;\r
1458         p_cm_rep->rnr_retry_cnt = QP_ATTRIB_RNR_RETRY;\r
1459 \r
1460         AL_EXIT( AL_DBG_NDI );\r
1461 }\r
1462 \r
1463 \r
1464 NTSTATUS\r
1465 __ndi_send_rep(\r
1466         IN              ib_qp_handle_t                                          h_qp,\r
1467         IN              PIRP                                                            p_irp )\r
1468 {\r
1469         IO_STACK_LOCATION       *p_io_stack;\r
1470         ib_cm_rep_t cm_rep;\r
1471         ib_qp_mod_t qp_mod;\r
1472         ib_api_status_t status;\r
1473         ual_ndi_rep_cm_ioctl_in_t *p_rep = \r
1474                 (ual_ndi_rep_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
1475 \r
1476         AL_ENTER( AL_DBG_NDI );\r
1477 \r
1478         if( h_qp->p_irp_queue->state != NDI_CM_IDLE )\r
1479         {\r
1480                 AL_EXIT( AL_DBG_NDI );\r
1481                 return STATUS_CONNECTION_ACTIVE;\r
1482         }\r
1483 \r
1484         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1485         p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject );\r
1486         if( p_irp->Tail.Overlay.DriverContext[1] == NULL )\r
1487         {\r
1488                 AL_EXIT( AL_DBG_NDI );\r
1489                 return STATUS_NO_MEMORY;\r
1490         }\r
1491         ref_al_obj( &h_qp->obj ); /* Take work item reference. */\r
1492 \r
1493         /* Format ib_cm_req_t structure */\r
1494         __ndi_fill_cm_rep( h_qp, p_rep, &cm_rep );\r
1495 \r
1496         ref_al_obj( &h_qp->obj ); /* Take CEP reference. */\r
1497 \r
1498         /* prepare Passive CEP for connection */\r
1499         status = al_cep_pre_rep_ex(\r
1500                 qp_get_al( h_qp ), p_rep->cid, __ndi_cm_handler, h_qp, deref_al_obj,\r
1501                 &cm_rep, &((al_conn_qp_t*)h_qp)->cid, &qp_mod );\r
1502         if( status != IB_SUCCESS )\r
1503         {\r
1504                 IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
1505                 p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
1506                 deref_al_obj( &h_qp->obj ); /* Release work item reference. */\r
1507                 al_destroy_cep( qp_get_al( h_qp ), &p_rep->cid, FALSE );\r
1508                 deref_al_obj( &h_qp->obj ); /* Release CEP reference. */\r
1509                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1510                         ("al_cep_pre_rep_ex returned %s.\n", ib_get_err_str( status )) );\r
1511                 switch (status)\r
1512                 {\r
1513                         case IB_INVALID_HANDLE:\r
1514                                 return STATUS_CANCELLED;\r
1515                         case IB_INVALID_STATE:\r
1516                                 return STATUS_CONNECTION_ABORTED;\r
1517                         case IB_RESOURCE_BUSY:\r
1518                                 return STATUS_CONNECTION_ACTIVE;\r
1519                         default:\r
1520                                 return ib_to_ntstatus( status );\r
1521                 }\r
1522         }\r
1523 \r
1524         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
1525                 ("Prepared Passive CEP with cid %d, h_al %p, context %p\n",\r
1526                 p_rep->cid, qp_get_al( h_qp ), h_qp ) );\r
1527 \r
1528         /*\r
1529          * transfer work to a worker thread so that QP transitions can be done\r
1530          * at PASSIVE_LEVEL\r
1531          */\r
1532         IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1],\r
1533                 __ndi_do_rep, DelayedWorkQueue, p_irp );\r
1534 \r
1535         AL_EXIT( AL_DBG_NDI );\r
1536         return STATUS_SUCCESS;\r
1537 }\r
1538 \r
1539 \r
1540 NTSTATUS\r
1541 ndi_rep_cm(\r
1542         IN              ib_qp_handle_t  const                           h_qp,\r
1543         IN              PIRP                                                            p_irp\r
1544         )\r
1545 {\r
1546         NTSTATUS status;\r
1547         KIRQL irql;\r
1548 \r
1549         AL_ENTER( AL_DBG_NDI );\r
1550 \r
1551         p_irp->Tail.Overlay.DriverContext[0] = h_qp;\r
1552 \r
1553         __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
1554         status = __ndi_send_rep( h_qp, p_irp );\r
1555         if( status == STATUS_SUCCESS )\r
1556         {\r
1557                 /*\r
1558                  * We're going to keep the IRP dangling for a bit - take a reference\r
1559                  * on the QP until it completes.\r
1560                  */\r
1561                 ref_al_obj( &h_qp->obj ); /* Take IRP reference. */\r
1562                 h_qp->p_irp_queue->state = NDI_CM_CONNECTING_REP_SENT;\r
1563                 IoMarkIrpPending( p_irp );\r
1564                 status = STATUS_PENDING;\r
1565         }\r
1566         __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
1567 \r
1568         AL_EXIT( AL_DBG_NDI );\r
1569         return status;\r
1570 }\r
1571 \r
1572 \r
1573 \r
1574 /*******************************************************************\r
1575  *\r
1576  * DREQ CM request\r
1577  *\r
1578  ******************************************************************/\r
1579 \r
1580 \r
1581 NTSTATUS\r
1582 __ndi_send_dreq(\r
1583         IN              IRP*                                                            p_irp\r
1584         )\r
1585 {\r
1586         ib_qp_handle_t h_qp = (ib_qp_handle_t)p_irp->Tail.Overlay.DriverContext[0];\r
1587         IO_STACK_LOCATION       *p_io_stack;\r
1588         ib_api_status_t status;\r
1589         NTSTATUS nt_status;\r
1590 \r
1591         AL_ENTER( AL_DBG_NDI );\r
1592 \r
1593         if ( h_qp->p_irp_queue->state != NDI_CM_CONNECTED &&\r
1594                 h_qp->p_irp_queue->state != NDI_CM_CONNECTED_DREQ_RCVD )\r
1595         {\r
1596                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
1597                         ("STATUS_CONNECTION_ACTIVE: h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n",\r
1598                         (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
1599                 return STATUS_CONNECTION_INVALID;\r
1600         }\r
1601 \r
1602         /*\r
1603          * Allocate a work item to perform the QP transition when disconnection\r
1604          * completes (or the IRP is cancelled).  We allocate here to trap errors\r
1605          * properly.\r
1606          */\r
1607         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1608         p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject );\r
1609         if( p_irp->Tail.Overlay.DriverContext[1] == NULL )\r
1610         {\r
1611                 AL_EXIT( AL_DBG_NDI );\r
1612                 return STATUS_NO_MEMORY;\r
1613         }\r
1614         ref_al_obj( &h_qp->obj ); /* Take work item reference. */\r
1615 \r
1616         status = al_cep_dreq( qp_get_al( h_qp ), ((al_conn_qp_t*)h_qp)->cid, NULL, 0 );\r
1617         switch( status )\r
1618         {\r
1619         case IB_INVALID_STATE:\r
1620                 /* We might have just received a DREQ, so try sending a DREP. */\r
1621                 __ndi_queue_drep( p_irp );\r
1622                 IoMarkIrpPending( p_irp );\r
1623                 /*\r
1624                  * We're going to keep the IRP dangling for a bit - take a reference\r
1625                  * on the QP until it completes.\r
1626                  */\r
1627                 ref_al_obj( &h_qp->obj ); /* Take IRP reference. */\r
1628 \r
1629         case IB_SUCCESS:\r
1630                 AL_EXIT( AL_DBG_NDI );\r
1631                 return( ib_to_ntstatus( status ) );\r
1632 \r
1633         case IB_INVALID_HANDLE:\r
1634                 nt_status = STATUS_CONNECTION_INVALID;\r
1635                 break;\r
1636         default:\r
1637                 nt_status = ib_to_ntstatus( status );\r
1638         }\r
1639         IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
1640         p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
1641         deref_al_obj( &h_qp->obj ); /* Release work item reference. */\r
1642         AL_EXIT( AL_DBG_NDI );\r
1643         return nt_status;\r
1644 }\r
1645 \r
1646 \r
1647 NTSTATUS\r
1648 ndi_dreq_cm(\r
1649         IN              ib_qp_handle_t  const                           h_qp,\r
1650         IN              PIRP                                                            p_irp\r
1651         )\r
1652 {\r
1653         NTSTATUS status;\r
1654 \r
1655         AL_ENTER( AL_DBG_NDI );\r
1656 \r
1657         p_irp->Tail.Overlay.DriverContext[0] = h_qp;\r
1658 \r
1659         status = IoCsqInsertIrpEx(\r
1660                 &h_qp->p_irp_queue->csq,\r
1661                 p_irp,\r
1662                 NULL,\r
1663                 (VOID*)(ULONG_PTR)NDI_CM_DISCONNECTING\r
1664                 );\r
1665         /*\r
1666          * Note that if al_cep_dreq returned IB_INVALID_STATE, we queued the\r
1667          * work item and will try sending the DREP and move the QP to error.\r
1668          *\r
1669          * The IRP should never be queued if the work item is queued, so \r
1670          * we trap the special error code for INVALID_STATE.\r
1671          */\r
1672         if( status == STATUS_SUCCESS || status == STATUS_INVALID_DEVICE_STATE )\r
1673                 status = STATUS_PENDING;\r
1674 \r
1675         AL_EXIT( AL_DBG_NDI );\r
1676         return status;\r
1677 }\r
1678 \r
1679 \r
1680 \r