[IBAL] This patch fixes ND CM IOCTL handling to work properly at scale. There were...
authorleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Wed, 9 Jul 2008 10:26:28 +0000 (10:26 +0000)
committerleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Wed, 9 Jul 2008 10:26:28 +0000 (10:26 +0000)
Signed-off-by: Fab Tillier <ftillier@microsoft.com>
git-svn-id: svn://openib.tc.cornell.edu/gen1/trunk@1355 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

core/al/al_dev.h
core/al/al_proxy.h
core/al/al_qp.h
core/al/kernel/al_ndi_cm.c
core/al/kernel/al_ndi_cm.h
core/al/kernel/al_proxy.c
core/al/kernel/al_proxy_ndi.c
inc/iba/ib_al_ioctl.h

index bb2211b..8c8cb02 100644 (file)
@@ -55,7 +55,7 @@
 #define AL_DEVICE_NAME L"\\Device\\ibal"\r
 #define        ALDEV_KEY               (0x3B)  /* Matches FILE_DEVICE_INFINIBAND from wdm.h */\r
 \r
-#define AL_IOCTL_VERSION                       (7)\r
+#define AL_IOCTL_VERSION                       (8)\r
 \r
 /* max number of devices with non-default pkey */\r
 #define        MAX_NUM_PKEY    16\r
@@ -404,6 +404,7 @@ typedef enum _al_ndi_ops
        ual_ndi_rej_cm_ioctl_cmd,\r
        ual_ndi_dreq_cm_ioctl_cmd,\r
     ual_ndi_noop,\r
+    ual_ndi_notify_dreq_cmd,\r
 \r
        al_ndi_maxops\r
 \r
@@ -426,6 +427,7 @@ typedef enum _al_ndi_ops
 #define UAL_NDI_REJ_CM                 IOCTL_CODE(ALDEV_KEY, ual_ndi_rej_cm_ioctl_cmd)\r
 #define UAL_NDI_DREQ_CM                        IOCTL_CODE(ALDEV_KEY, ual_ndi_dreq_cm_ioctl_cmd)\r
 #define UAL_NDI_NOOP            IOCTL_CODE(ALDEV_KEY, ual_ndi_noop)\r
+#define UAL_NDI_NOTIFY_DREQ     IOCTL_CODE(ALDEV_KEY, ual_ndi_notify_dreq_cmd)\r
 \r
 /*\r
  * Various Operation Allowable on the System Helper\r
index e4beca5..5bc853c 100644 (file)
@@ -257,5 +257,7 @@ ib_api_status_t
 proxy_pnp_port_cb(\r
        IN      ib_pnp_rec_t    *p_pnp_rec );\r
 \r
-\r
+NTSTATUS\r
+ib_to_ntstatus(\r
+    IN  ib_api_status_t ib_status );\r
 #endif /* _AL_PROXY_H_ */\r
index 95a0bd9..bb6d8ad 100644 (file)
@@ -155,7 +155,7 @@ typedef struct _ib_qp
        ib_pfn_join_mcast_t                     pfn_join_mcast;\r
 \r
 #ifdef CL_KERNEL\r
-       ndi_qp_csq_t                            *p_irp_que;\r
+       ndi_qp_csq_t                            *p_irp_queue;\r
 #endif\r
 \r
 }      ib_qp_t;\r
index 1ee4974..1378e7a 100644 (file)
@@ -61,6 +61,37 @@ uint8_t                      g_qp_retries = QP_ATTRIB_RETRY_COUNT;
 uint8_t                        g_pkt_life_modifier = 0;\r
 uint8_t                        g_max_cm_retries = CM_RETRIES;\r
 \r
+NTSTATUS\r
+__ndi_ats_query(\r
+       IN              IRP*                                                            p_irp\r
+       );\r
+\r
+NTSTATUS\r
+__ndi_pr_query(\r
+       IN              IRP*                                                            p_irp\r
+       );\r
+\r
+NTSTATUS\r
+__ndi_send_req(\r
+       IN              IRP*                                                            p_irp\r
+       );\r
+\r
+NTSTATUS\r
+__ndi_send_rep(\r
+       IN              ib_qp_handle_t                                          h_qp,\r
+       IN              PIRP                                                            p_irp\r
+       );\r
+\r
+NTSTATUS\r
+__ndi_send_dreq(\r
+       IN              IRP*                                                            p_irp\r
+       );\r
+\r
+static void\r
+__ndi_queue_drep(\r
+       IN                              IRP                                                     *p_irp\r
+       );\r
+\r
 /*******************************************************************\r
  *\r
  * Helpers\r
@@ -72,57 +103,50 @@ static char * State2String(ndi_cm_state_t state)
        switch (state) \r
        {\r
                case NDI_CM_IDLE                                        : return "NDI_CM_IDLE";\r
-               case NDI_CM_CONNECTING_ATS_SENT         : return "NDI_CM_CONNECTING_ATS_SENT";\r
-               case NDI_CM_CONNECTING_QPR_SENT         : return "NDI_CM_CONNECTING_QPR_SENT";\r
-               case NDI_CM_CONNECTING_REQ_SENT         : return "NDI_CM_CONNECTING_REQ_SENT";\r
-               case NDI_CM_CONNECTING_REP_RCVD         : return "NDI_CM_CONNECTING_REP_RCVD";\r
-               case NDI_CM_CONNECTING_REJ_RCVD         : return "NDI_CM_CONNECTING_REJ_RCVD";\r
+               case NDI_CM_CONNECTING_ATS_SENT         : return "NDI_CM_CONNECTING_ATS_SENT";\r
+               case NDI_CM_CONNECTING_QPR_SENT         : return "NDI_CM_CONNECTING_QPR_SENT";\r
+               case NDI_CM_CONNECTING_REQ_SENT         : return "NDI_CM_CONNECTING_REQ_SENT";\r
+               case NDI_CM_CONNECTING_REP_SENT         : return "NDI_CM_CONNECTING_REP_SENT";\r
+               case NDI_CM_CONNECTING_REP_RCVD         : return "NDI_CM_CONNECTING_REP_RCVD";\r
                case NDI_CM_CONNECTED                           : return "NDI_CM_CONNECTED";\r
-               case NDI_CM_BOUND                                       : return "NDI_CM_BOUND";\r
-               case NDI_CM_LISTENING                           : return "NDI_CM_LISTENING";\r
-               case NDI_CM_REP_SENT                            : return "NDI_CM_REP_SENT";\r
-               case NDI_CM_CONNECTED_DREP_SENT         : return "NDI_CM_CONNECTED_DREP_SENT";\r
-               case NDI_CM_CONNECTED_DREQ_SENT         : return "NDI_CM_CONNECTED_DREQ_SENT";\r
+               case NDI_CM_DISCONNECTING                       : return "NDI_CM_DISCONNECTING";\r
+               case NDI_CM_CONNECTED_DREQ_RCVD         : return "NDI_CM_CONNECTED_DREQ_RCVD";\r
+               case NDI_CM_INVALID                                     : return "NDI_CM_CONNECTING_REP_SENT";\r
                default : \r
                        ASSERT(FALSE);\r
        }\r
        return "Unknown state";\r
 }\r
 \r
+\r
 static inline void\r
 __ndi_complete_irp(\r
-       IN      ib_qp_handle_t FUNC_PTR64                                                       h_qp,\r
-       IN      PIRP                                                                    Irp,\r
-       IN      NTSTATUS                                                                code\r
+       IN      ib_qp_handle_t                                                  h_qp,\r
+       IN      PIRP                                                                    p_irp,\r
+       IN      NTSTATUS                                                                status\r
        )\r
 {\r
        AL_ENTER( AL_DBG_NDI );\r
 \r
-       CL_ASSERT( Irp );\r
+       CL_ASSERT( p_irp );\r
+       CL_ASSERT( p_irp->Tail.Overlay.DriverContext[1] == NULL );\r
 \r
-       cl_ioctl_complete( Irp, code, 0 );\r
-       deref_al_obj( &h_qp->obj );                     /* release IRP life reference */\r
-       h_qp->p_irp_que->h_ioctl = NULL;        /* mark IRP as cancelled */\r
+       p_irp->IoStatus.Status = status;\r
+       if( status == STATUS_SUCCESS )\r
+       {\r
+               p_irp->IoStatus.Information = cl_ioctl_out_size( p_irp );\r
+               IoCompleteRequest( p_irp, IO_NETWORK_INCREMENT );\r
+       }\r
+       else\r
+       {\r
+               p_irp->IoStatus.Information = 0;\r
+               IoCompleteRequest( p_irp, 0 );\r
+       }\r
+       deref_al_obj( &h_qp->obj ); /* Release IRP reference */\r
 \r
        AL_EXIT( AL_DBG_NDI );\r
 }\r
 \r
-static inline void\r
-__ndi_complete_irp_ex(\r
-       IN      ib_qp_handle_t FUNC_PTR64                                                       h_qp,\r
-       IN      NTSTATUS                                                                code,\r
-       IN      ndi_cm_state_t                                                  new_state\r
-       )\r
-{\r
-       PIRP Irp;\r
-\r
-       AL_ENTER( AL_DBG_NDI );\r
-       h_qp->p_irp_que->state = new_state;     \r
-       Irp = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
-       if ( Irp )\r
-               __ndi_complete_irp( h_qp, Irp, code );\r
-       AL_EXIT( AL_DBG_NDI );\r
-}\r
 \r
 /*\r
  * Transition the QP to the error state to flush all oustanding work\r
@@ -243,16 +267,52 @@ exit:
  *\r
  ******************************************************************/\r
 \r
