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