KMDF tracks all requests that pass through an IO queue. Even after a
authoroushandling 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>
Mon, 4 Jan 2010 19:00:54 +0000 (19:00 +0000)
committeroushandling 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>
Mon, 4 Jan 2010 19:00:54 +0000 (19:00 +0000)
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/trunk@2649 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

core/winverbs/kernel/wv_ep.c
core/winverbs/kernel/wv_ep.h
core/winverbs/kernel/wv_provider.h

index 2fbb5b3..3d5c6ce 100644 (file)
@@ -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
index f6d48d3..650b23c 100644 (file)
@@ -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
index 329145f..bd430fb 100644 (file)
 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;\r