-static VOID __ndi_insert_irp(\r
-       IN      PIO_CSQ                                                                 Csq,\r
-       IN      PIRP                                                                    Irp\r
+\r
+static NTSTATUS __ndi_insert_irp_ex(\r
+       IN      PIO_CSQ                                                                 pCsq,\r
+       IN      PIRP                                                                    pIrp,\r
+       IN      VOID                                                                    *Context\r
        )\r
 {\r
-       ndi_qp_csq_t *p_ndi_csq = (ndi_qp_csq_t*)Csq;\r
+       NTSTATUS status;\r
+       ndi_qp_csq_t *p_ndi_csq = (ndi_qp_csq_t*)pCsq;\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
-       InsertTailList( &p_ndi_csq->que, &Irp->Tail.Overlay.ListEntry );\r
+       switch( (ULONG_PTR)Context )\r
+       {\r
+       case NDI_CM_CONNECTING_ATS_SENT:\r
+               status = __ndi_ats_query( pIrp );\r
+               break;\r
+\r
+       case NDI_CM_CONNECTING_QPR_SENT:\r
+               status = __ndi_pr_query( pIrp );\r
+               break;\r
+\r
+       case NDI_CM_CONNECTING_REQ_SENT:\r
+               status = __ndi_send_req( pIrp );\r
+               break;\r
+\r
+       case NDI_CM_CONNECTING_REP_SENT:\r
+               status = __ndi_send_rep( p_ndi_csq->h_qp, pIrp );\r
+               break;\r
+\r
+       case NDI_CM_DISCONNECTING:\r
+               status = __ndi_send_dreq( pIrp );\r
+               break;\r
+\r
+       default:\r
+               status = STATUS_INVALID_DEVICE_REQUEST;\r
+               ASSERT( FALSE );\r
+       }\r
+\r
+       if( status == STATUS_SUCCESS )\r
+       {\r
+               p_ndi_csq->state = (ndi_cm_state_t)(ULONG_PTR)Context;\r
+               InsertTailList( &p_ndi_csq->queue, &pIrp->Tail.Overlay.ListEntry );\r
+               ref_al_obj( &p_ndi_csq->h_qp->obj ); /* Take IRP reference. */\r
+       }\r
        AL_EXIT( AL_DBG_NDI );\r
+       return status;\r
 }\r
 \r
 static VOID __ndi_remove_irp(\r
@@ -280,7 +340,7 @@ static PIRP __ndi_peek_next_irp(
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
-       listHead = &p_ndi_csq->que;\r
+       listHead = &p_ndi_csq->queue;\r
 \r
        // \r
        // If the IRP is NULL, we will start peeking from the listhead, else\r
@@ -303,11 +363,13 @@ static PIRP __ndi_peek_next_irp(
 \r
                if(PeekContext) \r
                {\r
-                       /* for now PeekContext is not used */\r
-               } \r
+                       if( cl_ioctl_ctl_code( nextIrp ) == (ULONG_PTR)PeekContext )\r
+                               break;\r
+               }\r
                else\r
                {\r
-                       break;\r
+                       if( cl_ioctl_ctl_code( nextIrp ) != UAL_NDI_NOTIFY_DREQ )\r
+                               break;\r
                }\r
 \r
                nextIrp = NULL;\r
@@ -348,70 +410,56 @@ static VOID __ndi_release_lock(
 \r
 static VOID __ndi_complete_cancelled_irp(\r
        IN      PIO_CSQ                                                                 Csq,\r
-       IN      PIRP                                                                    Irp\r
+       IN      PIRP                                                                    p_irp\r
        )\r
 {\r
        ndi_qp_csq_t *p_ndi_csq = (ndi_qp_csq_t*)Csq;\r
        ib_qp_handle_t h_qp = p_ndi_csq->h_qp;\r
+       KIRQL irql;\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
-       switch (p_ndi_csq->state)\r
+       switch( cl_ioctl_ctl_code( p_irp ) )\r
        {\r
-       case NDI_CM_CONNECTING_REQ_SENT:\r
-               /* Cleanup from issuing CM REQ. */\r
+       case UAL_NDI_REQ_CM:\r
+               __ndi_acquire_lock( Csq, &irql );\r
+               if( p_ndi_csq->state != NDI_CM_INVALID )\r
+               {\r
+                       switch( p_ndi_csq->state )\r
+                       {\r
+                       case NDI_CM_CONNECTING_ATS_SENT:\r
+                       case NDI_CM_CONNECTING_QPR_SENT:\r
+                               /*\r
+                                * Note that al_cancel_sa_req must be synchronized with any potential\r
+                                * SA callback.\r
+                                */\r
+                               al_cancel_sa_req( &h_qp->p_irp_queue->h_query->sa_req );\r
+                               break;\r
+\r
+                       default:\r
+                       CL_ASSERT( p_ndi_csq->state == NDI_CM_CONNECTING_ATS_SENT ||\r
+                               p_ndi_csq->state == NDI_CM_CONNECTING_QPR_SENT ||\r
+                               p_ndi_csq->state == NDI_CM_CONNECTING_REQ_SENT );\r
+                       }\r
+                       p_ndi_csq->state = NDI_CM_IDLE;\r
+               }\r
+               /* Always try to destroy the CEP.  The CEP manager handles invalid CIDs. */\r
                al_destroy_cep(\r
                        qp_get_al( h_qp ), &((al_conn_qp_t*)h_qp)->cid, TRUE, deref_al_obj );\r
-               break;\r
-\r
-       case NDI_CM_CONNECTING_ATS_SENT:\r
-       case NDI_CM_CONNECTING_QPR_SENT:\r
-               al_cancel_sa_req( &h_qp->p_irp_que->h_query->sa_req );\r
-               break;\r
-\r
-       default:\r
-               /* fall through */\r
-               break;\r
-       }\r
 \r
-       //TODO: is it always true ?\r
-       p_ndi_csq->state = NDI_CM_IDLE;\r
-       __ndi_complete_irp( h_qp, Irp, CL_CANCELED );\r
+               __ndi_release_lock( Csq, irql );\r
 \r
-       AL_EXIT( AL_DBG_NDI );\r
-}\r
+               __fallthrough;\r
 \r
-/* flush a queue of pending requests */\r
+       case UAL_NDI_NOTIFY_DREQ:\r
+               __ndi_complete_irp( h_qp, p_irp, STATUS_CANCELLED );\r
+               break;\r
 \r
-#pragma warning(disable:4706)\r
-static inline void __ndi_flush_que(\r
-       IN      ndi_qp_csq_t*                                                   p_ndi_csq,\r
-       IN      NTSTATUS                                                                completion_code\r
-       )\r
-{\r
-       PIRP Irp;\r
-       while( Irp = IoCsqRemoveNextIrp( &p_ndi_csq->csq, NULL ) )\r
-       {\r
-               AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, \r
-                       ("h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n", \r
-                       (uint64_t)p_ndi_csq->h_qp, p_ndi_csq->h_qp->obj.hdl, \r
-                       p_ndi_csq->h_qp->obj.ref_cnt ) );\r
-               cl_ioctl_complete( Irp, completion_code, 0 );\r
-               deref_al_obj( &p_ndi_csq->h_qp->obj );          /* release IRP life reference */\r
+       case UAL_NDI_DREQ_CM:\r
+               __ndi_queue_drep( p_irp );\r
+               break;\r
        }\r
-}\r
-#pragma warning(default:4706)\r
 \r
-void\r
-ndi_qp_flush_ques(\r
-       IN      ib_qp_handle_t FUNC_PTR64                                                       h_qp\r
-       )\r
-{\r
-       AL_ENTER( AL_DBG_NDI );\r
-       __ndi_flush_que( h_qp->p_irp_que, STATUS_CANCELLED );\r
-       AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, \r
-               ("h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n", \r
-               (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
        AL_EXIT( AL_DBG_NDI );\r
 }\r
 \r
@@ -434,24 +482,24 @@ ndi_qp_init(
                goto exit;\r
        }\r
        \r
-       h_qp->p_irp_que = (ndi_qp_csq_t*)cl_zalloc(sizeof(ndi_qp_csq_t));\r
-       if (!h_qp->p_irp_que)\r
+       h_qp->p_irp_queue = (ndi_qp_csq_t*)cl_zalloc(sizeof(ndi_qp_csq_t));\r
+       if (!h_qp->p_irp_queue)\r
        {\r
                status = STATUS_NO_MEMORY;\r
                goto exit;\r
        }\r
 \r
-       status = IoCsqInitialize( &h_qp->p_irp_que->csq, \r
-               __ndi_insert_irp, __ndi_remove_irp,\r
+       status = IoCsqInitializeEx( &h_qp->p_irp_queue->csq, \r
+               __ndi_insert_irp_ex, __ndi_remove_irp,\r
                __ndi_peek_next_irp, __ndi_acquire_lock,\r
                __ndi_release_lock, __ndi_complete_cancelled_irp );\r
        if ( !NT_SUCCESS( status ) )\r
                goto exit;\r
 \r
-       InitializeListHead( &h_qp->p_irp_que->que );\r
-       h_qp->p_irp_que->h_qp = h_qp;\r
-       h_qp->p_irp_que->h_query = NULL;\r
-       h_qp->p_irp_que->state = NDI_CM_IDLE;\r
+       InitializeListHead( &h_qp->p_irp_queue->queue );\r
+       h_qp->p_irp_queue->h_qp = h_qp;\r
+       h_qp->p_irp_queue->h_query = NULL;\r
+       h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
        status = STATUS_SUCCESS;\r
 \r
 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
@@ -463,42 +511,95 @@ exit:
        return status;\r
 }\r
 \r
+#pragma warning(disable:4706)\r
 void\r
 ndi_qp_destroy(\r
-       IN              ib_qp_handle_t FUNC_PTR64                                       h_qp )\r
+       IN              ib_qp_handle_t                                  h_qp )\r
 {\r
+       KIRQL irql;\r
+       PIRP Irp;\r
+\r
        AL_ENTER( AL_DBG_NDI );\r
 \r
-       if (h_qp->type == IB_QPT_RELIABLE_CONN && h_qp->p_irp_que)\r
+       if (h_qp->type == IB_QPT_RELIABLE_CONN && h_qp->p_irp_queue)\r
        {\r
                AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
-                       ("Destroying h_qp %#I64x, uhdl %#I64x, h_ioctl %p, cid %d\n", \r
-                       (uint64_t)h_qp, h_qp->obj.hdl, h_qp->p_irp_que->h_ioctl, ((al_conn_qp_t*)h_qp)->cid ) );\r
+                       ("Destroying h_qp %#I64x, uhdl %#I64x, cid %d\n", \r
+                       (uint64_t)h_qp, h_qp->obj.hdl, ((al_conn_qp_t*)h_qp)->cid ) );\r
+\r
+               /* Move the state before flushing, so that all new IRPs fail to queue. */\r
+               __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
+               h_qp->p_irp_queue->state = NDI_CM_INVALID;\r
+               __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
 \r
                /* cancel pending IRPS for NDI type CQ */\r
-               ndi_qp_flush_ques( h_qp );\r
+               AL_ENTER( AL_DBG_NDI );\r
+               while( Irp = IoCsqRemoveNextIrp( &h_qp->p_irp_queue->csq, NULL ) )\r
+               {\r
+                       AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, \r
+                               ("h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n", \r
+                               (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
+\r
+                       __ndi_complete_cancelled_irp( &h_qp->p_irp_queue->csq, Irp );\r
+               }\r
+               while( Irp = IoCsqRemoveNextIrp(\r
+            &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_NOTIFY_DREQ ) )\r
+               {\r
+                       AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, \r
+                               ("h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n", \r
+                               (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
+\r
+                       __ndi_complete_cancelled_irp( &h_qp->p_irp_queue->csq, Irp );\r
+               }\r
+               AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, \r
+                       ("h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n", \r
+                       (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
        }\r
 \r
        AL_EXIT( AL_DBG_NDI );\r
 }\r
+#pragma warning(default:4706)\r
+\r
 \r
 void\r
 ndi_qp_free(\r
-       IN              ib_qp_handle_t FUNC_PTR64                                       h_qp )\r
+       IN              ib_qp_handle_t                                  h_qp )\r
 {\r
        AL_ENTER( AL_DBG_NDI );\r
 \r
-       if (h_qp->type == IB_QPT_RELIABLE_CONN && h_qp->p_irp_que)\r
+       if (h_qp->type == IB_QPT_RELIABLE_CONN && h_qp->p_irp_queue)\r
        {\r
                /* free NDI context */\r
-               cl_free( h_qp->p_irp_que );\r
-               h_qp->p_irp_que = NULL;\r
+               cl_free( h_qp->p_irp_queue );\r
+               h_qp->p_irp_queue = NULL;\r
        }\r
 \r
        AL_EXIT( AL_DBG_NDI );\r
 }\r
 \r
 \r
+static inline void\r
+__ndi_complete_req_irp(\r
+       IN      ib_qp_handle_t                                                  h_qp,\r
+       IN      NTSTATUS                                                                code\r
+       )\r
+{\r
+       PIRP Irp;\r
+       KIRQL irql;\r
+\r
+       AL_ENTER( AL_DBG_NDI );\r
+       Irp = IoCsqRemoveNextIrp( &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_REQ_CM );\r
+       if ( Irp )\r
+       {\r
+               __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
+               if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
+                       h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
+               __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
+               __ndi_complete_irp( h_qp, Irp, code );\r
+       }\r
+       AL_EXIT( AL_DBG_NDI );\r
+}\r
+\r
 /*******************************************************************\r
  *\r
  * REQ CM request\r
@@ -506,42 +607,57 @@ ndi_qp_free(
  ******************************************************************/\r
 \r
 static void\r
-__ndi_req_cm_wi(\r
-       IN                              DEVICE_OBJECT*                          p_dev_obj,\r
-       IN                              void*                                           context )\r
+__ndi_notify_dreq(\r
+       IN                              ib_qp_handle_t const            h_qp )\r
 {\r
-       NTSTATUS status;\r
-       ib_qp_handle_t VOID_PTR64       h_qp = (ib_qp_handle_t VOID_PTR64)context;\r
-       UNUSED_PARAM(p_dev_obj);\r
+       IRP *p_irp = IoCsqRemoveNextIrp(\r
+               &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_NOTIFY_DREQ );\r
 \r
-       AL_ENTER( AL_DBG_NDI );\r
+       if( p_irp )\r
+       {\r
+               __ndi_complete_irp( h_qp, p_irp, STATUS_SUCCESS );\r
+       }\r
+}\r
 \r
-       IoFreeWorkItem( h_qp->p_irp_que->p_workitem );\r
 \r
-       __cep_timewait_qp( h_qp );\r
-       \r
-       h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
-       status = (h_qp->p_irp_que->state == NDI_CM_CONNECTED) ? STATUS_CONNECTION_DISCONNECTED : STATUS_CONNECTION_REFUSED;\r
-       __ndi_complete_irp( h_qp, h_qp->p_irp_que->h_ioctl, status );\r
-       deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
+static void\r
+__ndi_proc_dreq(\r
+       IN                              ib_qp_handle_t const            h_qp )\r
+{\r
+       IRP *p_irp;\r
+       KIRQL irql;\r
+       ndi_cm_state_t old_state;\r
 \r
-       AL_EXIT( AL_DBG_NDI );\r
+       __ndi_notify_dreq( h_qp );\r
+\r
+       __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
+       old_state = h_qp->p_irp_queue->state;\r
+       if( old_state == NDI_CM_CONNECTED )\r
+       {\r
+               h_qp->p_irp_queue->state = NDI_CM_CONNECTED_DREQ_RCVD;\r
+       }\r
+       __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
+\r
+       p_irp = IoCsqRemoveNextIrp(\r
+               &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_DREQ_CM );\r
+       if( p_irp != NULL )\r
+       {\r
+               __ndi_queue_drep( p_irp );\r
+       }\r
 }\r
 \r
+\r
 /*\r
  * A user-specified callback that is invoked after receiving a connection\r
  * rejection message (REJ).\r
  */\r
-       \r
-       \r
 static void\r
 __ndi_proc_rej(\r
-       IN              const   ib_cm_handle_t* const           p_cm,\r
+       IN                              ib_qp_handle_t const            h_qp,\r
        IN              const   mad_cm_rej_t* const             p_rej )\r
 {\r
-       NTSTATUS status;\r
-       ib_qp_handle_t VOID_PTR64       h_qp = p_cm->h_qp;\r
-       ndi_qp_csq_t *p_ndi_csq = h_qp->p_irp_que;\r
+       KIRQL irql;\r
+       IRP* p_irp;\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
@@ -549,195 +665,190 @@ __ndi_proc_rej(
                ("p_rej %p, h_qp %#I64x, uhdl %#I64x, connect reject, reason=%hd\n", \r
                p_rej, (uint64_t)h_qp, h_qp->obj.hdl, cl_ntoh16(p_rej->reason) ) );\r
 \r
-       al_destroy_cep(\r
-               p_cm->h_al, &((al_conn_qp_t*)h_qp)->cid, TRUE, deref_al_obj );\r
-\r
-       switch (p_ndi_csq->state)\r
+       p_irp = IoCsqRemoveNextIrp( &h_qp->p_irp_queue->csq, NULL );\r
+       __ndi_notify_dreq( h_qp );\r
+       __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
+       if( p_irp != NULL )\r
        {\r
-       case NDI_CM_CONNECTING_REQ_SENT:\r
-               status = (p_rej->reason == IB_REJ_TIMEOUT) ? STATUS_TIMEOUT : STATUS_CONNECTION_REFUSED;\r
-               __ndi_complete_irp_ex( h_qp, status, NDI_CM_CONNECTING_REJ_RCVD );\r
-               break;\r
-\r
-       case NDI_CM_CONNECTED:\r
-       case NDI_CM_REP_SENT:\r
-               /* a race: the passive side\92s REP times out, but active side has sent the RTU.  \r
-                  We are treating this case it like a DREQ */\r
+               switch( cl_ioctl_ctl_code( p_irp ) )\r
                {\r
-                       IO_STACK_LOCATION *p_io_stack;\r
-                       cl_ioctl_handle_t h_ioctl;\r
-\r
-                       h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
-                       if (!h_ioctl)\r
-                       { /* IRP has been cancelled */\r
-                               // TODO: no QP flash\r
-                               AL_PRINT(TRACE_LEVEL_INFORMATION, AL_DBG_NDI ,\r
-                                       ( "IRP cancelled: Can't flush the QP %p, ndi_state %d\n",\r
-                                       h_qp, p_ndi_csq->state ) );\r
-                               h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
-//                             ASSERT(FALSE);\r
-                       }\r
+               case UAL_NDI_REQ_CM:\r
+                       if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
+                               h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
+                       if( p_rej->reason == IB_REJ_TIMEOUT )\r
+                               __ndi_complete_irp( h_qp, p_irp, STATUS_TIMEOUT );\r
                        else\r
-                       {\r
-                               p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );\r
-                               h_qp->p_irp_que->p_workitem = IoAllocateWorkItem( p_io_stack->DeviceObject );\r
-                               if ( h_qp->p_irp_que->p_workitem )\r
-                               { /* asyncronous performing */\r
-                                       IoQueueWorkItem( h_qp->p_irp_que->p_workitem,\r
-                                               __ndi_req_cm_wi, DelayedWorkQueue, h_qp );\r
-                               }\r
-                               else\r
-                               { /* syncronous performing */\r
-                                       // TODO: no QP flash\r
-                                       AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
-                                               ( "Can't flush the QP %p, ndi_state %d\n",\r
-                                               h_qp, p_ndi_csq->state ) );\r
-                                       h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
-                                       status = (h_qp->p_irp_que->state == NDI_CM_CONNECTED) ? STATUS_CONNECTION_DISCONNECTED : STATUS_CONNECTION_REFUSED;\r
-                                       __ndi_complete_irp( h_qp, h_ioctl, status );\r
-                                       deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
-                                       h_qp->p_irp_que->h_ioctl = NULL;\r
-                               }\r
-                       }\r
+                               __ndi_complete_irp( h_qp, p_irp, STATUS_CONNECTION_REFUSED );\r
+\r
+                       al_destroy_cep(\r
+                               qp_get_al( h_qp ), &((al_conn_qp_t*)h_qp)->cid, TRUE, deref_al_obj );\r
+                       break;\r
+\r
+        // TODO: REP IRPs never get queued in the CSQ.  Can we delete?\r
+               //case UAL_NDI_REP_CM:\r
+               //      if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
+               //              h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
+               //      __ndi_complete_irp( h_qp, p_irp, STATUS_CONNECTION_ABORTED );\r
+               //      al_destroy_cep(\r
+               //              qp_get_al( h_qp ), &((al_conn_qp_t*)h_qp)->cid, TRUE, deref_al_obj );\r
+               //      break;\r
+\r
+               case UAL_NDI_DREQ_CM:\r
+                       __ndi_queue_drep( p_irp );\r
                        break;\r
                }\r
-               \r
-       default:        \r
-               // This is not the state that we waited for, not much that we can\r
-               // do. (This might happen in shutdown)\r
-               AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
-                       ("Not the expected state %s\n", State2String( p_ndi_csq->state )));\r
-               ASSERT(FALSE);\r
-               break;\r
        }\r
-       \r
+       else if( h_qp->p_irp_queue->state == NDI_CM_CONNECTED )\r
+       {\r
+               if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
+                       h_qp->p_irp_queue->state = NDI_CM_CONNECTED_DREQ_RCVD;\r
+       }\r
+       __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
+\r
        AL_EXIT( AL_DBG_NDI );\r
 }\r
 \r
+\r
 static void\r
 __ndi_proc_rep(\r
-       IN                              ib_cm_handle_t* const           p_cm,\r
-       IN                              mad_cm_rep_t* const                     p_rep )\r
+       IN                              ib_qp_handle_t const            h_qp,\r
+       IN                              net32_t                                         cid )\r
 {\r
-       ndi_qp_csq_t *p_ndi_csq = p_cm->h_qp->p_irp_que;\r
+       ndi_qp_csq_t *p_ndi_csq = h_qp->p_irp_queue;\r
+       IRP* p_irp;\r
+       KIRQL irql;\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
-    UNREFERENCED_PARAMETER( p_rep );\r
+       AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI ,("h_qp = 0x%p\n", h_qp));\r
 \r
-       AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI ,("h_qp = 0x%p\n", p_cm->h_qp));\r
-\r
-       if ( p_ndi_csq->state  != NDI_CM_CONNECTING_REQ_SENT) \r
+       p_irp = IoCsqRemoveNextIrp( &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_REQ_CM );\r
+       __ndi_acquire_lock( &p_ndi_csq->csq, &irql );\r
+       if( p_irp == NULL )\r
        {\r
-               // This is not the state that we waited for, not much that we can do\r
                AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
                        ("Not the expected state %s\n", State2String( p_ndi_csq->state )));\r
-               ASSERT(FALSE);\r
-               goto exit;\r
+               CL_ASSERT( IsListEmpty( &h_qp->p_irp_queue->queue ) );\r
+               al_cep_rej( qp_get_al( h_qp ), cid, IB_REJ_INVALID_COMM_INSTANCE, NULL, 0, NULL, 0 );\r
        }\r
+       else\r
+       {\r
+               p_ndi_csq->state = NDI_CM_CONNECTING_REP_RCVD;\r
 \r
-       __ndi_complete_irp_ex( p_cm->h_qp, STATUS_SUCCESS, NDI_CM_CONNECTING_REP_RCVD );\r
+               __ndi_complete_irp( h_qp, p_irp, STATUS_SUCCESS );\r
+       }\r
+       __ndi_release_lock( &p_ndi_csq->csq, irql );\r
 \r
-exit:  \r
        AL_EXIT( AL_DBG_NDI );\r
+       return;\r
 }\r
 \r
