winverbs: free port array
[mirror/winof/.git] / core / winverbs / kernel / wv_device.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_device.h"\r
31 #include "wv_pd.h"\r
32 #include "wv_cq.h"\r
33 #include "wv_ioctl.h"\r
34 \r
35 void WvDeviceGet(WV_DEVICE *pDevice)\r
36 {\r
37         InterlockedIncrement(&pDevice->Ref);\r
38 }\r
39 \r
40 void WvDevicePut(WV_DEVICE *pDevice)\r
41 {\r
42         if (InterlockedDecrement(&pDevice->Ref) == 0) {\r
43                 KeSetEvent(&pDevice->Event, 0, FALSE);\r
44         }\r
45 }\r
46 \r
47 WV_DEVICE *WvDeviceAcquire(WV_PROVIDER *pProvider, UINT64 Id)\r
48 {\r
49         WV_DEVICE *dev;\r
50 \r
51         KeAcquireGuardedMutex(&pProvider->Lock);\r
52         WvProviderDisableRemove(pProvider);\r
53         dev = IndexListAt(&pProvider->DevIndex, (SIZE_T) Id);\r
54         if (dev != NULL && dev->hVerbsDevice != NULL) {\r
55                 WvDeviceGet(dev);\r
56         } else {\r
57                 dev = NULL;\r
58                 WvProviderEnableRemove(pProvider);\r
59         }\r
60         KeReleaseGuardedMutex(&pProvider->Lock);\r
61 \r
62         return dev;\r
63 }\r
64 \r
65 void WvDeviceRelease(WV_DEVICE *pDevice)\r
66 {\r
67         WvProviderEnableRemove(pDevice->pProvider);\r
68         WvDevicePut(pDevice);\r
69 }\r
70 \r
71 static UINT32 WvDeviceConvertEvent(ib_async_event_t event)\r
72 {\r
73         switch (event) {\r
74         case IB_AE_LOCAL_FATAL:\r
75                 return WV_IO_EVENT_ERROR;\r
76         case IB_AE_PORT_ACTIVE:\r
77         case IB_AE_PORT_DOWN:\r
78                 return WV_IO_EVENT_STATE;\r
79         case IB_AE_CLIENT_REREGISTER:\r
80         case IB_AE_SM_CHANGE:\r
81                 return WV_IO_EVENT_MANAGEMENT;\r
82         case IB_AE_GID_CHANGE:\r
83                 return WV_IO_EVENT_ADDRESS;\r
84         case IB_AE_LID_CHANGE:\r
85                 return WV_IO_EVENT_LINK_ADDRESS;\r
86         case IB_AE_PKEY_CHANGE:\r
87                 return WV_IO_EVENT_PARTITION;\r
88         default:\r
89                 return 0;\r
90         }\r
91 }\r
92 \r
93 static void WvDeviceCompleteRequests(WV_PORT *pPort, NTSTATUS ReqStatus, UINT32 Event)\r
94 {\r
95         WDFREQUEST      request;\r
96         NTSTATUS        status;\r
97         UINT32          *flags;\r
98 \r
99         WdfObjectAcquireLock(pPort->Queue);\r
100         pPort->Flags |= Event;\r
101         Event = pPort->Flags;\r
102 \r
103         status = WdfIoQueueRetrieveNextRequest(pPort->Queue, &request);\r
104         while (NT_SUCCESS(status)) {\r
105                 pPort->Flags = 0;\r
106 \r
107                 status = WdfRequestRetrieveOutputBuffer(request, sizeof(UINT32), &flags, NULL);\r
108                 if (NT_SUCCESS(status)) {\r
109                         *flags = Event;\r
110                         WdfRequestCompleteWithInformation(request, ReqStatus, sizeof(UINT32));\r
111                 } else {\r
112                         WdfRequestComplete(request, status);\r
113                 }\r
114                 status = WdfIoQueueRetrieveNextRequest(pPort->Queue, &request);\r
115         }\r
116 \r
117         WdfObjectReleaseLock(pPort->Queue);\r
118 }\r
119 \r
120 static void WvDeviceEventHandler(ib_event_rec_t *pEvent)\r
121 {\r
122         WV_DEVICE       *dev;\r
123         UINT32          event;\r
124         UINT8           i;\r
125 \r
126         event = WvDeviceConvertEvent(pEvent->type);\r
127         if (event == 0) {\r
128                 return;\r
129         }\r
130 \r
131         dev = CONTAINING_RECORD(pEvent->context, WV_DEVICE, EventHandler);\r
132 \r
133         if (event == WV_IO_EVENT_ERROR) {\r
134                 for (i = 0; i < dev->PortCount; i++) {\r
135                         WvDeviceCompleteRequests(&dev->pPorts[i], STATUS_SUCCESS, event);\r
136                 }\r
137         } else {\r
138                 WvDeviceCompleteRequests(&dev->pPorts[pEvent->port_number - 1],\r
139                                                                  STATUS_SUCCESS, event);\r
140         }\r
141 }\r
142 \r
143 static WV_DEVICE *WvDeviceAlloc(WV_PROVIDER *pProvider)\r
144 {\r
145         WV_DEVICE       *dev;\r
146 \r
147         dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_DEVICE), 'cdvw');\r
148         if (dev == NULL) {\r
149                 return NULL;\r
150         }\r
151 \r
152         dev->pDevice = NULL;\r
153         dev->pVerbs = NULL;\r
154         dev->hVerbsDevice = NULL;\r
155         dev->pPorts = NULL;\r
156         dev->PortCount = 0;\r
157         dev->Ref = 1;\r
158         InitializeListHead(&dev->PdList);\r
159         InitializeListHead(&dev->CqList);\r
160         KeInitializeEvent(&dev->Event, NotificationEvent, FALSE);\r
161         dev->EventHandler.pfn_async_event_cb = WvDeviceEventHandler;\r
162 \r
163         dev->pProvider = pProvider;\r
164         WvProviderGet(pProvider);\r
165         return dev;\r
166 }\r
167 \r
168 static ib_ca_attr_t *WvQueryCaAttributes(WV_DEVICE *pDevice)\r
169 {\r
170         ib_ca_attr_t    *attr;\r
171         UINT32                  size;\r
172         ib_api_status_t ib_status;\r
173 \r
174         size = 0;\r
175         ib_status = pDevice->pVerbs->query_ca(pDevice->pDevice->hDevice, NULL,\r
176                                                                                   &size, NULL);\r
177         if (ib_status != IB_INSUFFICIENT_MEMORY) {\r
178                 attr = NULL;\r
179                 goto out;\r
180         }\r
181 \r
182         attr = ExAllocatePoolWithTag(PagedPool, size, 'acvw');\r
183         if (attr == NULL) {\r
184                 goto out;\r
185         }\r
186 \r
187         ib_status = pDevice->pVerbs->query_ca(pDevice->pDevice->hDevice, attr,\r
188                                                                                   &size, NULL);\r
189         if (ib_status != IB_SUCCESS) {\r
190                 ExFreePool(attr);\r
191                 attr = NULL;\r
192         }\r
193 \r
194 out:\r
195         return attr;\r
196 }\r
197 \r
198 static NTSTATUS WvDeviceCreatePorts(WV_DEVICE *pDevice)\r
199 {\r
200         WDF_IO_QUEUE_CONFIG     config;\r
201         ib_ca_attr_t            *attr;\r
202         NTSTATUS                        status;\r
203         UINT8                           i;\r
204 \r
205         attr = WvQueryCaAttributes(pDevice);\r
206         if (attr == NULL) {\r
207                 return STATUS_NO_MEMORY;\r
208         }\r
209 \r
210         pDevice->PortCount = attr->num_ports;\r
211         ExFreePool(attr);\r
212 \r
213         pDevice->pPorts = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_PORT) *\r
214                                                                                         pDevice->PortCount, 'cpvw');\r
215         if (pDevice->pPorts == NULL) {\r
216                 return STATUS_NO_MEMORY;\r
217         }\r
218 \r
219         WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual);\r
220         for (i = 0; i < pDevice->PortCount; i++) {\r
221                 pDevice->pPorts[i].Flags = 0;\r
222                 status = WdfIoQueueCreate(ControlDevice, &config, WDF_NO_OBJECT_ATTRIBUTES,\r
223                                                                   &pDevice->pPorts[i].Queue);\r
224                 if (!NT_SUCCESS(status)) {\r
225                         goto err;\r
226                 }\r
227         }\r
228 \r
229         return STATUS_SUCCESS;\r
230 \r
231 err:\r
232         while (i-- > 0) {\r
233                 WdfObjectDelete(pDevice->pPorts[i].Queue);\r
234         }\r
235         pDevice->PortCount = 0;\r
236         return status;\r
237 }\r
238 \r
239 static NTSTATUS WvDeviceInit(WV_DEVICE *pDevice, NET64 Guid,\r
240                                                          ci_umv_buf_t *pVerbsData)\r
241 {\r
242         WV_RDMA_DEVICE *dev;\r
243         ib_api_status_t ib_status;\r
244         NTSTATUS                status;\r
245 \r
246         dev = WvRdmaDeviceGet(Guid);\r
247         if (dev == NULL) {\r
248                 return STATUS_NO_SUCH_DEVICE;\r
249         }\r
250 \r
251         pDevice->pDevice = dev;\r
252         pDevice->pVerbs = &dev->Interface.Verbs;\r
253 \r
254         ib_status = pDevice->pVerbs->um_open_ca(dev->hDevice, pVerbsData,\r
255                                                                                         &pDevice->hVerbsDevice);\r
256         if (ib_status != IB_SUCCESS) {\r
257                 goto err1;\r
258         }\r
259 \r
260         status = WvDeviceCreatePorts(pDevice);\r
261         if (!NT_SUCCESS(status)) {\r
262                 goto err2;\r
263         }\r
264 \r
265         pDevice->pVerbs->register_event_handler(dev->hDevice, &pDevice->EventHandler);\r
266         return STATUS_SUCCESS;\r
267 \r
268 err2:\r
269         pDevice->pVerbs->um_close_ca(dev->hDevice, pDevice->hVerbsDevice);\r
270 err1:\r
271         WvRdmaDevicePut(dev);\r
272         pDevice->hVerbsDevice = NULL;\r
273         return STATUS_UNSUCCESSFUL;\r
274 }\r
275 \r
276 void WvDeviceOpen(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
277 {\r
278         WV_IO_ID                *inid, *outid;\r
279         size_t                  inlen, outlen;\r
280         WV_DEVICE               *dev;\r
281         NTSTATUS                status;\r
282         ci_umv_buf_t    verbsData;\r
283 \r
284         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen);\r
285         if (!NT_SUCCESS(status)) {\r
286                 goto err1;\r
287         }\r
288         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);\r
289         if (!NT_SUCCESS(status)) {\r
290                 goto err1;\r
291         }\r
292 \r
293         dev = WvDeviceAlloc(pProvider);\r
294         if (dev == NULL) {\r
295                 status = STATUS_NO_MEMORY;\r
296                 goto err1;\r
297         }\r
298 \r
299         KeAcquireGuardedMutex(&pProvider->Lock);\r
300         WvProviderDisableRemove(pProvider);\r
301         KeReleaseGuardedMutex(&pProvider->Lock);\r
302 \r
303         WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID),\r
304                                         outlen - sizeof(WV_IO_ID), inid + 1);\r
305         status = WvDeviceInit(dev, inid->Id, &verbsData);\r
306         if (!NT_SUCCESS(status)) {\r
307                 goto err2;\r
308         }\r
309 \r
310         KeAcquireGuardedMutex(&pProvider->Lock);\r
311         outid->Id = IndexListInsertHead(&pProvider->DevIndex, dev);\r
312         if (outid->Id == 0) {\r
313                 status = STATUS_NO_MEMORY;\r
314                 goto err2;\r
315         }\r
316         KeReleaseGuardedMutex(&pProvider->Lock);\r
317 \r
318         WvProviderEnableRemove(pProvider);\r
319         outid->VerbInfo = verbsData.status;\r
320         WdfRequestCompleteWithInformation(Request, status, outlen);\r
321         return;\r
322 \r
323 err2:\r
324         WvDeviceFree(dev);\r
325         WvProviderEnableRemove(pProvider);\r
326 err1:\r
327         WdfRequestComplete(Request, status);\r
328 }\r
329 \r
330 void WvDeviceClose(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
331 {\r
332         WV_DEVICE       *dev;\r
333         UINT64          *id;\r
334         NTSTATUS        status;\r
335 \r
336         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
337         if (!NT_SUCCESS(status)) {\r
338                 goto out;\r
339         }\r
340 \r
341         KeAcquireGuardedMutex(&pProvider->Lock);\r
342         WvProviderDisableRemove(pProvider);\r
343         dev = IndexListAt(&pProvider->DevIndex, (SIZE_T) *id);\r
344         if (dev == NULL) {\r
345                 status = STATUS_NO_SUCH_DEVICE;\r
346         } else if (dev->Ref > 1) {\r
347                 status = STATUS_ACCESS_DENIED;\r
348         } else {\r
349                 IndexListRemove(&pProvider->DevIndex, (SIZE_T) *id);\r
350                 status = STATUS_SUCCESS;\r
351         }\r
352         KeReleaseGuardedMutex(&pProvider->Lock);\r
353 \r
354         if (NT_SUCCESS(status)) {\r
355                 WvDeviceFree(dev);\r
356         }\r
357         WvProviderEnableRemove(pProvider);\r
358 out:\r
359         WdfRequestComplete(Request, status);\r
360 }\r
361 \r
362 static void WvDeviceFreePorts(WV_DEVICE *pDevice)\r
363 {\r
364         UINT8 i;\r
365 \r
366         for (i = 0; i < pDevice->PortCount; i++) {\r
367                 WdfIoQueuePurgeSynchronously(pDevice->pPorts[i].Queue);\r
368                 WdfObjectDelete(pDevice->pPorts[i].Queue);\r
369         }\r
370         if (pDevice->pPorts != NULL) {\r
371                 ExFreePoolWithTag(pDevice->pPorts, 'cpvw');\r
372         }\r
373 }\r
374 \r
375 void WvDeviceFree(WV_DEVICE *pDevice)\r
376 {\r
377         if (InterlockedDecrement(&pDevice->Ref) > 0) {\r
378                 KeWaitForSingleObject(&pDevice->Event, Executive, KernelMode, FALSE, NULL);\r
379         }\r
380 \r
381         if (pDevice->hVerbsDevice != NULL) {\r
382                 pDevice->pVerbs->unregister_event_handler(pDevice->pDevice->hDevice,\r
383                                                                                                   &pDevice->EventHandler);\r
384                 pDevice->pVerbs->um_close_ca(pDevice->pDevice->hDevice,\r
385                                                                          pDevice->hVerbsDevice);\r
386                 WvRdmaDevicePut(pDevice->pDevice);\r
387         }\r
388 \r
389         WvDeviceFreePorts(pDevice);\r
390         WvProviderPut(pDevice->pProvider);\r
391         ExFreePool(pDevice);\r
392 }\r
393 \r
394 void WvDeviceRemoveHandler(WV_DEVICE *pDevice)\r
395 {\r
396         LIST_ENTRY                              *entry;\r
397         WV_PROTECTION_DOMAIN    *pd;\r
398         WV_COMPLETION_QUEUE             *cq;\r
399 \r
400         for (entry = pDevice->PdList.Flink; entry != &pDevice->PdList;\r
401                  entry = entry->Flink) {\r
402                 pd = CONTAINING_RECORD(entry, WV_PROTECTION_DOMAIN, Entry);\r
403                 WvPdRemoveHandler(pd);\r
404         }\r
405 \r
406         for (entry = pDevice->CqList.Flink; entry != &pDevice->CqList;\r
407                  entry = entry->Flink) {\r
408                 cq = CONTAINING_RECORD(entry, WV_COMPLETION_QUEUE, Entry);\r
409                 pDevice->pVerbs->destroy_cq(cq->hVerbsCq);\r
410                 cq->hVerbsCq = NULL;\r
411                 cq->pVerbs = NULL;\r
412         }\r
413 \r
414         pDevice->pVerbs->um_close_ca(pDevice->pDevice->hDevice,\r
415                                                                  pDevice->hVerbsDevice);\r
416         WvRdmaDevicePut(pDevice->pDevice);\r
417         pDevice->pDevice = NULL;\r
418         pDevice->pVerbs = NULL;\r
419         pDevice->hVerbsDevice = NULL;\r
420 }\r
421 \r
422 static void WvSetDeviceCap(UINT32 *pFlags, ib_ca_attr_t *pCaAttr)\r
423 {\r
424         *pFlags = 0;\r
425 \r
426         *pFlags |= pCaAttr->bad_pkey_ctr_support ? WV_IO_BAD_PKEY_COUNTER : 0;\r
427         *pFlags |= pCaAttr->bad_qkey_ctr_support ? WV_IO_BAD_QKEY_COUNTER : 0;\r
428         *pFlags |= pCaAttr->apm_support ? WV_IO_PATH_MIGRATION : 0;\r
429         *pFlags |= pCaAttr->av_port_check ? WV_IO_AH_PORT_CHECKING : 0;\r
430         *pFlags |= pCaAttr->change_primary_port ? WV_IO_CHANGE_PHYSICAL_PORT : 0;\r
431         *pFlags |= pCaAttr->modify_wr_depth ? WV_IO_RESIZE_MAX_WR : 0;\r
432         *pFlags |= pCaAttr->modify_srq_depth ? WV_IO_SRQ_RESIZE : 0;\r
433         *pFlags |= pCaAttr->current_qp_state_support ? WV_IO_QP_STATE_MODIFIER : 0;\r
434         *pFlags |= pCaAttr->shutdown_port_capability ? WV_IO_SHUTDOWN_PORT : 0;\r
435         *pFlags |= pCaAttr->init_type_support ? WV_IO_INIT_TYPE : 0;\r
436         *pFlags |= pCaAttr->port_active_event_support ? WV_IO_PORT_ACTIVE_EVENT : 0;\r
437         *pFlags |= pCaAttr->system_image_guid_support ? WV_IO_SYSTEM_IMAGE_GUID : 0;\r
438         *pFlags |= WV_IO_RC_RNR_NAK_GENERATION;\r
439         *pFlags |= WV_IO_BATCH_NOTIFY_CQ;\r
440 }\r
441 \r
442 static void WvSetDevicePages(UINT32 *pFlags, ib_ca_attr_t *pCaAttr)\r
443 {\r
444         unsigned int i;\r
445         UINT32 size;\r
446 \r
447         *pFlags = 0;\r
448 \r
449         for (i = 0; i < pCaAttr->num_page_sizes; i++) {\r
450                 size = pCaAttr->p_page_size[i];\r
451                 *pFlags |= (size & (size - 1)) ? 0 : size;\r
452         }\r
453 }\r
454 \r
455 static void WvConvertDevAttr(WV_IO_DEVICE_ATTRIBUTES* pAttributes,\r
456                                                          ib_ca_attr_t *pCaAttr)\r
457 {\r
458         pAttributes->FwVersion                  = pCaAttr->fw_ver;\r
459         pAttributes->NodeGuid                   = pCaAttr->ca_guid;\r
460         pAttributes->SystemImageGuid    = pCaAttr->system_image_guid;\r
461         pAttributes->VendorId                   = pCaAttr->vend_id;\r
462         pAttributes->VendorPartId               = pCaAttr->dev_id;\r
463         pAttributes->HwVersion                  = pCaAttr->revision;\r
464 \r
465         WvSetDeviceCap(&pAttributes->CapabilityFlags, pCaAttr);\r
466         pAttributes->AtomicCapability   = (UINT32) pCaAttr->atomicity;\r
467         WvSetDevicePages(&pAttributes->PageSizeCapabilityFlags, pCaAttr);\r
468 \r
469         pAttributes->MaxMrSize                  = pCaAttr->init_region_size;\r
470         pAttributes->MaxQp                              = pCaAttr->max_qps;\r
471         pAttributes->MaxQpWr                    = pCaAttr->max_wrs;\r
472         pAttributes->MaxSge                             = pCaAttr->max_sges;\r
473         pAttributes->MaxCq                              = pCaAttr->max_cqs;\r
474         pAttributes->MaxCqEntries               = pCaAttr->max_cqes;\r
475         pAttributes->MaxMr                              = pCaAttr->init_regions;\r
476         pAttributes->MaxPd                              = pCaAttr->max_pds;\r
477         pAttributes->MaxQpResponderResources    = pCaAttr->max_qp_resp_res;\r
478         pAttributes->MaxResponderResources              = pCaAttr->max_resp_res;\r
479         pAttributes->MaxQpInitiatorDepth                = pCaAttr->max_qp_init_depth;\r
480         pAttributes->MaxMw                              = pCaAttr->init_windows;\r
481         pAttributes->MaxMulticast               = pCaAttr->max_mcast_grps;\r
482         pAttributes->MaxQpAttach                = pCaAttr->max_qps_per_mcast_grp;\r
483         pAttributes->MaxMulticastQp             = pCaAttr->max_mcast_qps;\r
484         pAttributes->MaxAh                              = (UINT32) pCaAttr->max_addr_handles;\r
485         pAttributes->MaxFmr                             = pCaAttr->max_fmr;\r
486         pAttributes->MaxMapPerFmr               = pCaAttr->max_map_per_fmr;\r
487         pAttributes->MaxSrq                             = pCaAttr->max_srq;\r
488         pAttributes->MaxSrqWr                   = pCaAttr->max_srq_wrs;\r
489         pAttributes->MaxSrqSge                  = pCaAttr->max_srq_sges;\r
490         pAttributes->MaxPkeys                   = pCaAttr->max_partitions;\r
491         pAttributes->DeviceType                 = WV_DEVICE_INFINIBAND; // TODO: missing in ib_ca_attr_t\r
492         pAttributes->LocalAckDelay              = pCaAttr->local_ack_delay;\r
493         pAttributes->PhysPortCount              = pCaAttr->num_ports;\r
494 }\r
495 \r
496 static void WvConvertPortCap(UINT32 *pFlags, ib_port_cap_t *pCap)\r
497 {\r
498         *pFlags = 0;\r
499 \r
500         *pFlags |= pCap->qkey_ctr ? WV_IO_BAD_QKEY_COUNTER : 0;\r
501         *pFlags |= pCap->pkey_ctr ? WV_IO_BAD_PKEY_COUNTER : 0;\r
502         *pFlags |= pCap->apm ? WV_IO_PATH_MIGRATION : 0;\r
503         *pFlags |= pCap->sysguid ? WV_IO_SYSTEM_IMAGE_GUID : 0;\r
504         *pFlags |= pCap->port_active ? WV_IO_PORT_ACTIVE_EVENT : 0;\r
505 \r
506         // TODO: missing in ib_port_attr_t:\r
507         // WV_IO_RESIZE_MAX_WR\r
508         // WV_IO_CHANGE_PHYSICAL_PORT\r
509         // WV_IO_AH_PORT_CHECKING\r
510         *pFlags |= WV_IO_QP_STATE_MODIFIER;\r
511         // WV_IO_SHUTDOWN_PORT\r
512         // WV_IO_INIT_TYPE\r
513         *pFlags |= WV_IO_RC_RNR_NAK_GENERATION;\r
514         // WV_IO_SRQ_RESIZE\r
515         *pFlags |= WV_IO_BATCH_NOTIFY_CQ;\r
516 }\r
517 \r
518 static void WvConvertPortAttr(WV_IO_PORT_ATTRIBUTES *pAttributes,\r
519                                                           ib_port_attr_t *pPortAttr)\r
520 {\r
521         WvConvertPortCap(&pAttributes->PortCabilityFlags, &pPortAttr->cap);\r
522         pAttributes->State                      = pPortAttr->link_state;\r
523         pAttributes->MaxMtu                     = 0x80 << pPortAttr->mtu;\r
524         pAttributes->ActiveMtu          = 0x80 << pPortAttr->mtu;\r
525         pAttributes->GidTableLength     = pPortAttr->num_gids;\r
526         pAttributes->MaxMessageSize     = (UINT32) pPortAttr->max_msg_size;\r
527         pAttributes->BadPkeyCounter     = pPortAttr->pkey_ctr;\r
528         pAttributes->QkeyViolationCounter       = pPortAttr->qkey_ctr;\r
529         pAttributes->PkeyTableLength            = pPortAttr->num_pkeys;\r
530         pAttributes->Lid                        = pPortAttr->lid;\r
531         pAttributes->SmLid                      = pPortAttr->sm_lid;\r
532         pAttributes->Lmc                        = pPortAttr->lmc;\r
533         pAttributes->MaxVls                     = (UINT8) pPortAttr->max_vls;\r
534         pAttributes->SmSl                       = pPortAttr->sm_sl;\r
535         pAttributes->SubnetTimeout      = pPortAttr->subnet_timeout;\r
536         pAttributes->InitTypeReply      = pPortAttr->init_type_reply;\r
537         pAttributes->ActiveWidth        = pPortAttr->active_width;\r
538         pAttributes->ActiveSpeed        = pPortAttr->active_speed;\r
539         pAttributes->PhysicalState      = pPortAttr->phys_state;\r
540         pAttributes->Reserved[0]        = 0;\r
541         pAttributes->Reserved[1]        = 0;\r
542 }\r
543 \r
544 void WvDeviceQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
545 {\r
546         UINT64                                  *id;\r
547         WV_IO_DEVICE_ATTRIBUTES *attr;\r
548         WV_DEVICE                               *dev;\r
549         ib_ca_attr_t                    *ca_attr;\r
550         NTSTATUS                                status;\r
551         UINT32                                  outlen = 0;\r
552 \r
553         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
554         if (!NT_SUCCESS(status)) {\r
555                 goto complete;\r
556         }\r
557         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_DEVICE_ATTRIBUTES),\r
558                                                                                         &attr, NULL);\r
559         if (!NT_SUCCESS(status)) {\r
560                 goto complete;\r
561         }\r
562 \r
563         dev = WvDeviceAcquire(pProvider, *id);\r
564         if (dev == NULL) {\r
565                 status = STATUS_NO_SUCH_DEVICE;\r
566                 goto complete;\r
567         }\r
568 \r
569         ca_attr = WvQueryCaAttributes(dev);\r
570         WvDeviceRelease(dev);\r
571 \r
572         if (ca_attr == NULL) {\r
573                 status = STATUS_NO_MEMORY;\r
574                 goto complete;\r
575         }\r
576 \r
577         WvConvertDevAttr(attr, ca_attr);\r
578         outlen = sizeof(WV_IO_DEVICE_ATTRIBUTES);\r
579         ExFreePool(ca_attr);\r
580 \r
581 complete:\r
582         WdfRequestCompleteWithInformation(Request, status, outlen);\r
583 }\r
584 \r
585 void WvDevicePortQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
586 {\r
587         WV_IO_DEVICE_PORT_QUERY *query;\r
588         WV_IO_PORT_ATTRIBUTES   *attr;\r
589         WV_DEVICE                               *dev;\r
590         ib_ca_attr_t                    *ca_attr;\r
591         NTSTATUS                                status;\r
592         UINT32                                  outlen = 0;\r
593 \r
594         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY),\r
595                                                                                    &query, NULL);\r
596         if (!NT_SUCCESS(status)) {\r
597                 goto complete;\r
598         }\r
599         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_PORT_ATTRIBUTES),\r
600                                                                                         &attr, NULL);\r
601         if (!NT_SUCCESS(status)) {\r
602                 goto complete;\r
603         }\r
604 \r
605         dev = WvDeviceAcquire(pProvider, query->Id);\r
606         if (dev == NULL) {\r
607                 status = STATUS_NO_SUCH_DEVICE;\r
608                 goto complete;\r
609         }\r
610 \r
611         ca_attr = WvQueryCaAttributes(dev);\r
612         WvDeviceRelease(dev);\r
613 \r
614         if (ca_attr == NULL) {\r
615                 status = STATUS_NO_MEMORY;\r
616                 goto complete;\r
617         }\r
618 \r
619         if (--query->PortNumber >= ca_attr->num_ports) {\r
620                 status = STATUS_INVALID_PORT_HANDLE;\r
621                 goto free;\r
622         }\r
623 \r
624         WvConvertPortAttr(attr, &ca_attr->p_port_attr[query->PortNumber]);\r
625         outlen = sizeof(WV_IO_PORT_ATTRIBUTES);\r
626 \r
627 free:\r
628         ExFreePool(ca_attr);\r
629 complete:\r
630         WdfRequestCompleteWithInformation(Request, status, outlen);\r
631 }\r
632 \r
633 void WvDeviceGidQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
634 {\r
635         WV_IO_DEVICE_PORT_QUERY *query;\r
636         WV_IO_GID                               *gid;\r
637         WV_DEVICE                               *dev;\r
638         ib_ca_attr_t                    *ca_attr;\r
639         ib_port_attr_t                  *port_attr;\r
640         NTSTATUS                                status;\r
641         size_t                                  i, size, outlen = 0;\r
642 \r
643         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY),\r
644                                                                                    &query, NULL);\r
645         if (!NT_SUCCESS(status)) {\r
646                 goto complete;\r
647         }\r
648         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_GID), &gid, &size);\r
649         if (!NT_SUCCESS(status)) {\r
650                 goto complete;\r
651         }\r
652 \r
653         dev = WvDeviceAcquire(pProvider, query->Id);\r
654         if (dev == NULL) {\r
655                 status = STATUS_NO_SUCH_DEVICE;\r
656                 goto complete;\r
657         }\r
658 \r
659         ca_attr = WvQueryCaAttributes(dev);\r
660         WvDeviceRelease(dev);\r
661 \r
662         if (ca_attr == NULL) {\r
663                 status = STATUS_NO_MEMORY;\r
664                 goto complete;\r
665         }\r
666 \r
667         if (--query->PortNumber >= ca_attr->num_ports) {\r
668                 status = STATUS_INVALID_PORT_HANDLE;\r
669                 goto free;\r
670         }\r
671 \r
672         size /= sizeof(WV_IO_GID);\r
673         port_attr = &ca_attr->p_port_attr[query->PortNumber];\r
674         for (i = 0; i < size && i < port_attr->num_gids; i++) {\r
675                 RtlCopyMemory(&gid[i], &port_attr->p_gid_table[i], sizeof(WV_IO_GID));\r
676         }\r
677 \r
678         outlen = i * sizeof(WV_IO_GID);\r
679         if (i < port_attr->num_gids) {\r
680                 status = STATUS_MORE_ENTRIES;\r
681         }\r
682 \r
683 free:\r
684         ExFreePool(ca_attr);\r
685 complete:\r
686         WdfRequestCompleteWithInformation(Request, status, outlen);\r
687 }\r
688 \r
689 void WvDevicePkeyQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
690 {\r
691         WV_IO_DEVICE_PORT_QUERY *query;\r
692         NET16                                   *pkey;\r
693         WV_DEVICE                               *dev;\r
694         ib_ca_attr_t                    *ca_attr;\r
695         ib_port_attr_t                  *port_attr;\r
696         NTSTATUS                                status;\r
697         size_t                                  i, size, outlen = 0;\r
698 \r
699         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY),\r
700                                                                                    &query, NULL);\r
701         if (!NT_SUCCESS(status)) {\r
702                 goto complete;\r
703         }\r
704         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(NET16), &pkey, &size);\r
705         if (!NT_SUCCESS(status)) {\r
706                 goto complete;\r
707         }\r
708 \r
709         dev = WvDeviceAcquire(pProvider, query->Id);\r
710         if (dev == NULL) {\r
711                 status = STATUS_NO_SUCH_DEVICE;\r
712                 goto complete;\r
713         }\r
714 \r
715         ca_attr = WvQueryCaAttributes(dev);\r
716         WvDeviceRelease(dev);\r
717 \r
718         if (ca_attr == NULL) {\r
719                 status = STATUS_NO_MEMORY;\r
720                 goto complete;\r
721         }\r
722 \r
723         if (--query->PortNumber >= ca_attr->num_ports) {\r
724                 status = STATUS_INVALID_PORT_HANDLE;\r
725                 goto free;\r
726         }\r
727 \r
728         size /= sizeof(NET16);\r
729         port_attr = &ca_attr->p_port_attr[query->PortNumber];\r
730         for (i = 0; i < size && i < port_attr->num_pkeys; i++) {\r
731                 pkey[i] = port_attr->p_pkey_table[i];\r
732         }\r
733 \r
734         outlen = i * sizeof(NET16);\r
735         if (i < port_attr->num_pkeys) {\r
736                 status = STATUS_MORE_ENTRIES;\r
737         }\r
738 \r
739 free:\r
740         ExFreePool(ca_attr);\r
741 complete:\r
742         WdfRequestCompleteWithInformation(Request, status, outlen);\r
743 }\r
744 \r
745 void WvDeviceNotify(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
746 {\r
747         WV_IO_ID                *id;\r
748         WV_DEVICE               *dev;\r
749         WV_PORT                 *port;\r
750         NTSTATUS                status;\r
751         UINT32                  *flags;\r
752 \r
753         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, NULL);\r
754         if (!NT_SUCCESS(status)) {\r
755                 goto complete;\r
756         }\r
757 \r
758         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(UINT32), &flags, NULL);\r
759         if (!NT_SUCCESS(status)) {\r
760                 goto complete;\r
761         }\r
762 \r
763         dev = WvDeviceAcquire(pProvider, id->Id);\r
764         if (dev == NULL) {\r
765                 status = STATUS_NOT_FOUND;\r
766                 goto complete;\r
767         }\r
768 \r
769         if (--id->Data >= dev->PortCount) {\r
770                 status = STATUS_INVALID_PORT_HANDLE;\r
771                 goto release;\r
772         }\r
773 \r
774         port = &dev->pPorts[id->Data];\r
775         WdfObjectAcquireLock(port->Queue);\r
776 \r
777         if (port->Flags == 0) {\r
778                 status = WdfRequestForwardToIoQueue(Request, port->Queue);\r
779         } else {\r
780                 *flags = port->Flags;\r
781                 WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, sizeof(UINT32));\r
782                 port->Flags = 0;\r
783         }\r
784 \r
785         WdfObjectReleaseLock(port->Queue);\r
786 release:\r
787         WvDeviceRelease(dev);\r
788 complete:\r
789         if (!NT_SUCCESS(status)) {\r
790                 WdfRequestComplete(Request, status);\r
791         }\r
792 }\r
793 \r
794 void WvDeviceCancel(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
795 {\r
796         UINT64                  *id;\r
797         WV_DEVICE               *dev;\r
798         NTSTATUS                status;\r
799         UINT8                   i;\r
800 \r
801         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
802         if (!NT_SUCCESS(status)) {\r
803                 goto out;\r
804         }\r
805 \r
806         dev = WvDeviceAcquire(pProvider, *id);\r
807         if (dev == NULL) {\r
808                 status = STATUS_NOT_FOUND;\r
809                 goto out;\r
810         }\r
811 \r
812         for (i = 0; i < dev->PortCount; i++) {\r
813                 WvDeviceCompleteRequests(&dev->pPorts[i], STATUS_CANCELLED, 0);\r
814         }\r
815         WvDeviceRelease(dev);\r
816 \r
817 out:\r
818         WdfRequestComplete(Request, status);\r
819 }\r