304588da201de8ca01a9fe75727b155a967fe812
[mirror/winof/.git] / core / winverbs / kernel / wv_pd.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_pd.h"\r
31 #include "wv_srq.h"\r
32 #include "wv_qp.h"\r
33 #include "wv_ioctl.h"\r
34 \r
35 void WvPdGet(WV_PROTECTION_DOMAIN *pPd)\r
36 {\r
37         InterlockedIncrement(&pPd->Ref);\r
38 }\r
39 \r
40 void WvPdPut(WV_PROTECTION_DOMAIN *pPd)\r
41 {\r
42         if (InterlockedDecrement(&pPd->Ref) == 0) {\r
43                 KeSetEvent(&pPd->Event, 0, FALSE);\r
44         }\r
45 }\r
46 \r
47 WV_PROTECTION_DOMAIN *WvPdAcquire(WV_PROVIDER *pProvider, UINT64 Id)\r
48 {\r
49         WV_PROTECTION_DOMAIN *pd;\r
50 \r
51         KeAcquireGuardedMutex(&pProvider->Lock);\r
52         WvProviderDisableRemove(pProvider);\r
53         pd = IndexListAt(&pProvider->PdIndex, (SIZE_T) Id);\r
54         if (pd != NULL && pd->hVerbsPd != NULL) {\r
55                 WvPdGet(pd);\r
56         } else {\r
57                 pd = NULL;\r
58                 WvProviderEnableRemove(pProvider);\r
59         }\r
60         KeReleaseGuardedMutex(&pProvider->Lock);\r
61 \r
62         return pd;\r
63 }\r
64 \r
65 void WvPdRelease(WV_PROTECTION_DOMAIN *pPd)\r
66 {\r
67         WvProviderEnableRemove(pPd->pDevice->pProvider);\r
68         WvPdPut(pPd);\r
69 }\r
70 \r
71 static NTSTATUS WvPdAlloc(WV_DEVICE *pDevice, WV_PROTECTION_DOMAIN **ppPd,\r
72                                                   ci_umv_buf_t *pVerbsData)\r
73 {\r
74         ib_api_status_t                 ib_status;\r
75         WV_PROTECTION_DOMAIN    *pd;\r
76 \r
77         pd = ExAllocatePoolWithTag(PagedPool, sizeof(WV_PROTECTION_DOMAIN), 'dpvw');\r
78         if (pd == NULL) {\r
79                 return STATUS_NO_MEMORY;\r
80         }\r
81 \r
82         pd->Ref = 1;\r
83         KeInitializeEvent(&pd->Event, NotificationEvent, FALSE);\r
84         InitializeListHead(&pd->QpList);\r
85         InitializeListHead(&pd->SrqList);\r
86         InitializeListHead(&pd->MwList);\r
87         InitializeListHead(&pd->AhList);\r
88         cl_qmap_init(&pd->MrMap);\r
89         KeInitializeGuardedMutex(&pd->Lock);\r
90 \r
91         ib_status = pDevice->pVerbs->allocate_pd(pDevice->hVerbsDevice, IB_PDT_NORMAL,\r
92                                                                                          &pd->hVerbsPd, pVerbsData);\r
93         if (ib_status != IB_SUCCESS) {\r
94                 goto err;\r
95         }\r
96 \r
97         WvDeviceGet(pDevice);\r
98         pd->pDevice = pDevice;\r
99         pd->pVerbs = pDevice->pVerbs;\r
100         *ppPd = pd;\r
101         return STATUS_SUCCESS;\r
102 \r
103 err:\r
104         ExFreePool(pd);\r
105         return STATUS_UNSUCCESSFUL;\r
106 }\r
107 \r
108 void WvPdAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
109 {\r
110         WV_IO_ID                                *inid, *outid;\r
111         size_t                                  inlen, outlen;\r
112         WV_DEVICE                               *dev;\r
113         WV_PROTECTION_DOMAIN    *pd;\r
114         NTSTATUS                                status;\r
115         ci_umv_buf_t                    verbsData;\r
116 \r
117         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen);\r
118         if (!NT_SUCCESS(status)) {\r
119                 goto err1;\r
120         }\r
121         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);\r
122         if (!NT_SUCCESS(status)) {\r
123                 goto err1;\r
124         }\r
125 \r
126         dev = WvDeviceAcquire(pProvider, inid->Id);\r
127         if (dev == NULL) {\r
128                 status = STATUS_NO_SUCH_DEVICE;\r
129                 goto err1;\r
130         }\r
131 \r
132         WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID),\r
133                                         outlen - sizeof(WV_IO_ID), inid + 1);\r
134         status = WvPdAlloc(dev, &pd, &verbsData);\r
135         if (!NT_SUCCESS(status)) {\r
136                 goto err2;\r
137         }\r
138 \r
139         KeAcquireGuardedMutex(&pProvider->Lock);\r
140         outid->Id = IndexListInsertHead(&pProvider->PdIndex, pd);\r
141         if (outid->Id == 0) {\r
142                 status = STATUS_NO_MEMORY;\r
143                 goto err3;\r
144         }\r
145         InsertHeadList(&dev->PdList, &pd->Entry);\r
146         KeReleaseGuardedMutex(&pProvider->Lock);\r
147 \r
148         WvDeviceRelease(dev);\r
149         outid->VerbInfo = verbsData.status;\r
150         WdfRequestCompleteWithInformation(Request, status, outlen);\r
151         return;\r
152 \r
153 err3:\r
154         KeReleaseGuardedMutex(&pProvider->Lock);\r
155         WvPdFree(pd);\r
156 err2:\r
157         WvDeviceRelease(dev);\r
158 err1:\r
159         WdfRequestComplete(Request, status);\r
160 }\r
161 \r
162 void WvPdDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
163 {\r
164         WV_PROTECTION_DOMAIN    *pd;\r
165         UINT64                                  *id;\r
166         NTSTATUS                                status;\r
167 \r
168         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
169         if (!NT_SUCCESS(status)) {\r
170                 goto out;\r
171         }\r
172 \r
173         KeAcquireGuardedMutex(&pProvider->Lock);\r
174         WvProviderDisableRemove(pProvider);\r
175         pd = IndexListAt(&pProvider->PdIndex, (SIZE_T) *id);\r
176         if (pd == NULL) {\r
177                 status = STATUS_NOT_FOUND;\r
178         } else if (pd->Ref > 1) {\r
179                 status = STATUS_ACCESS_DENIED;\r
180         } else {\r
181                 IndexListRemove(&pProvider->PdIndex, (SIZE_T) *id);\r
182                 RemoveEntryList(&pd->Entry);\r
183                 status = STATUS_SUCCESS;\r
184         }\r
185         KeReleaseGuardedMutex(&pProvider->Lock);\r
186 \r
187         if (NT_SUCCESS(status)) {\r
188                 WvPdFree(pd);\r
189         }\r
190         WvProviderEnableRemove(pProvider);\r
191 out:\r
192         WdfRequestComplete(Request, status);\r
193 }\r
194 \r
195 void WvPdCancel(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
196 {\r
197         WV_PROTECTION_DOMAIN    *pd;\r
198         UINT64                                  *id;\r
199         NTSTATUS                                status;\r
200 \r
201         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
202         if (!NT_SUCCESS(status)) {\r
203                 goto complete;\r
204         }\r
205 \r
206         pd = WvPdAcquire(pProvider, *id);\r
207         if (pd == NULL) {\r
208                 status = STATUS_NOT_FOUND;\r
209                 goto complete;\r
210         }\r
211 \r
212         // Registration is currently synchronous - nothing to do.\r
213         WvPdRelease(pd);\r
214 \r
215 complete:\r
216         WdfRequestComplete(Request, status);\r
217 }\r
218 \r
219 void WvPdFree(WV_PROTECTION_DOMAIN *pPd)\r
220 {\r
221         WV_MEMORY_REGION        *mr;\r
222         cl_map_item_t           *item;\r
223 \r
224         if (InterlockedDecrement(&pPd->Ref) > 0) {\r
225                 KeWaitForSingleObject(&pPd->Event, Executive, KernelMode, FALSE, NULL);\r
226         }\r
227 \r
228         for (item = cl_qmap_head(&pPd->MrMap); item != cl_qmap_end(&pPd->MrMap);\r
229                  item = cl_qmap_head(&pPd->MrMap)) {\r
230                 mr = CONTAINING_RECORD(item, WV_MEMORY_REGION, Item);\r
231                 if (mr->hVerbsMr != NULL) {\r
232                         pPd->pVerbs->deregister_mr(mr->hVerbsMr);\r
233                 }\r
234 \r
235                 cl_qmap_remove_item(&pPd->MrMap, &mr->Item);\r
236                 ExFreePool(mr);\r
237         }\r
238 \r
239         if (pPd->hVerbsPd != NULL) {\r
240                 pPd->pVerbs->deallocate_pd(pPd->hVerbsPd);\r
241         }\r
242 \r
243         WvDevicePut(pPd->pDevice);\r
244         ExFreePool(pPd);\r
245 }\r
246 \r
247 void WvPdRemoveHandler(WV_PROTECTION_DOMAIN *pPd)\r
248 {\r
249         WV_QUEUE_PAIR                   *qp;\r
250         WV_SHARED_RECEIVE_QUEUE *srq;\r
251         WV_MEMORY_REGION                *mr;\r
252         WV_ADDRESS_HANDLE               *ah;\r
253         WV_MEMORY_WINDOW                *mw;\r
254         cl_map_item_t                   *item;\r
255         LIST_ENTRY                              *entry;\r
256 \r
257         for (entry = pPd->MwList.Flink; entry != &pPd->MwList; entry = entry->Flink) {\r
258                 mw = CONTAINING_RECORD(entry, WV_MEMORY_WINDOW, Entry);\r
259                 pPd->pVerbs->destroy_mw(mw->hVerbsMw);\r
260                 mw->hVerbsMw = NULL;\r
261         }\r
262 \r
263         for (entry = pPd->AhList.Flink; entry != &pPd->AhList; entry = entry->Flink) {\r
264                 ah = CONTAINING_RECORD(entry, WV_ADDRESS_HANDLE, Entry);\r
265                 pPd->pVerbs->destroy_av(ah->hVerbsAh);\r
266                 ah->hVerbsAh = NULL;\r
267         }\r
268 \r
269         for (item = cl_qmap_head(&pPd->MrMap); item != cl_qmap_end(&pPd->MrMap);\r
270                  item = cl_qmap_next(item)) {\r
271                 mr = CONTAINING_RECORD(item, WV_MEMORY_REGION, Item);\r
272                 pPd->pVerbs->deregister_mr(mr->hVerbsMr);\r
273                 mr->hVerbsMr = NULL;\r
274         }\r
275 \r
276         for (entry = pPd->QpList.Flink; entry != &pPd->QpList; entry = entry->Flink) {\r
277                 qp = CONTAINING_RECORD(entry, WV_QUEUE_PAIR, Entry);\r
278                 WvQpRemoveHandler(qp);\r
279         }\r
280 \r
281         for (entry = pPd->SrqList.Flink; entry != &pPd->SrqList; entry = entry->Flink) {\r
282                 srq = CONTAINING_RECORD(entry, WV_SHARED_RECEIVE_QUEUE, Entry);\r
283                 pPd->pVerbs->destroy_srq(srq->hVerbsSrq);\r
284                 srq->hVerbsSrq = NULL;\r
285                 srq->pVerbs = NULL;\r
286         }\r
287 \r
288         pPd->pVerbs->deallocate_pd(pPd->hVerbsPd);\r
289         pPd->pVerbs = NULL;\r
290         pPd->hVerbsPd = NULL;\r
291 }\r
292 \r
293 void WvMrRegister(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
294 {\r
295         WV_IO_MEMORY_REGISTER   *reg;\r
296         WV_IO_MEMORY_KEYS               *keys;\r
297         WV_PROTECTION_DOMAIN    *pd;\r
298         WV_MEMORY_REGION                *mr;\r
299         ib_mr_create_t                  attr;\r
300         NTSTATUS                                status;\r
301         ib_api_status_t                 ib_status;\r
302 \r
303         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_MEMORY_REGISTER),\r
304                                                                                    &reg, NULL);\r
305         if (!NT_SUCCESS(status)) {\r
306                 goto err1;\r
307         }\r
308         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_MEMORY_KEYS),\r
309                                                                                         &keys, NULL);\r
310         if (!NT_SUCCESS(status)) {\r
311                 goto err1;\r
312         }\r
313 \r
314         pd = WvPdAcquire(pProvider, reg->Id);\r
315         if (pd == NULL) {\r
316                 status = STATUS_NOT_FOUND;\r
317                 goto err1;\r
318         }\r
319 \r
320         mr = ExAllocatePoolWithTag(PagedPool, sizeof(WV_MEMORY_REGION), 'rmvw');\r
321         if (mr == NULL) {\r
322                 status = STATUS_NO_MEMORY;\r
323                 goto err2;\r
324         }\r
325 \r
326         attr.access_ctrl = reg->AccessFlags;\r
327         attr.length = reg->BufferLength;\r
328         attr.vaddr = (void *) (ULONG_PTR) reg->Address;\r
329         ib_status = pd->pVerbs->register_mr(pd->hVerbsPd, &attr, &keys->Lkey,\r
330                                                                                 &keys->Rkey, &mr->hVerbsMr, TRUE);\r
331         if (ib_status != IB_SUCCESS) {\r
332                 status = STATUS_UNSUCCESSFUL;\r
333                 goto err3;\r
334         }\r
335 \r
336         KeAcquireGuardedMutex(&pd->Lock);\r
337         cl_qmap_insert(&pd->MrMap, keys->Lkey, &mr->Item);\r
338         KeReleaseGuardedMutex(&pd->Lock);\r
339 \r
340         WvPdRelease(pd);\r
341         WdfRequestCompleteWithInformation(Request, status, sizeof(WV_IO_MEMORY_KEYS));\r
342         return;\r
343 \r
344 err3:\r
345         ExFreePool(mr);\r
346 err2:\r
347         WvPdRelease(pd);\r
348 err1:\r
349         WdfRequestComplete(Request, status);\r
350 }\r
351 \r
352 void WvMrDeregister(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
353 {\r
354         WV_IO_ID                                *id;\r
355         WV_PROTECTION_DOMAIN    *pd;\r
356         WV_MEMORY_REGION                *mr;\r
357         cl_map_item_t                   *item;\r
358         NTSTATUS                                status;\r
359         ib_api_status_t                 ib_status;\r
360 \r
361         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, NULL);\r
362         if (!NT_SUCCESS(status)) {\r
363                 goto complete;\r
364         }\r
365 \r
366         pd = WvPdAcquire(pProvider, id->Id);\r
367         if (pd == NULL) {\r
368                 status = STATUS_NOT_FOUND;\r
369                 goto complete;\r
370         }\r
371 \r
372         KeAcquireGuardedMutex(&pd->Lock);\r
373         item = cl_qmap_remove(&pd->MrMap, id->Data);\r
374         KeReleaseGuardedMutex(&pd->Lock);\r
375 \r
376         if (item == cl_qmap_end(&pd->MrMap)) {\r
377                 status = STATUS_NOT_FOUND;\r
378                 goto release;\r
379         }\r
380 \r
381         mr = CONTAINING_RECORD(item, WV_MEMORY_REGION, Item);\r
382 \r
383         ib_status = pd->pVerbs->deregister_mr(mr->hVerbsMr);\r
384         if (ib_status != IB_SUCCESS) {\r
385                 status = STATUS_UNSUCCESSFUL;\r
386                 KeAcquireGuardedMutex(&pd->Lock);\r
387                 cl_qmap_insert(&pd->MrMap, id->Data, &mr->Item);\r
388                 KeReleaseGuardedMutex(&pd->Lock);\r
389                 goto release;\r
390         }\r
391 \r
392         ExFreePool(mr);\r
393 release:\r
394         WvPdRelease(pd);\r
395 complete:\r
396         WdfRequestComplete(Request, status);\r
397 }\r
398 \r
399 void WvMwAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
400 {\r
401         WV_IO_ID                                *inid, *outid;\r
402         size_t                                  inlen, outlen;\r
403         WV_PROTECTION_DOMAIN    *pd;\r
404         WV_MEMORY_WINDOW                *mw;\r
405         NTSTATUS                                status;\r
406         ib_api_status_t                 ib_status;\r
407         ci_umv_buf_t                    verbsData;\r
408 \r
409         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen);\r
410         if (!NT_SUCCESS(status)) {\r
411                 goto err1;\r
412         }\r
413         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);\r
414         if (!NT_SUCCESS(status)) {\r
415                 goto err1;\r
416         }\r
417 \r
418         pd = WvPdAcquire(pProvider, inid->Id);\r
419         if (pd == NULL) {\r
420                 status = STATUS_NOT_FOUND;\r
421                 goto err1;\r
422         }\r
423 \r
424         mw = ExAllocatePoolWithTag(PagedPool, sizeof(WV_MEMORY_WINDOW), 'wmvw');\r
425         if (mw == NULL) {\r
426                 status = STATUS_NO_MEMORY;\r
427                 goto err2;\r
428         }\r
429 \r
430         WvPdGet(pd);\r
431         mw->pPd = pd;\r
432 \r
433         WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID),\r
434                                         outlen - sizeof(WV_IO_ID), inid + 1);\r
435         ib_status = pd->pVerbs->create_mw(pd->hVerbsPd, &outid->Data, &mw->hVerbsMw,\r
436                                                                           &verbsData);\r
437         if (ib_status != IB_SUCCESS) {\r
438                 status = STATUS_UNSUCCESSFUL;\r
439                 goto err3;\r
440         }\r
441 \r
442         KeAcquireGuardedMutex(&pProvider->Lock);\r
443         outid->Id = IndexListInsertHead(&pProvider->MwIndex, mw);\r
444         if (outid->Id == 0) {\r
445                 status = STATUS_NO_MEMORY;\r
446                 goto err4;\r
447         }\r
448         InsertHeadList(&pd->MwList, &mw->Entry);\r
449         KeReleaseGuardedMutex(&pProvider->Lock);\r
450 \r
451         WvPdRelease(pd);\r
452         outid->VerbInfo = verbsData.status;\r
453         WdfRequestCompleteWithInformation(Request, status, outlen);\r
454         return;\r
455 \r
456 err4:\r
457         KeReleaseGuardedMutex(&pProvider->Lock);\r
458 err3:\r
459         WvMwFree(mw);\r
460 err2:\r
461         WvPdRelease(pd);\r
462 err1:\r
463         WdfRequestComplete(Request, status);\r
464 }\r
465 \r
466 void WvMwDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
467 {\r
468         WV_MEMORY_WINDOW        *mw;\r
469         UINT64                          *id;\r
470         NTSTATUS                        status;\r
471 \r
472         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
473         if (!NT_SUCCESS(status)) {\r
474                 goto out;\r
475         }\r
476 \r
477         KeAcquireGuardedMutex(&pProvider->Lock);\r
478         WvProviderDisableRemove(pProvider);\r
479         mw = IndexListAt(&pProvider->MwIndex, (SIZE_T) *id);\r
480         if (mw == NULL) {\r
481                 status = STATUS_NOT_FOUND;\r
482         } else {\r
483                 IndexListRemove(&pProvider->MwIndex, (SIZE_T) *id);\r
484                 RemoveEntryList(&mw->Entry);\r
485                 status = STATUS_SUCCESS;\r
486         }\r
487         KeReleaseGuardedMutex(&pProvider->Lock);\r
488 \r
489         if (NT_SUCCESS(status)) {\r
490                 WvMwFree(mw);\r
491         }\r
492         WvProviderEnableRemove(pProvider);\r
493 out:\r
494         WdfRequestComplete(Request, status);\r
495 }\r
496 \r
497 void WvMwFree(WV_MEMORY_WINDOW *pMw)\r
498 {\r
499         if (pMw->hVerbsMw != NULL) {\r
500                 pMw->pPd->pVerbs->destroy_mw(pMw->hVerbsMw);\r
501         }\r
502 \r
503         WvPdPut(pMw->pPd);\r
504         ExFreePool(pMw);\r
505 }\r
506 \r
507 static void WvVerbsConvertAv(ib_av_attr_t *pVerbsAv, WV_IO_AV *pAv)\r
508 {\r
509         pVerbsAv->grh_valid = pAv->NetworkRouteValid;\r
510         if (pVerbsAv->grh_valid) {\r
511                 pVerbsAv->grh.ver_class_flow =\r
512                         RtlUlongByteSwap(RtlUlongByteSwap(pAv->FlowLabel) | (pAv->TrafficClass << 20));\r
513                 pVerbsAv->grh.hop_limit = pAv->HopLimit;\r
514                 RtlCopyMemory(&pVerbsAv->grh.src_gid, pAv->SGid, sizeof(pAv->SGid));\r
515                 RtlCopyMemory(&pVerbsAv->grh.dest_gid, pAv->DGid, sizeof(pAv->DGid));\r
516         }\r
517 \r
518         pVerbsAv->port_num = pAv->PortNumber;\r
519         pVerbsAv->sl = pAv->ServiceLevel;\r
520         pVerbsAv->dlid = pAv->DLid;\r
521         pVerbsAv->static_rate = pAv->StaticRate;\r
522         pVerbsAv->path_bits = pAv->SourcePathBits;\r
523 }\r
524 \r
525 void WvAhCreate(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
526 {\r
527         size_t                                  inlen, outlen;\r
528         WV_PROTECTION_DOMAIN    *pd;\r
529         WV_ADDRESS_HANDLE               *ah;\r
530         WV_IO_AH_CREATE                 *pinAv, *poutAv;\r
531         ib_av_attr_t                    av;\r
532         NTSTATUS                                status;\r
533         ib_api_status_t                 ib_status;\r
534         ci_umv_buf_t                    verbsData;\r
535 \r
536         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_AH_CREATE),\r
537                                                                                    &pinAv, &inlen);\r
538         if (!NT_SUCCESS(status)) {\r
539                 goto err1;\r
540         }\r
541         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_AH_CREATE),\r
542                                                                                         &poutAv, &outlen);\r
543         if (!NT_SUCCESS(status)) {\r
544                 goto err1;\r
545         }\r
546 \r
547         pd = WvPdAcquire(pProvider, pinAv->Id.Id);\r
548         if (pd == NULL) {\r
549                 status = STATUS_NOT_FOUND;\r
550                 goto err1;\r
551         }\r
552 \r
553         ah = ExAllocatePoolWithTag(PagedPool, sizeof(WV_ADDRESS_HANDLE), 'havw');\r
554         if (ah == NULL) {\r
555                 status = STATUS_NO_MEMORY;\r
556                 goto err2;\r
557         }\r
558 \r
559         WvPdGet(pd);\r
560         ah->pPd = pd;\r
561 \r
562         WvVerbsConvertAv(&av, &pinAv->AddressVector);\r
563         WvInitVerbsData(&verbsData, pinAv->Id.VerbInfo, inlen - sizeof(WV_IO_AH_CREATE),\r
564                                         outlen - sizeof(WV_IO_AH_CREATE), pinAv + 1);\r
565         ib_status = pd->pVerbs->create_av(pd->hVerbsPd, &av, &ah->hVerbsAh, &verbsData);\r
566         if (ib_status != IB_SUCCESS) {\r
567                 status = STATUS_UNSUCCESSFUL;\r
568                 goto err3;\r
569         }\r
570 \r
571         KeAcquireGuardedMutex(&pProvider->Lock);\r
572         poutAv->Id.Id = IndexListInsertHead(&pProvider->AhIndex, ah);\r
573         if (poutAv->Id.Id == 0) {\r
574                 status = STATUS_NO_MEMORY;\r
575                 goto err4;\r
576         }\r
577         InsertHeadList(&pd->AhList, &ah->Entry);\r
578         KeReleaseGuardedMutex(&pProvider->Lock);\r
579 \r
580         WvPdRelease(pd);\r
581         poutAv->Id.VerbInfo = verbsData.status;\r
582         WdfRequestCompleteWithInformation(Request, status, outlen);\r
583         return;\r
584 \r
585 err4:\r
586         KeReleaseGuardedMutex(&pProvider->Lock);\r
587 err3:\r
588         WvAhFree(ah);\r
589 err2:\r
590         WvPdRelease(pd);\r
591 err1:\r
592         WdfRequestComplete(Request, status);\r
593 }\r
594 \r
595 void WvAhDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
596 {\r
597         WV_ADDRESS_HANDLE       *ah;\r
598         UINT64                          *id;\r
599         NTSTATUS                        status;\r
600 \r
601         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
602         if (!NT_SUCCESS(status)) {\r
603                 goto out;\r
604         }\r
605 \r
606         KeAcquireGuardedMutex(&pProvider->Lock);\r
607         WvProviderDisableRemove(pProvider);\r
608         ah = IndexListAt(&pProvider->AhIndex, (SIZE_T) *id);\r
609         if (ah == NULL) {\r
610                 status = STATUS_NOT_FOUND;\r
611         } else {\r
612                 IndexListRemove(&pProvider->AhIndex, (SIZE_T) *id);\r
613                 RemoveEntryList(&ah->Entry);\r
614                 status = STATUS_SUCCESS;\r
615         }\r
616         KeReleaseGuardedMutex(&pProvider->Lock);\r
617 \r
618         if (NT_SUCCESS(status)) {\r
619                 WvAhFree(ah);\r
620         }\r
621         WvProviderEnableRemove(pProvider);\r
622 out:\r
623         WdfRequestComplete(Request, status);\r
624 }\r
625 \r
626 void WvAhFree(WV_ADDRESS_HANDLE *pAh)\r
627 {\r
628         if (pAh->hVerbsAh != NULL) {\r
629                 pAh->pPd->pVerbs->destroy_av(pAh->hVerbsAh);\r
630         }\r
631 \r
632         WvPdPut(pAh->pPd);\r
633         ExFreePool(pAh);\r
634 }\r