-typedef struct _ndi_async_dreq\r
-{\r
-       cl_async_proc_item_t    item;\r
-       ib_cm_handle_t                  cm;\r
-\r
-}      ndi_async_dreq_t;\r
 \r
-static void\r
-__ndi_proc_dreq_async(\r
-       IN                              cl_async_proc_item_t            *p_item )\r
+void\r
+__ndi_do_drep(\r
+       IN                              DEVICE_OBJECT*                          p_dev_obj,\r
+       IN                              PIRP                                            p_irp )\r
 {\r
+       ib_qp_handle_t h_qp = p_irp->Tail.Overlay.DriverContext[0];\r
        ib_qp_mod_t qp_mod;\r
        ib_api_status_t status;\r
-       ib_cm_drep_t cm_drep = { NULL, 0 };\r
-       ndi_async_dreq_t *p_async_dreq = PARENT_STRUCT( p_item, ndi_async_dreq_t, item );\r
+       uint64_t timewait_us;\r
+       KIRQL irql;\r
+       NTSTATUS nt_status;\r
+\r
+       UNREFERENCED_PARAMETER( p_dev_obj );\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
-       /* bring QP to error state */\r
-       cl_memclr( &qp_mod, sizeof(qp_mod) );\r
-       qp_mod.req_state = IB_QPS_ERROR;\r
+       CL_ASSERT( p_irp->Tail.Overlay.DriverContext[1] );\r
+       IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
+       p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
+       deref_al_obj( &h_qp->obj ); /* Release work item reference. */\r
 \r
-       status = modify_qp( p_async_dreq->cm.h_qp, &qp_mod, NULL );\r
-       if ( status != IB_SUCCESS )\r
+       status = al_cep_get_timewait( qp_get_al( h_qp ), \r
+               ((al_conn_qp_t*)h_qp)->cid, &timewait_us );\r
+\r
+       if (status != IB_SUCCESS)\r
        {\r
-               AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
-                       ("al_modify_qp to ERROR returned %s.\n", ib_get_err_str(status) ) );\r
+               nt_status = STATUS_CONNECTION_INVALID;\r
                goto exit;\r
        }\r
 \r
-       status = al_cep_drep( p_async_dreq->cm.h_al,\r
-               ((al_conn_qp_t*)p_async_dreq->cm.h_qp)->cid, &cm_drep);\r
+       /* Store the timestamp after which the QP exits timewait. */\r
+       h_qp->timewait = cl_get_time_stamp() + timewait_us;\r
+\r
+       al_destroy_cep(\r
+               qp_get_al( h_qp ), &((al_conn_qp_t*)h_qp)->cid, TRUE, deref_al_obj );\r
 \r
+       /* bring QP to error state */\r
+       cl_memclr( &qp_mod, sizeof(qp_mod) );\r
+       qp_mod.req_state = IB_QPS_ERROR;\r
+       \r
+       status = ndi_modify_qp( h_qp, &qp_mod, \r
+               cl_ioctl_out_size( p_irp ), cl_ioctl_out_buf( p_irp ) );\r
        if ( status != IB_SUCCESS )\r
        {\r
                AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
-                       ("al_cep_drep returned %s.\n", ib_get_err_str(status) ) );\r
+                       ("ndi_modify_qp to ERROR returned %s.\n", ib_get_err_str(status) ) );\r
        }\r
-       //TODO: what state is to be set here ?\r
-       //p_async_dreq->cm.h_qp->p_irp_que->state = NDI_CM_IDLE;        \r
+\r
+       nt_status = ib_to_ntstatus( status );\r
 \r
 exit:\r
-    deref_al_obj( &p_async_dreq->cm.h_qp->obj );\r
-       cl_free( p_async_dreq );\r
+       __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
+       if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
+               h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
+       __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
+\r
+       __ndi_complete_irp( h_qp, p_irp, nt_status );\r
        AL_EXIT( AL_DBG_NDI );\r
 }\r
 \r
+\r
 static void\r
-__ndi_proc_dreq(\r
-       IN                              ib_cm_handle_t* const           p_cm,\r
-       IN                              mad_cm_dreq_t* const            p_dreq )\r
+__ndi_queue_drep(\r
+       IN                              IRP                                                     *p_irp )\r
 {\r
-       ndi_async_dreq_t *p_async_dreq;\r
-       UNUSED_PARAM(p_dreq);\r
+       CL_ASSERT( p_irp->Tail.Overlay.DriverContext[1] != NULL );\r
+       IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1],\r
+               __ndi_do_drep, DelayedWorkQueue, p_irp );\r
+}\r
 \r
