]> git.openfabrics.org - ~shefty/rdma-win.git/commitdiff
uncommit
authorSean Hefty <sean.hefty@intel.com>
Thu, 21 Jan 2010 20:14:58 +0000 (12:14 -0800)
committerSean Hefty <sean.hefty@intel.com>
Thu, 21 Jan 2010 20:14:58 +0000 (12:14 -0800)
meta
patches/ib-cm-fix-handling-failed-send [new file with mode: 0644]
patches/ibal-ib-cm-fix-handling-failed [new file with mode: 0644]
patches/ipoib_ndis6_cm-fix-the-wrong-l [new file with mode: 0644]
patches/kmdf-tracks-all-requests-that- [new file with mode: 0644]

diff --git a/meta b/meta
index 9dd591205bbe558e29c8e369c849c8818e99998d..2a23e720c846b89e2243ec0247bcd2099dbb5e2b 100644 (file)
--- a/meta
+++ b/meta
@@ -1,7 +1,11 @@
 Version: 1
-Previous: 2703ee274627f0d65ce0e3695ee67d4070a8f429
+Previous: 2f77d05ffe6f0d3f3587941619505d2bad406287
 Head: 9e58e346f0e153e088a2e901f00d73e9123d2fbf
 Applied:
+  kmdf-tracks-all-requests-that-: c310382fb09a4ae6730f1a69739ee3aa5980152f
+  ib-cm-fix-handling-failed-send: dde56985a9d93c48e35c3018ea5cb36b6848c847
+  ipoib_ndis6_cm-fix-the-wrong-l: eeeba68f83b087d215e5c6ce302b74ac426095cd
+  ibal-ib-cm-fix-handling-failed: 9e58e346f0e153e088a2e901f00d73e9123d2fbf
 Unapplied:
   winverbs-winverbs-use-separate: 150de58b413e633220018f0647be8197d4eec773
   winof-whitespace-cleanup-remov: 791e27c01ab5c52f83cc9c53b2a9c3f50e1c2555
