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 "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
49 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WV_RDMA_DEVICE, WvRdmaDeviceGetContext)
\r
51 WDFDEVICE ControlDevice;
\r
52 static LIST_ENTRY DevList;
\r
53 static LIST_ENTRY ProvList;
\r
54 static KGUARDED_MUTEX Lock;
\r
57 INFINIBAND_INTERFACE_CM IbCmInterface;
\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
67 WV_RDMA_DEVICE *WvRdmaDeviceGet(NET64 Guid)
\r
69 WV_RDMA_DEVICE *cur_dev, *dev = NULL;
\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
81 KeReleaseGuardedMutex(&Lock);
\r
85 void WvRdmaDevicePut(WV_RDMA_DEVICE *pDevice)
\r
87 if (InterlockedDecrement(&pDevice->Ref) == 0) {
\r
88 KeSetEvent(&pDevice->Event, 0, FALSE);
\r
93 void WvCompleteRequests(WDFQUEUE Queue, NTSTATUS ReqStatus)
\r
98 status = WdfIoQueueRetrieveNextRequest(Queue, &request);
\r
100 while (NT_SUCCESS(status)) {
\r
101 WdfRequestComplete(request, ReqStatus);
\r
102 status = WdfIoQueueRetrieveNextRequest(Queue, &request);
\r
106 void WvFlushQueue(WDFQUEUE Queue, NTSTATUS ReqStatus)
\r
108 WdfObjectAcquireLock(Queue);
\r
109 WvCompleteRequests(Queue, ReqStatus);
\r
110 WdfObjectReleaseLock(Queue);
\r
113 void WvCompleteRequestsWithInformation(WDFQUEUE Queue, NTSTATUS ReqStatus)
\r
115 WDFREQUEST request;
\r
120 status = WdfIoQueueRetrieveNextRequest(Queue, &request);
\r
122 while (NT_SUCCESS(status)) {
\r
124 WdfRequestRetrieveOutputBuffer(request, 0, &out, &outlen);
\r
125 WdfRequestCompleteWithInformation(request, ReqStatus, outlen);
\r
126 status = WdfIoQueueRetrieveNextRequest(Queue, &request);
\r
130 static void WvGuidQuery(WDFREQUEST Request)
\r
132 WV_IO_GUID_LIST *list;
\r
134 WV_RDMA_DEVICE *dev;
\r
139 status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_GUID_LIST),
\r
141 if (!NT_SUCCESS(status)) {
\r
145 count = (ULONG) ((len - sizeof(NET64)) / sizeof(NET64));
\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
152 list->Guid[i] = dev->Interface.Verbs.guid;
\r
153 len += sizeof(NET64);
\r
158 KeReleaseGuardedMutex(&Lock);
\r
161 WdfRequestCompleteWithInformation(Request, status, len);
\r
164 static void WvLibraryQuery(WDFREQUEST Request)
\r
168 size_t len = 0, bytes;
\r
169 WV_RDMA_DEVICE *dev;
\r
172 status = WdfRequestRetrieveInputBuffer(Request, sizeof(NET64), &guid, NULL);
\r
173 if (!NT_SUCCESS(status)) {
\r
176 status = WdfRequestRetrieveOutputBuffer(Request, 1, &name, &bytes);
\r
177 if (!NT_SUCCESS(status)) {
\r
181 dev = WvRdmaDeviceGet(*guid);
\r
183 status = STATUS_NO_SUCH_DEVICE;
\r
187 len = strlen(dev->Interface.Verbs.libname) + 1;
\r
188 if (bytes >= len) {
\r
189 RtlCopyMemory(name, dev->Interface.Verbs.libname, len);
\r
191 status = STATUS_BUFFER_TOO_SMALL;
\r
192 *name = (char) len;
\r
195 WvRdmaDevicePut(dev);
\r
198 WdfRequestCompleteWithInformation(Request, status, len);
\r
201 static VOID WvIoDeviceControl(WDFQUEUE Queue, WDFREQUEST Request,
\r
202 size_t OutLen, size_t InLen, ULONG IoControlCode)
\r
204 WDFFILEOBJECT file;
\r
206 UNREFERENCED_PARAMETER(OutLen);
\r
207 UNREFERENCED_PARAMETER(InLen);
\r
208 UNREFERENCED_PARAMETER(Queue);
\r
210 file = WdfRequestGetFileObject(Request);
\r
211 prov = WvProviderGetContext(file);
\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
218 case WV_IOCTL_LIBRARY_QUERY:
\r
219 WvLibraryQuery(Request);
\r
221 case WV_IOCTL_DEVICE_OPEN:
\r
222 WvDeviceOpen(prov, Request);
\r
224 case WV_IOCTL_DEVICE_CLOSE:
\r
225 WvDeviceClose(prov, Request);
\r
227 case WV_IOCTL_DEVICE_QUERY:
\r
228 WvDeviceQuery(prov, Request);
\r
230 case WV_IOCTL_DEVICE_PORT_QUERY:
\r
231 WvDevicePortQuery(prov, Request);
\r
233 case WV_IOCTL_DEVICE_GID_QUERY:
\r
234 WvDeviceGidQuery(prov, Request);
\r
236 case WV_IOCTL_DEVICE_PKEY_QUERY:
\r
237 WvDevicePkeyQuery(prov, Request);
\r
239 case WV_IOCTL_DEVICE_NOTIFY:
\r
240 WvDeviceNotify(prov, Request);
\r
242 case WV_IOCTL_DEVICE_CANCEL:
\r
243 WvDeviceCancel(prov, Request);
\r
245 case WV_IOCTL_PD_ALLOCATE:
\r
246 WvPdAllocate(prov, Request);
\r
248 case WV_IOCTL_PD_CANCEL:
\r
249 WvPdCancel(prov, Request);
\r
251 case WV_IOCTL_PD_DEALLOCATE:
\r
252 WvPdDeallocate(prov, Request);
\r
254 case WV_IOCTL_MEMORY_REGISTER:
\r
255 WvMrRegister(prov, Request);
\r
257 case WV_IOCTL_MEMORY_DEREGISTER:
\r
258 WvMrDeregister(prov, Request);
\r
260 case WV_IOCTL_MW_ALLOCATE:
\r
261 WvMwAllocate(prov, Request);
\r
263 case WV_IOCTL_MW_DEALLOCATE:
\r
264 WvMwDeallocate(prov, Request);
\r
266 case WV_IOCTL_AH_CREATE:
\r
267 WvAhCreate(prov, Request);
\r
269 case WV_IOCTL_AH_DESTROY:
\r
270 WvAhDestroy(prov, Request);
\r
272 case WV_IOCTL_CQ_CREATE:
\r
273 WvCqCreate(prov, Request);
\r
275 case WV_IOCTL_CQ_DESTROY:
\r
276 WvCqDestroy(prov, Request);
\r
278 case WV_IOCTL_CQ_RESIZE:
\r
279 WvCqResize(prov, Request);
\r
281 case WV_IOCTL_CQ_NOTIFY:
\r
282 WvCqNotify(prov, Request);
\r
284 case WV_IOCTL_CQ_CANCEL:
\r
285 WvCqCancel(prov, Request);
\r
287 case WV_IOCTL_SRQ_CREATE:
\r
288 WvSrqCreate(prov, Request);
\r
290 case WV_IOCTL_SRQ_DESTROY:
\r
291 WvSrqDestroy(prov, Request);
\r
293 case WV_IOCTL_SRQ_QUERY:
\r
294 WvSrqQuery(prov, Request);
\r
296 case WV_IOCTL_SRQ_MODIFY:
\r
297 WvSrqModify(prov, Request);
\r
299 case WV_IOCTL_SRQ_NOTIFY:
\r
300 WvSrqNotify(prov, Request);
\r
302 case WV_IOCTL_SRQ_CANCEL:
\r
303 WvSrqCancel(prov, Request);
\r
305 case WV_IOCTL_QP_CREATE:
\r
306 WvQpCreate(prov, Request);
\r
308 case WV_IOCTL_QP_DESTROY:
\r
309 WvQpDestroy(prov, Request);
\r
311 case WV_IOCTL_QP_QUERY:
\r
312 WvQpQuery(prov, Request);
\r
314 case WV_IOCTL_QP_MODIFY:
\r
315 WvQpModify(prov, Request);
\r
317 case WV_IOCTL_QP_ATTACH:
\r
318 WvQpAttach(prov, Request);
\r
320 case WV_IOCTL_QP_DETACH:
\r
321 WvQpDetach(prov, Request);
\r
323 case WV_IOCTL_QP_CANCEL:
\r
324 WvQpCancel(prov, Request);
\r
326 case WV_IOCTL_EP_CREATE:
\r
327 WvEpCreate(prov, Request);
\r
329 case WV_IOCTL_EP_DESTROY:
\r
330 WvEpDestroy(prov, Request);
\r
332 case WV_IOCTL_EP_MODIFY:
\r
333 WvEpModify(prov, Request);
\r
335 case WV_IOCTL_EP_BIND:
\r
336 WvEpBind(prov, Request);
\r
338 case WV_IOCTL_EP_REJECT:
\r
339 WvEpReject(prov, Request);
\r
341 case WV_IOCTL_EP_CONNECT:
\r
342 WvEpConnect(prov, Request);
\r
344 case WV_IOCTL_EP_ACCEPT:
\r
345 WvEpAccept(prov, Request);
\r
347 case WV_IOCTL_EP_DISCONNECT:
\r
348 WvEpDisconnect(prov, Request);
\r
350 case WV_IOCTL_EP_DISCONNECT_NOTIFY:
\r
351 WvEpDisconnectNotify(prov, Request);
\r
353 case WV_IOCTL_EP_QUERY:
\r
354 WvEpQuery(prov, Request);
\r
356 case WV_IOCTL_EP_LOOKUP:
\r
357 WvEpLookup(prov, Request);
\r
359 case WV_IOCTL_EP_MULTICAST_JOIN:
\r
360 WvEpMulticastJoin(prov, Request);
\r
362 case WV_IOCTL_EP_MULTICAST_LEAVE:
\r
363 WvEpMulticastLeave(prov, Request);
\r
365 case WV_IOCTL_EP_CANCEL:
\r
366 WvEpCancel(prov, Request);
\r
368 case WV_IOCTL_EP_LISTEN:
\r
369 WvEpListen(prov, Request);
\r
371 case WV_IOCTL_EP_GET_REQUEST:
\r
372 WvEpGetRequest(prov, Request);
\r
375 WdfRequestComplete(Request, STATUS_PROCEDURE_NOT_FOUND);
\r
380 static VOID WvFileCreate(WDFDEVICE Device, WDFREQUEST Request,
\r
381 WDFFILEOBJECT FileObject)
\r
383 WV_PROVIDER *prov = WvProviderGetContext(FileObject);
\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
392 WdfRequestComplete(Request, STATUS_SUCCESS);
\r
395 static VOID WvFileCleanup(WDFFILEOBJECT FileObject)
\r
397 WV_PROVIDER *prov = WvProviderGetContext(FileObject);
\r
399 KeAcquireGuardedMutex(&Lock);
\r
400 RemoveEntryList(&prov->Entry);
\r
401 KeReleaseGuardedMutex(&Lock);
\r
402 WvProviderCleanup(prov);
\r
405 static VOID WvFileClose(WDFFILEOBJECT FileObject)
\r
407 UNREFERENCED_PARAMETER(FileObject);
\r
410 static VOID WvCreateControlDevice(WDFDRIVER Driver)
\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
418 DECLARE_CONST_UNICODE_STRING(name, L"\\Device\\WinVerbs");
\r
419 DECLARE_CONST_UNICODE_STRING(symlink, L"\\DosDevices\\WinVerbs");
\r
421 pinit = WdfControlDeviceInitAllocate(Driver,
\r
422 &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);
\r
423 if (pinit == NULL) {
\r
427 WdfDeviceInitSetExclusive(pinit, FALSE);
\r
428 status = WdfDeviceInitAssignName(pinit, &name);
\r
429 if (!NT_SUCCESS(status)) {
\r
433 WDF_FILEOBJECT_CONFIG_INIT(&fileconfig, WvFileCreate, WvFileClose,
\r
435 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WV_PROVIDER);
\r
436 WdfDeviceInitSetFileObjectConfig(pinit, &fileconfig, &attr);
\r
438 WDF_OBJECT_ATTRIBUTES_INIT(&attr);
\r
439 status = WdfDeviceCreate(&pinit, &attr, &ControlDevice);
\r
440 if (!NT_SUCCESS(status)) {
\r
444 status = WdfDeviceCreateSymbolicLink(ControlDevice, &symlink);
\r
445 if (!NT_SUCCESS(status)) {
\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
457 WdfControlFinishInitializing(ControlDevice);
\r
461 WdfObjectDelete(ControlDevice);
\r
464 WdfDeviceInitFree(pinit);
\r
467 static NTSTATUS WvPowerD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE PreviousState)
\r
469 WV_RDMA_DEVICE *dev;
\r
473 dev = WvRdmaDeviceGetContext(Device);
\r
474 if (dev->hDevice != NULL) {
\r
475 return STATUS_SUCCESS;
\r
478 status = WdfFdoQueryForInterface(Device, &GUID_RDMA_INTERFACE_VERBS,
\r
479 (PINTERFACE) &dev->Interface,
\r
480 sizeof(dev->Interface), VerbsVersion(2, 0),
\r
482 if (!NT_SUCCESS(status)) {
\r
485 dev->hDevice = dev->Interface.Verbs.p_hca_obj;
\r
487 KeAcquireGuardedMutex(&Lock);
\r
488 create = IsListEmpty(&DevList);
\r
489 InsertHeadList(&DevList, &dev->Entry);
\r
490 KeReleaseGuardedMutex(&Lock);
\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
503 static NTSTATUS WvRdmaDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
\r
505 WDF_OBJECT_ATTRIBUTES attr;
\r
506 WDF_PNPPOWER_EVENT_CALLBACKS power;
\r
508 WV_RDMA_DEVICE *pdev;
\r
511 WdfFdoInitSetFilter(DeviceInit);
\r
513 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WV_RDMA_DEVICE);
\r
514 attr.EvtCleanupCallback = WvRdmaDeviceCleanup;
\r
516 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&power);
\r
517 power.EvtDeviceD0Entry = WvPowerD0Entry;
\r
518 WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &power);
\r
520 status = WdfDeviceCreate(&DeviceInit, &attr, &dev);
\r
521 if (!NT_SUCCESS(status)) {
\r
525 pdev = WvRdmaDeviceGetContext(dev);
\r
526 RtlZeroMemory(pdev, sizeof *pdev);
\r
528 KeInitializeEvent(&pdev->Event, NotificationEvent, FALSE);
\r
530 return STATUS_SUCCESS;
\r
533 static VOID WvRdmaDeviceCleanup(WDFDEVICE Device)
\r
535 WV_RDMA_DEVICE *pdev;
\r
541 pdev = WvRdmaDeviceGetContext(Device);
\r
542 if (pdev->hDevice == NULL) {
\r
546 KeAcquireGuardedMutex(&Lock);
\r
547 RemoveEntryList(&pdev->Entry);
\r
548 destroy = IsListEmpty(&DevList);
\r
549 ctrldev = ControlDevice;
\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
556 KeReleaseGuardedMutex(&Lock);
\r
558 if (InterlockedDecrement(&pdev->Ref) > 0) {
\r
559 KeWaitForSingleObject(&pdev->Event, Executive, KernelMode, FALSE, NULL);
\r
562 pdev->Interface.InterfaceHeader.InterfaceDereference(pdev->Interface.
\r
563 InterfaceHeader.Context);
\r
566 if (IbCmInterface.CM.create_id != NULL) {
\r
567 IbCmInterface.InterfaceHeader.InterfaceDereference(IbCmInterface.
\r
568 InterfaceHeader.Context);
\r
570 WdfObjectDelete(ctrldev);
\r
574 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
\r
576 WDF_DRIVER_CONFIG config;
\r
580 InitializeListHead(&DevList);
\r
581 InitializeListHead(&ProvList);
\r
582 KeInitializeGuardedMutex(&Lock);
\r
583 RandomSeed = (ULONG) (ULONG_PTR) DriverObject;
\r
585 WDF_DRIVER_CONFIG_INIT(&config, WvRdmaDeviceAdd);
\r
586 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
\r
588 if (!NT_SUCCESS(status)) {
\r
592 return STATUS_SUCCESS;
\r