-       AL_ENTER( AL_DBG_NDI );\r
 \r
-       AL_PRINT(TRACE_LEVEL_INFORMATION ,AL_DBG_NDI ,("h_qp = 0x%p\n", p_cm->h_qp));\r
+static void\r
+__ndi_proc_drep(\r
+       IN                              ib_qp_handle_t const            h_qp )\r
+{\r
+       IRP* p_irp;\r
+\r
+       AL_ENTER( AL_DBG_NDI );\r
 \r
-       p_async_dreq = (ndi_async_dreq_t*)cl_zalloc( sizeof(ndi_async_dreq_t) );\r
-       if( !p_async_dreq )\r
+       p_irp = IoCsqRemoveNextIrp(\r
+               &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_DREQ_CM );\r
+       if( p_irp != NULL )\r
        {\r
-               AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
-                       ("failed to cl_zalloc ndi_async_dreq_t (%d bytes)\n",\r
-                       sizeof(ndi_async_dreq_t)) );\r
-               ASSERT(FALSE);\r
-               goto exit;\r
+               __ndi_queue_drep( p_irp );\r
        }\r
 \r
-    ref_al_obj( &p_cm->h_qp->obj );\r
-       p_async_dreq->cm = *p_cm;\r
-       p_async_dreq->item.pfn_callback = __ndi_proc_dreq_async;\r
-\r
-       /* Queue the MAD for asynchronous processing. */\r
-       cl_async_proc_queue( gp_async_proc_mgr, &p_async_dreq->item );\r
-\r
-exit:  \r
        AL_EXIT( AL_DBG_NDI );\r
 }\r
 \r
+\r
 static void\r
 __ndi_cm_handler(\r
-       IN              const   ib_al_handle_t FUNC_PTR64                               h_al,\r
+       IN              const   ib_al_handle_t                          h_al,\r
        IN              const   net32_t                                         cid )\r
 {\r
-       void* VOID_PTR64                context;\r
+       void*                           context;\r
        net32_t                         new_cid;\r
        ib_mad_element_t        *p_mad_el;\r
-       ib_cm_handle_t          h_cm;\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
        while( al_cep_poll( h_al, cid, &context, &new_cid, &p_mad_el ) == IB_SUCCESS )\r
        {\r
                ib_mad_t*p_mad = ib_get_mad_buf( p_mad_el );\r
-               ib_qp_handle_t VOID_PTR64 h_qp = (ib_qp_handle_t VOID_PTR64)context;\r
+               ib_qp_handle_t h_qp = (ib_qp_handle_t)context;\r
 \r
                if( p_mad_el->status != IB_SUCCESS )\r
                {\r
@@ -747,17 +858,21 @@ __ndi_cm_handler(
                                AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
                                        ("REQ timeouted for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
                                        cid, h_al, h_qp, new_cid ) );\r
-                               __ndi_complete_irp_ex( h_qp, STATUS_TIMEOUT, NDI_CM_IDLE );\r
+                               __ndi_complete_req_irp( h_qp, STATUS_TIMEOUT );\r
                                break;\r
 \r
                        case CM_REP_ATTR_ID:\r
                                AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
                                        ("REP timeouted for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
                                        cid, h_al, h_qp, new_cid ) );\r
-                               __ndi_complete_irp_ex( h_qp, STATUS_CONNECTION_ABORTED, NDI_CM_IDLE );\r
+                // TODO: REP IRPs don't get queued int he IRP queue, so don't complete some random IRP (like a DREQ)\r
+                               //__ndi_complete_irp_ex( h_qp, STATUS_CONNECTION_ABORTED );\r
                                break;\r
 \r
                        case CM_DREQ_ATTR_ID:\r
+                               __ndi_proc_drep( h_qp );\r
+                               break;\r
+\r
                        default:\r
                                AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
                                        ("Unhandled MAD attr ID %d for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
@@ -767,10 +882,6 @@ __ndi_cm_handler(
                }\r
                else\r
                {\r
-                       h_cm.h_al = h_al;\r
-                       h_cm.h_qp = h_qp;\r
-                       h_cm.cid = cid;\r
-                       \r
                        switch( p_mad->attr_id )\r
                        {\r
                        case CM_REP_ATTR_ID:\r
@@ -780,14 +891,14 @@ __ndi_cm_handler(
                                CL_ASSERT( ((al_conn_qp_t*)h_qp)->cid == (int32_t)cid || \r
                                        ((al_conn_qp_t*)h_qp)->cid == AL_INVALID_CID ||\r
                                        ((al_conn_qp_t*)h_qp)->cid == AL_RESERVED_CID );\r
-                               __ndi_proc_rep( &h_cm, (mad_cm_rep_t*)p_mad );\r
+                               __ndi_proc_rep( h_qp, cid );\r
                                break;\r
                        \r
                        case CM_REJ_ATTR_ID:\r
                                AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
                                        ("REJ received for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", \r
                                        cid, h_al, h_qp, new_cid ) );\r
-                               __ndi_proc_rej( &h_cm, (mad_cm_rej_t*)p_mad );\r
+                               __ndi_proc_rej( h_qp, (mad_cm_rej_t*)p_mad );\r
                                break;\r
                \r
                        case CM_DREQ_ATTR_ID:\r
@@ -797,7 +908,11 @@ __ndi_cm_handler(
                                CL_ASSERT( ((al_conn_qp_t*)h_qp)->cid == (int32_t)cid || \r
                                ((al_conn_qp_t*)h_qp)->cid == AL_INVALID_CID ||\r
                                ((al_conn_qp_t*)h_qp)->cid == AL_RESERVED_CID );\r
-                               __ndi_proc_dreq( &h_cm, (mad_cm_dreq_t*)p_mad );\r
+                               __ndi_proc_dreq( h_qp );\r
+                               break;\r
+\r
+                       case CM_DREP_ATTR_ID:\r
+                               __ndi_proc_drep( h_qp );\r
                                break;\r
                \r
                        default:\r
@@ -859,57 +974,47 @@ __ndi_fill_cm_req(
        AL_EXIT( AL_DBG_NDI );\r
 }\r
 \r
-static void AL_API\r
-__ndi_pr_query_cb(\r
-                                       ib_query_rec_t                          *p_query_rec )\r
+\r
+NTSTATUS\r
+__ndi_send_req(\r
+       IN              IRP*                                                            p_irp\r
+       )\r
 {\r
        ib_api_status_t status;\r
-       cl_ioctl_handle_t h_ioctl;\r
+       ib_qp_handle_t h_qp = (ib_qp_handle_t)p_irp->Tail.Overlay.DriverContext[0];\r
+       ib_path_rec_t *p_path_rec = p_irp->Tail.Overlay.DriverContext[1];\r
+       ual_ndi_req_cm_ioctl_in_t *p_req = \r
+               (ual_ndi_req_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
+       NTSTATUS nt_status;\r
        ib_cm_req_t cm_req;\r
-       uint8_t pkt_life;\r
        ib_qp_mod_t qp_mod;\r
-       ib_path_rec_t *p_path_rec;\r
-       ual_ndi_req_cm_ioctl_in_t *p_req = (ual_ndi_req_cm_ioctl_in_t* __ptr64)p_query_rec->query_context;\r
-       ib_qp_handle_t h_qp = (ib_qp_handle_t)(ULONG_PTR)p_req->h_qp;\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
-       AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
-               ("status is %d, count is %d, context %p\n", p_query_rec->status,\r
-               p_query_rec->result_cnt, p_query_rec->query_context) );\r
-\r
-       status = p_query_rec->status;\r
-       h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
-       if( !h_ioctl || status != IB_SUCCESS || !p_query_rec->result_cnt )\r
-               goto err_irp_complete;\r
-\r
-       /* Path Record has been received ! */\r
-       p_path_rec = ib_get_query_path_rec( p_query_rec->p_result_mad, 0 );\r
+    p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
 \r
-       /* fix packet life */\r
-       CL_ASSERT( p_path_rec );\r
-       pkt_life = ib_path_rec_pkt_life( p_path_rec ) + g_pkt_life_modifier;\r
-       if( pkt_life > 0x1F )\r
-               pkt_life = 0x1F;\r
-\r
-       p_path_rec->pkt_life &= IB_PATH_REC_SELECTOR_MASK;\r
-       p_path_rec->pkt_life |= pkt_life;\r
+       if( h_qp->p_irp_queue->state != NDI_CM_CONNECTING_QPR_SENT )\r
+       {\r
+               AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
+                       ("Unexpected state: %d\n", h_qp->p_irp_queue->state) );\r
+               return STATUS_CONNECTION_ABORTED;\r
+       }\r
 \r
        /* Get a CEP and bind it to the QP. */\r
        status = al_create_cep(\r
                qp_get_al( h_qp ), __ndi_cm_handler, h_qp, &((al_conn_qp_t*)h_qp)->cid );\r
        if( status != IB_SUCCESS )\r
        {\r
-               AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
+               h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
+               AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
                        ("al_create_cep returned %s.\n", ib_get_err_str( status )) );\r
-               goto err_irp_complete;\r
+               return STATUS_INSUFFICIENT_RESOURCES;\r
        }\r
        AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
                ("Created Active CEP with cid %d, h_al %p, context %p\n",\r
                ((al_conn_qp_t*)h_qp)->cid, qp_get_al( h_qp ), h_qp ) );\r
 \r
-       /* Take a reference on behalf of the CEP. */\r
-       ref_al_obj( &h_qp->obj );\r
+       ref_al_obj( &h_qp->obj ); /* Take CEP reference. */\r
 \r
        /* Format ib_cm_req_t structure */\r
        __ndi_fill_cm_req( h_qp, p_req, p_path_rec, &cm_req );\r
@@ -917,113 +1022,195 @@ __ndi_pr_query_cb(
        /* prepare CEP for connection */\r
        status = al_cep_pre_req( qp_get_al( h_qp ),\r
                ((al_conn_qp_t*)h_qp)->cid, &cm_req, &qp_mod );\r
-       if( status != IB_SUCCESS )\r
+       if( status != STATUS_SUCCESS )\r
        {\r
                AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
                        ("al_cep_pre_req returned %s.\n", ib_get_err_str( status )) );\r
-               goto err_cep_destroy;\r
+               goto error;\r
        }\r
 \r
-       /* insert IRP in the queue */\r
-       h_qp->p_irp_que->state = NDI_CM_CONNECTING_REQ_SENT;\r
-       IoCsqInsertIrp( &h_qp->p_irp_que->csq, h_ioctl, NULL );\r
-\r
        /* send CM REQ */\r
        status = al_cep_send_req( qp_get_al( h_qp ), ((al_conn_qp_t*)h_qp)->cid );\r
        if( status != IB_SUCCESS )\r
-               goto err_irp_remove;\r
-\r
-       /* we can release it now. In case of QP destroy __destroying_qp will remove CEP */\r
-       deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
+       {\r
+               AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
+                       ("al_cep_send_req returned %s.\n", ib_get_err_str( status )) );\r
+               goto error;\r
+       }\r
 \r
        /* SUCCESS ! */\r
-       goto exit;\r
-\r
-err_irp_remove:\r
-       h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
+       AL_EXIT( AL_DBG_NDI );\r
+       return STATUS_SUCCESS;\r
 \r
-err_cep_destroy:\r
+error:\r
        al_destroy_cep(\r
                qp_get_al( h_qp ), &((al_conn_qp_t*)h_qp)->cid, TRUE, deref_al_obj );\r
        \r
-err_irp_complete:\r
-       h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
-       /* the IRP "has" 2 QP references, taken in __ndi_ats_query */\r
-       if ( h_ioctl )\r
+       switch( status )\r
        {\r
+       case IB_INVALID_HANDLE:\r
+               nt_status = STATUS_CANCELLED;\r
+               break;\r
+\r
+       case IB_INVALID_STATE:\r
+               nt_status = STATUS_CONNECTION_ABORTED;\r
+               break;\r
+\r
+       default:\r
+               nt_status = ib_to_ntstatus( status );\r
+       }\r
+\r
+       h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
+       AL_EXIT( AL_DBG_NDI );\r
+       return nt_status;\r
+}\r
+\r
+\r
+static void AL_API\r
+__ndi_pr_query_cb(\r
+                                       ib_query_rec_t                          *p_query_rec )\r
+{\r
+       ib_api_status_t status;\r
+       cl_ioctl_handle_t p_irp;\r
+       uint8_t pkt_life;\r
+       ib_path_rec_t *p_path_rec;\r
+       ib_qp_handle_t h_qp = (ib_qp_handle_t)p_query_rec->query_context;\r
+       NTSTATUS nt_status;\r
+       KIRQL irql;\r
+\r
+       AL_ENTER( AL_DBG_NDI );\r
+\r
+       AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
+               ("status is %d, count is %d, context %p\n", p_query_rec->status,\r
+               p_query_rec->result_cnt, p_query_rec->query_context) );\r
+\r
+       p_irp = IoCsqRemoveNextIrp( &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_REQ_CM );\r
+       if( p_irp == NULL )\r
+       {\r
+               goto exit;\r
+       }\r
+\r
+       status = p_query_rec->status;\r
+       if( status != IB_SUCCESS || !p_query_rec->result_cnt )\r
+       {\r
+               __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
+               if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
+                       h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
+               __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
                switch( status )\r
                {\r
                case IB_TIMEOUT:\r
-                       __ndi_complete_irp( h_qp, h_ioctl, STATUS_TIMEOUT );\r
+                       __ndi_complete_irp( h_qp, p_irp, STATUS_TIMEOUT );\r
                        break;\r
 \r
-               case IB_INVALID_STATE:\r
-                       __ndi_complete_irp( h_qp, h_ioctl, STATUS_CONNECTION_ACTIVE );\r
+               case IB_CANCELED:\r
+                       __ndi_complete_irp( h_qp, p_irp, STATUS_CANCELLED );\r
                        break;\r
 \r
                default:\r
-                       __ndi_complete_irp( h_qp, h_ioctl, STATUS_HOST_UNREACHABLE );\r
+                       __ndi_complete_irp( h_qp, p_irp, STATUS_HOST_UNREACHABLE );\r
                }\r
+               goto exit;\r
        }\r
-       deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
 \r
-exit:  \r
-       cl_free( p_req );\r
+       /* Path Record has been received ! */\r
+       p_path_rec = ib_get_query_path_rec( p_query_rec->p_result_mad, 0 );\r
+\r
+       /* fix packet life */\r
+       CL_ASSERT( p_path_rec );\r
+       pkt_life = ib_path_rec_pkt_life( p_path_rec ) + g_pkt_life_modifier;\r
+       if( pkt_life > 0x1F )\r
+               pkt_life = 0x1F;\r
+\r
+       p_path_rec->pkt_life &= IB_PATH_REC_SELECTOR_MASK;\r
+       p_path_rec->pkt_life |= pkt_life;\r
+\r
+       p_irp->Tail.Overlay.DriverContext[1] = p_path_rec;\r
+\r
+       nt_status = IoCsqInsertIrpEx(\r
+               &h_qp->p_irp_queue->csq,\r
+               p_irp,\r
+               NULL,\r
+               (VOID*)(ULONG_PTR)NDI_CM_CONNECTING_REQ_SENT\r
+               );\r
+       if( nt_status != STATUS_SUCCESS )\r
+       {\r
+               p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
+               __ndi_complete_irp( h_qp, p_irp, nt_status );\r
+       }\r
+       else\r
+       {\r
+               /*\r
+                * Release the previous reference because IoCsqInsertIrpEx\r
+                * took a new one.\r
+                */\r
+               deref_al_obj( &h_qp->obj ); /* Release IRP reference. */\r
+       }\r
+\r
+exit:\r
+\r
        if( p_query_rec->p_result_mad )\r
                ib_put_mad( p_query_rec->p_result_mad );\r
 \r
+       deref_al_obj( &h_qp->obj );     /* release path query reference */\r
        AL_EXIT( AL_DBG_NDI );\r
 }\r
 \r
 \r
 \r
-/* Synchronously query the SA for a GUID. Return 0 on success. */\r
-void\r
+/*\r
+ * Send asynchronous query to the SA for a path record.\r
+ *\r
+ * Called from the __ndi_insert_irp_ex function, so the CSQ lock is held.\r
+ */\r
+NTSTATUS\r
 __ndi_pr_query(\r
-       IN              cl_ioctl_handle_t                                       h_ioctl,\r
-       IN              ual_ndi_req_cm_ioctl_in_t                       *p_req,\r
-       IN              ib_gid_t                                                        *p_dest_gid )\r
+       IN              IRP*                                                            p_irp\r
+       )\r
 {\r
-       ib_gid_pair_t user_query;\r
        ib_query_req_t query_req;\r
        ib_api_status_t status;\r
-       ib_qp_handle_t VOID_PTR64 h_qp = (ib_qp_handle_t VOID_PTR64)HDL_TO_PTR(p_req->h_qp);\r
+       ual_ndi_req_cm_ioctl_in_t *p_req = \r
+               (ual_ndi_req_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
+       ib_qp_handle_t h_qp = (ib_qp_handle_t)p_irp->Tail.Overlay.DriverContext[0];\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
+       if ( h_qp->p_irp_queue->state != NDI_CM_CONNECTING_ATS_SENT )\r
+       {\r
+               AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
+                       ("STATUS_CONNECTION_ACTIVE: h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n",\r
+                       (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
+               return STATUS_CONNECTION_ABORTED;\r
+       }\r
+\r
        query_req.query_type = IB_QUERY_PATH_REC_BY_GIDS;\r
-       query_req.p_query_input = &user_query;\r
+       query_req.p_query_input = &p_req->gids;\r
        query_req.port_guid = p_req->guid;\r
        query_req.timeout_ms = g_sa_timeout;\r
        query_req.retry_cnt = g_sa_retries;\r
        query_req.flags = 0;    /* IB_FLAGS_SYNC */\r
-       query_req.query_context = p_req;\r
+       query_req.query_context = h_qp;\r
        query_req.pfn_query_cb = __ndi_pr_query_cb;\r
 \r
-       user_query.src_gid.unicast.prefix = p_dest_gid->unicast.prefix;\r
-       user_query.src_gid.unicast.interface_id = p_req->guid;\r
-       user_query.dest_gid = *p_dest_gid;\r
-\r
        AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
                ("Query for path from %I64x to %I64x\n",\r
-               p_req->guid, ib_gid_get_guid( p_dest_gid )) );\r
+               p_req->guid, ib_gid_get_guid( &p_req->gids.dest_gid )) );\r
 \r
-       /* insert IRP in the queue */\r
-       h_qp->p_irp_que->state = NDI_CM_CONNECTING_QPR_SENT;\r
-       IoCsqInsertIrp( &h_qp->p_irp_que->csq, h_ioctl, NULL );\r
+       ref_al_obj( &h_qp->obj );               /* take path query reference */\r
 \r
-       status = ib_query( qp_get_al( h_qp ), &query_req, &h_qp->p_irp_que->h_query );\r
+       status = ib_query( qp_get_al( h_qp ), &query_req, &h_qp->p_irp_queue->h_query );\r
 \r
        if( status != IB_SUCCESS )\r
        {\r
-               AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("ib_query failed (%d)\n", status) );\r
-               cl_free( p_req );\r
-               __ndi_complete_irp_ex( h_qp, CL_ERROR, NDI_CM_IDLE );\r
-               /* relase additional reference, taken in __ndi_ats_query */\r
-               deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
+               h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
+               AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("ib_query failed (%d)\n", status) );\r
+               deref_al_obj( &h_qp->obj );     /* release path query reference */\r
+               return ib_to_ntstatus( status );\r
        }\r
 \r
        AL_EXIT( AL_DBG_NDI );\r
