[opensm] removed opensm\user\include\ib_types.h, even though it was not used, it...
[mirror/winof/.git] / core / winverbs / kernel / wv_cq.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 "wv_driver.h"\r
31 #include "wv_cq.h"\r
32 #include "wv_ioctl.h"\r
33 \r
34 void WvCqGet(WV_COMPLETION_QUEUE *pCq)\r
35 {\r
36         InterlockedIncrement(&pCq->Ref);\r
37 }\r
38 \r
39 void WvCqPut(WV_COMPLETION_QUEUE *pCq)\r
40 {\r
41         if (InterlockedDecrement(&pCq->Ref) == 0) {\r
42                 KeSetEvent(&pCq->Event, 0, FALSE);\r
43         }\r
44 }\r
45 \r
46 WV_COMPLETION_QUEUE *WvCqAcquire(WV_PROVIDER *pProvider, UINT64 Id)\r
47 {\r
48         WV_COMPLETION_QUEUE *cq;\r
49 \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
54                 WvCqGet(cq);\r
55         } else {\r
56                 cq = NULL;\r
57                 WvProviderEnableRemove(pProvider);\r
58         }\r
59         KeReleaseGuardedMutex(&pProvider->Lock);\r
60 \r
61         return cq;\r
62 }\r
63 \r
64 void WvCqRelease(WV_COMPLETION_QUEUE *pCq)\r
65 {\r
66         WvProviderEnableRemove(pCq->pDevice->pProvider);\r
67         WvCqPut(pCq);\r
68 }\r
69 \r
70 static void WvCqEventHandler(ib_event_rec_t *pEvent)\r
71 {\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
75 }\r
76 \r
77 static void WvCqHandler(void *Context)\r
78 {\r
79         WV_COMPLETION_QUEUE     *cq = Context;\r
80 \r
81         WvFlushQueue(cq->Queue, STATUS_SUCCESS);\r
82 }\r
83 \r
84 static NTSTATUS WvCqAlloc(WV_DEVICE *pDevice, UINT32 *pSize,\r
85                                                   WV_COMPLETION_QUEUE **ppCq, ci_umv_buf_t *pVerbsData)\r
86 {\r
87         ib_api_status_t         ib_status;\r
88         WV_COMPLETION_QUEUE     *cq;\r
89         WDF_IO_QUEUE_CONFIG     config;\r
90         NTSTATUS                        status;\r
91 \r
92         cq = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_COMPLETION_QUEUE), 'qcvw');\r
93         if (cq == NULL) {\r
94                 return STATUS_NO_MEMORY;\r
95         }\r
96 \r
97         cq->Ref = 1;\r
98         KeInitializeEvent(&cq->Event, NotificationEvent, FALSE);\r
99 \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
104                 goto err1;\r
105         }\r
106 \r
107         status = WdfIoQueueCreate(ControlDevice, &config,\r
108                                                           WDF_NO_OBJECT_ATTRIBUTES, &cq->ErrorQueue);\r
109         if (!NT_SUCCESS(status)) {\r
110                 goto err2;\r
111         }\r
112 \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
118                 goto err3;\r
119         }\r
120 \r
121         cq->pDevice = pDevice;\r
122         cq->pVerbs = pDevice->pVerbs;\r
123         *ppCq = cq;\r
124         return STATUS_SUCCESS;\r
125 \r
126 err3:\r
127         WdfObjectDelete(cq->ErrorQueue);\r
128 err2:\r
129         WdfObjectDelete(cq->Queue);\r
130 err1:\r
131         ExFreePoolWithTag(cq, 'qcvw');\r
132         return status;\r
133 }\r
134 \r
135 void WvCqCreate(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
136 {\r
137         WV_IO_ID                                *inid, *outid;\r
138         size_t                                  inlen, outlen;\r
139         WV_DEVICE                               *dev;\r
140         WV_COMPLETION_QUEUE             *cq;\r
141         NTSTATUS                                status;\r
142         ci_umv_buf_t                    verbsData;\r
143 \r
144         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen);\r
145         if (!NT_SUCCESS(status)) {\r
146                 goto err1;\r
147         }\r
148         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);\r
149         if (!NT_SUCCESS(status)) {\r
150                 goto err1;\r
151         }\r
152 \r
153         dev = WvDeviceAcquire(pProvider, inid->Id);\r
154         if (dev == NULL) {\r
155                 status = STATUS_NO_SUCH_DEVICE;\r
156                 goto err1;\r
157         }\r
158 \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
163                 goto err2;\r
164         }\r
165 \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
170                 goto err3;\r
171         }\r
172         InsertHeadList(&dev->CqList, &cq->Entry);\r
173         KeReleaseGuardedMutex(&pProvider->Lock);\r
174 \r
175         WvProviderEnableRemove(pProvider);\r
176         outid->Data = inid->Data;\r
177         outid->VerbInfo = verbsData.status;\r
178         WdfRequestCompleteWithInformation(Request, status, outlen);\r
179         return;\r
180 \r
181 err3:\r
182         KeReleaseGuardedMutex(&pProvider->Lock);\r
183         WvCqFree(cq);\r
184 err2:\r
185         WvDeviceRelease(dev);\r
186 err1:\r
187         WdfRequestComplete(Request, status);\r
188 }\r
189 \r
190 void WvCqDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
191 {\r
192         WV_COMPLETION_QUEUE             *cq;\r
193         UINT64                                  *id;\r
194         NTSTATUS                                status;\r
195 \r
196         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
197         if (!NT_SUCCESS(status)) {\r
198                 goto out;\r
199         }\r
200 \r
201         KeAcquireGuardedMutex(&pProvider->Lock);\r
202         WvProviderDisableRemove(pProvider);\r
203         cq = IndexListAt(&pProvider->CqIndex, (SIZE_T) *id);\r
204         if (cq == NULL) {\r
205                 status = STATUS_NOT_FOUND;\r
206         } else if (cq->Ref > 1) {\r
207                 status = STATUS_ACCESS_DENIED;\r
208         } else {\r
209                 IndexListRemove(&pProvider->CqIndex, (SIZE_T) *id);\r
210                 RemoveEntryList(&cq->Entry);\r
211                 status = STATUS_SUCCESS;\r
212         }\r
213         KeReleaseGuardedMutex(&pProvider->Lock);\r
214 \r
215         if (NT_SUCCESS(status)) {\r
216                 WvCqFree(cq);\r
217         }\r
218         WvProviderEnableRemove(pProvider);\r
219 out:\r
220         WdfRequestComplete(Request, status);\r
221 }\r
222 \r
223 void WvCqFree(WV_COMPLETION_QUEUE *pCq)\r
224 {\r
225         if (InterlockedDecrement(&pCq->Ref) > 0) {\r
226                 KeWaitForSingleObject(&pCq->Event, Executive, KernelMode, FALSE, NULL);\r
227         }\r
228 \r
229         if (pCq->hVerbsCq != NULL) {\r
230                 pCq->pVerbs->destroy_cq(pCq->hVerbsCq);\r
231         }\r
232 \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
239 }\r
240 \r
241 void WvCqResize(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
242 {\r
243         WV_IO_ID                                *inid, *outid;\r
244         size_t                                  inlen, outlen, len = 0;\r
245         WV_COMPLETION_QUEUE             *cq;\r
246         NTSTATUS                                status;\r
247         ib_api_status_t                 ib_status;\r
248         ci_umv_buf_t                    verbsData;\r
249 \r
250         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen);\r
251         if (!NT_SUCCESS(status)) {\r
252                 goto complete;\r
253         }\r
254         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);\r
255         if (!NT_SUCCESS(status)) {\r
256                 goto complete;\r
257         }\r
258 \r
259         cq = WvCqAcquire(pProvider, inid->Id);\r
260         if (cq == NULL) {\r
261                 status = STATUS_NOT_FOUND;\r
262                 goto complete;\r
263         }\r
264 \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
268         WvCqRelease(cq);\r
269 \r
270         if (ib_status != IB_SUCCESS) {\r
271                 status = STATUS_UNSUCCESSFUL;\r
272         }\r
273 \r
274         len = outlen;\r
275         outid->Data = inid->Data;\r
276         outid->VerbInfo = verbsData.status;\r
277 \r
278 complete:\r
279         WdfRequestCompleteWithInformation(Request, status, len);\r
280 }\r
281 \r
282 void WvCqNotify(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
283 {\r
284         WV_IO_ID                                *id;\r
285         WV_COMPLETION_QUEUE             *cq;\r
286         NTSTATUS                                status;\r
287         WDFQUEUE                                queue;\r
288 \r
289         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, NULL);\r
290         if (!NT_SUCCESS(status)) {\r
291                 goto out;\r
292         }\r
293 \r
294         cq = WvCqAcquire(pProvider, id->Id);\r
295         if (cq == NULL) {\r
296                 status = STATUS_NOT_FOUND;\r
297                 goto out;\r
298         }\r
299 \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
304         WvCqRelease(cq);\r
305 \r
306 out:\r
307         if (!NT_SUCCESS(status)) {\r
308                 WdfRequestComplete(Request, status);\r
309         }\r
310 }\r
311 \r
312 void WvCqCancel(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
313 {\r
314         UINT64                                  *id;\r
315         WV_COMPLETION_QUEUE             *cq;\r
316         NTSTATUS                                status;\r
317 \r
318         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
319         if (!NT_SUCCESS(status)) {\r
320                 goto out;\r
321         }\r
322 \r
323         cq = WvCqAcquire(pProvider, *id);\r
324         if (cq == NULL) {\r
325                 status = STATUS_NOT_FOUND;\r
326                 goto out;\r
327         }\r
328 \r
329         WvFlushQueue(cq->Queue, STATUS_CANCELLED);\r
330         WvFlushQueue(cq->ErrorQueue, STATUS_CANCELLED);\r
331         WvCqRelease(cq);\r
332 \r
333 out:\r
334         WdfRequestComplete(Request, status);\r
335 }\r