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
30 #include "wv_driver.h"
\r
32 #include "wv_ioctl.h"
\r
34 void WvCqGet(WV_COMPLETION_QUEUE *pCq)
\r
36 InterlockedIncrement(&pCq->Ref);
\r
39 void WvCqPut(WV_COMPLETION_QUEUE *pCq)
\r
41 if (InterlockedDecrement(&pCq->Ref) == 0) {
\r
42 KeSetEvent(&pCq->Event, 0, FALSE);
\r
46 WV_COMPLETION_QUEUE *WvCqAcquire(WV_PROVIDER *pProvider, UINT64 Id)
\r
48 WV_COMPLETION_QUEUE *cq;
\r
50 KeAcquireGuardedMutex(&pProvider->Lock);
\r
51 WvProviderDisableRemove(pProvider);
\r
52 cq = IndexListAt(&pProvider->CqIndex, (SIZE_T) Id);
\r
53 if (cq != NULL && cq->hVerbsCq != NULL) {
\r
57 WvProviderEnableRemove(pProvider);
\r
59 KeReleaseGuardedMutex(&pProvider->Lock);
\r
64 void WvCqRelease(WV_COMPLETION_QUEUE *pCq)
\r
66 WvProviderEnableRemove(pCq->pDevice->pProvider);
\r
70 static void WvCqEventHandler(ib_event_rec_t *pEvent)
\r
72 WV_COMPLETION_QUEUE *cq = pEvent->context;
\r
73 WvFlushQueue(cq->Queue, STATUS_UNEXPECTED_IO_ERROR);
\r
74 WvFlushQueue(cq->ErrorQueue, STATUS_UNEXPECTED_IO_ERROR);
\r
77 static void WvCqHandler(void *Context)
\r
79 WV_COMPLETION_QUEUE *cq = Context;
\r
81 WvFlushQueue(cq->Queue, STATUS_SUCCESS);
\r
84 static NTSTATUS WvCqAlloc(WV_DEVICE *pDevice, UINT32 *pSize,
\r
85 WV_COMPLETION_QUEUE **ppCq, ci_umv_buf_t *pVerbsData)
\r
87 ib_api_status_t ib_status;
\r
88 WV_COMPLETION_QUEUE *cq;
\r
89 WDF_IO_QUEUE_CONFIG config;
\r
92 cq = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_COMPLETION_QUEUE), 'qcvw');
\r
94 return STATUS_NO_MEMORY;
\r
98 KeInitializeEvent(&cq->Event, NotificationEvent, FALSE);
\r
100 WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual);
\r
101 status = WdfIoQueueCreate(ControlDevice, &config,
\r
102 WDF_NO_OBJECT_ATTRIBUTES, &cq->Queue);
\r
103 if (!NT_SUCCESS(status)) {
\r
107 status = WdfIoQueueCreate(ControlDevice, &config,
\r
108 WDF_NO_OBJECT_ATTRIBUTES, &cq->ErrorQueue);
\r
109 if (!NT_SUCCESS(status)) {
\r
113 ib_status = pDevice->pVerbs->create_cq(pDevice->hVerbsDevice, cq,
\r
114 WvCqEventHandler, WvCqHandler,
\r
115 pSize, &cq->hVerbsCq, pVerbsData);
\r
116 if (ib_status != IB_SUCCESS) {
\r
117 status = STATUS_UNSUCCESSFUL;
\r
121 cq->pDevice = pDevice;
\r
122 cq->pVerbs = pDevice->pVerbs;
\r
124 return STATUS_SUCCESS;
\r
127 WdfObjectDelete(cq->ErrorQueue);
\r
129 WdfObjectDelete(cq->Queue);
\r
131 ExFreePoolWithTag(cq, 'qcvw');
\r
135 void WvCqCreate(WV_PROVIDER *pProvider, WDFREQUEST Request)
\r
137 WV_IO_ID *inid, *outid;
\r
138 size_t inlen, outlen;
\r
140 WV_COMPLETION_QUEUE *cq;
\r
142 ci_umv_buf_t verbsData;
\r
144 status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen);
\r
145 if (!NT_SUCCESS(status)) {
\r
148 status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);
\r
149 if (!NT_SUCCESS(status)) {
\r
153 dev = WvDeviceAcquire(pProvider, inid->Id);
\r
155 status = STATUS_NO_SUCH_DEVICE;
\r
159 WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID),
\r
160 outlen - sizeof(WV_IO_ID), inid + 1);
\r
161 status = WvCqAlloc(dev, &inid->Data, &cq, &verbsData);
\r
162 if (!NT_SUCCESS(status)) {
\r
166 KeAcquireGuardedMutex(&pProvider->Lock);
\r
167 outid->Id = IndexListInsertHead(&pProvider->CqIndex, cq);
\r
168 if (outid->Id == 0) {
\r
169 status = STATUS_NO_MEMORY;
\r
172 InsertHeadList(&dev->CqList, &cq->Entry);
\r
173 KeReleaseGuardedMutex(&pProvider->Lock);
\r
175 WvProviderEnableRemove(pProvider);
\r
176 outid->Data = inid->Data;
\r
177 outid->VerbInfo = verbsData.status;
\r
178 WdfRequestCompleteWithInformation(Request, status, outlen);
\r
182 KeReleaseGuardedMutex(&pProvider->Lock);
\r
185 WvDeviceRelease(dev);
\r
187 WdfRequestComplete(Request, status);
\r
190 void WvCqDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request)
\r
192 WV_COMPLETION_QUEUE *cq;
\r
196 status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);
\r
197 if (!NT_SUCCESS(status)) {
\r
201 KeAcquireGuardedMutex(&pProvider->Lock);
\r
202 WvProviderDisableRemove(pProvider);
\r
203 cq = IndexListAt(&pProvider->CqIndex, (SIZE_T) *id);
\r
205 status = STATUS_NOT_FOUND;
\r
206 } else if (cq->Ref > 1) {
\r
207 status = STATUS_ACCESS_DENIED;
\r
209 IndexListRemove(&pProvider->CqIndex, (SIZE_T) *id);
\r
210 RemoveEntryList(&cq->Entry);
\r
211 status = STATUS_SUCCESS;
\r
213 KeReleaseGuardedMutex(&pProvider->Lock);
\r
215 if (NT_SUCCESS(status)) {
\r
218 WvProviderEnableRemove(pProvider);
\r
220 WdfRequestComplete(Request, status);
\r
223 void WvCqFree(WV_COMPLETION_QUEUE *pCq)
\r
225 if (InterlockedDecrement(&pCq->Ref) > 0) {
\r
226 KeWaitForSingleObject(&pCq->Event, Executive, KernelMode, FALSE, NULL);
\r
229 if (pCq->hVerbsCq != NULL) {
\r
230 pCq->pVerbs->destroy_cq(pCq->hVerbsCq);
\r
233 WdfIoQueuePurgeSynchronously(pCq->Queue);
\r
234 WdfIoQueuePurgeSynchronously(pCq->ErrorQueue);
\r
235 WdfObjectDelete(pCq->Queue);
\r
236 WdfObjectDelete(pCq->ErrorQueue);
\r
237 WvDevicePut(pCq->pDevice);
\r
238 ExFreePoolWithTag(pCq, 'qcvw');
\r
241 void WvCqResize(WV_PROVIDER *pProvider, WDFREQUEST Request)
\r
243 WV_IO_ID *inid, *outid;
\r
244 size_t inlen, outlen, len = 0;
\r
245 WV_COMPLETION_QUEUE *cq;
\r
247 ib_api_status_t ib_status;
\r
248 ci_umv_buf_t verbsData;
\r
250 status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen);
\r
251 if (!NT_SUCCESS(status)) {
\r
254 status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);
\r
255 if (!NT_SUCCESS(status)) {
\r
259 cq = WvCqAcquire(pProvider, inid->Id);
\r
261 status = STATUS_NOT_FOUND;
\r
265 WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID),
\r
266 outlen - sizeof(WV_IO_ID), inid + 1);
\r
267 ib_status = cq->pVerbs->resize_cq(cq->hVerbsCq, &inid->Data, &verbsData);
\r
270 if (ib_status != IB_SUCCESS) {
\r
271 status = STATUS_UNSUCCESSFUL;
\r
275 outid->Data = inid->Data;
\r
276 outid->VerbInfo = verbsData.status;
\r
279 WdfRequestCompleteWithInformation(Request, status, len);
\r
282 void WvCqNotify(WV_PROVIDER *pProvider, WDFREQUEST Request)
\r
285 WV_COMPLETION_QUEUE *cq;
\r
289 status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, NULL);
\r
290 if (!NT_SUCCESS(status)) {
\r
294 cq = WvCqAcquire(pProvider, id->Id);
\r
296 status = STATUS_NOT_FOUND;
\r
300 queue = (id->Data == WV_CQ_ERROR) ? cq->ErrorQueue : cq->Queue;
\r
301 WdfObjectAcquireLock(queue);
\r
302 status = WdfRequestForwardToIoQueue(Request, queue);
\r
303 WdfObjectReleaseLock(queue);
\r
307 if (!NT_SUCCESS(status)) {
\r
308 WdfRequestComplete(Request, status);
\r
312 void WvCqCancel(WV_PROVIDER *pProvider, WDFREQUEST Request)
\r
315 WV_COMPLETION_QUEUE *cq;
\r
318 status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);
\r
319 if (!NT_SUCCESS(status)) {
\r
323 cq = WvCqAcquire(pProvider, *id);
\r
325 status = STATUS_NOT_FOUND;
\r
329 WvFlushQueue(cq->Queue, STATUS_CANCELLED);
\r
330 WvFlushQueue(cq->ErrorQueue, STATUS_CANCELLED);
\r
334 WdfRequestComplete(Request, status);
\r