+       return STATUS_SUCCESS;\r
 }\r
 \r
 \r
@@ -1031,10 +1218,12 @@ static void AL_API
 __ndi_ats_query_cb(\r
        IN                              ib_query_rec_t                          *p_query_rec )\r
 {\r
-       cl_ioctl_handle_t h_ioctl;\r
+       cl_ioctl_handle_t p_irp;\r
        ib_service_record_t *service_record;\r
-       ual_ndi_req_cm_ioctl_in_t *p_req = (ual_ndi_req_cm_ioctl_in_t* VOID_PTR64)p_query_rec->query_context;\r
-       ib_qp_handle_t VOID_PTR64 h_qp = (ib_qp_handle_t VOID_PTR64)HDL_TO_PTR(p_req->h_qp);\r
+       ib_qp_handle_t h_qp = (ib_qp_handle_t)p_query_rec->query_context;\r
+       ual_ndi_req_cm_ioctl_in_t *p_req;\r
+       KIRQL irql;\r
+       NTSTATUS status;\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
@@ -1042,59 +1231,99 @@ __ndi_ats_query_cb(
                ("status is %d, count is %d, context %p\n", p_query_rec->status,\r
                p_query_rec->result_cnt, p_query_rec->query_context) );\r
 \r
-       h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
-       if( !h_ioctl || p_query_rec->status != IB_SUCCESS || !p_query_rec->result_cnt )\r
+       p_irp = IoCsqRemoveNextIrp( &h_qp->p_irp_queue->csq, (VOID*)(ULONG_PTR)UAL_NDI_REQ_CM );\r
+       if( p_irp == NULL )\r
        {\r
-        NTSTATUS status;\r
-        if( p_query_rec->status == IB_TIMEOUT )\r
-        {\r
-            status = STATUS_TIMEOUT;\r
-        }\r
-        else\r
-        {\r
-            status = STATUS_HOST_UNREACHABLE;\r
-        }\r
-               h_qp->p_irp_que->state = NDI_CM_IDLE; \r
-               if ( h_ioctl )\r
-                       __ndi_complete_irp( h_qp, h_ioctl, status );\r
-               deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
-               cl_free( p_req );\r
+               goto exit;\r
+       }\r
+\r
+       if( p_query_rec->status != IB_SUCCESS || !p_query_rec->result_cnt )\r
+       {\r
+               __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
+               if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
+                       h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
+               __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
+\r
+               if( p_query_rec->status == IB_TIMEOUT )\r
+               {\r
+                       __ndi_complete_irp( h_qp, p_irp, STATUS_TIMEOUT );\r
+               }\r
+               else\r
+               {\r
+                       __ndi_complete_irp( h_qp, p_irp, STATUS_HOST_UNREACHABLE );\r
+               }\r
+\r
                goto exit;              /* ATS request failed */\r
        }\r
 \r
        /* send Path Request */\r
        service_record = ib_get_query_svc_rec( p_query_rec->p_result_mad, 0 );\r
-       __ndi_pr_query( h_ioctl, p_req, &service_record->service_gid );\r
+       p_req = (ual_ndi_req_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
+       p_req->gids.src_gid.unicast.prefix = service_record->service_gid.unicast.prefix;\r
+       p_req->gids.src_gid.unicast.interface_id = p_req->guid;\r
+       p_req->gids.dest_gid = service_record->service_gid;\r
+       status = IoCsqInsertIrpEx(\r
+               &h_qp->p_irp_queue->csq,\r
+               p_irp,\r
+               NULL,\r
+               (VOID*)(ULONG_PTR)NDI_CM_CONNECTING_QPR_SENT\r
+               );\r
+       if( status != STATUS_SUCCESS )\r
+       {\r
+               __ndi_complete_irp( h_qp, p_irp, status );\r
+       }\r
+       else\r
+       {\r
+               /*\r
+                * Release the previous reference because IoCsqInsertIrpEx\r
+                * took a new one.\r
+                */\r
+               deref_al_obj( &h_qp->obj ); /* Release IRP reference. */\r
+       }\r
 \r
 exit:  \r
        if( p_query_rec->p_result_mad )\r
                ib_put_mad( p_query_rec->p_result_mad );\r
 \r
+       deref_al_obj( &h_qp->obj );     /* release ATS query reference */\r
        AL_EXIT( AL_DBG_NDI );\r
 }\r
 \r
-/* Send asynchronous query to SA for a GUID. Return STATUS_PENDING on success. */\r
+/*\r
+ * Send asynchronous query to the SA for an ATS record.\r
+ *\r
+ * Called from the __ndi_insert_irp_ex function, so the CSQ lock is held.\r
+ */\r
 NTSTATUS\r
 __ndi_ats_query(\r
-       IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
-       IN              cl_ioctl_handle_t                                       h_ioctl,\r
-       IN              ual_ndi_req_cm_ioctl_in_t                       *p_req )\r
+       IN              IRP*                                                            p_irp\r
+       )\r
 {\r
        ib_user_query_t user_query;\r
        ib_service_record_t service_record;\r
        ib_query_req_t query_req;\r
        ib_api_status_t status;\r
-       NTSTATUS nt_status = STATUS_PENDING;\r
+       ual_ndi_req_cm_ioctl_in_t *p_req = \r
+               (ual_ndi_req_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
+       ib_qp_handle_t h_qp = (ib_qp_handle_t)p_irp->Tail.Overlay.DriverContext[0];\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
+       if ( h_qp->p_irp_queue->state != NDI_CM_IDLE )\r
+       {\r
+               AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
+                       ("STATUS_CONNECTION_ACTIVE: h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n",\r
+                       (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
+               return STATUS_CONNECTION_ACTIVE;\r
+       }\r
+\r
        query_req.query_type = IB_QUERY_USER_DEFINED;\r
        query_req.p_query_input = &user_query;\r
        query_req.port_guid = p_req->guid;\r
        query_req.timeout_ms = g_sa_timeout;\r
        query_req.retry_cnt = g_sa_retries;\r
        query_req.flags = 0;    /* IB_FLAGS_SYNC */\r
-       query_req.query_context = p_req;\r
+       query_req.query_context = h_qp;\r
        query_req.pfn_query_cb = __ndi_ats_query_cb;\r
 \r
        /* TODO: which method one is correct? */\r
@@ -1135,81 +1364,45 @@ __ndi_ats_query(
                ("h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n", \r
                (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
 \r
-       // preserve QP for the life of this IOCTL\r
-       ref_al_obj( &h_qp->obj );               /* take IRP life reference */\r
-\r
-       /* insert IRP in the queue */\r
-       IoCsqInsertIrp( &h_qp->p_irp_que->csq, h_ioctl, NULL );\r
-\r
-       /* prevent destroying QP after cancelling of the IRP and before ib_query calback*/\r
-       ref_al_obj( &h_qp->obj );               /* take IRP SA reference */\r
+       ref_al_obj( &h_qp->obj );               /* take ATS query reference */\r
 \r
        /* query SA */\r
-       status = ib_query( qp_get_al( h_qp ), &query_req, &h_qp->p_irp_que->h_query );\r
+       status = ib_query( qp_get_al( h_qp ), &query_req, &h_qp->p_irp_queue->h_query );\r
        if( status != IB_SUCCESS )\r
        {\r
-               AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("ib_query failed (%d)\n", status) );\r
-               deref_al_obj( &h_qp->obj );     /* release IRP SA reference */\r
-               h_ioctl = IoCsqRemoveNextIrp( &h_qp->p_irp_que->csq, NULL );\r
-               if ( h_ioctl )\r
-               { /* IOCTL should be released in the caller */\r
-                       deref_al_obj( &h_qp->obj );             /* release IRP life reference */\r
-                       nt_status = STATUS_DRIVER_INTERNAL_ERROR;\r
-               }\r
+               AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("ib_query failed (%d)\n", status) );\r
+               deref_al_obj( &h_qp->obj );     /* release ATS query reference */\r
+               return STATUS_UNSUCCESSFUL;\r
        }\r
 \r
        AL_EXIT( AL_DBG_NDI );\r
-       return nt_status;\r
+       return STATUS_SUCCESS;\r
 }\r
 \r
+\r
 NTSTATUS\r
 ndi_req_cm(\r
-       IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
-       IN              cl_ioctl_handle_t                                       h_ioctl,\r
-       IN              ual_ndi_req_cm_ioctl_in_t                       *p_req\r
+       IN              ib_qp_handle_t  const                           h_qp,\r
+       IN              IRP                                                     *p_irp\r
        )\r
 {\r
        NTSTATUS nt_status;\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
-       /* check outstanding request */\r
-       __ndi_acquire_lock( &h_qp->p_irp_que->csq, NULL);\r
-       if ( h_qp->p_irp_que->h_ioctl )\r
-       {\r
-               AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
-                       ("STATUS_CONNECTION_ACTIVE: h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n",\r
-                       (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
-               nt_status = STATUS_CONNECTION_ACTIVE;\r
-               __ndi_release_lock( &h_qp->p_irp_que->csq, 0 );\r
-               goto exit;\r
-       }\r
-       if ( h_qp->p_irp_que->state != NDI_CM_IDLE )\r
-       {\r
-               AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
-                       ("STATUS_INVALID_DEVICE_STATE: h_qp %I64x, ref_cnt %d, state %d\n",\r
-                       (uint64_t)h_qp, h_qp->obj.ref_cnt, h_qp->p_irp_que->state ) );\r
-               nt_status = STATUS_INVALID_DEVICE_STATE;\r
-               __ndi_release_lock( &h_qp->p_irp_que->csq, 0 );\r
-               goto exit;\r
-       }\r
-       h_qp->p_irp_que->h_ioctl = h_ioctl;     /* mark IRP as present */\r
-       h_qp->p_irp_que->state = NDI_CM_CONNECTING_ATS_SENT;\r
-       __ndi_release_lock( &h_qp->p_irp_que->csq, 0 );\r
+       p_irp->Tail.Overlay.DriverContext[0] = (ib_qp_t*)h_qp;\r
 \r
-       /* send ATS request */\r
-       nt_status = __ndi_ats_query( h_qp, h_ioctl, p_req );\r
+       nt_status = IoCsqInsertIrpEx(\r
+               &h_qp->p_irp_queue->csq,\r
+               p_irp,\r
+               NULL,\r
+               (VOID*)(ULONG_PTR)NDI_CM_CONNECTING_ATS_SENT\r
+               );\r
+       if( nt_status == STATUS_SUCCESS )\r
+               nt_status = STATUS_PENDING;\r
 \r
-exit:\r
-       if ( nt_status != STATUS_PENDING )\r
-       {\r
-               cl_free( p_req );\r
-               h_qp->p_irp_que->state = NDI_CM_IDLE; \r
-               h_qp->p_irp_que->h_ioctl = NULL; /* mark IRP as present */\r
-               cl_ioctl_complete( h_ioctl, nt_status, 0 );\r
-       }\r
        AL_EXIT( AL_DBG_NDI );\r
-       return STATUS_PENDING;\r
+       return nt_status;\r
 }\r
 \r
 \r
@@ -1220,13 +1413,14 @@ exit:
  ******************************************************************/\r
 \r
 static void\r
-__ndi_rtu_cm(\r
+__ndi_do_rtu(\r
        IN                              DEVICE_OBJECT*                          p_dev_obj,\r
        IN                              PIRP                                            p_irp )\r
 {\r
-       NTSTATUS nt_status;\r
        ib_api_status_t status;\r
        ib_qp_handle_t h_qp = p_irp->Tail.Overlay.DriverContext[0];\r
+       KIRQL irql;\r
+       NTSTATUS nt_status;\r
 \r
        UNUSED_PARAM(p_dev_obj);\r
 \r
@@ -1234,10 +1428,23 @@ __ndi_rtu_cm(
 \r
        /* free the work item if any */\r
        if ( p_irp->Tail.Overlay.DriverContext[1] )\r
+       {\r
                IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
+               p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
+               deref_al_obj( &h_qp->obj ); /* Release work item reference. */\r
+       }\r
+\r
+       __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
+       if( h_qp->p_irp_queue->state != NDI_CM_CONNECTING_REP_RCVD )\r
+       {\r
+               nt_status = STATUS_CONNECTION_ABORTED;\r
+               goto exit;\r
+       }\r
+       __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
 \r
        /* change the QP state to RTS */\r
        status = __ndi_qp2rts( h_qp, p_irp );\r
+\r
        if ( status != IB_SUCCESS )\r
        {\r
                goto err;\r
@@ -1260,29 +1467,32 @@ err:
 \r
                AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
                        ("al_cep_rtu returned %s.\n", ib_get_err_str( status )) );\r
-               h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
-               nt_status = STATUS_DRIVER_INTERNAL_ERROR;\r
-               p_irp->IoStatus.Information = 0;\r
+\r
+               __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
+               if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
+                       h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
+               __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
+\r
+               nt_status = STATUS_CONNECTION_ABORTED;\r
                goto exit;\r
        }\r
 \r
-       p_irp->IoStatus.Information = sizeof(uint32_t);;\r
-       h_qp->p_irp_que->state = NDI_CM_CONNECTED;\r
-       nt_status = STATUS_SUCCESS;\r
+       __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
+       if( h_qp->p_irp_queue->state == NDI_CM_CONNECTING_REP_RCVD )\r
+               h_qp->p_irp_queue->state = NDI_CM_CONNECTED;\r
+       __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
 \r
-exit:  \r
-       /* release the reference only for async case */\r
-       if ( p_irp->Tail.Overlay.DriverContext[1] )\r
-               deref_al_obj( &h_qp->obj );\r
+       nt_status = STATUS_SUCCESS;\r
 \r
-       p_irp->IoStatus.Status = nt_status;\r
-       IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+exit:\r
+       __ndi_complete_irp( h_qp, p_irp, nt_status );\r
        AL_EXIT( AL_DBG_NDI );\r
 }\r
 \r
+\r
 cl_status_t\r
 ndi_rtu_cm(\r
-       IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
+       IN              ib_qp_handle_t  const                           h_qp,\r
        IN              PIRP                                                            p_irp\r
        )\r
 {\r
@@ -1293,18 +1503,19 @@ ndi_rtu_cm(
        p_irp->Tail.Overlay.DriverContext[0] = h_qp;\r
        p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
        p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject );\r
+       ref_al_obj( &h_qp->obj ); /* Take IRP reference. */\r
+\r
        if ( p_irp->Tail.Overlay.DriverContext[1] )\r
        { /* asyncronous performing */\r
                /* take a ref to prevent QP destroy before calling work item */\r
-               ref_al_obj( &h_qp->obj );\r
+               ref_al_obj( &h_qp->obj ); /* Take work item reference. */\r
                IoMarkIrpPending( p_irp );\r
                IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1],\r
-                       __ndi_rtu_cm, DelayedWorkQueue, p_irp );\r
+                       __ndi_do_rtu, DelayedWorkQueue, p_irp );\r
        }\r
        else\r
        { /* syncronous performing */\r
-               p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
-               __ndi_rtu_cm( p_io_stack->DeviceObject, p_irp );\r
+               __ndi_do_rtu( p_io_stack->DeviceObject, p_irp );\r
        }\r
 \r
        AL_EXIT( AL_DBG_NDI );\r
@@ -1319,29 +1530,32 @@ ndi_rtu_cm(
  ******************************************************************/\r
 \r
 static void\r
-__ndi_rep_cm(\r
+__ndi_do_rep(\r
        IN                              DEVICE_OBJECT*                          p_dev_obj,\r
-       IN                              PIRP                                            p_irp )\r
+       IN              PIRP                                                            p_irp )\r
 {\r
-       NTSTATUS nt_status;\r
+       ib_qp_handle_t h_qp = p_irp->Tail.Overlay.DriverContext[0];\r
        ib_api_status_t status;\r
-       ib_qp_handle_t VOID_PTR64 h_qp = p_irp->Tail.Overlay.DriverContext[0];\r
-       ual_ndi_rep_cm_ioctl_in_t *p_rep = \r
-               (ual_ndi_rep_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
+       ual_ndi_rep_cm_ioctl_in_t *p_rep;\r
+       KIRQL irql;\r
+       NTSTATUS nt_status;\r
 \r
        UNUSED_PARAM(p_dev_obj);\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
        /* free the work item if any */\r
-       if ( p_irp->Tail.Overlay.DriverContext[1] )\r
-               IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
+       CL_ASSERT( p_irp->Tail.Overlay.DriverContext[1] != NULL );\r
+       IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
+       p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
+       deref_al_obj( &h_qp->obj ); /* Release work item reference. */\r
+\r
+       p_rep = (ual_ndi_rep_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
 \r
        /* change the QP state to RTS */\r
        status = __ndi_qp2rts( h_qp, p_irp );\r
        if ( status != IB_SUCCESS )\r
        {\r
-               nt_status = STATUS_CONNECTION_ABORTED;\r
                goto err;\r
        }\r
        \r
@@ -1351,10 +1565,6 @@ __ndi_rep_cm(
        {\r
                AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
                        ("al_cep_send_rep returned %s\n", ib_get_err_str(status)) );\r
-               if (status == IB_INSUFFICIENT_RESOURCES)\r
-                       nt_status = STATUS_INSUFFICIENT_RESOURCES;\r
-               else\r
-                       nt_status = STATUS_CONNECTION_ABORTED;\r
 err:\r
                /* Reject and abort the connection. */\r
                al_cep_rej( qp_get_al( h_qp ), p_rep->cid, IB_REJ_INSUF_QP, NULL, 0, NULL, 0 );\r
@@ -1367,28 +1577,31 @@ err:
 \r
                AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
                        ("al_cep_rtu returned %s.\n", ib_get_err_str( status )) );\r
-               h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
-               p_irp->IoStatus.Information = 0;\r
+               __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
+               if( h_qp->p_irp_queue->state != NDI_CM_INVALID )\r
+                       h_qp->p_irp_queue->state = NDI_CM_IDLE;\r
+               __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
+               if (status == IB_INVALID_STATE)\r
+                       nt_status = STATUS_CONNECTION_ABORTED;\r
+               else\r
+                       nt_status =STATUS_INSUFFICIENT_RESOURCES;\r
                goto exit;\r
        }\r
 \r
-       p_irp->IoStatus.Information = cl_ioctl_out_size( p_irp );\r
-       h_qp->p_irp_que->state = NDI_CM_CONNECTED;\r
+       __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
+       if( h_qp->p_irp_queue->state == NDI_CM_CONNECTING_REP_SENT )\r
+               h_qp->p_irp_queue->state = NDI_CM_CONNECTED;\r
+       __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
        nt_status = STATUS_SUCCESS;\r
 \r
-exit:  \r
-       /* release the reference only for async case */\r
-       if ( p_irp->Tail.Overlay.DriverContext[1] )\r
-               deref_al_obj( &h_qp->obj );\r
-\r
-       p_irp->IoStatus.Status = nt_status;\r
-       IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
+exit:\r
+       __ndi_complete_irp( h_qp, p_irp, nt_status );\r
        AL_EXIT( AL_DBG_NDI );\r
 }\r
 \r
 static void\r
 __ndi_fill_cm_rep(\r
-       IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
+       IN              ib_qp_handle_t  const                           h_qp,\r
        IN              ual_ndi_rep_cm_ioctl_in_t                       *p_rep,\r
                OUT     ib_cm_rep_t                                                     *p_cm_rep)\r
 {\r
@@ -1413,141 +1626,220 @@ __ndi_fill_cm_rep(
        AL_EXIT( AL_DBG_NDI );\r
 }\r
 \r
+\r
 NTSTATUS\r
-ndi_rep_cm(\r
-       IN              ib_qp_handle_t  const                           h_qp,\r
-       IN              net32_t                                                         cid,\r
-       IN              PIRP                                                            p_irp,\r
-       IN              ual_ndi_rep_cm_ioctl_in_t                       *p_rep\r
-       )\r
+__ndi_send_rep(\r
+       IN              ib_qp_handle_t                                          h_qp,\r
+       IN              PIRP                                                            p_irp )\r
 {\r
        IO_STACK_LOCATION       *p_io_stack;\r
        ib_cm_rep_t cm_rep;\r
        ib_qp_mod_t qp_mod;\r
        ib_api_status_t status;\r
-       NTSTATUS nt_status;\r
+       ual_ndi_rep_cm_ioctl_in_t *p_rep = \r
+               (ual_ndi_rep_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp );\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
+       if( h_qp->p_irp_queue->state != NDI_CM_IDLE )\r
+       {\r
+               AL_EXIT( AL_DBG_NDI );\r
+               return STATUS_CONNECTION_ACTIVE;\r
+       }\r
+\r
+       p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+       p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject );\r
+       if( p_irp->Tail.Overlay.DriverContext[1] == NULL )\r
+       {\r
+               AL_EXIT( AL_DBG_NDI );\r
+               return STATUS_NO_MEMORY;\r
+       }\r
+       ref_al_obj( &h_qp->obj ); /* Take work item reference. */\r
+\r
        /* Format ib_cm_req_t structure */\r
        __ndi_fill_cm_rep( h_qp, p_rep, &cm_rep );\r
 \r
+       ref_al_obj( &h_qp->obj ); /* Take CEP reference. */\r
+\r
        /* prepare Passive CEP for connection */\r
        status = al_cep_pre_rep_ex(\r
-               qp_get_al( h_qp ), cid, __ndi_cm_handler, h_qp, &cm_rep,\r
+               qp_get_al( h_qp ), p_rep->cid, __ndi_cm_handler, h_qp, &cm_rep,\r
                &((al_conn_qp_t*)h_qp)->cid, &qp_mod );\r
        if( status != IB_SUCCESS )\r
        {\r
-               AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
+               IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
+               p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
+               deref_al_obj( &h_qp->obj ); /* Release work item reference. */\r
+               al_destroy_cep( qp_get_al( h_qp ), &p_rep->cid, FALSE, NULL );\r
+               deref_al_obj( &h_qp->obj ); /* Release CEP reference. */\r
+               AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
                        ("al_cep_pre_rep_ex returned %s.\n", ib_get_err_str( status )) );\r
                switch (status)\r
                {\r
                        case IB_INVALID_HANDLE:\r
-                               nt_status = STATUS_CANCELLED;\r
-                               break;\r
+                               return STATUS_CANCELLED;\r
                        case IB_INVALID_STATE:\r
-                               nt_status = STATUS_CONNECTION_ABORTED;\r
-                               break;\r
+                               return STATUS_CONNECTION_ABORTED;\r
                        case IB_RESOURCE_BUSY:\r
-                               nt_status = STATUS_CONNECTION_ACTIVE;\r
-                               break;\r
+                               return STATUS_CONNECTION_ACTIVE;\r
                        default:\r
-                               nt_status = STATUS_INSUFFICIENT_RESOURCES;\r
-                               break;\r
+                               return ib_to_ntstatus( status );\r
                }\r
-               al_destroy_cep( qp_get_al( h_qp ), &cid, FALSE, NULL );\r
-               \r
-               h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
-               cl_ioctl_complete( p_irp, nt_status, 0 );\r
-               goto exit;\r
        }\r
 \r
-       /* Take a reference on behalf of the CEP. */\r
-       ref_al_obj( &h_qp->obj );\r
-\r
        AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
                ("Prepared Passive CEP with cid %d, h_al %p, context %p\n",\r
-               cid, qp_get_al( h_qp ), h_qp ) );\r
+               p_rep->cid, qp_get_al( h_qp ), h_qp ) );\r
+\r
+       /*\r
+        * transfer work to a worker thread so that QP transitions can be done\r
+        * at PASSIVE_LEVEL\r
+        */\r
+       IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1],\r
+               __ndi_do_rep, DelayedWorkQueue, p_irp );\r
+\r
+       AL_EXIT( AL_DBG_NDI );\r
+       return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+NTSTATUS\r
+ndi_rep_cm(\r
+       IN              ib_qp_handle_t  const                           h_qp,\r
+       IN              PIRP                                                            p_irp\r
+       )\r
+{\r
+       NTSTATUS status;\r
+       KIRQL irql;\r
+\r
+       AL_ENTER( AL_DBG_NDI );\r
 \r
-       /* transfer work to a work the thread */\r
        p_irp->Tail.Overlay.DriverContext[0] = h_qp;\r
-       p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
-       p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject );\r
-       if ( p_irp->Tail.Overlay.DriverContext[1] )\r
-       { /* asyncronous performing */\r
-               /* take a ref to prevent QP destroy before calling work item */\r
-               ref_al_obj( &h_qp->obj );\r
+\r
+       __ndi_acquire_lock( &h_qp->p_irp_queue->csq, &irql );\r
+       status = __ndi_send_rep( h_qp, p_irp );\r
+       if( status == STATUS_SUCCESS )\r
+       {\r
+               /*\r
+                * We're going to keep the IRP dangling for a bit - take a reference\r
+                * on the QP until it completes.\r
+                */\r
+               ref_al_obj( &h_qp->obj ); /* Take IRP reference. */\r
+               h_qp->p_irp_queue->state = NDI_CM_CONNECTING_REP_SENT;\r
                IoMarkIrpPending( p_irp );\r
-               IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1],\r
-                       __ndi_rep_cm, DelayedWorkQueue, p_irp );\r
-       }\r
-       else\r
-       { /* syncronous performing */\r
-               __ndi_rep_cm( p_io_stack->DeviceObject, p_irp );\r
+               status = STATUS_PENDING;\r
        }\r
