8ac92b66bca138add8aa9af5c4a3227306855ade
[mirror/winof/.git] / core / winmad / kernel / wm_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 "wm_ioctl.h"\r
37 #include "wm_driver.h"\r
38 #include "wm_provider.h"\r
39 #include "wm_reg.h"\r
40 \r
41 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WM_IB_DEVICE, WmIbDeviceGetContext)\r
42 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WM_PROVIDER, WmProviderGetContext)\r
43 \r
44 WDFDEVICE                               ControlDevice;\r
45 static LIST_ENTRY               DevList;\r
46 static LIST_ENTRY               ProvList;\r
47 static KGUARDED_MUTEX   Lock;\r
48 \r
49 static EVT_WDF_DRIVER_DEVICE_ADD                        WmIbDeviceAdd;\r
50 static EVT_WDF_OBJECT_CONTEXT_CLEANUP           WmIbDeviceCleanup;\r
51 static EVT_WDF_DEVICE_D0_ENTRY                          WmPowerD0Entry;\r
52 static EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL       WmIoDeviceControl;\r
53 static EVT_WDF_IO_QUEUE_IO_READ                         WmIoRead;\r
54 static EVT_WDF_IO_QUEUE_IO_WRITE                        WmIoWrite;\r
55 static EVT_WDF_DEVICE_FILE_CREATE                       WmFileCreate;\r
56 static EVT_WDF_FILE_CLEANUP                                     WmFileCleanup;\r
57 static EVT_WDF_FILE_CLOSE                                       WmFileClose;\r
58 \r
59 static WM_IB_DEVICE *WmIbDeviceFind(NET64 Guid)\r
60 {\r
61         WM_IB_DEVICE    *cur_dev, *dev = NULL;\r
62         LIST_ENTRY              *entry;\r
63 \r
64         for (entry = DevList.Flink; entry != &DevList; entry = entry->Flink) {\r
65                 cur_dev = CONTAINING_RECORD(entry, WM_IB_DEVICE, Entry);\r
66                 if (cur_dev->Guid == Guid) {\r
67                         dev = cur_dev;\r
68                         break;\r
69                 }\r
70         }\r
71         return dev;\r
72 }\r
73 \r
74 WM_IB_DEVICE *WmIbDeviceGet(NET64 Guid)\r
75 {\r
76         WM_IB_DEVICE *dev;\r
77 \r
78         KeAcquireGuardedMutex(&Lock);\r
79         dev = WmIbDeviceFind(Guid);\r
80         if (dev != NULL) {\r
81                         InterlockedIncrement(&dev->Ref);\r
82         }\r
83         KeReleaseGuardedMutex(&Lock);\r
84         return dev;\r
85 }\r
86 \r
87 void WmIbDevicePut(WM_IB_DEVICE *pDevice)\r
88 {\r
89         if (InterlockedDecrement(&pDevice->Ref) == 0) {\r
90                 KeSetEvent(&pDevice->Event, 0, FALSE);\r
91         }\r
92 }\r
93 \r
94 static VOID WmIoDeviceControl(WDFQUEUE Queue, WDFREQUEST Request,\r
95                                                           size_t OutLen, size_t InLen, ULONG IoControlCode)\r
96 {\r
97         WDFFILEOBJECT   file;\r
98         WM_PROVIDER             *prov;\r
99         UNREFERENCED_PARAMETER(OutLen);\r
100         UNREFERENCED_PARAMETER(InLen);\r
101         UNREFERENCED_PARAMETER(Queue);\r
102 \r
103         file = WdfRequestGetFileObject(Request);\r
104         prov = WmProviderGetContext(file);\r
105 \r
106         switch (IoControlCode) {\r
107         case WM_IOCTL_REGISTER:\r
108                 WmRegister(prov, Request);\r
109                 break;\r
110         case WM_IOCTL_DEREGISTER:\r
111                 WmDeregister(prov, Request);\r
112                 break;\r
113         case WM_IOCTL_CANCEL:\r
114                 WmProviderCancel(prov, Request);\r
115                 break;\r
116         default:\r
117                 WdfRequestComplete(Request, STATUS_PROCEDURE_NOT_FOUND);\r
118                 break;\r
119         }\r
120 }\r
121 \r
122 static VOID WmIoRead(WDFQUEUE Queue, WDFREQUEST Request, size_t Length)\r
123 {\r
124         WDFFILEOBJECT   file;\r
125         WM_PROVIDER             *prov;\r
126         UNREFERENCED_PARAMETER(Queue);\r
127 \r
128         file = WdfRequestGetFileObject(Request);\r
129         prov = WmProviderGetContext(file);\r
130         WmProviderRead(prov, Request);\r
131 }\r
132 \r
133 static VOID WmIoWrite(WDFQUEUE Queue, WDFREQUEST Request, size_t Length)\r
134 {\r
135         WDFFILEOBJECT   file;\r
136         WM_PROVIDER             *prov;\r
137         UNREFERENCED_PARAMETER(Queue);\r
138 \r
139         file = WdfRequestGetFileObject(Request);\r
140         prov = WmProviderGetContext(file);\r
141         WmProviderWrite(prov, Request);\r
142 }\r
143 \r
144 static VOID WmFileCreate(WDFDEVICE Device, WDFREQUEST Request,\r
145                                                  WDFFILEOBJECT FileObject)\r
146 {\r
147         WM_PROVIDER     *prov = WmProviderGetContext(FileObject);\r
148         UNREFERENCED_PARAMETER(Device);\r
149 \r
150         WmProviderInit(prov);\r
151         KeAcquireGuardedMutex(&Lock);\r
152         InsertHeadList(&ProvList, &prov->Entry);\r
153         KeReleaseGuardedMutex(&Lock);\r
154         WdfRequestComplete(Request, STATUS_SUCCESS);\r
155 }\r
156 \r
157 static VOID WmFileCleanup(WDFFILEOBJECT FileObject)\r
158 {\r
159         WM_PROVIDER *prov = WmProviderGetContext(FileObject);\r
160 \r
161         KeAcquireGuardedMutex(&Lock);\r
162         RemoveEntryList(&prov->Entry);\r
163         KeReleaseGuardedMutex(&Lock);\r
164         WmProviderCleanup(prov);\r
165 }\r
166 \r
167 static VOID WmFileClose(WDFFILEOBJECT FileObject)\r
168 {\r
169         UNREFERENCED_PARAMETER(FileObject);\r
170 }\r
171 \r
172 static VOID WmCreateControlDevice(WDFDRIVER Driver)\r
173 {\r
174         PWDFDEVICE_INIT                 pinit;\r
175         WDF_FILEOBJECT_CONFIG   fileconfig;\r
176         WDF_OBJECT_ATTRIBUTES   attr;\r
177         WDF_IO_QUEUE_CONFIG             ioconfig;\r
178         NTSTATUS                                status;\r
179         WDFQUEUE                                queue;\r
180         DECLARE_CONST_UNICODE_STRING(name, L"\\Device\\WinMad");\r
181         DECLARE_CONST_UNICODE_STRING(symlink, L"\\DosDevices\\WinMad");\r
182 \r
183         pinit = WdfControlDeviceInitAllocate(Driver,\r
184                                                                                  &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);\r
185         if (pinit == NULL) {\r
186                         return;\r
187         }\r
188 \r
189         WdfDeviceInitSetExclusive(pinit, FALSE);\r
190         status = WdfDeviceInitAssignName(pinit, &name);\r
191         if (!NT_SUCCESS(status)) {\r
192                 goto err1;\r
193         }\r
194 \r
195         WDF_FILEOBJECT_CONFIG_INIT(&fileconfig, WmFileCreate, WmFileClose,\r
196                                                            WmFileCleanup);\r
197         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WM_PROVIDER);\r
198         WdfDeviceInitSetFileObjectConfig(pinit, &fileconfig, &attr);\r
199 \r
200         WDF_OBJECT_ATTRIBUTES_INIT(&attr);\r
201         status = WdfDeviceCreate(&pinit, &attr, &ControlDevice);\r
202         if (!NT_SUCCESS(status)) {\r
203                 goto err1;\r
204         }\r
205 \r
206         status = WdfDeviceCreateSymbolicLink(ControlDevice, &symlink);\r
207         if (!NT_SUCCESS(status)) {\r
208                 goto err2;\r
209         }\r
210 \r
211         WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioconfig, WdfIoQueueDispatchParallel);\r
212         ioconfig.EvtIoDeviceControl = WmIoDeviceControl;\r
213         ioconfig.EvtIoRead = WmIoRead;\r
214         ioconfig.EvtIoWrite = WmIoWrite;\r
215         status = WdfIoQueueCreate(ControlDevice, &ioconfig,\r
216                                                           WDF_NO_OBJECT_ATTRIBUTES, &queue);\r
217         if (!NT_SUCCESS(status)) {\r
218                 goto err2;\r
219         }\r
220 \r
221         WdfControlFinishInitializing(ControlDevice);\r
222         return;\r
223 \r
224 err2:\r
225         WdfObjectDelete(ControlDevice);\r
226         return;\r
227 err1:\r
228         WdfDeviceInitFree(pinit);\r
229 }\r
230 \r
231 static ib_ca_attr_t *WmQueryCaAttributes(WM_IB_DEVICE *pDevice)\r
232 {\r
233         ib_ca_attr_t    *attr;\r
234         UINT32                  size;\r
235         ib_api_status_t ib_status;\r
236 \r
237         size = 0;\r
238         ib_status = pDevice->VerbsInterface.Verbs.\r
239                                 query_ca(pDevice->VerbsInterface.Verbs.p_hca_dev, NULL, &size, NULL);\r
240         if (ib_status != IB_INSUFFICIENT_MEMORY) {\r
241                 attr = NULL;\r
242                 goto out;\r
243         }\r
244 \r
245         attr = ExAllocatePoolWithTag(PagedPool, size, 'acmw');\r
246         if (attr == NULL) {\r
247                 goto out;\r
248         }\r
249 \r
250         ib_status = pDevice->VerbsInterface.Verbs.\r
251                                 query_ca(pDevice->VerbsInterface.Verbs.p_hca_dev, attr, &size, NULL);\r
252         if (ib_status != IB_SUCCESS) {\r
253                 ExFreePool(attr);\r
254                 attr = NULL;\r
255         }\r
256 \r
257 out:\r
258         return attr;\r
259 }\r
260 \r
261 static NTSTATUS WmAddCa(WM_IB_DEVICE *pDevice)\r
262 {\r
263         NTSTATUS                status;\r
264         ib_api_status_t ib_status;\r
265         ib_ca_attr_t    *attr;\r
266         UINT32                  size;\r
267         UINT8                   i;\r
268 \r
269         attr = WmQueryCaAttributes(pDevice);\r
270         if (attr == NULL) {\r
271                 return STATUS_NO_MEMORY;\r
272         }\r
273 \r
274         size = sizeof(WM_IB_PORT) * attr->num_ports;\r
275         pDevice->pPortArray = ExAllocatePoolWithTag(PagedPool, size, 'pimw');\r
276         if (pDevice->pPortArray == NULL) {\r
277                 status = STATUS_NO_MEMORY;\r
278                 goto out;\r
279         }\r
280 \r
281         for (i = 0; i < attr->num_ports; i++) {\r
282                 pDevice->pPortArray[i].Guid = attr->p_port_attr[i].port_guid;\r
283         }\r
284         pDevice->PortCount = attr->num_ports;\r
285 \r
286         status = STATUS_SUCCESS;\r
287 out:\r
288         ExFreePool(attr);\r
289         return status;\r
290 }\r
291 \r
292 static NTSTATUS WmPowerD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE PreviousState)\r
293 {\r
294         WM_IB_DEVICE    *dev;\r
295         BOOLEAN                 create;\r
296         NTSTATUS                status;\r
297 \r
298         dev = WmIbDeviceGetContext(Device);\r
299         status = WdfFdoQueryForInterface(Device, &GUID_RDMA_INTERFACE_VERBS,\r
300                                                                          (PINTERFACE) &dev->VerbsInterface,\r
301                                                                          sizeof(dev->VerbsInterface), VerbsVersion(2, 0),\r
302                                                                          NULL);\r
303         if (!NT_SUCCESS(status)) {\r
304                 return status;\r
305         }\r
306 \r
307         dev->Guid = dev->VerbsInterface.Verbs.guid;\r
308         status = WmAddCa(dev);\r
309 \r
310         dev->VerbsInterface.InterfaceHeader.InterfaceDereference(dev->VerbsInterface.\r
311                                                                                                                          InterfaceHeader.Context);\r
312         if (!NT_SUCCESS(status)) {\r
313                 return status;\r
314         }\r
315 \r
316         status = WdfFdoQueryForInterface(Device, &GUID_IB_AL_INTERFACE,\r
317                                                                          (PINTERFACE) &dev->IbInterface,\r
318                                                                          sizeof(dev->IbInterface),\r
319                                                                          AL_INTERFACE_VERSION, NULL);\r
320         if (!NT_SUCCESS(status)) {\r
321                 return status;\r
322         }\r
323 \r
324         KeAcquireGuardedMutex(&Lock);\r
325         create = IsListEmpty(&DevList);\r
326         InsertHeadList(&DevList, &dev->Entry);\r
327         KeReleaseGuardedMutex(&Lock);\r
328 \r
329         if (create) {\r
330                 WmCreateControlDevice(WdfGetDriver());\r
331         }\r
332         return STATUS_SUCCESS;\r
333 }\r
334 \r
335 static NTSTATUS WmIbDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)\r
336 {\r
337         WDF_OBJECT_ATTRIBUTES                   attr;\r
338         WDF_PNPPOWER_EVENT_CALLBACKS    power;\r
339         WDFDEVICE                                               dev;\r
340         WM_IB_DEVICE                                    *pdev;\r
341         NTSTATUS                                                status;\r
342 \r
343         WdfFdoInitSetFilter(DeviceInit);\r
344 \r
345         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WM_IB_DEVICE);\r
346         attr.EvtCleanupCallback = WmIbDeviceCleanup;\r
347 \r
348         WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&power);\r
349         power.EvtDeviceD0Entry = WmPowerD0Entry;\r
350         WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &power);\r
351 \r
352         status = WdfDeviceCreate(&DeviceInit, &attr, &dev);\r
353         if (!NT_SUCCESS(status)) {\r
354                 return status;\r
355         }\r
356 \r
357         pdev = WmIbDeviceGetContext(dev);\r
358         RtlZeroMemory(pdev, sizeof *pdev);\r
359         pdev->Ref = 1;\r
360         KeInitializeEvent(&pdev->Event, NotificationEvent, FALSE);\r
361 \r
362         return STATUS_SUCCESS;\r
363 }\r
364 \r
365 static VOID WmIbDeviceCleanup(WDFDEVICE Device)\r
366 {\r
367         WM_PROVIDER                     *prov;\r
368         WM_IB_DEVICE            *pdev;\r
369         WM_REGISTRATION         *reg;\r
370         LIST_ENTRY                      *entry;\r
371         BOOLEAN                         destroy;\r
372         WDFDEVICE                       ctrldev;\r
373 \r
374         pdev = (WmIbDeviceGetContext(Device));\r
375 \r
376         KeAcquireGuardedMutex(&Lock);\r
377         RemoveEntryList(&pdev->Entry);\r
378         destroy = IsListEmpty(&DevList);\r
379         ctrldev = ControlDevice;\r
380 \r
381         for (entry = ProvList.Flink; entry != &ProvList; entry = entry->Flink) {\r
382                 prov = CONTAINING_RECORD(entry, WM_PROVIDER, Entry);\r
383                 WmProviderRemoveHandler(prov, pdev);\r
384         } \r
385         KeReleaseGuardedMutex(&Lock);\r
386 \r
387         if (InterlockedDecrement(&pdev->Ref) > 0) {\r
388                 KeWaitForSingleObject(&pdev->Event, Executive, KernelMode, FALSE, NULL);\r
389         }\r
390 \r
391         pdev->IbInterface.wdm.InterfaceDereference(pdev->IbInterface.wdm.Context);\r
392         if (pdev->pPortArray != NULL) {\r
393                 ExFreePool(pdev->pPortArray);\r
394         }\r
395 \r
396         if (destroy) {\r
397                 WdfObjectDelete(ctrldev);\r
398         }\r
399 }\r
400 \r
401 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)\r
402 {\r
403         WDF_DRIVER_CONFIG               config;\r
404         NTSTATUS                                status;\r
405         WDFDRIVER                               driv;\r
406 \r
407         InitializeListHead(&DevList);\r
408         InitializeListHead(&ProvList);\r
409         KeInitializeGuardedMutex(&Lock);\r
410 \r
411         WDF_DRIVER_CONFIG_INIT(&config, WmIbDeviceAdd);\r
412         status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,\r
413                                                          &config, &driv);\r
414         if (!NT_SUCCESS(status)) {\r
415                 return status;\r
416         }\r
417 \r
418         return STATUS_SUCCESS;\r
419 }\r