diff --git a/patches/ib-cm-fix-handling-failed-send b/patches/ib-cm-fix-handling-failed-send
new file mode 100644 (file)
index 0000000..39d7bb7
--- /dev/null
@@ -0,0 +1,232 @@
+Bottom: ed7908e04b3bbaa4e2413f01b2efe982eb5349d8
+Top:    7edcb31c25e21f961a1e6f9af11bf03fa5d98c65
+Author: E~1\svn\LOCALS~1\Temp/report.7.tmp <E~1\svn\LOCALS~1\Temp/report.7.tmp@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
+Date:   2010-01-04 19:01:09 +0000
+
+ib/cm: fix handling failed send completions
+
+__cep_mad_send_cb() assumes that the mad being processed is
+associated with the current state of the CEP.  This may not be
+the case.
+
+For example, for a short lived connection, it was observed that
+a REP mad completed with status canceled.  This is normal.  However,
+the user already attempted to disconnect the connection by sending
+a DREQ.  This left the cep in the DREQ_SENT state by the time that
+the REP mad completed.  Since the REP failed, but the state was
+DREQ_SENT, the code assumed that the DREQ had failed and transitioned
+the cep into TIMEWAIT.  The result is that the DREQ is never
+matched with a DREP or canceled, but holds a reference on the CEP.
+
+Until the DREQ times out (time depends on connection, but easily
+up to a minute), attempts to destroy the CEP are blocked.
+
+Fix this by simply discarding any completed sends that were not
+sent from the current state of the cep when the completion handler
+is invoked.
+
+Signed-off-by: Sean Hefty <sean.hefty@intel.com>
+
+git-svn-id: svn://openib.tc.cornell.edu/gen1@2650 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86
+
+
+---
+
+diff --git a/trunk/core/al/kernel/al_cm.c b/trunk/core/al/kernel/al_cm.c
+index 48b0cb5..955985a 100644
+--- a/trunk/core/al/kernel/al_cm.c
++++ b/trunk/core/al/kernel/al_cm.c
+@@ -37,7 +37,7 @@
+ typedef struct _iba_cm_id_priv\r
+ {\r
+       iba_cm_id       id;\r
+-      KEVENT          destroy_event;  \r
++      KEVENT          destroy_event;\r
\r
+ }     iba_cm_id_priv;\r
\r
+diff --git a/trunk/core/al/kernel/al_cm_cep.c b/trunk/core/al/kernel/al_cm_cep.c
+index 49fa417..4987207 100644
+--- a/trunk/core/al/kernel/al_cm_cep.c
++++ b/trunk/core/al/kernel/al_cm_cep.c
+@@ -27,7 +27,7 @@
+  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+  * SOFTWARE.\r
+  *\r
+- * $Id$\r
++ * $Id: al_cm_cep.c 2540 2009-11-03 17:23:09Z shefty $\r
+  */\r
\r
\r
+@@ -2213,10 +2213,7 @@ __cep_mad_send_cb(
\r
+       p_cep = (kcep_t*)p_mad->context1;\r
\r
+-      /*\r
+-       * The connection context is not set when performing immediate responses,\r
+-       * such as repeating MADS.\r
+-       */\r
++      /* The cep context is only set for MADs that are retried. */\r
+       if( !p_cep )\r
+       {\r
+               ib_put_mad( p_mad );\r
+@@ -2224,94 +2221,71 @@ __cep_mad_send_cb(
+               return;\r
+       }\r
\r
++      CL_ASSERT( p_mad->status != IB_WCS_SUCCESS );\r
+       p_mad->context1 = NULL;\r
\r
+       KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl );\r
+-      /* Clear the sent MAD pointer so that we don't try cancelling again. */\r
+-      if( p_cep->p_send_mad == p_mad )\r
+-              p_cep->p_send_mad = NULL;\r
+-\r
+-      switch( p_mad->status )\r
++      if( p_cep->p_send_mad != p_mad )\r
+       {\r
+-      case IB_WCS_SUCCESS:\r
+               KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl );\r
+               ib_put_mad( p_mad );\r
+-              break;\r
+-\r
+-      case IB_WCS_CANCELED:\r
+-              if( p_cep->state != CEP_STATE_REQ_SENT &&\r
+-                      p_cep->state != CEP_STATE_REQ_MRA_RCVD &&\r
+-                      p_cep->state != CEP_STATE_REP_SENT &&\r
+-                      p_cep->state != CEP_STATE_REP_MRA_RCVD &&\r
+-                      p_cep->state != CEP_STATE_LAP_SENT &&\r
+-                      p_cep->state != CEP_STATE_LAP_MRA_RCVD &&\r
+-                      p_cep->state != CEP_STATE_DREQ_SENT &&\r
+-                      p_cep->state != CEP_STATE_SREQ_SENT )\r
+-              {\r
+-                      KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl );\r
+-                      ib_put_mad( p_mad );\r
+-                      break;\r
+-              }\r
+-              /* Treat as a timeout so we don't stall the state machine. */\r
+-              p_mad->status = IB_WCS_TIMEOUT_RETRY_ERR;\r
+-\r
+-              /* Fall through. */\r
+-      case IB_WCS_TIMEOUT_RETRY_ERR:\r
+-      default:\r
+-              /* Timeout.  Reject the connection. */\r
+-              switch( p_cep->state )\r
+-              {\r
+-              case CEP_STATE_REQ_SENT:\r
+-              case CEP_STATE_REQ_MRA_RCVD:\r
+-              case CEP_STATE_REP_SENT:\r
+-              case CEP_STATE_REP_MRA_RCVD:\r
+-                      /* Send the REJ. */\r
+-                      __reject_timeout( p_port_cep, p_cep, p_mad );\r
+-                      __remove_cep( p_cep );\r
+-                      p_cep->state = CEP_STATE_IDLE;\r
+-                      break;\r
+-\r
+-              case CEP_STATE_DREQ_DESTROY:\r
+-                      p_cep->state = CEP_STATE_DESTROY;\r
+-                      __insert_timewait( p_cep );\r
+-                      /* Fall through. */\r
++              goto done;\r
++      }\r
\r
+-              case CEP_STATE_DESTROY:\r
+-                      KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl );\r
+-                      ib_put_mad( p_mad );\r
+-                      goto done;\r
++      /* Clear the sent MAD pointer so that we don't try cancelling again. */\r
++      p_cep->p_send_mad = NULL;\r
\r
+-              case CEP_STATE_DREQ_SENT:\r
+-                      /*\r
+-                       * Make up a DREP mad so we can respond if we receive\r
+-                       * a DREQ while in timewait.\r
+-                       */\r
+-                      __format_mad_hdr( &p_cep->mads.drep.hdr, p_cep, CM_DREP_ATTR_ID );\r
+-                      __format_drep( p_cep, NULL, 0, &p_cep->mads.drep );\r
+-                      p_cep->state = CEP_STATE_TIMEWAIT;\r
+-                      __insert_timewait( p_cep );\r
+-                      break;\r
++      switch( p_cep->state )\r
++      {\r
++      case CEP_STATE_REQ_SENT:\r
++      case CEP_STATE_REQ_MRA_RCVD:\r
++      case CEP_STATE_REP_SENT:\r
++      case CEP_STATE_REP_MRA_RCVD:\r
++              /* Send the REJ. */\r
++              __reject_timeout( p_port_cep, p_cep, p_mad );\r
++              __remove_cep( p_cep );\r
++              p_cep->state = CEP_STATE_IDLE;\r
++              break;\r
\r
+-              case CEP_STATE_LAP_SENT:\r
+-                      /*\r
+-                       * Before CEP was sent, we have been in CEP_STATE_ESTABLISHED as we\r
+-                       * failed to send, we return to that state.\r
+-                       */\r
+-                      p_cep->state = CEP_STATE_ESTABLISHED;\r
+-                      break;\r
+-              default:\r
+-                      break;\r
+-              }\r
++      case CEP_STATE_DREQ_DESTROY:\r
++              p_cep->state = CEP_STATE_DESTROY;\r
++              __insert_timewait( p_cep );\r
++              /* Fall through. */\r
\r
+-              status = __cep_queue_mad( p_cep, p_mad );\r
+-              CL_ASSERT( status != IB_INVALID_STATE );\r
++      case CEP_STATE_DESTROY:\r
+               KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl );\r
++              ib_put_mad( p_mad );\r
++              goto done;\r
\r
+-              if( status == IB_SUCCESS )\r
+-                      __process_cep( p_cep );\r
++      case CEP_STATE_DREQ_SENT:\r
++              /*\r
++               * Make up a DREP mad so we can respond if we receive\r
++               * a DREQ while in timewait.\r
++               */\r
++              __format_mad_hdr( &p_cep->mads.drep.hdr, p_cep, CM_DREP_ATTR_ID );\r
++              __format_drep( p_cep, NULL, 0, &p_cep->mads.drep );\r
++              p_cep->state = CEP_STATE_TIMEWAIT;\r
++              __insert_timewait( p_cep );\r
++              break;\r
++\r
++      case CEP_STATE_LAP_SENT:\r
++              /*\r
++               * Before CEP was sent, we have been in CEP_STATE_ESTABLISHED as we\r
++               * failed to send, we return to that state.\r
++               */\r
++              p_cep->state = CEP_STATE_ESTABLISHED;\r
++              break;\r
++      default:\r
+               break;\r
+       }\r
\r
++      status = __cep_queue_mad( p_cep, p_mad );\r
++      CL_ASSERT( status != IB_INVALID_STATE );\r
++      KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl );\r
++\r
++      if( status == IB_SUCCESS )\r
++              __process_cep( p_cep );\r
++\r
+ done:\r
+       pfn_destroy_cb = p_cep->pfn_destroy_cb;\r
+       cep_context = p_cep->context;\r
+@@ -3938,12 +3912,8 @@ __cleanup_cep(
+       CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );\r
\r
+       /* If we've already come through here, we're done. */\r
+-      if( p_cep->state == CEP_STATE_DESTROY ||\r
+-              p_cep->state == CEP_STATE_DREQ_DESTROY )\r
+-      {\r
+-              AL_EXIT( AL_DBG_CM );\r
+-              return -1;\r
+-      }\r
++      CL_ASSERT( p_cep->state != CEP_STATE_DESTROY &&\r
++              p_cep->state != CEP_STATE_DREQ_DESTROY );\r
\r
+       /* Cleanup the pending MAD list. */\r
+       while( p_cep->p_mad_head )
diff --git a/patches/ibal-ib-cm-fix-handling-failed b/patches/ibal-ib-cm-fix-handling-failed
new file mode 100644 (file)
index 0000000..4ea3991
--- /dev/null
@@ -0,0 +1,218 @@
+Bottom: 8c81b098194a73a6b885161efe4ac769111b5c88
+Top:    8ebcb054bec1d85cae3b87aaad82a6488d5fc842
+Author: stansmith <stansmith@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
+Date:   2010-01-05 18:59:21 +0000
+
+[IBAL] ib/cm: fix handling failed send completions
+__cep_mad_send_cb() assumes that the mad being processed is
+associated with the current state of the CEP.  This may not be
+the case.
+For example, for a short lived connection, it was observed that
+a REP mad completed with status canceled.  This is normal.  However,
+the user already attempted to disconnect the connection by sending
+a DREQ.  This left the cep in the DREQ_SENT state by the time that
+the REP mad completed.  Since the REP status was not success, but the
+state was DREQ_SENT, the code assumed that the DREQ had failed and
+transitioned the cep into TIMEWAIT.  The result is that the DREQ is never
+>matched with a DREP or canceled, but holds a reference on the CEP.
+Until the DREQ times out (time depends on connection, but easily
+up to a minute), attempts to destroy the CEP are blocked.
+Fix this by simply discarding any completed sends that were not
+sent from the current state of the cep when the completion handler
+is invoked.
+Signed-off-by: Sean Hefty <sean.hefty@intel.com>
+
+git-svn-id: svn://openib.tc.cornell.edu/gen1@2652 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86
+
+
+---
+
+diff --git a/branches/WOF2-2/core/al/kernel/al_cm.c b/branches/WOF2-2/core/al/kernel/al_cm.c
+index 48b0cb5..955985a 100644
+--- a/branches/WOF2-2/core/al/kernel/al_cm.c
++++ b/branches/WOF2-2/core/al/kernel/al_cm.c
+@@ -37,7 +37,7 @@
+ typedef struct _iba_cm_id_priv\r
+ {\r
+       iba_cm_id       id;\r
+-      KEVENT          destroy_event;  \r
++      KEVENT          destroy_event;\r
\r
+ }     iba_cm_id_priv;\r
\r
+diff --git a/branches/WOF2-2/core/al/kernel/al_cm_cep.c b/branches/WOF2-2/core/al/kernel/al_cm_cep.c
+index 49fa417..89ffe12 100644
+--- a/branches/WOF2-2/core/al/kernel/al_cm_cep.c
++++ b/branches/WOF2-2/core/al/kernel/al_cm_cep.c
+@@ -2213,10 +2213,7 @@ __cep_mad_send_cb(
\r
+       p_cep = (kcep_t*)p_mad->context1;\r
\r
+-      /*\r
+-       * The connection context is not set when performing immediate responses,\r
+-       * such as repeating MADS.\r
+-       */\r
++      /* The cep context is only set for MADs that are retried. */\r
+       if( !p_cep )\r
+       {\r
+               ib_put_mad( p_mad );\r
+@@ -2224,94 +2221,71 @@ __cep_mad_send_cb(
+               return;\r
+       }\r
\r
++      CL_ASSERT( p_mad->status != IB_WCS_SUCCESS );\r
+       p_mad->context1 = NULL;\r
\r
+       KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl );\r
+-      /* Clear the sent MAD pointer so that we don't try cancelling again. */\r
+-      if( p_cep->p_send_mad == p_mad )\r
+-              p_cep->p_send_mad = NULL;\r
+-\r
+-      switch( p_mad->status )\r
++      if( p_cep->p_send_mad != p_mad )\r
+       {\r
+-      case IB_WCS_SUCCESS:\r
+               KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl );\r
+               ib_put_mad( p_mad );\r
+-              break;\r
+-\r
+-      case IB_WCS_CANCELED:\r
+-              if( p_cep->state != CEP_STATE_REQ_SENT &&\r
+-                      p_cep->state != CEP_STATE_REQ_MRA_RCVD &&\r
+-                      p_cep->state != CEP_STATE_REP_SENT &&\r
+-                      p_cep->state != CEP_STATE_REP_MRA_RCVD &&\r
+-                      p_cep->state != CEP_STATE_LAP_SENT &&\r
+-                      p_cep->state != CEP_STATE_LAP_MRA_RCVD &&\r
+-                      p_cep->state != CEP_STATE_DREQ_SENT &&\r
+-                      p_cep->state != CEP_STATE_SREQ_SENT )\r
+-              {\r
+-                      KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl );\r
+-                      ib_put_mad( p_mad );\r
+-                      break;\r
+-              }\r
+-              /* Treat as a timeout so we don't stall the state machine. */\r
+-              p_mad->status = IB_WCS_TIMEOUT_RETRY_ERR;\r
+-\r
+-              /* Fall through. */\r
+-      case IB_WCS_TIMEOUT_RETRY_ERR:\r
+-      default:\r
+-              /* Timeout.  Reject the connection. */\r
+-              switch( p_cep->state )\r
+-              {\r
+-              case CEP_STATE_REQ_SENT:\r
+-              case CEP_STATE_REQ_MRA_RCVD:\r
+-              case CEP_STATE_REP_SENT:\r
+-              case CEP_STATE_REP_MRA_RCVD:\r
+-                      /* Send the REJ. */\r
+-                      __reject_timeout( p_port_cep, p_cep, p_mad );\r
+-                      __remove_cep( p_cep );\r
+-                      p_cep->state = CEP_STATE_IDLE;\r
+-                      break;\r
+-\r
+-              case CEP_STATE_DREQ_DESTROY:\r
+-                      p_cep->state = CEP_STATE_DESTROY;\r
+-                      __insert_timewait( p_cep );\r
+-                      /* Fall through. */\r
++              goto done;\r
++      }\r
\r
+-              case CEP_STATE_DESTROY:\r
+-                      KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl );\r
+-                      ib_put_mad( p_mad );\r
+-                      goto done;\r
++      /* Clear the sent MAD pointer so that we don't try cancelling again. */\r
++      p_cep->p_send_mad = NULL;\r
\r
+-              case CEP_STATE_DREQ_SENT:\r
+-                      /*\r
+-                       * Make up a DREP mad so we can respond if we receive\r
+-                       * a DREQ while in timewait.\r
+-                       */\r
+-                      __format_mad_hdr( &p_cep->mads.drep.hdr, p_cep, CM_DREP_ATTR_ID );\r
+-                      __format_drep( p_cep, NULL, 0, &p_cep->mads.drep );\r
+-                      p_cep->state = CEP_STATE_TIMEWAIT;\r
+-                      __insert_timewait( p_cep );\r
+-                      break;\r
++      switch( p_cep->state )\r
++      {\r
++      case CEP_STATE_REQ_SENT:\r
++      case CEP_STATE_REQ_MRA_RCVD:\r
++      case CEP_STATE_REP_SENT:\r
++      case CEP_STATE_REP_MRA_RCVD:\r
++              /* Send the REJ. */\r
++              __reject_timeout( p_port_cep, p_cep, p_mad );\r
++              __remove_cep( p_cep );\r
++              p_cep->state = CEP_STATE_IDLE;\r
++              break;\r
\r
+-              case CEP_STATE_LAP_SENT:\r
+-                      /*\r
+-                       * Before CEP was sent, we have been in CEP_STATE_ESTABLISHED as we\r
+-                       * failed to send, we return to that state.\r
+-                       */\r
+-                      p_cep->state = CEP_STATE_ESTABLISHED;\r
+-                      break;\r
+-              default:\r
+-                      break;\r
+-              }\r
++      case CEP_STATE_DREQ_DESTROY:\r
++              p_cep->state = CEP_STATE_DESTROY;\r
++              __insert_timewait( p_cep );\r
++              /* Fall through. */\r
\r
+-              status = __cep_queue_mad( p_cep, p_mad );\r
+-              CL_ASSERT( status != IB_INVALID_STATE );\r
++      case CEP_STATE_DESTROY:\r
+               KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl );\r
++              ib_put_mad( p_mad );\r
++              goto done;\r
\r
+-              if( status == IB_SUCCESS )\r
+-                      __process_cep( p_cep );\r
++      case CEP_STATE_DREQ_SENT:\r
++              /*\r
++               * Make up a DREP mad so we can respond if we receive\r
++               * a DREQ while in timewait.\r
++               */\r
++              __format_mad_hdr( &p_cep->mads.drep.hdr, p_cep, CM_DREP_ATTR_ID );\r
++              __format_drep( p_cep, NULL, 0, &p_cep->mads.drep );\r
++              p_cep->state = CEP_STATE_TIMEWAIT;\r
++              __insert_timewait( p_cep );\r
++              break;\r
++\r
++      case CEP_STATE_LAP_SENT:\r
++              /*\r
++               * Before CEP was sent, we have been in CEP_STATE_ESTABLISHED as we\r
++               * failed to send, we return to that state.\r
++               */\r
++              p_cep->state = CEP_STATE_ESTABLISHED;\r
++              break;\r
++      default:\r
+               break;\r
+       }\r
\r
++      status = __cep_queue_mad( p_cep, p_mad );\r
++      CL_ASSERT( status != IB_INVALID_STATE );\r
++      KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl );\r
++\r
++      if( status == IB_SUCCESS )\r
++              __process_cep( p_cep );\r
++\r
+ done:\r
+       pfn_destroy_cb = p_cep->pfn_destroy_cb;\r
+       cep_context = p_cep->context;\r
+@@ -3938,12 +3912,8 @@ __cleanup_cep(
+       CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );\r
\r
+       /* If we've already come through here, we're done. */\r
+-      if( p_cep->state == CEP_STATE_DESTROY ||\r
+-              p_cep->state == CEP_STATE_DREQ_DESTROY )\r
+-      {\r
+-              AL_EXIT( AL_DBG_CM );\r
+-              return -1;\r
+-      }\r
++      CL_ASSERT( p_cep->state != CEP_STATE_DESTROY &&\r
++              p_cep->state != CEP_STATE_DREQ_DESTROY );\r
\r
+       /* Cleanup the pending MAD list. */\r
+       while( p_cep->p_mad_head )
diff --git a/patches/ipoib_ndis6_cm-fix-the-wrong-l b/patches/ipoib_ndis6_cm-fix-the-wrong-l
new file mode 100644 (file)
index 0000000..a65d6f1
--- /dev/null
@@ -0,0 +1,61 @@
+Bottom: 7edcb31c25e21f961a1e6f9af11bf03fa5d98c65
+Top:    8c81b098194a73a6b885161efe4ac769111b5c88
+Author: stansmith <stansmith@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
+Date:   2010-01-05 18:51:23 +0000
+
+[IPoIB_NDIS6_CM] fix the wrong length calculation of
+first MDL within Net Buffer object.
+The actual length of first MDL should be incremented by it's offset
+signed-off by: Alexander Naslednikov (xalex at mellanox.co.il)
+
+git-svn-id: svn://openib.tc.cornell.edu/gen1@2651 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86
+
+
+---
+
+diff --git a/branches/WOF2-2/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp b/branches/WOF2-2/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp
+index 641c094..ee60eed 100644
+--- a/branches/WOF2-2/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp
++++ b/branches/WOF2-2/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp
+@@ -3513,6 +3513,9 @@ __send_mgr_get_eth_hdr(
+               return NDIS_STATUS_FAILURE;\r
+       }\r
\r
++      ULONG MdlDataOffset = NET_BUFFER_CURRENT_MDL_OFFSET(p_net_buffer);\r
++      *p_mdl_len -= MdlDataOffset;\r
++ \r
+       if( *p_mdl_len < sizeof(eth_hdr_t) )\r
+       {\r
+               IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+@@ -3521,7 +3524,7 @@ __send_mgr_get_eth_hdr(
+               return NDIS_STATUS_BUFFER_TOO_SHORT;\r
+       }\r
\r
+-      *pp_eth_hdr = (eth_hdr_t*)(p_head + NET_BUFFER_CURRENT_MDL_OFFSET(p_net_buffer));\r
++      *pp_eth_hdr = (eth_hdr_t*)(p_head + MdlDataOffset);\r
\r
+       IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND,\r
+               ("Ethernet header:\n"\r
+diff --git a/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp
+index 641c094..ee60eed 100644
+--- a/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp
++++ b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp
+@@ -3513,6 +3513,9 @@ __send_mgr_get_eth_hdr(
+               return NDIS_STATUS_FAILURE;\r
+       }\r
\r
++      ULONG MdlDataOffset = NET_BUFFER_CURRENT_MDL_OFFSET(p_net_buffer);\r
++      *p_mdl_len -= MdlDataOffset;\r
++ \r
+       if( *p_mdl_len < sizeof(eth_hdr_t) )\r
+       {\r
+               IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+@@ -3521,7 +3524,7 @@ __send_mgr_get_eth_hdr(
+               return NDIS_STATUS_BUFFER_TOO_SHORT;\r
+       }\r
\r
+-      *pp_eth_hdr = (eth_hdr_t*)(p_head + NET_BUFFER_CURRENT_MDL_OFFSET(p_net_buffer));\r
++      *pp_eth_hdr = (eth_hdr_t*)(p_head + MdlDataOffset);\r
\r
+       IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND,\r
+               ("Ethernet header:\n"
diff --git a/patches/kmdf-tracks-all-requests-that- b/patches/kmdf-tracks-all-requests-that-
new file mode 100644 (file)
index 0000000..d27ab3d
--- /dev/null
@@ -0,0 +1,659 @@
+Bottom: 6a0d87b4622bc7319d396436b319ad51c6ae3636
+Top:    ed7908e04b3bbaa4e2413f01b2efe982eb5349d8
+Author: oushandling code to queue a separate data structure, so that all requestscan remain on the IO queues.Signed-off-by: Sean Hefty sean.hefty@intel.com <oushandling code to queue a separate data structure, so that all requestscan remain on the IO queues.Signed-off-by: Sean Hefty sean.hefty@intel.com@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
+Date:   2010-01-04 19:00:54 +0000
+
+KMDF tracks all requests that pass through an IO queue.  Even after a
+request has been removed from the queue, the request still maintains a
+reference on the queue.  Any attempt to delete the queue will block
+until all requests holding references on the queue have completed.
+
+To avoid deadlock conditions during cleanup, we need to ensure that
+all requests can complete during cleanup.  Modify the asynchronous
+handling code to queue a separate data structure, so that all requests
+can remain on the IO queues.
+
+Signed-off-by: Sean Hefty <sean.hefty@intel.com>
+
+git-svn-id: svn://openib.tc.cornell.edu/gen1@2649 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86
+
+
+---
+
+diff --git a/trunk/core/winverbs/kernel/wv_ep.c b/trunk/core/winverbs/kernel/wv_ep.c
+index 2fbb5b3..3d5c6ce 100644
+--- a/trunk/core/winverbs/kernel/wv_ep.c
++++ b/trunk/core/winverbs/kernel/wv_ep.c
+@@ -38,6 +38,8 @@
+ #define WV_AF_INET    2\r
+ #define WV_AF_INET6   23\r
\r
++static void WvEpWorkHandler(WORK_ENTRY *pWork);\r
++\r
+ static void WvEpGet(WV_ENDPOINT *pEndpoint)\r
+ {\r
+       InterlockedIncrement(&pEndpoint->Ref);\r
+@@ -87,6 +89,12 @@ static NTSTATUS WvEpAllocate(WV_PROVIDER *pProvider, UINT16 EpType,
+       }\r
\r
+       RtlZeroMemory(ep, sizeof(WV_ENDPOINT));\r
++      ep->pWork = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_WORK_ENTRY), 'wevw');\r
++      if (ep->pWork == NULL) {\r
++              status = STATUS_NO_MEMORY;\r
++              goto err1;\r
++      }\r
++\r
+       ep->Ref = 1;\r
+       ep->pProvider = pProvider;\r
+       ep->EpType = EpType;\r
+@@ -97,13 +105,15 @@ static NTSTATUS WvEpAllocate(WV_PROVIDER *pProvider, UINT16 EpType,
+       status = WdfIoQueueCreate(ControlDevice, &config,\r
+                                                         WDF_NO_OBJECT_ATTRIBUTES, &ep->Queue);\r
+       if (!NT_SUCCESS(status)) {\r
+-              goto err;\r
++              goto err2;\r
+       }\r
\r
+       *ppEndpoint = ep;\r
+       return STATUS_SUCCESS;\r
\r
+-err:\r
++err2:\r
++      ExFreePoolWithTag(ep->pWork, 'wevw');\r
++err1:\r
+       ExFreePoolWithTag(ep, 'pevw');\r
+       return status;\r
+ }\r
+@@ -137,6 +147,7 @@ void WvEpCreate(WV_PROVIDER *pProvider, WDFREQUEST Request)
+       }\r
+       KeReleaseGuardedMutex(&pProvider->Lock);\r
\r
++      WvWorkEntryInit(ep->pWork, *pId, WvEpWorkHandler, pProvider);\r
+       WdfRequestCompleteWithInformation(Request, status, sizeof(UINT64));\r
+       return;\r
\r
+@@ -195,6 +206,9 @@ void WvEpFree(WV_ENDPOINT *pEndpoint)
\r
+       WdfIoQueuePurgeSynchronously(pEndpoint->Queue);\r
+       WdfObjectDelete(pEndpoint->Queue);\r
++      if (pEndpoint->pWork != NULL) {\r
++              ExFreePoolWithTag(pEndpoint->pWork, 'wevw');\r
++      }\r
+       ExFreePoolWithTag(pEndpoint, 'pevw');\r
+ }\r
\r
+@@ -413,77 +427,72 @@ static NTSTATUS WvEpDisconnectQp(WV_PROVIDER *pProvider, UINT64 QpId,
+       return status;\r
+ }\r
\r
+-static void WvEpDisconnectHandler(WORK_ENTRY *pWork)\r
++static NTSTATUS WvEpAsyncDisconnect(WV_ENDPOINT *pEndpoint, WDFREQUEST Request)\r
+ {\r
+-      WV_PROVIDER                     *prov;\r
+-      WDFREQUEST                      request;\r
+       WV_IO_EP_DISCONNECT     *pattr;\r
+       UINT8                           *out;\r
+       size_t                          outlen = 0;\r
+       NTSTATUS                        status;\r
\r
+-      request = (WDFREQUEST) pWork->Context;\r
+-      prov = WvProviderGetContext(WdfRequestGetFileObject(request));\r
+-\r
+-      status = WdfRequestRetrieveInputBuffer(request, sizeof(WV_IO_EP_DISCONNECT),\r
++      status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_DISCONNECT),\r
+                                                                                  &pattr, NULL);\r
+       if (!NT_SUCCESS(status)) {\r
+-              goto complete;\r
++              return status;\r
+       }\r
\r
+-      status = WdfRequestRetrieveOutputBuffer(request, 0, &out, &outlen);\r
++      status = WdfRequestRetrieveOutputBuffer(Request, 0, &out, &outlen);\r
+       if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) {\r
+-              goto complete;\r
++              return status;\r
+       }\r
\r
+-      status = (NTSTATUS) WdfRequestGetInformation(request);\r
++      status = (NTSTATUS) WdfRequestGetInformation(Request);\r
+       if (NT_SUCCESS(status)) {\r
+-              status = WvEpDisconnectQp(prov, pattr->QpId, out, outlen);\r
++              status = WvEpDisconnectQp(pEndpoint->pProvider, pattr->QpId, out, outlen);\r
+       } else {\r
+-              WvEpDisconnectQp(prov, pattr->QpId, out, outlen);\r
++              WvEpDisconnectQp(pEndpoint->pProvider, pattr->QpId, out, outlen);\r
+       }\r
\r
+-complete:\r
+-      WdfRequestCompleteWithInformation(request, status, outlen);\r
+-      WvProviderPut(prov);\r
++      WdfRequestCompleteWithInformation(Request, status, outlen);\r
++      return STATUS_SUCCESS;\r
+ }\r
\r
+-// We use IRP DriverContext to queue the request for further processing,\r
+-// but the request/IRP are no longer owned by the framework.\r
+ static void WvEpCompleteDisconnect(WV_ENDPOINT *pEndpoint, NTSTATUS DiscStatus)\r
+ {\r
+       WDFREQUEST                              request;\r
++      WDFREQUEST                              disc_req = NULL;\r
+       WDF_REQUEST_PARAMETERS  param;\r
+-      WORK_ENTRY                              *work;\r
+       NTSTATUS                                status;\r
\r
+       WdfObjectAcquireLock(pEndpoint->Queue);\r
+-      if (pEndpoint->State == WvEpDestroying) {\r
++      if (pEndpoint->State == WvEpDestroying || !pEndpoint->pWork) {\r
+               goto release;\r
+       }\r
+       pEndpoint->State = WvEpDisconnected;\r
\r
+       status = WdfIoQueueRetrieveNextRequest(pEndpoint->Queue, &request);\r
+       while (NT_SUCCESS(status)) {\r
+-              WdfObjectReleaseLock(pEndpoint->Queue);\r
\r
+               WDF_REQUEST_PARAMETERS_INIT(&param);\r
+               WdfRequestGetParameters(request, &param);\r
+               if (param.Parameters.DeviceIoControl.IoControlCode == WV_IOCTL_EP_DISCONNECT) {\r
+-                      work = WorkEntryFromIrp(WdfRequestWdmGetIrp(request));\r
+                       WdfRequestSetInformation(request, DiscStatus);\r
+-                      WorkEntryInit(work, WvEpDisconnectHandler, request);\r
+                       WvProviderGet(pEndpoint->pProvider);\r
+-                      WorkQueueInsert(&pEndpoint->pProvider->WorkQueue, work);\r
++                      WorkQueueInsert(&pEndpoint->pProvider->WorkQueue, &pEndpoint->pWork->Work);\r
++                      pEndpoint->pWork = NULL;\r
++                      disc_req = request;\r
+               } else {\r
+                       WdfRequestComplete(request, DiscStatus);\r
+               }\r
\r
+-              WdfObjectAcquireLock(pEndpoint->Queue);\r
+               status = WdfIoQueueRetrieveNextRequest(pEndpoint->Queue, &request);\r
+       }\r
++\r
++      if (disc_req != NULL) {\r
++              WdfRequestRequeue(disc_req);\r
++      }\r
+ release:\r
+       WdfObjectReleaseLock(pEndpoint->Queue);\r
++\r
+ }\r
\r
+ static NTSTATUS WvEpIbCmHandler(iba_cm_id *pId, iba_cm_event *pEvent)\r
+@@ -565,49 +574,31 @@ static NTSTATUS WvEpIbCmHandler(iba_cm_id *pId, iba_cm_event *pEvent)
+       return STATUS_SUCCESS;\r
+ }\r
\r
+-void WvEpConnectHandler(WORK_ENTRY *pWork)\r
++static NTSTATUS WvEpAsyncConnect(WV_ENDPOINT *pEndpoint, WDFREQUEST Request)\r
+ {\r
+-      WV_PROVIDER                     *prov;\r
+-      WDFREQUEST                      request;\r
+       WV_IO_EP_CONNECT        *pattr;\r
+-      WV_ENDPOINT                     *ep;\r
+       WV_QUEUE_PAIR           *qp;\r
+       iba_cm_req                      req;\r
+       NTSTATUS                        status;\r
+       UINT8                           data[IB_REQ_PDATA_SIZE];\r
\r
+-      request = (WDFREQUEST) pWork->Context;\r
+-      prov = WvProviderGetContext(WdfRequestGetFileObject(request));\r
+-\r
+-      status = WdfRequestRetrieveInputBuffer(request, sizeof(WV_IO_EP_CONNECT),\r
++      status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_CONNECT),\r
+                                                                                  &pattr, NULL);\r
+       if (!NT_SUCCESS(status)) {\r
+-              goto complete;\r
+-      }\r
+-\r
+-      if (pattr->Param.DataLength > sizeof(pattr->Param.Data)) {\r
+-              status = STATUS_INVALID_BUFFER_SIZE;\r
+-              goto complete;\r
+-      }\r
+-\r
+-      ep = WvEpAcquire(prov, pattr->Id);\r
+-      if (ep == NULL) {\r
+-              status = STATUS_NOT_FOUND;\r
+-              goto complete;\r
++              return status;\r
+       }\r
\r
+-      qp = WvQpAcquire(prov, pattr->QpId);\r
++      qp = WvQpAcquire(pEndpoint->pProvider, pattr->QpId);\r
+       if (qp == NULL) {\r
+-              status = STATUS_NOT_FOUND;\r
+-              goto release;\r
++              return STATUS_NOT_FOUND;\r
+       }\r
\r
+-      ep->Attributes.PeerAddress = pattr->PeerAddress;\r
+-      WvFormatCmaHeader((IB_CMA_HEADER *) data, &ep->Attributes.LocalAddress,\r
+-                                        &ep->Attributes.PeerAddress);\r
++      pEndpoint->Attributes.PeerAddress = pattr->PeerAddress;\r
++      WvFormatCmaHeader((IB_CMA_HEADER *) data, &pEndpoint->Attributes.LocalAddress,\r
++                                        &pEndpoint->Attributes.PeerAddress);\r
\r
+-      req.service_id = WvGetServiceId(ep->EpType, &ep->Attributes.PeerAddress);\r
+-      req.p_primary_path = &ep->Route;\r
++      req.service_id = WvGetServiceId(pEndpoint->EpType, &pEndpoint->Attributes.PeerAddress);\r
++      req.p_primary_path = &pEndpoint->Route;\r
+       req.p_alt_path = NULL;\r
+       req.qpn = qp->Qpn;\r
+       req.qp_type = IB_QPT_RELIABLE_CONN;\r
+@@ -627,54 +618,86 @@ void WvEpConnectHandler(WORK_ENTRY *pWork)
+       req.srq = (qp->pSrq != NULL);\r
\r
+       WvQpRelease(qp);\r
+-      RtlCopyMemory(&ep->Attributes.Param.Connect, &pattr->Param,\r
++      RtlCopyMemory(&pEndpoint->Attributes.Param.Connect, &pattr->Param,\r
+                                 sizeof(pattr->Param));\r
\r
+-      WdfObjectAcquireLock(ep->Queue);\r
+-      if (ep->State != WvEpRouteResolved) {\r
++      WdfObjectAcquireLock(pEndpoint->Queue);\r
++      if (pEndpoint->State != WvEpRouteResolved) {\r
+               status = STATUS_NOT_SUPPORTED;\r
+-              goto unlock;\r
++              goto out;\r
+       }\r
\r
+-      status = IbCmInterface.CM.create_id(WvEpIbCmHandler, ep, &ep->pIbCmId);\r
++      status = IbCmInterface.CM.create_id(WvEpIbCmHandler, pEndpoint, &pEndpoint->pIbCmId);\r
+       if (!NT_SUCCESS(status)) {\r
+-              goto unlock;\r
++              goto out;\r
+       }\r
\r
+-      ep->State = WvEpActiveConnect;\r
+-      status = IbCmInterface.CM.send_req(ep->pIbCmId, &req);\r
++      pEndpoint->State = WvEpActiveConnect;\r
++      status = IbCmInterface.CM.send_req(pEndpoint->pIbCmId, &req);\r
+       if (NT_SUCCESS(status)) {\r
+-              status = WdfRequestForwardToIoQueue(request, ep->Queue);\r
++              status = WdfRequestRequeue(Request);\r
+       }\r
\r
+       if (!NT_SUCCESS(status)) {\r
+-              ep->State = WvEpDisconnected;\r
+-      }\r
+-unlock:\r
+-      WdfObjectReleaseLock(ep->Queue);\r
+-release:\r
+-      WvEpRelease(ep);\r
+-complete:\r
+-      if (!NT_SUCCESS(status)) {\r
+-              WdfRequestComplete(request, status);\r
++              pEndpoint->State = WvEpDisconnected;\r
+       }\r
+-      WvProviderPut(prov);\r
++\r
++out:\r
++      WdfObjectReleaseLock(pEndpoint->Queue);\r
++      return status;\r
+ }\r
\r
+-static void WvEpProcessAsync(WV_PROVIDER *pProvider, WDFREQUEST Request,\r
+-                                                       void (*AsyncHandler)(struct _WORK_ENTRY *Work))\r
++static NTSTATUS WvEpProcessAsync(WV_PROVIDER *pProvider, UINT64 Id, WDFREQUEST Request)\r
+ {\r
+-      WORK_ENTRY      *work;\r
++      WV_ENDPOINT     *ep;\r
++      NTSTATUS        status;\r
++\r
++      ep = WvEpAcquire(pProvider, Id);\r
++      if (ep == NULL) {\r
++              return STATUS_NOT_FOUND;\r
++      }\r
++\r
++      WdfObjectAcquireLock(ep->Queue);\r
++      if (!ep->pWork) {\r
++              status = STATUS_TOO_MANY_COMMANDS;\r
++              goto out;\r
++      }\r
\r
+-      work = WorkEntryFromIrp(WdfRequestWdmGetIrp(Request));\r
+-      WorkEntryInit(work, AsyncHandler, Request);\r
+-      WvProviderGet(pProvider);\r
+-      WorkQueueInsert(&pProvider->WorkQueue, work);\r
++      status = WdfRequestForwardToIoQueue(Request, ep->Queue);\r
++      if (NT_SUCCESS(status)) {\r
++              WvProviderGet(pProvider);\r
++              WorkQueueInsert(&pProvider->WorkQueue, &ep->pWork->Work);\r
++              ep->pWork = NULL;\r
++      }\r
++\r
++out:\r
++      WdfObjectReleaseLock(ep->Queue);\r
++      WvEpRelease(ep);\r
++      return status;\r
+ }\r
\r
+ void WvEpConnect(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+ {\r
+-      WvEpProcessAsync(pProvider, Request, WvEpConnectHandler);\r
++      WV_IO_EP_CONNECT        *pattr;\r
++      NTSTATUS                        status;\r
++\r
++      status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_CONNECT),\r
++                                                                                 &pattr, NULL);\r
++      if (!NT_SUCCESS(status)) {\r
++              goto out;\r
++      }\r
++\r
++      if (pattr->Param.DataLength > sizeof(pattr->Param.Data)) {\r
++              status = STATUS_INVALID_BUFFER_SIZE;\r
++              goto out;\r
++      }\r
++\r
++      status = WvEpProcessAsync(pProvider, pattr->Id, Request);\r
++\r
++out:\r
++      if (!NT_SUCCESS(status)) {\r
++              WdfRequestComplete(Request, status);\r
++      }\r
+ }\r
\r
+ static NTSTATUS WvEpModifyQpRtr(WV_ENDPOINT *pEndpoint, WV_QUEUE_PAIR *pQp,\r
+@@ -823,7 +846,7 @@ static NTSTATUS WvEpAcceptPassive(WDFREQUEST Request, UINT8 *pVerbsData, size_t
\r
+       status = IbCmInterface.CM.send_rep(pEndpoint->pIbCmId, &rep);\r
+       if (NT_SUCCESS(status)) {\r
+-              status = WdfRequestForwardToIoQueue(Request, pEndpoint->Queue);\r
++              status = WdfRequestRequeue(Request);\r
+       }\r
+       \r
+       if (!NT_SUCCESS(status)) {\r
+@@ -836,65 +859,114 @@ out:
+       return status;\r
+ }\r
\r
+-void WvEpAcceptHandler(WORK_ENTRY *pWork)\r
++static NTSTATUS WvEpAsyncAccept(WV_ENDPOINT *pEndpoint, WDFREQUEST Request)\r
+ {\r
+-      WV_PROVIDER                     *prov;\r
+-      WDFREQUEST                      request;\r
+       WV_IO_EP_ACCEPT         *pattr;\r
+-      WV_ENDPOINT                     *ep;\r
+       NTSTATUS                        status;\r
+       UINT8                           *out;\r
+       size_t                          outlen;\r
\r
+-      request = (WDFREQUEST) pWork->Context;\r
+-      prov = WvProviderGetContext(WdfRequestGetFileObject(request));\r
+-\r
+-      status = WdfRequestRetrieveInputBuffer(request, sizeof(WV_IO_EP_ACCEPT),\r
++      status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_ACCEPT),\r
+                                                                                  &pattr, NULL);\r
+       if (!NT_SUCCESS(status)) {\r
+-              goto complete;\r
++              return status;\r
+       }\r
\r
+-      status = WdfRequestRetrieveOutputBuffer(request, 0, &out, &outlen);\r
++      status = WdfRequestRetrieveOutputBuffer(Request, 0, &out, &outlen);\r
+       if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) {\r
+-              goto complete;\r
+-      }\r
+-\r
+-      if (pattr->Param.DataLength > sizeof(pattr->Param.Data)) {\r
+-              status = STATUS_INVALID_BUFFER_SIZE;\r
+-              goto complete;\r
+-      }\r
+-\r
+-      ep = WvEpAcquire(prov, pattr->Id);\r
+-      if (ep == NULL) {\r
+-              status = STATUS_NOT_FOUND;\r
+-              goto complete;\r
++              return status;\r
+       }\r
\r
+       /* EP state is re-checked under lock in WvEpAccept* calls */\r
+-      switch (ep->State) {\r
++      switch (pEndpoint->State) {\r
+       case WvEpActiveConnect:\r
+-              status = WvEpAcceptActive(request, out, outlen, ep, pattr);\r
++              status = WvEpAcceptActive(Request, out, outlen, pEndpoint, pattr);\r
+               break;\r
+       case WvEpPassiveConnect:\r
+-              status = WvEpAcceptPassive(request, out, outlen, ep, pattr);\r
++              status = WvEpAcceptPassive(Request, out, outlen, pEndpoint, pattr);\r
+               break;\r
+       default:\r
+               status = STATUS_NOT_SUPPORTED;\r
+               break;\r
+       }\r
\r
+-      WvEpRelease(ep);\r
+-complete:\r
++      return status;\r
++}\r
++\r
++static void WvEpWorkHandler(WORK_ENTRY *pWork)\r
++{\r
++      WV_PROVIDER                             *prov;\r
++      WV_ENDPOINT                             *ep;\r
++      WV_WORK_ENTRY                   *work;\r
++      WDFREQUEST                              request;\r
++      WDF_REQUEST_PARAMETERS  param;\r
++      NTSTATUS                                status;\r
++\r
++      work = CONTAINING_RECORD(pWork, WV_WORK_ENTRY, Work);\r
++      prov = (WV_PROVIDER *) pWork->Context;\r
++\r
++      ep = WvEpAcquire(prov, work->Id);\r
++      if (ep == NULL) {\r
++              ExFreePoolWithTag(work, 'wevw');\r
++              goto out;\r
++      }\r
++\r
++      WdfObjectAcquireLock(ep->Queue);\r
++      ep->pWork = work;\r
++      status = WdfIoQueueRetrieveNextRequest(ep->Queue, &request);\r
++      WdfObjectReleaseLock(ep->Queue);\r
++\r
++      if (!NT_SUCCESS(status)) {\r
++              goto put;\r
++      }\r
++\r
++      WDF_REQUEST_PARAMETERS_INIT(&param);\r
++      WdfRequestGetParameters(request, &param);\r
++      switch (param.Parameters.DeviceIoControl.IoControlCode) {\r
++      case WV_IOCTL_EP_CONNECT:\r
++              status = WvEpAsyncConnect(ep, request);\r
++              break;\r
++      case WV_IOCTL_EP_ACCEPT:\r
++              status = WvEpAsyncAccept(ep, request);\r
++              break;\r
++      case WV_IOCTL_EP_DISCONNECT:\r
++              status = WvEpAsyncDisconnect(ep, request);\r
++              break;\r
++      default:\r
++              status = STATUS_NOT_IMPLEMENTED;\r
++      }\r
++\r
+       if (!NT_SUCCESS(status)) {\r
+               WdfRequestComplete(request, status);\r
+       }\r
++put:\r
++      WvEpRelease(ep);\r
++out:\r
+       WvProviderPut(prov);\r
+ }\r
\r
+ void WvEpAccept(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+ {\r
+-      WvEpProcessAsync(pProvider, Request, WvEpAcceptHandler);\r
++      WV_IO_EP_ACCEPT         *pattr;\r
++      NTSTATUS                        status;\r
++\r
++      status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_ACCEPT),\r
++                                                                                 &pattr, NULL);\r
++      if (!NT_SUCCESS(status)) {\r
++              goto out;\r
++      }\r
++\r
++      if (pattr->Param.DataLength > sizeof(pattr->Param.Data)) {\r
++              status = STATUS_INVALID_BUFFER_SIZE;\r
++              goto out;\r
++      }\r
++\r
++      status = WvEpProcessAsync(pProvider, pattr->Id, Request);\r
++\r
++out:\r
++      if (!NT_SUCCESS(status)) {\r
++              WdfRequestComplete(Request, status);\r
++      }\r
+ }\r
\r
+ void WvEpReject(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+@@ -932,69 +1004,7 @@ complete:
+       WdfRequestComplete(Request, status);\r
+ }\r
\r
+-static NTSTATUS WvEpDisconnectActive(WDFREQUEST Request,\r
+-                                                                       UINT8 *pVerbsData, size_t VerbsSize,\r
+-                                                                       WV_ENDPOINT *pEndpoint,\r
+-                                                                       WV_IO_EP_DISCONNECT *pAttr)\r
+-{\r
+-      NTSTATUS status, failure;\r
+-\r
+-      WdfObjectAcquireLock(pEndpoint->Queue);\r
+-      if (pEndpoint->State != WvEpConnected) {\r
+-              status = STATUS_NOT_SUPPORTED;\r
+-              goto release;\r
+-      }\r
+-\r
+-      pEndpoint->State = WvEpActiveDisconnect;\r
+-      IbCmInterface.CM.send_dreq(pEndpoint->pIbCmId, NULL, 0);\r
+-\r
+-      status = WdfRequestForwardToIoQueue(Request, pEndpoint->Queue);\r
+-      if (!NT_SUCCESS(status)) {\r
+-              pEndpoint->State = WvEpDisconnected;\r
+-              WvCompleteRequests(pEndpoint->Queue, STATUS_UNSUCCESSFUL);\r
+-              WdfObjectReleaseLock(pEndpoint->Queue);\r
+-\r
+-              failure = status;\r
+-              status = WvEpDisconnectQp(pEndpoint->pProvider, pAttr->QpId,\r
+-                                                                pVerbsData, VerbsSize);\r
+-              if (NT_SUCCESS(status)) {\r
+-                      WdfRequestCompleteWithInformation(Request, failure, VerbsSize);\r
+-              }\r
+-              return status;\r
+-      }\r
+-\r
+-release:\r
+-      WdfObjectReleaseLock(pEndpoint->Queue);\r
+-      return status;\r
+-}\r
+-\r
+-static NTSTATUS WvEpDisconnectPassive(WDFREQUEST Request,\r
+-                                                                        UINT8 *pVerbsData, size_t VerbsSize,\r
+-                                                                        WV_ENDPOINT *pEndpoint,\r
+-                                                                        WV_IO_EP_DISCONNECT *pAttr)\r
+-{\r
+-      NTSTATUS status;\r
+-\r
+-      WdfObjectAcquireLock(pEndpoint->Queue);\r
+-      if (pEndpoint->State != WvEpPassiveDisconnect) {\r
+-              WdfObjectReleaseLock(pEndpoint->Queue);\r
+-              return STATUS_NOT_SUPPORTED;\r
+-      }\r
+-\r
+-      pEndpoint->State = WvEpDisconnected;\r
+-      WdfObjectReleaseLock(pEndpoint->Queue);\r
+-\r
+-      IbCmInterface.CM.send_drep(pEndpoint->pIbCmId, NULL, 0);\r
+-\r
+-      status = WvEpDisconnectQp(pEndpoint->pProvider, pAttr->QpId,\r
+-                                                        pVerbsData, VerbsSize);\r
+-      if (NT_SUCCESS(status)) {\r
+-              WdfRequestCompleteWithInformation(Request, status, VerbsSize);\r
+-      }\r
+-\r
+-      return status;\r
+-}\r
+-\r
++// The IB CM could have received and processed a DREQ that we haven't seen yet.\r
+ void WvEpDisconnect(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+ {\r
+       WV_IO_EP_DISCONNECT     *pattr;\r
+@@ -1020,19 +1030,36 @@ void WvEpDisconnect(WV_PROVIDER *pProvider, WDFREQUEST Request)
+               goto complete;\r
+       }\r
\r
+-      /* EP state is re-checked under lock in WvEpDisconnect* calls */\r
++      WdfObjectAcquireLock(ep->Queue);\r
+       switch (ep->State) {\r
+       case WvEpConnected:\r
+-              status = WvEpDisconnectActive(Request, out, outlen, ep, pattr);\r
+-              break;\r
++              status = IbCmInterface.CM.send_dreq(ep->pIbCmId, NULL, 0);\r
++              if (NT_SUCCESS(status)) {\r
++                      status = WdfRequestForwardToIoQueue(Request, ep->Queue);\r
++                      if (NT_SUCCESS(status)) {\r
++                              ep->State = WvEpActiveDisconnect;\r
++                              break;\r
++                      }\r
++              }\r
++              /* Fall through to passive disconnect case on failure */\r
+       case WvEpPassiveDisconnect:\r
+-              status = WvEpDisconnectPassive(Request, out, outlen, ep, pattr);\r
+-              break;\r
++              ep->State = WvEpDisconnected;\r
++              WdfObjectReleaseLock(ep->Queue);\r
++\r
++              IbCmInterface.CM.send_drep(ep->pIbCmId, NULL, 0);\r
++\r
++              status = WvEpDisconnectQp(ep->pProvider, pattr->QpId, out, outlen);\r
++              if (NT_SUCCESS(status)) {\r
++                      WdfRequestCompleteWithInformation(Request, status, outlen);\r
++              }\r
++              goto release;\r
+       default:\r
+-              status = STATUS_NOT_SUPPORTED;\r
++              status = STATUS_INVALID_DEVICE_STATE;\r
+               break;\r
+       }\r
++      WdfObjectReleaseLock(ep->Queue);\r
\r
++release:\r
+       WvEpRelease(ep);\r
+ complete:\r
+       if (!NT_SUCCESS(status)) {\r
+diff --git a/trunk/core/winverbs/kernel/wv_ep.h b/trunk/core/winverbs/kernel/wv_ep.h
+index f6d48d3..650b23c 100644
+--- a/trunk/core/winverbs/kernel/wv_ep.h
++++ b/trunk/core/winverbs/kernel/wv_ep.h
+@@ -72,6 +72,7 @@ typedef struct _WV_ENDPOINT
+       KEVENT                          Event;\r
+       LONG                            Ref;\r
+       WDFQUEUE                        Queue;\r
++      WV_WORK_ENTRY           *pWork;\r
\r
+ }     WV_ENDPOINT;\r
\r
+diff --git a/trunk/core/winverbs/kernel/wv_provider.h b/trunk/core/winverbs/kernel/wv_provider.h
+index 329145f..bd430fb 100644
+--- a/trunk/core/winverbs/kernel/wv_provider.h
++++ b/trunk/core/winverbs/kernel/wv_provider.h
+@@ -44,6 +44,20 @@
+ struct _WV_DEVICE;\r
+ struct _WV_PROTECTION_DOMAIN;\r
\r
++typedef struct _WV_WORK_ENTRY\r
++{\r
++      WORK_ENTRY              Work;\r
++      UINT64                  Id;\r
++\r
++}     WV_WORK_ENTRY;\r
++\r
++static void WvWorkEntryInit(WV_WORK_ENTRY *pWork, UINT64 Id,\r
++                                                      void (*WorkHandler)(WORK_ENTRY *Work), void *Context)\r
++{\r
++      pWork->Id = Id;\r
++      WorkEntryInit(&pWork->Work, WorkHandler, Context);\r
++}\r
++\r
+ typedef struct _WV_PROVIDER\r
+ {\r
+       LIST_ENTRY              Entry;