+       __ndi_release_lock( &h_qp->p_irp_queue->csq, irql );\r
 \r
-exit:\r
        AL_EXIT( AL_DBG_NDI );\r
-       return CL_PENDING;\r
+       return status;\r
 }\r
 \r
 \r
+\r
 /*******************************************************************\r
  *\r
  * DREQ CM request\r
  *\r
  ******************************************************************/\r
 \r
+\r
 NTSTATUS\r
-ndi_dreq_cm(\r
-       IN              ib_qp_handle_t FUNC_PTR64       const                           h_qp,\r
-       IN              PIRP                                                            p_irp\r
+__ndi_send_dreq(\r
+       IN              IRP*                                                            p_irp\r
        )\r
 {\r
-       ib_qp_mod_t qp_mod;\r
+       ib_qp_handle_t h_qp = (ib_qp_handle_t)p_irp->Tail.Overlay.DriverContext[0];\r
+       IO_STACK_LOCATION       *p_io_stack;\r
        ib_api_status_t status;\r
        NTSTATUS nt_status;\r
-       uint64_t timewait_us;\r
 \r
        AL_ENTER( AL_DBG_NDI );\r
 \r
-       status = al_cep_get_timewait( qp_get_al( h_qp ), \r
-               ((al_conn_qp_t*)h_qp)->cid, &timewait_us );\r
-\r
-       if (status != IB_SUCCESS)\r
+       if ( h_qp->p_irp_queue->state != NDI_CM_CONNECTED &&\r
+               h_qp->p_irp_queue->state != NDI_CM_CONNECTED_DREQ_RCVD )\r
        {\r
-               nt_status = STATUS_CONNECTION_INVALID;\r
-               goto exit;\r
+               AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, \r
+                       ("STATUS_CONNECTION_ACTIVE: h_qp %#I64x, uhdl %#I64x, ref_cnt %d\n",\r
+                       (uint64_t)h_qp, h_qp->obj.hdl, h_qp->obj.ref_cnt ) );\r
+               return STATUS_CONNECTION_INVALID;\r
        }\r
 \r
-       al_destroy_cep(\r
-               qp_get_al( h_qp ), &((al_conn_qp_t*)h_qp)->cid, TRUE, deref_al_obj );\r
+       /*\r
+        * Allocate a work item to perform the QP transition when disconnection\r
+        * completes (or the IRP is cancelled).  We allocate here to trap errors\r
+        * properly.\r
+        */\r
+       p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+       p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject );\r
+       if( p_irp->Tail.Overlay.DriverContext[1] == NULL )\r
+       {\r
+               AL_EXIT( AL_DBG_NDI );\r
+               return STATUS_NO_MEMORY;\r
+       }\r
+       ref_al_obj( &h_qp->obj ); /* Take work item reference. */\r
 \r
