winverbs: store devices in order that they are added
[mirror/winof/.git] / core / winverbs / kernel / wv_driver.c
1 /*\r
2  * Copyright (c) 2008 Intel Corporation. All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.org BSD license\r
5  * below:\r
6  *\r
7  *     Redistribution and use in source and binary forms, with or\r
8  *     without modification, are permitted provided that the following\r
9  *     conditions are met:\r
10  *\r
11  *      - Redistributions of source code must retain the above\r
12  *        copyright notice, this list of conditions and the following\r
13  *        disclaimer.\r
14  *\r
15  *      - Redistributions in binary form must reproduce the above\r
16  *        copyright notice, this list of conditions and the following\r
17  *        disclaimer in the documentation and/or other materials\r
18  *        provided with the distribution.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
27  * SOFTWARE.\r
28  */\r
29 \r
30 #include <ntddk.h>\r
31 #include <wdf.h>\r
32 #include <wdmsec.h>\r
33 #include <ntstatus.h>\r
34 #include <initguid.h>\r
35 \r
36 #include "index_list.c"\r
37 #include <rdma/verbs.h>\r
38 #include "wv_driver.h"\r
39 #include "wv_ioctl.h"\r
40 #include "wv_provider.h"\r
41 #include "wv_device.h"\r
42 #include "wv_pd.h"\r
43 #include "wv_srq.h"\r
44 #include "wv_cq.h"\r
45 #include "wv_srq.h"\r
46 #include "wv_qp.h"\r
47 #include "wv_ep.h"\r
48 \r
49 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WV_RDMA_DEVICE, WvRdmaDeviceGetContext)\r
50 \r
51 WDFDEVICE                               ControlDevice;\r
52 static LIST_ENTRY               DevList;\r
53 static LIST_ENTRY               ProvList;\r
54 static KGUARDED_MUTEX   Lock;\r
55 ULONG                                   RandomSeed;\r
56 \r
57 INFINIBAND_INTERFACE_CM IbCmInterface;\r
58 \r
59 static EVT_WDF_DRIVER_DEVICE_ADD                        WvRdmaDeviceAdd;\r
60 static EVT_WDF_OBJECT_CONTEXT_CLEANUP           WvRdmaDeviceCleanup;\r
61 static EVT_WDF_DEVICE_D0_ENTRY                          WvPowerD0Entry;\r
62 static EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL       WvIoDeviceControl;\r
63 static EVT_WDF_DEVICE_FILE_CREATE                       WvFileCreate;\r
64 static EVT_WDF_FILE_CLEANUP                                     WvFileCleanup;\r
65 static EVT_WDF_FILE_CLOSE                                       WvFileClose;\r
66 \r
67 WV_RDMA_DEVICE *WvRdmaDeviceGet(NET64 Guid)\r
68 {\r
69         WV_RDMA_DEVICE  *cur_dev, *dev = NULL;\r
70         LIST_ENTRY              *entry;\r
71 \r
72         KeAcquireGuardedMutex(&Lock);\r
73         for (entry = DevList.Flink; entry != &DevList; entry = entry->Flink) {\r
74                 cur_dev = CONTAINING_RECORD(entry, WV_RDMA_DEVICE, Entry);\r
75                 if (cur_dev->Interface.Verbs.guid == Guid) {\r
76                         InterlockedIncrement(&cur_dev->Ref);\r
77                         dev = cur_dev;\r
78                         break;\r
79                 }\r
80         }\r
81         KeReleaseGuardedMutex(&Lock);\r
82         return dev;\r
83 }\r
84 \r
85 void WvRdmaDevicePut(WV_RDMA_DEVICE *pDevice)\r
86 {\r
87         if (InterlockedDecrement(&pDevice->Ref) == 0) {\r
88                 KeSetEvent(&pDevice->Event, 0, FALSE);\r
89         }\r
90 }\r
91 \r
92 \r
93 void WvCompleteRequests(WDFQUEUE Queue, NTSTATUS ReqStatus)\r
94 {\r
95         WDFREQUEST      request;\r
96         NTSTATUS        status;\r
97 \r
98         status = WdfIoQueueRetrieveNextRequest(Queue, &request);\r
99 \r
100         while (NT_SUCCESS(status)) {\r
101                 WdfRequestComplete(request, ReqStatus);\r
102                 status = WdfIoQueueRetrieveNextRequest(Queue, &request);\r
103         }\r
104 }\r
105 \r
106 void WvFlushQueue(WDFQUEUE Queue, NTSTATUS ReqStatus)\r
107 {\r
108         WdfObjectAcquireLock(Queue);\r
109         WvCompleteRequests(Queue, ReqStatus);\r
110         WdfObjectReleaseLock(Queue);\r
111 }\r
112 \r
113 void WvCompleteRequestsWithInformation(WDFQUEUE Queue, NTSTATUS ReqStatus)\r
114 {\r
115         WDFREQUEST      request;\r
116         NTSTATUS        status;\r
117         UINT8           *out;\r
118         size_t          outlen;\r
119 \r
120         status = WdfIoQueueRetrieveNextRequest(Queue, &request);\r
121 \r
122         while (NT_SUCCESS(status)) {\r
123                 outlen = 0;\r
124                 WdfRequestRetrieveOutputBuffer(request, 0, &out, &outlen);\r
125                 WdfRequestCompleteWithInformation(request, ReqStatus, outlen);\r
126                 status = WdfIoQueueRetrieveNextRequest(Queue, &request);\r
127         }\r
128 }\r
129 \r
130 static void WvGuidQuery(WDFREQUEST Request)\r
131 {\r
132         WV_IO_GUID_LIST *list;\r
133         size_t                  len = 0;\r
134         WV_RDMA_DEVICE  *dev;\r
135         ULONG                   count, i;\r
136         LIST_ENTRY              *entry;\r
137         NTSTATUS                status;\r
138 \r
139         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_GUID_LIST),\r
140                                                                                         &list, &len);\r
141         if (!NT_SUCCESS(status)) {\r
142                 goto out;\r
143         }\r
144 \r
145         count = (ULONG) ((len - sizeof(NET64)) / sizeof(NET64));\r
146         i = 0;\r
147         len = sizeof(NET64);\r
148         KeAcquireGuardedMutex(&Lock);\r
149         for (entry = DevList.Flink; entry != &DevList; entry = entry->Flink) {\r
150                 dev = CONTAINING_RECORD(entry, WV_RDMA_DEVICE, Entry);\r
151                 if (i < count) {\r
152                         list->Guid[i] = dev->Interface.Verbs.guid;\r
153                         len += sizeof(NET64);\r
154                 }\r
155                 i++;\r
156         }\r
157         list->Count = i;\r
158         KeReleaseGuardedMutex(&Lock);\r
159 \r
160 out:\r
161         WdfRequestCompleteWithInformation(Request, status, len);\r
162 }\r
163 \r
164 static void WvLibraryQuery(WDFREQUEST Request)\r
165 {\r
166         NET64                   *guid;\r
167         char                    *name;\r
168         size_t                  len = 0, bytes;\r
169         WV_RDMA_DEVICE  *dev;\r
170         NTSTATUS                status;\r
171 \r
172         status = WdfRequestRetrieveInputBuffer(Request, sizeof(NET64), &guid, NULL);\r
173         if (!NT_SUCCESS(status)) {\r
174                 goto out;\r
175         }\r
176         status = WdfRequestRetrieveOutputBuffer(Request, 1, &name, &bytes);\r
177         if (!NT_SUCCESS(status)) {\r
178                 goto out;\r
179         }\r
180 \r
181         dev = WvRdmaDeviceGet(*guid);\r
182         if (dev == NULL) {\r
183                 status = STATUS_NO_SUCH_DEVICE;\r
184                 goto out;\r
185         }\r
186 \r
187         len = strlen(dev->Interface.Verbs.libname) + 1;\r
188         if (bytes >= len) {\r
189                 RtlCopyMemory(name, dev->Interface.Verbs.libname, len);\r
190         } else {\r
191                 status = STATUS_BUFFER_TOO_SMALL;\r
192                 *name = (char) len;\r
193                 len = 1;\r
194         }\r
195         WvRdmaDevicePut(dev);\r
196 \r
197 out:\r
198         WdfRequestCompleteWithInformation(Request, status, len);\r
199 }\r
200 \r
201 static VOID WvIoDeviceControl(WDFQUEUE Queue, WDFREQUEST Request,\r
202                                                           size_t OutLen, size_t InLen, ULONG IoControlCode)\r
203 {\r
204         WDFFILEOBJECT   file;\r
205         WV_PROVIDER             *prov;\r
206         UNREFERENCED_PARAMETER(OutLen);\r
207         UNREFERENCED_PARAMETER(InLen);\r
208         UNREFERENCED_PARAMETER(Queue);\r
209 \r
210         file = WdfRequestGetFileObject(Request);\r
211         prov = WvProviderGetContext(file);\r
212 \r
213         // TODO: verify this compiles as a jump table, or use function pointers\r
214         switch (IoControlCode) {\r
215         case WV_IOCTL_GUID_QUERY:\r
216                 WvGuidQuery(Request);\r
217                 break;\r
218         case WV_IOCTL_LIBRARY_QUERY:\r
219                 WvLibraryQuery(Request);\r
220                 break;\r
221         case WV_IOCTL_DEVICE_OPEN:\r
222                 WvDeviceOpen(prov, Request);\r
223                 break;\r
224         case WV_IOCTL_DEVICE_CLOSE:\r
225                 WvDeviceClose(prov, Request);\r
226                 break;\r
227         case WV_IOCTL_DEVICE_QUERY:\r
228                 WvDeviceQuery(prov, Request);\r
229                 break;\r
230         case WV_IOCTL_DEVICE_PORT_QUERY:\r
231                 WvDevicePortQuery(prov, Request);\r
232                 break;\r
233         case WV_IOCTL_DEVICE_GID_QUERY:\r
234                 WvDeviceGidQuery(prov, Request);\r
235                 break;\r
236         case WV_IOCTL_DEVICE_PKEY_QUERY:\r
237                 WvDevicePkeyQuery(prov, Request);\r
238                 break;\r
239         case WV_IOCTL_DEVICE_NOTIFY:\r
240                 WvDeviceNotify(prov, Request);\r
241                 break;\r
242         case WV_IOCTL_DEVICE_CANCEL:\r
243                 WvDeviceCancel(prov, Request);\r
244                 break;\r
245         case WV_IOCTL_PD_ALLOCATE:\r
246                 WvPdAllocate(prov, Request);\r
247                 break;\r
248         case WV_IOCTL_PD_CANCEL:\r
249                 WvPdCancel(prov, Request);\r
250                 break;\r
251         case WV_IOCTL_PD_DEALLOCATE:\r
252                 WvPdDeallocate(prov, Request);\r
253                 break;\r
254         case WV_IOCTL_MEMORY_REGISTER:\r
255                 WvMrRegister(prov, Request);\r
256                 break;\r
257         case WV_IOCTL_MEMORY_DEREGISTER:\r
258                 WvMrDeregister(prov, Request);\r
259                 break;\r
260         case WV_IOCTL_MW_ALLOCATE:\r
261                 WvMwAllocate(prov, Request);\r
262                 break;\r
263         case WV_IOCTL_MW_DEALLOCATE:\r
264                 WvMwDeallocate(prov, Request);\r
265                 break;\r
266         case WV_IOCTL_AH_CREATE:\r
267                 WvAhCreate(prov, Request);\r
268                 break;\r
269         case WV_IOCTL_AH_DESTROY:\r
270                 WvAhDestroy(prov, Request);\r
271                 break;\r
272         case WV_IOCTL_CQ_CREATE:\r
273                 WvCqCreate(prov, Request);\r
274                 break;\r
275         case WV_IOCTL_CQ_DESTROY:\r
276                 WvCqDestroy(prov, Request);\r
277                 break;\r
278         case WV_IOCTL_CQ_RESIZE:\r
279                 WvCqResize(prov, Request);\r
280                 break;\r
281         case WV_IOCTL_CQ_NOTIFY:\r
282                 WvCqNotify(prov, Request);\r
283                 break;\r
284         case WV_IOCTL_CQ_CANCEL:\r
285                 WvCqCancel(prov, Request);\r
286                 break;\r
287         case WV_IOCTL_SRQ_CREATE:\r
288                 WvSrqCreate(prov, Request);\r
289                 break;\r
290         case WV_IOCTL_SRQ_DESTROY:\r
291                 WvSrqDestroy(prov, Request);\r
292                 break;\r
293         case WV_IOCTL_SRQ_QUERY:\r
294                 WvSrqQuery(prov, Request);\r
295                 break;\r
296         case WV_IOCTL_SRQ_MODIFY:\r
297                 WvSrqModify(prov, Request);\r
298                 break;\r
299         case WV_IOCTL_SRQ_NOTIFY:\r
300                 WvSrqNotify(prov, Request);\r
301                 break;\r
302         case WV_IOCTL_SRQ_CANCEL:\r
303                 WvSrqCancel(prov, Request);\r
304                 break;\r
305         case WV_IOCTL_QP_CREATE:\r
306                 WvQpCreate(prov, Request);\r
307                 break;\r
308         case WV_IOCTL_QP_DESTROY:\r
309                 WvQpDestroy(prov, Request);\r
310                 break;\r
311         case WV_IOCTL_QP_QUERY:\r
312                 WvQpQuery(prov, Request);\r
313                 break;\r
314         case WV_IOCTL_QP_MODIFY:\r
315                 WvQpModify(prov, Request);\r
316                 break;\r
317         case WV_IOCTL_QP_ATTACH:\r
318                 WvQpAttach(prov, Request);\r
319                 break;\r
320         case WV_IOCTL_QP_DETACH:\r
321                 WvQpDetach(prov, Request);\r
322                 break;\r
323         case WV_IOCTL_QP_CANCEL:\r
324                 WvQpCancel(prov, Request);\r
325                 break;\r
326         case WV_IOCTL_EP_CREATE:\r
327                 WvEpCreate(prov, Request);\r
328                 break;\r
329         case WV_IOCTL_EP_DESTROY:\r
330                 WvEpDestroy(prov, Request);\r
331                 break;\r
332         case WV_IOCTL_EP_MODIFY:\r
333                 WvEpModify(prov, Request);\r
334                 break;\r
335         case WV_IOCTL_EP_BIND:\r
336                 WvEpBind(prov, Request);\r
337                 break;\r
338         case WV_IOCTL_EP_REJECT:\r
339                 WvEpReject(prov, Request);\r
340                 break;\r
341         case WV_IOCTL_EP_CONNECT:\r
342                 WvEpConnect(prov, Request);\r
343                 break;\r
344         case WV_IOCTL_EP_ACCEPT:\r
345                 WvEpAccept(prov, Request);\r
346                 break;\r
347         case WV_IOCTL_EP_DISCONNECT:\r
348                 WvEpDisconnect(prov, Request);\r
349                 break;\r
350         case WV_IOCTL_EP_DISCONNECT_NOTIFY:\r
351                 WvEpDisconnectNotify(prov, Request);\r
352                 break;\r
353         case WV_IOCTL_EP_QUERY:\r
354                 WvEpQuery(prov, Request);\r
355                 break;\r
356         case WV_IOCTL_EP_LOOKUP:\r
357                 WvEpLookup(prov, Request);\r
358                 break;\r
359         case WV_IOCTL_EP_MULTICAST_JOIN:\r
360                 WvEpMulticastJoin(prov, Request);\r
361                 break;\r
362         case WV_IOCTL_EP_MULTICAST_LEAVE:\r
363                 WvEpMulticastLeave(prov, Request);\r
364                 break;\r
365         case WV_IOCTL_EP_CANCEL:\r
366                 WvEpCancel(prov, Request);\r
367                 break;\r
368         case WV_IOCTL_EP_LISTEN:\r
369                 WvEpListen(prov, Request);\r
370                 break;\r
371         case WV_IOCTL_EP_GET_REQUEST:\r
372                 WvEpGetRequest(prov, Request);\r
373                 break;\r
374         default:\r
375                 WdfRequestComplete(Request, STATUS_PROCEDURE_NOT_FOUND);\r
376                 break;\r
377         }\r
378 }\r
379 \r
380 static VOID WvFileCreate(WDFDEVICE Device, WDFREQUEST Request,\r
381                                                  WDFFILEOBJECT FileObject)\r
382 {\r
383         WV_PROVIDER     *prov = WvProviderGetContext(FileObject);\r
384         NTSTATUS status;\r
385 \r
386         status = WvProviderInit(Device, prov);\r
387         if (NT_SUCCESS(status)) {\r
388                 KeAcquireGuardedMutex(&Lock);\r
389                 InsertHeadList(&ProvList, &prov->Entry);\r
390                 KeReleaseGuardedMutex(&Lock);\r
391         }\r
392         WdfRequestComplete(Request, STATUS_SUCCESS);\r
393 }\r
394 \r
395 static VOID WvFileCleanup(WDFFILEOBJECT FileObject)\r
396 {\r
397         WV_PROVIDER *prov = WvProviderGetContext(FileObject);\r
398 \r
399         KeAcquireGuardedMutex(&Lock);\r
400         RemoveEntryList(&prov->Entry);\r
401         KeReleaseGuardedMutex(&Lock);\r
402         WvProviderCleanup(prov);\r
403 }\r
404 \r
405 static VOID WvFileClose(WDFFILEOBJECT FileObject)\r
406 {\r
407         UNREFERENCED_PARAMETER(FileObject);\r
408 }\r
409 \r
410 static VOID WvCreateControlDevice(WDFDRIVER Driver)\r
411 {\r
412         PWDFDEVICE_INIT                 pinit;\r
413         WDF_FILEOBJECT_CONFIG   fileconfig;\r
414         WDF_OBJECT_ATTRIBUTES   attr;\r
415         WDF_IO_QUEUE_CONFIG             ioconfig;\r
416         NTSTATUS                                status;\r
417         WDFQUEUE                                queue;\r
418         DECLARE_CONST_UNICODE_STRING(name, L"\\Device\\WinVerbs");\r
419         DECLARE_CONST_UNICODE_STRING(symlink, L"\\DosDevices\\WinVerbs");\r
420 \r
421         pinit = WdfControlDeviceInitAllocate(Driver,\r
422                                                                                  &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);\r
423         if (pinit == NULL) {\r
424                         return;\r
425         }\r
426 \r
427         WdfDeviceInitSetExclusive(pinit, FALSE);\r
428         status = WdfDeviceInitAssignName(pinit, &name);\r
429         if (!NT_SUCCESS(status)) {\r
430                 goto err1;\r
431         }\r
432 \r
433         WDF_FILEOBJECT_CONFIG_INIT(&fileconfig, WvFileCreate, WvFileClose,\r
434                                                            WvFileCleanup);\r
435         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WV_PROVIDER);\r
436         WdfDeviceInitSetFileObjectConfig(pinit, &fileconfig, &attr);\r
437 \r
438         WDF_OBJECT_ATTRIBUTES_INIT(&attr);\r
439         status = WdfDeviceCreate(&pinit, &attr, &ControlDevice);\r
440         if (!NT_SUCCESS(status)) {\r
441                 goto err1;\r
442         }\r
443 \r
444         status = WdfDeviceCreateSymbolicLink(ControlDevice, &symlink);\r
445         if (!NT_SUCCESS(status)) {\r
446                 goto err2;\r
447         }\r
448 \r
449         WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioconfig, WdfIoQueueDispatchParallel);\r
450         ioconfig.EvtIoDeviceControl = WvIoDeviceControl;\r
451         status = WdfIoQueueCreate(ControlDevice, &ioconfig,\r
452                                                           WDF_NO_OBJECT_ATTRIBUTES, &queue);\r
453         if (!NT_SUCCESS(status)) {\r
454                 goto err2;\r
455         }\r
456 \r
457         WdfControlFinishInitializing(ControlDevice);\r
458         return;\r
459 \r
460 err2:\r
461         WdfObjectDelete(ControlDevice);\r
462         return;\r
463 err1:\r
464         WdfDeviceInitFree(pinit);\r
465 }\r
466 \r
467 static NTSTATUS WvPowerD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE PreviousState)\r
468 {\r
469         WV_RDMA_DEVICE  *dev;\r
470         BOOLEAN                 create;\r
471         NTSTATUS                status;\r
472 \r
473         dev = WvRdmaDeviceGetContext(Device);\r
474         if (dev->hDevice != NULL) {\r
475                 return STATUS_SUCCESS;\r
476         }\r
477 \r
478         status = WdfFdoQueryForInterface(Device, &GUID_RDMA_INTERFACE_VERBS,\r
479                                                                          (PINTERFACE) &dev->Interface,\r
480                                                                          sizeof(dev->Interface), VerbsVersion(2, 0),\r
481                                                                          NULL);\r
482         if (!NT_SUCCESS(status)) {\r
483                 return status;\r
484         }\r
485         dev->hDevice = dev->Interface.Verbs.p_hca_obj;\r
486 \r
487         KeAcquireGuardedMutex(&Lock);\r
488         create = IsListEmpty(&DevList);\r
489         InsertTailList(&DevList, &dev->Entry);\r
490         KeReleaseGuardedMutex(&Lock);\r
491 \r
492         if (create) {\r
493                 WvCreateControlDevice(WdfGetDriver());\r
494                 status = WdfFdoQueryForInterface(Device, &GUID_INFINIBAND_INTERFACE_CM,\r
495                                                                                  (PINTERFACE) &IbCmInterface,\r
496                                                                                  sizeof(IbCmInterface),\r
497                                                                                  IbaCmVersion(1, 0), NULL);\r
498         }\r
499 \r
500         return status;\r
501 }\r
502 \r
503 static NTSTATUS WvRdmaDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)\r
504 {\r
505         WDF_OBJECT_ATTRIBUTES                   attr;\r
506         WDF_PNPPOWER_EVENT_CALLBACKS    power;\r
507         WDFDEVICE                                               dev;\r
508         WV_RDMA_DEVICE                                  *pdev;\r
509         NTSTATUS                                                status;\r
510 \r
511         WdfFdoInitSetFilter(DeviceInit);\r
512 \r
513         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WV_RDMA_DEVICE);\r
514         attr.EvtCleanupCallback = WvRdmaDeviceCleanup;\r
515 \r
516         WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&power);\r
517         power.EvtDeviceD0Entry = WvPowerD0Entry;\r
518         WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &power);\r
519 \r
520         status = WdfDeviceCreate(&DeviceInit, &attr, &dev);\r
521         if (!NT_SUCCESS(status)) {\r
522                 return status;\r
523         }\r
524 \r
525         pdev = WvRdmaDeviceGetContext(dev);\r
526         RtlZeroMemory(pdev, sizeof *pdev);\r
527         pdev->Ref = 1;\r
528         KeInitializeEvent(&pdev->Event, NotificationEvent, FALSE);\r
529 \r
530         return STATUS_SUCCESS;\r
531 }\r
532 \r
533 static VOID WvRdmaDeviceCleanup(WDFDEVICE Device)\r
534 {\r
535         WV_RDMA_DEVICE                  *pdev;\r
536         WV_PROVIDER                             *prov;\r
537         LIST_ENTRY                              *entry;\r
538         BOOLEAN                                 destroy;\r
539         WDFDEVICE                               ctrldev;\r
540 \r
541         pdev = WvRdmaDeviceGetContext(Device);\r
542         if (pdev->hDevice == NULL) {\r
543                 return;\r
544         }\r
545 \r
546         KeAcquireGuardedMutex(&Lock);\r
547         RemoveEntryList(&pdev->Entry);\r
548         destroy = IsListEmpty(&DevList);\r
549         ctrldev = ControlDevice;\r
550 \r
551         for (entry = ProvList.Flink; entry != &ProvList; entry = entry->Flink) {\r
552                 prov = CONTAINING_RECORD(entry, WV_PROVIDER, Entry);\r
553                 WvProviderRemoveHandler(prov, pdev);\r
554         }\r
555 \r
556         KeReleaseGuardedMutex(&Lock);\r
557 \r
558         if (InterlockedDecrement(&pdev->Ref) > 0) {\r
559                 KeWaitForSingleObject(&pdev->Event, Executive, KernelMode, FALSE, NULL);\r
560         }\r
561 \r
562         pdev->Interface.InterfaceHeader.InterfaceDereference(pdev->Interface.\r
563                                                                                                                  InterfaceHeader.Context);\r
564 \r
565         if (destroy) {\r
566                 if (IbCmInterface.CM.create_id != NULL) {\r
567                         IbCmInterface.InterfaceHeader.InterfaceDereference(IbCmInterface.\r
568                                                                                                                            InterfaceHeader.Context);\r
569                 }\r
570                 WdfObjectDelete(ctrldev);\r
571         }\r
572 }\r
573 \r
574 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)\r
575 {\r
576         WDF_DRIVER_CONFIG               config;\r
577         NTSTATUS                                status;\r
578         WDFDRIVER                               driv;\r
579 \r
580         InitializeListHead(&DevList);\r
581         InitializeListHead(&ProvList);\r
582         KeInitializeGuardedMutex(&Lock);\r
583         RandomSeed = (ULONG) (ULONG_PTR) DriverObject;\r
584 \r
585         WDF_DRIVER_CONFIG_INIT(&config, WvRdmaDeviceAdd);\r
586         status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,\r
587                                                          &config, &driv);\r
588         if (!NT_SUCCESS(status)) {\r
589                 return status;\r
590         }\r
591 \r
592         return STATUS_SUCCESS;\r
593 }\r