2 * Copyright (c) 2008 Intel Corporation. All rights reserved.
\r
4 * This software is available to you under the OpenIB.org BSD license
\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
11 * - Redistributions of source code must retain the above
\r
12 * copyright notice, this list of conditions and the following
\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
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
33 #include <ntstatus.h>
\r
34 #include <initguid.h>
\r
36 #include "wm_ioctl.h"
\r
37 #include "wm_driver.h"
\r
38 #include "wm_provider.h"
\r
41 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WM_IB_DEVICE, WmIbDeviceGetContext)
\r
42 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WM_PROVIDER, WmProviderGetContext)
\r
44 WDFDEVICE ControlDevice;
\r
45 static LIST_ENTRY DevList;
\r
46 static LIST_ENTRY ProvList;
\r
47 static KGUARDED_MUTEX Lock;
\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
56 static WM_IB_DEVICE *WmIbDeviceFind(NET64 Guid)
\r
58 WM_IB_DEVICE *cur_dev, *dev = NULL;
\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
71 WM_IB_DEVICE *WmIbDeviceGet(NET64 Guid)
\r
75 KeAcquireGuardedMutex(&Lock);
\r
76 dev = WmIbDeviceFind(Guid);
\r
78 InterlockedIncrement(&dev->Ref);
\r
80 KeReleaseGuardedMutex(&Lock);
\r
84 void WmIbDevicePut(WM_IB_DEVICE *pDevice)
\r
86 if (InterlockedDecrement(&pDevice->Ref) == 0) {
\r
87 KeSetEvent(&pDevice->Event, 0, FALSE);
\r
91 static VOID WmIoDeviceControl(WDFQUEUE Queue, WDFREQUEST Request,
\r
92 size_t OutLen, size_t InLen, ULONG IoControlCode)
\r
96 UNREFERENCED_PARAMETER(OutLen);
\r
97 UNREFERENCED_PARAMETER(InLen);
\r
98 UNREFERENCED_PARAMETER(Queue);
\r
100 file = WdfRequestGetFileObject(Request);
\r
101 prov = WmProviderGetContext(file);
\r
103 switch (IoControlCode) {
\r
104 case WM_IOCTL_REGISTER:
\r
105 WmRegister(prov, Request);
\r
107 case WM_IOCTL_DEREGISTER:
\r
108 WmDeregister(prov, Request);
\r
110 case WM_IOCTL_CANCEL:
\r
111 WmProviderCancel(prov, Request);
\r
114 WdfRequestComplete(Request, STATUS_PROCEDURE_NOT_FOUND);
\r
119 static VOID WmIoRead(WDFQUEUE Queue, WDFREQUEST Request, size_t Length)
\r
121 WDFFILEOBJECT file;
\r
123 UNREFERENCED_PARAMETER(Queue);
\r
125 file = WdfRequestGetFileObject(Request);
\r
126 prov = WmProviderGetContext(file);
\r
127 WmProviderRead(prov, Request);
\r
130 static VOID WmIoWrite(WDFQUEUE Queue, WDFREQUEST Request, size_t Length)
\r
132 WDFFILEOBJECT file;
\r
134 UNREFERENCED_PARAMETER(Queue);
\r
136 file = WdfRequestGetFileObject(Request);
\r
137 prov = WmProviderGetContext(file);
\r
138 WmProviderWrite(prov, Request);
\r
141 static VOID WmFileCreate(WDFDEVICE Device, WDFREQUEST Request,
\r
142 WDFFILEOBJECT FileObject)
\r
144 WM_PROVIDER *prov = WmProviderGetContext(FileObject);
\r
145 UNREFERENCED_PARAMETER(Device);
\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
154 static VOID WmFileCleanup(WDFFILEOBJECT FileObject)
\r
156 WM_PROVIDER *prov = WmProviderGetContext(FileObject);
\r
158 KeAcquireGuardedMutex(&Lock);
\r
159 RemoveEntryList(&prov->Entry);
\r
160 KeReleaseGuardedMutex(&Lock);
\r
161 WmProviderCleanup(prov);
\r
164 static VOID WmFileClose(WDFFILEOBJECT FileObject)
\r
166 UNREFERENCED_PARAMETER(FileObject);
\r
169 static VOID WmCreateControlDevice(WDFDRIVER Driver)
\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
177 DECLARE_CONST_UNICODE_STRING(name, L"\\Device\\WinMad");
\r
178 DECLARE_CONST_UNICODE_STRING(symlink, L"\\DosDevices\\WinMad");
\r
180 pinit = WdfControlDeviceInitAllocate(Driver,
\r
181 &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);
\r
182 if (pinit == NULL) {
\r
186 WdfDeviceInitSetExclusive(pinit, FALSE);
\r
187 status = WdfDeviceInitAssignName(pinit, &name);
\r
188 if (!NT_SUCCESS(status)) {
\r
192 WDF_FILEOBJECT_CONFIG_INIT(&fileconfig, WmFileCreate, WmFileClose,
\r
194 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WM_PROVIDER);
\r
195 WdfDeviceInitSetFileObjectConfig(pinit, &fileconfig, &attr);
\r
197 WDF_OBJECT_ATTRIBUTES_INIT(&attr);
\r
198 status = WdfDeviceCreate(&pinit, &attr, &ControlDevice);
\r
199 if (!NT_SUCCESS(status)) {
\r
203 status = WdfDeviceCreateSymbolicLink(ControlDevice, &symlink);
\r
204 if (!NT_SUCCESS(status)) {
\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
218 WdfControlFinishInitializing(ControlDevice);
\r
222 WdfObjectDelete(ControlDevice);
\r
225 WdfDeviceInitFree(pinit);
\r
228 static ib_ca_attr_t *WmQueryCaAttributes(WM_IB_DEVICE *pDevice)
\r
230 ib_ca_attr_t *attr;
\r
232 ib_api_status_t ib_status;
\r
235 ib_status = pDevice->VerbsInterface.Verbs.
\r
236 query_ca(pDevice->VerbsInterface.Verbs.p_hca_dev, NULL, &size, NULL);
\r
237 if (ib_status != IB_INSUFFICIENT_MEMORY) {
\r
242 attr = ExAllocatePoolWithTag(PagedPool, size, 'acmw');
\r
243 if (attr == NULL) {
\r
247 ib_status = pDevice->VerbsInterface.Verbs.
\r
248 query_ca(pDevice->VerbsInterface.Verbs.p_hca_dev, attr, &size, NULL);
\r
249 if (ib_status != IB_SUCCESS) {
\r
258 static NTSTATUS WmAddCa(WM_IB_DEVICE *pDevice)
\r
261 ib_api_status_t ib_status;
\r
262 ib_ca_attr_t *attr;
\r
266 attr = WmQueryCaAttributes(pDevice);
\r
267 if (attr == NULL) {
\r
268 return STATUS_NO_MEMORY;
\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
278 for (i = 0; i < attr->num_ports; i++) {
\r
279 pDevice->pPortArray[i].Guid = attr->p_port_attr[i].port_guid;
\r
281 pDevice->PortCount = attr->num_ports;
\r
283 status = STATUS_SUCCESS;
\r
289 static NTSTATUS WmPowerD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE PreviousState)
\r
295 dev = WmIbDeviceGetContext(Device);
\r
296 RtlZeroMemory(dev, sizeof *dev);
\r
298 KeInitializeEvent(&dev->Event, NotificationEvent, FALSE);
\r
300 status = WdfFdoQueryForInterface(Device, &GUID_RDMA_INTERFACE_VERBS,
\r
301 (PINTERFACE) &dev->VerbsInterface,
\r
302 sizeof(dev->VerbsInterface), VerbsVersion(2, 0),
\r
304 if (!NT_SUCCESS(status)) {
\r
308 dev->Guid = dev->VerbsInterface.Verbs.guid;
\r
309 status = WmAddCa(dev);
\r
311 dev->VerbsInterface.InterfaceHeader.InterfaceDereference(dev->VerbsInterface.
\r
312 InterfaceHeader.Context);
\r
313 if (!NT_SUCCESS(status)) {
\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
325 KeAcquireGuardedMutex(&Lock);
\r
326 create = IsListEmpty(&DevList);
\r
327 InsertHeadList(&DevList, &dev->Entry);
\r
328 KeReleaseGuardedMutex(&Lock);
\r
331 WmCreateControlDevice(WdfGetDriver());
\r
333 return STATUS_SUCCESS;
\r
336 static NTSTATUS WmPowerD0Exit(WDFDEVICE Device, WDF_POWER_DEVICE_STATE TargetState)
\r
339 WM_IB_DEVICE *pdev;
\r
340 WM_REGISTRATION *reg;
\r
345 pdev = WmIbDeviceGetContext(Device);
\r
347 KeAcquireGuardedMutex(&Lock);
\r
348 RemoveEntryList(&pdev->Entry);
\r
349 destroy = IsListEmpty(&DevList);
\r
350 ctrldev = ControlDevice;
\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
356 KeReleaseGuardedMutex(&Lock);
\r
358 if (InterlockedDecrement(&pdev->Ref) > 0) {
\r
359 KeWaitForSingleObject(&pdev->Event, Executive, KernelMode, FALSE, NULL);
\r
362 pdev->IbInterface.wdm.InterfaceDereference(pdev->IbInterface.wdm.Context);
\r
363 if (pdev->pPortArray != NULL) {
\r
364 ExFreePool(pdev->pPortArray);
\r
368 WdfObjectDelete(ctrldev);
\r
371 return STATUS_SUCCESS;
\r
374 static NTSTATUS WmIbDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
\r
376 WDF_OBJECT_ATTRIBUTES attr;
\r
377 WDF_PNPPOWER_EVENT_CALLBACKS power;
\r
381 WdfFdoInitSetFilter(DeviceInit);
\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
389 status = WdfDeviceCreate(&DeviceInit, &attr, &dev);
\r
390 if (!NT_SUCCESS(status)) {
\r
394 return STATUS_SUCCESS;
\r
397 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
\r
399 WDF_DRIVER_CONFIG config;
\r
403 InitializeListHead(&DevList);
\r
404 InitializeListHead(&ProvList);
\r
405 KeInitializeGuardedMutex(&Lock);
\r
407 WDF_DRIVER_CONFIG_INIT(&config, WmIbDeviceAdd);
\r
408 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
\r
410 if (!NT_SUCCESS(status)) {
\r
414 return STATUS_SUCCESS;
\r