-       /* bring QP to error state */\r
-       cl_memclr( &qp_mod, sizeof(qp_mod) );\r
-       qp_mod.req_state = IB_QPS_ERROR;\r
-       \r
-       status = ndi_modify_qp( h_qp, &qp_mod, \r
-               cl_ioctl_out_size( p_irp ), cl_ioctl_out_buf( p_irp ) );\r
-       if ( status != IB_SUCCESS )\r
+       status = al_cep_dreq( qp_get_al( h_qp ), ((al_conn_qp_t*)h_qp)->cid, NULL, 0 );\r
+       switch( status )\r
        {\r
-               AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
-                       ("ndi_modify_qp to ERROR returned %s.\n", ib_get_err_str(status) ) );\r
+       case IB_INVALID_STATE:\r
+               /* We might have just received a DREQ, so try sending a DREP. */\r
+               __ndi_queue_drep( p_irp );\r
+               IoMarkIrpPending( p_irp );\r
+               /*\r
+                * We're going to keep the IRP dangling for a bit - take a reference\r
+                * on the QP until it completes.\r
+                */\r
+               ref_al_obj( &h_qp->obj ); /* Take IRP reference. */\r
+\r
+       case IB_SUCCESS:\r
+               AL_EXIT( AL_DBG_NDI );\r
+               return( ib_to_ntstatus( status ) );\r
+\r
+       case IB_INVALID_HANDLE:\r
                nt_status = STATUS_CONNECTION_INVALID;\r
-               goto exit;\r
+               break;\r
+       default:\r
+               nt_status = ib_to_ntstatus( status );\r
        }\r
+       IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
+       p_irp->Tail.Overlay.DriverContext[1] = NULL;\r
+       deref_al_obj( &h_qp->obj ); /* Release work item reference. */\r
+       AL_EXIT( AL_DBG_NDI );\r
+       return nt_status;\r
+}\r
 \r
-       /* Store the timestamp after which the QP exits timewait. */\r
-       h_qp->timewait = cl_get_time_stamp() + timewait_us;\r
 \r
