5cc20bd6f1047e9dc9cdfc27f8675a13be1505bc
[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 }\r
371 \r
372 void WvDeviceFree(WV_DEVICE *pDevice)\r
373 {\r
374         if (InterlockedDecrement(&pDevice->Ref) > 0) {\r
375                 KeWaitForSingleObject(&pDevice->Event, Executive, KernelMode, FALSE, NULL);\r
376         }\r
377 \r
378         if (pDevice->hVerbsDevice != NULL) {\r
379                 pDevice->pVerbs->unregister_event_handler(pDevice->pDevice->hDevice,\r
380                                                                                                   &pDevice->EventHandler);\r
381                 pDevice->pVerbs->um_close_ca(pDevice->pDevice->hDevice,\r
382                                                                          pDevice->hVerbsDevice);\r
383                 WvRdmaDevicePut(pDevice->pDevice);\r
384         }\r
385 \r
386         WvDeviceFreePorts(pDevice);\r
387         WvProviderPut(pDevice->pProvider);\r
388         ExFreePool(pDevice);\r
389 }\r
390 \r
391 void WvDeviceRemoveHandler(WV_DEVICE *pDevice)\r
392 {\r
393         LIST_ENTRY                              *entry;\r
394         WV_PROTECTION_DOMAIN    *pd;\r
395         WV_COMPLETION_QUEUE             *cq;\r
396 \r
397         for (entry = pDevice->PdList.Flink; entry != &pDevice->PdList;\r
398                  entry = entry->Flink) {\r
399                 pd = CONTAINING_RECORD(entry, WV_PROTECTION_DOMAIN, Entry);\r
400                 WvPdRemoveHandler(pd);\r
401         }\r
402 \r
403         for (entry = pDevice->CqList.Flink; entry != &pDevice->CqList;\r
404                  entry = entry->Flink) {\r
405                 cq = CONTAINING_RECORD(entry, WV_COMPLETION_QUEUE, Entry);\r
406                 pDevice->pVerbs->destroy_cq(cq->hVerbsCq);\r
407                 cq->hVerbsCq = NULL;\r
408                 cq->pVerbs = NULL;\r
409         }\r
410 \r
411         pDevice->pVerbs->um_close_ca(pDevice->pDevice->hDevice,\r
412                                                                  pDevice->hVerbsDevice);\r
413         WvRdmaDevicePut(pDevice->pDevice);\r
414         pDevice->pDevice = NULL;\r
415         pDevice->pVerbs = NULL;\r
416         pDevice->hVerbsDevice = NULL;\r
417 }\r
418 \r
419 static void WvSetDeviceCap(UINT32 *pFlags, ib_ca_attr_t *pCaAttr)\r
420 {\r
421         *pFlags = 0;\r
422 \r
423         *pFlags |= pCaAttr->bad_pkey_ctr_support ? WV_IO_BAD_PKEY_COUNTER : 0;\r
424         *pFlags |= pCaAttr->bad_qkey_ctr_support ? WV_IO_BAD_QKEY_COUNTER : 0;\r
425         *pFlags |= pCaAttr->apm_support ? WV_IO_PATH_MIGRATION : 0;\r
426         *pFlags |= pCaAttr->av_port_check ? WV_IO_AH_PORT_CHECKING : 0;\r
427         *pFlags |= pCaAttr->change_primary_port ? WV_IO_CHANGE_PHYSICAL_PORT : 0;\r
428         *pFlags |= pCaAttr->modify_wr_depth ? WV_IO_RESIZE_MAX_WR : 0;\r
429         *pFlags |= pCaAttr->modify_srq_depth ? WV_IO_SRQ_RESIZE : 0;\r
430         *pFlags |= pCaAttr->current_qp_state_support ? WV_IO_QP_STATE_MODIFIER : 0;\r
431         *pFlags |= pCaAttr->shutdown_port_capability ? WV_IO_SHUTDOWN_PORT : 0;\r
432         *pFlags |= pCaAttr->init_type_support ? WV_IO_INIT_TYPE : 0;\r
433         *pFlags |= pCaAttr->port_active_event_support ? WV_IO_PORT_ACTIVE_EVENT : 0;\r
434         *pFlags |= pCaAttr->system_image_guid_support ? WV_IO_SYSTEM_IMAGE_GUID : 0;\r
435         *pFlags |= WV_IO_RC_RNR_NAK_GENERATION;\r
436         *pFlags |= WV_IO_BATCH_NOTIFY_CQ;\r
437 }\r
438 \r
439 static void WvSetDevicePages(UINT32 *pFlags, ib_ca_attr_t *pCaAttr)\r
440 {\r
441         unsigned int i;\r
442         UINT32 size;\r
443 \r
444         *pFlags = 0;\r
445 \r
446         for (i = 0; i < pCaAttr->num_page_sizes; i++) {\r
447                 size = pCaAttr->p_page_size[i];\r
448                 *pFlags |= (size & (size - 1)) ? 0 : size;\r
449         }\r
450 }\r
451 \r
452 static void WvConvertDevAttr(WV_IO_DEVICE_ATTRIBUTES* pAttributes,\r
453                                                          ib_ca_attr_t *pCaAttr)\r
454 {\r
455         pAttributes->FwVersion                  = pCaAttr->fw_ver;\r
456         pAttributes->NodeGuid                   = pCaAttr->ca_guid;\r
457         pAttributes->SystemImageGuid    = pCaAttr->system_image_guid;\r
458         pAttributes->VendorId                   = pCaAttr->vend_id;\r
459         pAttributes->VendorPartId               = pCaAttr->dev_id;\r
460         pAttributes->HwVersion                  = pCaAttr->revision;\r
461 \r
462         WvSetDeviceCap(&pAttributes->CapabilityFlags, pCaAttr);\r
463         pAttributes->AtomicCapability   = (UINT32) pCaAttr->atomicity;\r
464         WvSetDevicePages(&pAttributes->PageSizeCapabilityFlags, pCaAttr);\r
465 \r
466         pAttributes->MaxMrSize                  = pCaAttr->init_region_size;\r
467         pAttributes->MaxQp                              = pCaAttr->max_qps;\r
468         pAttributes->MaxQpWr                    = pCaAttr->max_wrs;\r
469         pAttributes->MaxSge                             = pCaAttr->max_sges;\r
470         pAttributes->MaxCq                              = pCaAttr->max_cqs;\r
471         pAttributes->MaxCqEntries               = pCaAttr->max_cqes;\r
472         pAttributes->MaxMr                              = pCaAttr->init_regions;\r
473         pAttributes->MaxPd                              = pCaAttr->max_pds;\r
474         pAttributes->MaxQpResponderResources    = pCaAttr->max_qp_resp_res;\r
475         pAttributes->MaxResponderResources              = pCaAttr->max_resp_res;\r
476         pAttributes->MaxQpInitiatorDepth                = pCaAttr->max_qp_init_depth;\r
477         pAttributes->MaxMw                              = pCaAttr->init_windows;\r
478         pAttributes->MaxMulticast               = pCaAttr->max_mcast_grps;\r
479         pAttributes->MaxQpAttach                = pCaAttr->max_qps_per_mcast_grp;\r
480         pAttributes->MaxMulticastQp             = pCaAttr->max_mcast_qps;\r
481         pAttributes->MaxAh                              = (UINT32) pCaAttr->max_addr_handles;\r
482         pAttributes->MaxFmr                             = pCaAttr->max_fmr;\r
483         pAttributes->MaxMapPerFmr               = pCaAttr->max_map_per_fmr;\r
484         pAttributes->MaxSrq                             = pCaAttr->max_srq;\r
485         pAttributes->MaxSrqWr                   = pCaAttr->max_srq_wrs;\r
486         pAttributes->MaxSrqSge                  = pCaAttr->max_srq_sges;\r
487         pAttributes->MaxPkeys                   = pCaAttr->max_partitions;\r
488         pAttributes->DeviceType                 = WV_DEVICE_INFINIBAND; // TODO: missing in ib_ca_attr_t\r
489         pAttributes->LocalAckDelay              = pCaAttr->local_ack_delay;\r
490         pAttributes->PhysPortCount              = pCaAttr->num_ports;\r
491 }\r
492 \r
493 static void WvConvertPortCap(UINT32 *pFlags, ib_port_cap_t *pCap)\r
494 {\r
495         *pFlags = 0;\r
496 \r
497         *pFlags |= pCap->qkey_ctr ? WV_IO_BAD_QKEY_COUNTER : 0;\r
498         *pFlags |= pCap->pkey_ctr ? WV_IO_BAD_PKEY_COUNTER : 0;\r
499         *pFlags |= pCap->apm ? WV_IO_PATH_MIGRATION : 0;\r
500         *pFlags |= pCap->sysguid ? WV_IO_SYSTEM_IMAGE_GUID : 0;\r
501         *pFlags |= pCap->port_active ? WV_IO_PORT_ACTIVE_EVENT : 0;\r
502 \r
503         // TODO: missing in ib_port_attr_t:\r
504         // WV_IO_RESIZE_MAX_WR\r
505         // WV_IO_CHANGE_PHYSICAL_PORT\r
506         // WV_IO_AH_PORT_CHECKING\r
507         *pFlags |= WV_IO_QP_STATE_MODIFIER;\r
508         // WV_IO_SHUTDOWN_PORT\r
509         // WV_IO_INIT_TYPE\r
510         *pFlags |= WV_IO_RC_RNR_NAK_GENERATION;\r
511         // WV_IO_SRQ_RESIZE\r
512         *pFlags |= WV_IO_BATCH_NOTIFY_CQ;\r
513 }\r
514 \r
515 static void WvConvertPortAttr(WV_IO_PORT_ATTRIBUTES *pAttributes,\r
516                                                           ib_port_attr_t *pPortAttr)\r
517 {\r
518         WvConvertPortCap(&pAttributes->PortCabilityFlags, &pPortAttr->cap);\r
519         pAttributes->State                      = pPortAttr->link_state;\r
520         pAttributes->MaxMtu                     = 0x80 << pPortAttr->mtu;\r
521         pAttributes->ActiveMtu          = 0x80 << pPortAttr->mtu;\r
522         pAttributes->GidTableLength     = pPortAttr->num_gids;\r
523         pAttributes->MaxMessageSize     = (UINT32) pPortAttr->max_msg_size;\r
524         pAttributes->BadPkeyCounter     = pPortAttr->pkey_ctr;\r
525         pAttributes->QkeyViolationCounter       = pPortAttr->qkey_ctr;\r
526         pAttributes->PkeyTableLength            = pPortAttr->num_pkeys;\r
527         pAttributes->Lid                        = pPortAttr->lid;\r
528         pAttributes->SmLid                      = pPortAttr->sm_lid;\r
529         pAttributes->Lmc                        = pPortAttr->lmc;\r
530         pAttributes->MaxVls                     = (UINT8) pPortAttr->max_vls;\r
531         pAttributes->SmSl                       = pPortAttr->sm_sl;\r
532         pAttributes->SubnetTimeout      = pPortAttr->subnet_timeout;\r
533         pAttributes->InitTypeReply      = pPortAttr->init_type_reply;\r
534         pAttributes->ActiveWidth        = pPortAttr->active_width;\r
535         pAttributes->ActiveSpeed        = pPortAttr->active_speed;\r
536         pAttributes->PhysicalState      = pPortAttr->phys_state;\r
537         pAttributes->Reserved[0]        = 0;\r
538         pAttributes->Reserved[1]        = 0;\r
539 }\r
540 \r
541 void WvDeviceQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
542 {\r
543         UINT64                                  *id;\r
544         WV_IO_DEVICE_ATTRIBUTES *attr;\r
545         WV_DEVICE                               *dev;\r
546         ib_ca_attr_t                    *ca_attr;\r
547         NTSTATUS                                status;\r
548         UINT32                                  outlen = 0;\r
549 \r
550         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
551         if (!NT_SUCCESS(status)) {\r
552                 goto complete;\r
553         }\r
554         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_DEVICE_ATTRIBUTES),\r
555                                                                                         &attr, NULL);\r
556         if (!NT_SUCCESS(status)) {\r
557                 goto complete;\r
558         }\r
559 \r
560         dev = WvDeviceAcquire(pProvider, *id);\r
561         if (dev == NULL) {\r
562                 status = STATUS_NO_SUCH_DEVICE;\r
563                 goto complete;\r
564         }\r
565 \r
566         ca_attr = WvQueryCaAttributes(dev);\r
567         WvDeviceRelease(dev);\r
568 \r
569         if (ca_attr == NULL) {\r
570                 status = STATUS_NO_MEMORY;\r
571                 goto complete;\r
572         }\r
573 \r
574         WvConvertDevAttr(attr, ca_attr);\r
575         outlen = sizeof(WV_IO_DEVICE_ATTRIBUTES);\r
576         ExFreePool(ca_attr);\r
577 \r
578 complete:\r
579         WdfRequestCompleteWithInformation(Request, status, outlen);\r
580 }\r
581 \r
582 void WvDevicePortQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
583 {\r
584         WV_IO_DEVICE_PORT_QUERY *query;\r
585         WV_IO_PORT_ATTRIBUTES   *attr;\r
586         WV_DEVICE                               *dev;\r
587         ib_ca_attr_t                    *ca_attr;\r
588         NTSTATUS                                status;\r
589         UINT32                                  outlen = 0;\r
590 \r
591         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY),\r
592                                                                                    &query, NULL);\r
593         if (!NT_SUCCESS(status)) {\r
594                 goto complete;\r
595         }\r
596         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_PORT_ATTRIBUTES),\r
597                                                                                         &attr, NULL);\r
598         if (!NT_SUCCESS(status)) {\r
599                 goto complete;\r
600         }\r
601 \r
602         dev = WvDeviceAcquire(pProvider, query->Id);\r
603         if (dev == NULL) {\r
604                 status = STATUS_NO_SUCH_DEVICE;\r
605                 goto complete;\r
606         }\r
607 \r
608         ca_attr = WvQueryCaAttributes(dev);\r
609         WvDeviceRelease(dev);\r
610 \r
611         if (ca_attr == NULL) {\r
612                 status = STATUS_NO_MEMORY;\r
613                 goto complete;\r
614         }\r
615 \r
616         if (--query->PortNumber >= ca_attr->num_ports) {\r
617                 status = STATUS_INVALID_PORT_HANDLE;\r
618                 goto free;\r
619         }\r
620 \r
621         WvConvertPortAttr(attr, &ca_attr->p_port_attr[query->PortNumber]);\r
622         outlen = sizeof(WV_IO_PORT_ATTRIBUTES);\r
623 \r
624 free:\r
625         ExFreePool(ca_attr);\r
626 complete:\r
627         WdfRequestCompleteWithInformation(Request, status, outlen);\r
628 }\r
629 \r
630 void WvDeviceGidQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
631 {\r
632         WV_IO_DEVICE_PORT_QUERY *query;\r
633         WV_IO_GID                               *gid;\r
634         WV_DEVICE                               *dev;\r
635         ib_ca_attr_t                    *ca_attr;\r
636         ib_port_attr_t                  *port_attr;\r
637         NTSTATUS                                status;\r
638         size_t                                  i, size, outlen = 0;\r
639 \r
640         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY),\r
641                                                                                    &query, NULL);\r
642         if (!NT_SUCCESS(status)) {\r
643                 goto complete;\r
644         }\r
645         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_GID), &gid, &size);\r
646         if (!NT_SUCCESS(status)) {\r
647                 goto complete;\r
648         }\r
649 \r
650         dev = WvDeviceAcquire(pProvider, query->Id);\r
651         if (dev == NULL) {\r
652                 status = STATUS_NO_SUCH_DEVICE;\r
653                 goto complete;\r
654         }\r
655 \r
656         ca_attr = WvQueryCaAttributes(dev);\r
657         WvDeviceRelease(dev);\r
658 \r
659         if (ca_attr == NULL) {\r
660                 status = STATUS_NO_MEMORY;\r
661                 goto complete;\r
662         }\r
663 \r
664         if (--query->PortNumber >= ca_attr->num_ports) {\r
665                 status = STATUS_INVALID_PORT_HANDLE;\r
666                 goto free;\r
667         }\r
668 \r
669         size /= sizeof(WV_IO_GID);\r
670         port_attr = &ca_attr->p_port_attr[query->PortNumber];\r
671         for (i = 0; i < size && i < port_attr->num_gids; i++) {\r
672                 RtlCopyMemory(&gid[i], &port_attr->p_gid_table[i], sizeof(WV_IO_GID));\r
673         }\r
674 \r
675         outlen = i * sizeof(WV_IO_GID);\r
676         if (i < port_attr->num_gids) {\r
677                 status = STATUS_MORE_ENTRIES;\r
678         }\r
679 \r
680 free:\r
681         ExFreePool(ca_attr);\r
682 complete:\r
683         WdfRequestCompleteWithInformation(Request, status, outlen);\r
684 }\r
685 \r
686 void WvDevicePkeyQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
687 {\r
688         WV_IO_DEVICE_PORT_QUERY *query;\r
689         NET16                                   *pkey;\r
690         WV_DEVICE                               *dev;\r
691         ib_ca_attr_t                    *ca_attr;\r
692         ib_port_attr_t                  *port_attr;\r
693         NTSTATUS                                status;\r
694         size_t                                  i, size, outlen = 0;\r
695 \r
696         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY),\r
697                                                                                    &query, NULL);\r
698         if (!NT_SUCCESS(status)) {\r
699                 goto complete;\r
700         }\r
701         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(NET16), &pkey, &size);\r
702         if (!NT_SUCCESS(status)) {\r
703                 goto complete;\r
704         }\r
705 \r
706         dev = WvDeviceAcquire(pProvider, query->Id);\r
707         if (dev == NULL) {\r
708                 status = STATUS_NO_SUCH_DEVICE;\r
709                 goto complete;\r
710         }\r
711 \r
712         ca_attr = WvQueryCaAttributes(dev);\r
713         WvDeviceRelease(dev);\r
714 \r
715         if (ca_attr == NULL) {\r
716                 status = STATUS_NO_MEMORY;\r
717                 goto complete;\r
718         }\r
719 \r
720         if (--query->PortNumber >= ca_attr->num_ports) {\r
721                 status = STATUS_INVALID_PORT_HANDLE;\r
722                 goto free;\r
723         }\r
724 \r
725         size /= sizeof(NET16);\r
726         port_attr = &ca_attr->p_port_attr[query->PortNumber];\r
727         for (i = 0; i < size && i < port_attr->num_pkeys; i++) {\r
728                 pkey[i] = port_attr->p_pkey_table[i];\r
729         }\r
730 \r
731         outlen = i * sizeof(NET16);\r
732         if (i < port_attr->num_pkeys) {\r
733                 status = STATUS_MORE_ENTRIES;\r
734         }\r
735 \r
736 free:\r
737         ExFreePool(ca_attr);\r
738 complete:\r
739         WdfRequestCompleteWithInformation(Request, status, outlen);\r
740 }\r
741 \r
742 void WvDeviceNotify(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
743 {\r
744         WV_IO_ID                *id;\r
745         WV_DEVICE               *dev;\r
746         WV_PORT                 *port;\r
747         NTSTATUS                status;\r
748         UINT32                  *flags;\r
749 \r
750         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, NULL);\r
751         if (!NT_SUCCESS(status)) {\r
752                 goto complete;\r
753         }\r
754 \r
755         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(UINT32), &flags, NULL);\r
756         if (!NT_SUCCESS(status)) {\r
757                 goto complete;\r
758         }\r
759 \r
760         dev = WvDeviceAcquire(pProvider, id->Id);\r
761         if (dev == NULL) {\r
762                 status = STATUS_NOT_FOUND;\r
763                 goto complete;\r
764         }\r
765 \r
766         if (--id->Data >= dev->PortCount) {\r
767                 status = STATUS_INVALID_PORT_HANDLE;\r
768                 goto release;\r
769         }\r
770 \r
771         port = &dev->pPorts[id->Data];\r
772         WdfObjectAcquireLock(port->Queue);\r
773 \r
774         if (port->Flags == 0) {\r
775                 status = WdfRequestForwardToIoQueue(Request, port->Queue);\r
776         } else {\r
777                 *flags = port->Flags;\r
778                 WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, sizeof(UINT32));\r
779                 port->Flags = 0;\r
780         }\r
781 \r
782         WdfObjectReleaseLock(port->Queue);\r
783 release:\r
784         WvDeviceRelease(dev);\r
785 complete:\r
786         if (!NT_SUCCESS(status)) {\r
787                 WdfRequestComplete(Request, status);\r
788         }\r
789 }\r
790 \r
791 void WvDeviceCancel(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
792 {\r
793         UINT64                  *id;\r
794         WV_DEVICE               *dev;\r
795         NTSTATUS                status;\r
796         UINT8                   i;\r
797 \r
798         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
799         if (!NT_SUCCESS(status)) {\r
800                 goto out;\r
801         }\r
802 \r
803         dev = WvDeviceAcquire(pProvider, *id);\r
804         if (dev == NULL) {\r
805                 status = STATUS_NOT_FOUND;\r
806                 goto out;\r
807         }\r
808 \r
809         for (i = 0; i < dev->PortCount; i++) {\r
810                 WvDeviceCompleteRequests(&dev->pPorts[i], STATUS_CANCELLED, 0);\r
811         }\r
812         WvDeviceRelease(dev);\r
813 \r
814 out:\r
815         WdfRequestComplete(Request, status);\r
816 }\r