-       nt_status = STATUS_SUCCESS;\r
+NTSTATUS\r
+ndi_dreq_cm(\r
+       IN              ib_qp_handle_t  const                           h_qp,\r
+       IN              PIRP                                                            p_irp\r
+       )\r
+{\r
+       NTSTATUS status;\r
 \r
-exit:\r
-       h_qp->p_irp_que->state = NDI_CM_IDLE;   \r
-       cl_ioctl_complete( p_irp, nt_status, cl_ioctl_out_size( p_irp ) );\r
+       AL_ENTER( AL_DBG_NDI );\r
+\r
+       p_irp->Tail.Overlay.DriverContext[0] = h_qp;\r
+\r
+       status = IoCsqInsertIrpEx(\r
+               &h_qp->p_irp_queue->csq,\r
+               p_irp,\r
+               NULL,\r
+               (VOID*)(ULONG_PTR)NDI_CM_DISCONNECTING\r
+               );\r
+       /*\r
+        * Note that if al_cep_dreq returned IB_INVALID_STATE, we queued the\r
+        * work item and will try sending the DREP and move the QP to error.\r
+        *\r
+        * The IRP should never be queued if the work item is queued, so \r
+        * we trap the special error code for INVALID_STATE.\r
+        */\r
+       if( status == STATUS_SUCCESS || status == STATUS_INVALID_DEVICE_STATE )\r
+               status = STATUS_PENDING;\r
 \r
        AL_EXIT( AL_DBG_NDI );\r
-       return STATUS_EVENT_DONE;       /* CL_COMPLETED */\r
+       return status;\r
 }\r
 \r
 \r
index 8e6c50d..ad3a3bf 100644 (file)
@@ -67,14 +67,13 @@ typedef enum _ndi_cm_state
        NDI_CM_CONNECTING_ATS_SENT, // ATS = Address Translation Service\r
        NDI_CM_CONNECTING_QPR_SENT, // QPR = Query path record\r
        NDI_CM_CONNECTING_REQ_SENT,\r
+       NDI_CM_CONNECTING_REP_SENT,\r
        NDI_CM_CONNECTING_REP_RCVD,\r
-       NDI_CM_CONNECTING_REJ_RCVD,\r
        NDI_CM_CONNECTED,\r
-       NDI_CM_BOUND,\r
-       NDI_CM_LISTENING,\r
-       NDI_CM_REP_SENT,\r
-       NDI_CM_CONNECTED_DREP_SENT,\r
-       NDI_CM_CONNECTED_DREQ_SENT,\r
+    NDI_CM_DISCONNECTING,\r
+       NDI_CM_CONNECTED_DREQ_RCVD,\r
+    NDI_CM_INVALID\r
+\r
 } ndi_cm_state_t;\r
 \r
 typedef struct _ib_qp  ib_qp_t;\r
@@ -82,12 +81,12 @@ typedef struct _ib_qp       ib_qp_t;
 typedef struct _ndi_qp_csq\r
 {\r
        IO_CSQ                                          csq;\r
+       LIST_ENTRY                                      queue;\r
        ib_qp_t*                                        h_qp;\r
        ib_query_handle_t                       h_query;\r
-       LIST_ENTRY                                      que;\r
        ndi_cm_state_t                          state;\r
        PIO_WORKITEM                            p_workitem;\r
-       PIRP                                            h_ioctl;\r
+\r
 } ndi_qp_csq_t;\r
 \r
 ib_api_status_t\r
@@ -100,16 +99,13 @@ ndi_modify_qp(
 NTSTATUS\r
 ndi_req_cm(\r
        IN              ib_qp_handle_t  const                   h_qp,\r
-       IN              cl_ioctl_handle_t                               h_ioctl,\r
-       IN              ual_ndi_req_cm_ioctl_in_t               *p_req\r
+       IN              cl_ioctl_handle_t                               h_ioctl\r
        );\r
 \r
 NTSTATUS\r
 ndi_rep_cm(\r
        IN              ib_qp_handle_t  const                   h_qp,\r
-       IN              net32_t                                                 cid,\r
-       IN              cl_ioctl_handle_t                               h_ioctl,\r
-       IN              ual_ndi_rep_cm_ioctl_in_t               *p_ndi_rep_cm\r
+       IN              PIRP                                                    p_irp\r
        );\r
 \r
 cl_status_t\r
@@ -123,11 +119,6 @@ ndi_dreq_cm(
        IN              ib_qp_handle_t  const                   h_qp,\r
        IN              PIRP                                                    p_irp\r
        );\r
-\r
-void\r
-ndi_qp_flush_ques(\r
-       IN                              ib_qp_handle_t FUNC_PTR64                               h_qp );\r
-\r
        \r
 NTSTATUS\r
 ndi_qp_init(\r
index 3feed04..bb15047 100644 (file)
@@ -1204,3 +1204,84 @@ al_ioctl(
        AL_EXIT( AL_DBG_DEV );\r
        return cl_status;\r
 }\r
+\r
+\r
+NTSTATUS\r
+ib_to_ntstatus(\r
+    IN  ib_api_status_t ib_status )\r
+{\r
+    switch( ib_status )\r
+    {\r
+    case IB_SUCCESS:\r
+        return STATUS_SUCCESS;\r
+       case IB_INSUFFICIENT_RESOURCES:\r
+       case IB_MAX_MCAST_QPS_REACHED:\r
+        return STATUS_INSUFFICIENT_RESOURCES;\r
+       case IB_INSUFFICIENT_MEMORY:\r
+        return STATUS_NO_MEMORY;\r
+       case IB_INVALID_PARAMETER:\r
+       case IB_INVALID_SETTING:\r
+       case IB_INVALID_PKEY:\r
+       case IB_INVALID_LKEY:\r
+       case IB_INVALID_RKEY:\r
+       case IB_INVALID_MAX_WRS:\r
+       case IB_INVALID_MAX_SGE:\r
+       case IB_INVALID_CQ_SIZE:\r
+       case IB_INVALID_SRQ_SIZE:\r
+       case IB_INVALID_SERVICE_TYPE:\r
+       case IB_INVALID_GID:\r
+       case IB_INVALID_LID:\r
+       case IB_INVALID_GUID:\r
+       case IB_INVALID_WR_TYPE:\r
+       case IB_INVALID_PORT:\r
+       case IB_INVALID_INDEX:\r
+        return STATUS_INVALID_PARAMETER;\r
+       case IB_NO_MATCH:\r
+       case IB_NOT_FOUND:\r
+        return STATUS_NOT_FOUND;\r
+       case IB_TIMEOUT:\r
+        return STATUS_TIMEOUT;\r
+       case IB_CANCELED:\r
+        return STATUS_CANCELLED;\r
+       case IB_INTERRUPTED:\r
+       case IB_NOT_DONE:\r
+        return STATUS_ABANDONED;\r
+       case IB_INVALID_PERMISSION:\r
+        return STATUS_ACCESS_DENIED;\r
+       case IB_UNSUPPORTED:\r
+       case IB_QP_IN_TIMEWAIT:\r
+       case IB_EE_IN_TIMEWAIT:\r
+        return STATUS_INVALID_DEVICE_REQUEST;\r
+       case IB_OVERFLOW:\r
+        return STATUS_BUFFER_OVERFLOW;\r
+       case IB_INVALID_QP_STATE:\r
+       case IB_INVALID_APM_STATE:\r
+       case IB_INVALID_PORT_STATE:\r
+       case IB_INVALID_STATE:\r
+        return STATUS_INVALID_DEVICE_STATE;\r
+       case IB_RESOURCE_BUSY:\r
+        return STATUS_DEVICE_BUSY;\r
+       case IB_INVALID_CA_HANDLE:\r
+       case IB_INVALID_AV_HANDLE:\r
+       case IB_INVALID_CQ_HANDLE:\r
+       case IB_INVALID_QP_HANDLE:\r
+       case IB_INVALID_SRQ_HANDLE:\r
+       case IB_INVALID_PD_HANDLE:\r
+       case IB_INVALID_MR_HANDLE:\r
+       case IB_INVALID_FMR_HANDLE:\r
+       case IB_INVALID_MW_HANDLE:\r
+       case IB_INVALID_MCAST_HANDLE:\r
+       case IB_INVALID_CALLBACK:\r
+       case IB_INVALID_AL_HANDLE:\r
+       case IB_INVALID_HANDLE:\r
+        return STATUS_INVALID_HANDLE;\r
+       case IB_VERBS_PROCESSING_DONE:\r
+        return STATUS_EVENT_DONE;\r
+       case IB_PENDING:\r
+        return STATUS_PENDING;\r
+       case IB_ERROR:\r
+       case IB_REMOTE_ERROR:\r
+    default:\r
+        return STATUS_UNSUCCESSFUL;\r
+    }\r
+}\r
index 20eacde..2b72dc0 100644 (file)
@@ -313,7 +313,7 @@ __ndi_req_cm(
        cl_status_t cl_status;\r
        ib_qp_handle_t h_qp = NULL;\r
        al_dev_open_context_t *p_context;\r
-       ual_ndi_req_cm_ioctl_in_t *p_parm, *p_req = \r
+       ual_ndi_req_cm_ioctl_in_t *p_req = \r
                (ual_ndi_req_cm_ioctl_in_t*)cl_ioctl_in_buf( h_ioctl );\r
        UNUSED_PARAM(p_ret_bytes);\r
        \r
@@ -340,33 +340,23 @@ __ndi_req_cm(
        if( h_qp->type != IB_QPT_RELIABLE_CONN )\r
        {\r
                cl_status = CL_INVALID_HANDLE;\r
-               goto exit;\r
+               goto err;\r
        }\r
 \r
        /* Check psize */\r
        if ( p_req->pdata_size > sizeof(p_req->pdata) )\r
        {\r
                cl_status = CL_INVALID_PARAMETER;\r
-               goto exit;\r
-       }\r
-\r
-       /* copy request parameters a side to prevent problems from cancelled IRP */\r
-       p_parm = cl_zalloc( sizeof(ual_ndi_req_cm_ioctl_in_t) );\r
-       if (!p_parm )\r
-       {\r
-               cl_status = CL_INSUFFICIENT_MEMORY;\r
-               goto exit;\r
+               goto err;\r
        }\r
-       RtlCopyMemory( p_parm, p_req, sizeof(ual_ndi_req_cm_ioctl_in_t) );\r
-       p_parm->h_qp = (uint64_t)h_qp;\r
        \r
        /* perform the ioctl */\r
-       cl_status = ndi_req_cm( h_qp, h_ioctl, p_parm );\r
+       cl_status = ndi_req_cm( h_qp, h_ioctl );\r
 \r
-exit:\r
-       if (h_qp)\r
-               deref_al_obj( &h_qp->obj );\r
+err:\r
+       deref_al_obj( &h_qp->obj );\r
 \r
+exit:\r
        AL_EXIT( AL_DBG_NDI );\r
        return cl_status;\r
 }\r
@@ -390,8 +380,7 @@ __ndi_rep_cm(
        p_context = (al_dev_open_context_t*)p_open_context;\r
 \r
        /* Validate user parameters. */\r
-       if( (cl_ioctl_in_size( h_ioctl ) < sizeof(ual_ndi_rep_cm_ioctl_in_t)) ||\r
-               cl_ioctl_out_size( h_ioctl ) < sizeof(net32_t) )\r
+       if( (cl_ioctl_in_size( h_ioctl ) < sizeof(ual_ndi_rep_cm_ioctl_in_t)) )\r
        {\r
                cl_status = CL_INVALID_PARAMETER;\r
                goto exit;\r
@@ -408,26 +397,26 @@ __ndi_rep_cm(
        if( h_qp->type != IB_QPT_RELIABLE_CONN )\r
        {\r
                cl_status = CL_INVALID_HANDLE;\r
-               goto exit;\r
+               goto err;\r
        }\r
 \r
        /* Check psize */\r
        if ( p_rep->pdata_size >= sizeof(p_rep->pdata) )\r
        {\r
                cl_status = CL_INVALID_PARAMETER;\r
-               goto exit;\r
+               goto err;\r
        }\r
        \r
        /* Get and validate CID */\r
        cid = p_rep->cid;\r
 \r
        /* perform the ioctls */\r
-       cl_status = ndi_rep_cm( h_qp, cid, h_ioctl, p_rep );\r
+       cl_status = ndi_rep_cm( h_qp, h_ioctl );\r
 \r
-exit:\r
-       if (h_qp)\r
-               deref_al_obj( &h_qp->obj );\r
+err:\r
+       deref_al_obj( &h_qp->obj );\r
 \r
+exit:\r
        AL_EXIT( AL_DBG_NDI );\r
        return cl_status;\r
 }\r
index 066d370..2e4d0c9 100644 (file)
@@ -3512,6 +3512,7 @@ typedef struct _ual_ndi_notify_cq_ioctl_in
 */\r
 typedef struct _ual_ndi_req_cm_ioctl_in\r
 {\r
+    ib_gid_pair_t               gids;\r
        uint64_t                                        h_qp;\r
        net64_t                                         guid;\r
        uint16_t                                        dst_port;\r