cb4d757f7e676cad2a9bc8d72076e8cd3fd4b127
[mirror/winof/.git] / hw / mlx4 / kernel / hca / drv.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. \r
4  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\r
8  *     Redistribution and use in source and binary forms, with or\r
9  *     without modification, are permitted provided that the following\r
10  *     conditions are met:\r
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\r
16  *      - Redistributions in binary form must reproduce the above\r
17  *        copyright notice, this list of conditions and the following\r
18  *        disclaimer in the documentation and/or other materials\r
19  *        provided with the distribution.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
25  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
26  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
28  * SOFTWARE.\r
29  *\r
30  * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $\r
31  */\r
32 \r
33 #include "precomp.h"\r
34 #include <initguid.h>\r
35 #include <wdmguid.h>\r
36 #include <rdma\verbs.h>\r
37 \r
38 #if defined(EVENT_TRACING)\r
39 #ifdef offsetof\r
40 #undef offsetof\r
41 #endif\r
42 #include "drv.tmh"\r
43 #endif \r
44 \r
45 GLOBALS g;\r
46 \r
47 /*\r
48  * UVP name does not include file extension.  For debug builds, UAL\r
49  * will append "d.dll".  For release builds, UAL will append ".dll"\r
50  */\r
51 char                    mlnx_uvp_lib_name[MAX_LIB_NAME] = {"mlx4u"};\r
52 \r
53 static int __get_dev_info(PFDO_DEVICE_DATA p_fdo, __be64 *node_guid, u32 *hw_id)\r
54 {\r
55         struct ib_device_attr device_attr;\r
56         struct ib_device *p_ibdev = p_fdo->bus_ib_ifc.p_ibdev;\r
57         int err;\r
58 \r
59         HCA_ENTER( HCA_DBG_PNP );\r
60         if ( hca_is_livefish(p_fdo) ) {\r
61                 *node_guid = cl_hton64((uint64_t)(ULONG_PTR)p_ibdev);\r
62                 p_ibdev->node_guid = *node_guid;\r
63                 *hw_id = 0;\r
64                 return 0;\r
65         }\r
66 \r
67         err = (p_ibdev->query_device)( p_ibdev, &device_attr );\r
68         if (err)\r
69                 return err;\r
70 \r
71         *node_guid = p_ibdev->node_guid;\r
72         *hw_id = device_attr.hw_ver;\r
73         HCA_EXIT( HCA_DBG_PNP );\r
74         return 0;\r
75 }\r
76 \r
77 #ifndef USE_WDM_FRAMEWORK\r
78 \r
79 //\r
80 // TODO: add support for Hibernate/Standby as in WDM version below\r
81 //\r
82 \r
83 \r
84 \r
85 static ci_interface_t*\r
86 __alloc_hca_ifc(\r
87         IN                              PFDO_DEVICE_DATA const          p_fdo )\r
88 {\r
89         ci_interface_t  *pIfc;\r
90 \r
91         HCA_ENTER( HCA_DBG_PNP );\r
92 \r
93         pIfc =\r
94                 (ci_interface_t*)ExAllocatePoolWithTag( PagedPool, sizeof(ci_interface_t), MT_TAG_KERNEL );\r
95         if( !pIfc )\r
96         {\r
97                 HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, \r
98                         ("Failed to allocate ci_interface_t (%d bytes).\n",\r
99                         sizeof(ci_interface_t)));\r
100                 return NULL;\r
101         }\r
102 \r
103         setup_ci_interface( p_fdo->hca.guid, !!hca_is_livefish(p_fdo), pIfc );\r
104 \r
105         pIfc->p_hca_obj = &p_fdo->hca;\r
106         pIfc->vend_id = (uint32_t)p_fdo->bus_ib_ifc.pdev->ven_id;\r
107         pIfc->dev_id = (uint16_t)p_fdo->bus_ib_ifc.pdev->dev_id;\r
108         pIfc->dev_revision = (uint16_t)p_fdo->hca.hw_ver;\r
109 \r
110         HCA_EXIT( HCA_DBG_PNP );\r
111         return pIfc;\r
112 }\r
113 \r
114 static void\r
115 __unmap_hca_memory(\r
116         IN                              PFDO_DEVICE_DATA const p_fdo )\r
117 {\r
118         struct pci_dev *pdev = p_fdo->bus_ib_ifc.pdev;\r
119         int                             i;\r
120 \r
121         HCA_ENTER( HCA_DBG_PNP );\r
122 \r
123         for( i = 0; i < HCA_BAR_TYPE_MAX; i++ ) {\r
124                 if (pdev->bar[i].virt) {\r
125                         MmUnmapIoSpace( pdev->bar[i].virt, pdev->bar[i].size );\r
126                         cl_memclr( &pdev->bar[i], sizeof(hca_bar_t) );\r
127                 }\r
128         }\r
129 \r
130         HCA_EXIT( HCA_DBG_PNP );\r
131 }\r
132 \r
133 /* release the resources, allocated in hca_start */\r
134 static void\r
135 __hca_release_resources(\r
136         IN      WDFDEVICE  Device )\r
137 {\r
138         PFDO_DEVICE_DATA p_fdo = FdoGetData(Device);\r
139 \r
140         HCA_ENTER( HCA_DBG_PNP );\r
141 \r
142         switch( p_fdo->state )\r
143         {\r
144         case HCA_STARTED:\r
145                 /* dequeue HCA  */\r
146                 mlnx_hca_remove( &p_fdo->hca );\r
147         }\r
148         \r
149         __unmap_hca_memory( p_fdo );\r
150 \r
151         p_fdo->state = HCA_ADDED;\r
152 \r
153         HCA_EXIT( HCA_DBG_PNP );\r
154 }\r
155 \r
156 static void\r
157 __ref_ifc(\r
158         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
159 {\r
160         PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
161 \r
162         HCA_ENTER( HCA_DBG_PNP );\r
163 \r
164         cl_atomic_inc( &p_fdo->n_hca_ifc_ref );\r
165         ObReferenceObject( p_dev_obj );\r
166 \r
167         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
168                 ("MLX4_HCA: CA_guid %I64x, hca_ifc_ref %d\n",\r
169                 p_fdo->hca.guid, p_fdo->n_hca_ifc_ref) );\r
170 \r
171         HCA_EXIT( HCA_DBG_PNP );\r
172 }\r
173 \r
174 static void\r
175 __deref_ifc(\r
176         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
177 {\r
178         PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
179 \r
180         HCA_ENTER( HCA_DBG_PNP );\r
181 \r
182         cl_atomic_dec( &p_fdo->n_hca_ifc_ref );\r
183         ObDereferenceObject( p_dev_obj );\r
184 \r
185         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
186                 ("MLX4_HCA: CA_guid %I64x, hca_ifc_ref %d\n",\r
187                 p_fdo->hca.guid, p_fdo->n_hca_ifc_ref) );\r
188 \r
189         HCA_EXIT( HCA_DBG_PNP );\r
190 }\r
191 \r
192 \r
193 \r
194 NTSTATUS\r
195 EvtDeviceD0Entry(\r
196         IN WDFDEVICE  Device,\r
197         IN WDF_POWER_DEVICE_STATE  PreviousState\r
198         )\r
199 {\r
200         UNUSED_PARAM(Device);\r
201         UNUSED_PARAM(PreviousState);\r
202         HCA_ENTER( HCA_DBG_PNP );\r
203         HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, ("EvtDeviceD0Entry: PreviousState 0x%x\n", PreviousState));\r
204         HCA_EXIT( HCA_DBG_PNP );\r
205         return STATUS_SUCCESS;\r
206 }\r
207 \r
208 NTSTATUS\r
209 EvtDeviceD0Exit(\r
210         IN WDFDEVICE  Device,\r
211         IN WDF_POWER_DEVICE_STATE  TargetState\r
212         )\r
213 {\r
214         NTSTATUS status;\r
215         PFDO_DEVICE_DATA p_fdo = FdoGetData(Device);\r
216 \r
217         HCA_ENTER( HCA_DBG_PNP );\r
218 \r
219         HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, ("EvtDeviceD0Exit: TargetState 0x%x\n", TargetState));\r
220 \r
221         switch (TargetState) {\r
222         case WdfPowerDeviceD1:  /* hopefully, it is STANDBY state */\r
223         case WdfPowerDevicePrepareForHibernation:\r
224                 if (atomic_read(&p_fdo->usecnt)) {\r
225                         status = STATUS_UNSUCCESSFUL;\r
226                         break;\r
227                 }\r
228                 /* Fall through. */\r
229         default:\r
230                 status = STATUS_SUCCESS;\r
231                 break;\r
232         }\r
233 \r
234         HCA_EXIT( HCA_DBG_PNP );\r
235         return status;\r
236 }\r
237 \r
238 NTSTATUS\r
239 EvtDevicePrepareHardware(\r
240         IN WDFDEVICE  Device,\r
241         IN WDFCMRESLIST  ResourcesRaw,\r
242         IN WDFCMRESLIST  ResourcesTranslated\r
243         )\r
244 {\r
245         int err;\r
246         NTSTATUS status;\r
247         PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
248         BUS_INTERFACE_STANDARD  bus_pci_ifc;\r
249         ci_interface_t *p_hca_ifc;\r
250         RDMA_INTERFACE_VERBS rdma_ifc, *p_ifc = &rdma_ifc;\r
251         WDF_QUERY_INTERFACE_CONFIG qiConfig;\r
252                 \r
253         UNUSED_PARAM(ResourcesRaw);\r
254         UNUSED_PARAM(ResourcesTranslated);\r
255 \r
256         HCA_ENTER( HCA_DBG_PNP );\r
257         \r
258         HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, ("EvtPrepareHardware: \n"));\r
259 \r
260         /* get PCI BUS interface */\r
261         status = WdfFdoQueryForInterface( Device, &GUID_BUS_INTERFACE_STANDARD,\r
262                 (PINTERFACE)&bus_pci_ifc, sizeof(BUS_INTERFACE_STANDARD), 1, NULL );\r
263         if( !NT_SUCCESS( status ) ) {\r
264                 HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting PCI BUS interface failed: status=0x%x\n", status));\r
265                 return status;\r
266         }\r
267         RtlCopyMemory( &p_fdo->bus_pci_ifc, &bus_pci_ifc, sizeof(BUS_INTERFACE_STANDARD) );\r
268         p_fdo->bus_pci_ifc_taken = TRUE;\r
269         \r
270         /* get MLX4_BUS IB interface */\r
271         status = WdfFdoQueryForInterface( Device, &MLX4_BUS_IB_INTERFACE_GUID,\r
272                 (PINTERFACE)&p_fdo->bus_ib_ifc, sizeof(MLX4_BUS_IB_INTERFACE), MLX4_BUS_IB_INTERFACE_VERSION, NULL );\r
273         if( !NT_SUCCESS( status ) ) {\r
274                 HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting MLX4 BUS interface failed: status=0x%x\n", status));\r
275                 return status;\r
276         }\r
277         p_fdo->bus_ib_ifc_taken = TRUE;\r
278         p_fdo->bus_ib_ifc.p_ibdev->x.p_fdo = p_fdo;\r
279 \r
280         InitializeListHead(&p_fdo->hca.event_list);\r
281         KeInitializeSpinLock(&p_fdo->hca.event_list_lock);\r
282 \r
283         /* get node GUID */\r
284         err = __get_dev_info( p_fdo, &p_fdo->hca.guid, &p_fdo->hca.hw_ver );\r
285         if (err) {\r
286 \r
287                 HCA_PRINT(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,\r
288                         ("can't get guid - ib_query_device() failed (%08X)\n", err ));\r
289                 //TODO: no cleanup on error\r
290                 return STATUS_INSUFFICIENT_RESOURCES;\r
291         }\r
292 \r
293         /* queue HCA  */\r
294         mlnx_hca_insert( &p_fdo->hca );\r
295 \r
296         /* Allocate and populate our HCA interface structure. */\r
297         p_hca_ifc = __alloc_hca_ifc( p_fdo );\r
298         if( !p_hca_ifc ) {\r
299                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_PNP  ,("__alloc_hca_ifc failed.\n"));\r
300                 return STATUS_NO_MEMORY;\r
301         }\r
302 \r
303         /* fill interface fields */\r
304         p_ifc->InterfaceHeader.Size = sizeof(RDMA_INTERFACE_VERBS);\r
305         p_ifc->InterfaceHeader.Version = VerbsVersion(VERBS_MAJOR_VER, VERBS_MINOR_VER);\r
306         p_ifc->InterfaceHeader.Context = p_fdo->p_dev_obj;\r
307         p_ifc->InterfaceHeader.InterfaceReference = __ref_ifc;\r
308         p_ifc->InterfaceHeader.InterfaceDereference = __deref_ifc;\r
309         p_ifc->Verbs = *p_hca_ifc;\r
310         ExFreePool( p_hca_ifc );\r
311 \r
312         /* create an upper interface */\r
313         WDF_QUERY_INTERFACE_CONFIG_INIT( &qiConfig, (PINTERFACE)p_ifc,\r
314                 &GUID_RDMA_INTERFACE_VERBS, NULL);\r
315 \r
316         status = WdfDeviceAddQueryInterface( Device, &qiConfig );\r
317         if (!NT_SUCCESS(status)) {\r
318                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_PNP  ,("WdfDeviceAddQueryInterface failed %#x\n", status));\r
319                 return status;\r
320         }\r
321 \r
322         /*\r
323          * Change the state since the PnP callback can happen\r
324          * before the callback returns.\r
325          */\r
326         p_fdo->state = HCA_STARTED;\r
327         \r
328         HCA_EXIT( HCA_DBG_PNP );\r
329         return STATUS_SUCCESS;\r
330 }\r
331 \r
332 \r
333 NTSTATUS\r
334 EvtDeviceReleaseHardware(\r
335         IN WDFDEVICE  Device,\r
336         IN WDFCMRESLIST  ResourcesTranslated\r
337         )\r
338 {\r
339         PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
340 \r
341         UNUSED_PARAM(ResourcesTranslated);\r
342 \r
343         HCA_ENTER( HCA_DBG_PNP );\r
344 \r
345         HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, ("EvtDeviceReleaseHardware: FdoData=0x%p\n", p_fdo));\r
346 \r
347         // release IBBUS resources\r
348         __hca_release_resources(Device);\r
349 \r
350         // release MLX4_BUS resources\r
351         if(p_fdo->bus_ib_ifc_taken) {\r
352                 PINTERFACE p_ifc = (PINTERFACE)&p_fdo->bus_ib_ifc;\r
353                 p_ifc->InterfaceDereference( p_ifc->Context );\r
354                 p_fdo->bus_ib_ifc_taken = FALSE;\r
355         }\r
356 \r
357         // release PCI BUS resources\r
358         if(p_fdo->bus_pci_ifc_taken) {\r
359                 PINTERFACE p_ifc = (PINTERFACE)&p_fdo->bus_pci_ifc;\r
360                 p_ifc->InterfaceDereference( p_ifc->Context );\r
361                 p_fdo->bus_pci_ifc_taken = FALSE;\r
362         }\r
363 \r
364         HCA_EXIT( HCA_DBG_PNP );\r
365         return STATUS_SUCCESS;\r
366 }\r
367 \r
368 NTSTATUS\r
369 EvtDeviceQueryRemove(\r
370         IN WDFDEVICE  Device\r
371         )\r
372 {\r
373         PFDO_DEVICE_DATA p_fdo = FdoGetData(Device);\r
374         HCA_ENTER( HCA_DBG_PNP );\r
375         if (atomic_read(&p_fdo->usecnt)) {\r
376                 cl_dbg_out( "MLX4_HCA: Can't get unloaded. %d applications are still in work\n", p_fdo->usecnt);\r
377                 return STATUS_UNSUCCESSFUL;\r
378         }\r
379         HCA_EXIT( HCA_DBG_PNP );\r
380         return STATUS_SUCCESS;\r
381 }\r
382 \r
383 \r
384 NTSTATUS\r
385 EvtDriverDeviceAdd(\r
386         IN WDFDRIVER        Driver,\r
387         IN PWDFDEVICE_INIT  DeviceInit\r
388         )\r
389 /*++\r
390 Routine Description:\r
391 \r
392         EvtDriverDeviceAdd is called by the framework in response to AddDevice\r
393         call from the PnP manager. We create and initialize a device object to\r
394         represent a new instance of mxe bus.\r
395 \r
396 Arguments:\r
397 \r
398         Driver - Handle to a framework driver object created in DriverEntry\r
399 \r
400         DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.\r
401 \r
402 Return Value:\r
403 \r
404         NTSTATUS\r
405 \r
406 --*/\r
407 {\r
408         WDF_OBJECT_ATTRIBUTES                   attributes;\r
409         NTSTATUS                                                status;\r
410         WDFDEVICE                                               device;\r
411         PFDO_DEVICE_DATA                                p_fdo;\r
412         WDF_PNPPOWER_EVENT_CALLBACKS    Callbacks;\r
413 \r
414         UNREFERENCED_PARAMETER(Driver);\r
415 \r
416         PAGED_CODE ();\r
417         \r
418         HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, ("EvtDriverDeviceAdd: 0x%p\n", Driver));\r
419         //\r
420         // register PnP & Power stuff\r
421         //\r
422         WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks);\r
423         Callbacks.EvtDevicePrepareHardware = EvtDevicePrepareHardware;\r
424         Callbacks.EvtDeviceReleaseHardware = EvtDeviceReleaseHardware;\r
425         Callbacks.EvtDeviceQueryRemove  = EvtDeviceQueryRemove;\r
426         Callbacks.EvtDeviceD0Entry = EvtDeviceD0Entry;\r
427         Callbacks.EvtDeviceD0Exit = EvtDeviceD0Exit;\r
428 \r
429         WdfDeviceInitSetPnpPowerEventCallbacks( DeviceInit, &Callbacks );\r
430         \r
431         //\r
432         // Initialize all the properties specific to the device.\r
433         // Framework has default values for the one that are not\r
434         // set explicitly here. So please read the doc and make sure\r
435         // you are okay with the defaults.\r
436         //\r
437         WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_INFINIBAND);\r
438         WdfDeviceInitSetExclusive(DeviceInit, FALSE);\r
439 \r
440         //\r
441         // Initialize attributes structure to specify size and accessor function\r
442         // for storing device context.\r
443         //\r
444         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_DEVICE_DATA);\r
445 \r
446         //\r
447         // Create a framework device object. In response to this call, framework\r
448         // creates a WDM deviceobject.\r
449         //\r
450         status = WdfDeviceCreate(&DeviceInit, &attributes, &device);\r
451         if (!NT_SUCCESS(status)) {\r
452                 HCA_PRINT(TRACE_LEVEL_VERBOSE, HCA_DBG_PNP, ("EvtDriverDeviceAdd: WdfDeviceCreate failed with 0x%x\n", status));\r
453                 goto end;\r
454         }\r
455 \r
456         //\r
457         // Init device context.\r
458         //\r
459         p_fdo = FdoGetData(device);\r
460         RtlZeroMemory(p_fdo, sizeof(FDO_DEVICE_DATA));\r
461         p_fdo->FdoDevice = device;\r
462         p_fdo->p_dev_obj = WdfDeviceWdmGetDeviceObject( device );\r
463         spin_lock_init( &p_fdo->uctx_lock );\r
464         cl_qlist_init( &p_fdo->uctx_list );\r
465         atomic_set(&p_fdo->usecnt, 0);\r
466         p_fdo->state = HCA_ADDED;\r
467 \r
468         //\r
469         // WMI\r
470         //\r
471         status = WmiRegistration(device);\r
472         if (!NT_SUCCESS(status)) {\r
473                 return status;\r
474         }\r
475 \r
476         status = STATUS_SUCCESS;\r
477 \r
478 end:    \r
479         HCA_EXIT( HCA_DBG_PNP );\r
480         return status;\r
481 }\r
482 \r
483 \r
484 void\r
485 EvtDriverUnload(\r
486         IN              WDFDRIVER  Driver\r
487         )\r
488 {\r
489         HCA_ENTER( HCA_DBG_PNP );\r
490 \r
491         UNUSED_PARAM( Driver );\r
492 \r
493         HCA_EXIT( HCA_DBG_PNP );\r
494 #if defined(EVENT_TRACING)\r
495         WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver));\r
496 #endif\r
497 }\r
498 \r
499 NTSTATUS\r
500 DriverEntry(\r
501         IN PDRIVER_OBJECT DriverObject,\r
502         IN PUNICODE_STRING RegistryPath\r
503         )\r
504 /*++\r
505 Routine Description:\r
506 \r
507         Initialize the call backs structure of Driver Framework.\r
508 \r
509 Arguments:\r
510 \r
511         DriverObject - pointer to the driver object\r
512 \r
513         RegistryPath - pointer to a unicode string representing the path,\r
514                                         to driver-specific key in the registry.\r
515 \r
516 Return Value:\r
517 \r
518         NT Status Code\r
519 \r
520 --*/\r
521 {\r
522         WDF_DRIVER_CONFIG   config;\r
523         NTSTATUS            status;\r
524         WDFDRIVER hDriver;\r
525 \r
526 #if defined(EVENT_TRACING)\r
527         WPP_INIT_TRACING(DriverObject, RegistryPath);\r
528 #endif\r
529 \r
530         // global initializations\r
531         g.DebugPrintLevel = TRACE_LEVEL_VERBOSE;\r
532         g.DebugPrintFlags = 0xffff;\r
533         HCA_ENTER( HCA_DBG_PNP );\r
534 \r
535         status = mlnx_hcas_init();\r
536         if( status  != STATUS_SUCCESS ) {\r
537                 HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,\r
538                         ("mlnx_hcas_init returned %#x.\n", status));\r
539                 goto end;\r
540         }\r
541 \r
542         //\r
543         // Initiialize driver config to control the attributes that\r
544         // are global to the driver. Note that framework by default\r
545         // provides a driver unload routine. If you create any resources\r
546         // in the DriverEntry and want to be cleaned in driver unload,\r
547         // you can override that by specifing one in the Config structure.\r
548         //\r
549 \r
550         WDF_DRIVER_CONFIG_INIT(\r
551                 &config, EvtDriverDeviceAdd );\r
552         config.EvtDriverUnload = EvtDriverUnload;\r
553 \r
554         //\r
555         // Create a framework driver object to represent our driver.\r
556         //\r
557         status = WdfDriverCreate(DriverObject,\r
558                 RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,\r
559                 &config, &hDriver);\r
560 \r
561         if (!NT_SUCCESS(status)) {\r
562                 HCA_PRINT(TRACE_LEVEL_VERBOSE, HCA_DBG_PNP, ("WdfDriverCreate failed with status 0x%x\n", status));\r
563                 goto end;\r
564         }\r
565 \r
566         //\r
567         // read registry parameters\r
568         //\r
569         {\r
570                 DECLARE_CONST_UNICODE_STRING(valueName0, L"DebugLevel");\r
571                 DECLARE_CONST_UNICODE_STRING(valueName1, L"DebugFlags");\r
572                 ULONG value;\r
573                 WDFKEY hKey = NULL;\r
574 \r
575                 status = WdfDriverOpenParametersRegistryKey( hDriver,\r
576                         STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey );\r
577 \r
578                 if (NT_SUCCESS (status)) {\r
579 \r
580                         status = WdfRegistryQueryULong(hKey, &valueName0, &value);\r
581                         if (NT_SUCCESS (status)) g.DebugPrintLevel = value;\r
582                         \r
583                         status = WdfRegistryQueryULong(hKey, &valueName1, &value);\r
584                         if (NT_SUCCESS (status)) g.DebugPrintFlags = value;\r
585                         \r
586                         WdfRegistryClose(hKey);\r
587                 }\r
588 \r
589                 // we don't matter the failure in the work with Registry\r
590                 status = STATUS_SUCCESS;\r
591         }\r
592 \r
593 end:\r
594         HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,\r
595                 ("exit status %#x.\n", status));\r
596         HCA_EXIT( HCA_DBG_PNP );\r
597         return status;\r
598 \r
599 }\r
600 \r
601 #else\r
602 \r
603 \r
604 UNICODE_STRING                          g_param_path;\r
605 static cl_vfptr_pnp_po_t        vfptrHcaPnp;\r
606 \r
607 NTSTATUS\r
608 DriverEntry(\r
609         IN                              PDRIVER_OBJECT                          p_driver_obj,\r
610         IN                              PUNICODE_STRING                         p_registry_path );\r
611 \r
612 static NTSTATUS\r
613 __read_registry(\r
614         IN                              UNICODE_STRING* const           p_Param_Path );\r
615 \r
616 static void\r
617 hca_drv_unload(\r
618         IN                              PDRIVER_OBJECT                          p_driver_obj );\r
619 \r
620 static NTSTATUS\r
621 hca_sysctl(\r
622         IN                              PDEVICE_OBJECT                          p_dev_obj,\r
623         IN                              PIRP                                            p_irp );\r
624 \r
625 NTSTATUS\r
626 hca_add_device(\r
627         IN                              PDRIVER_OBJECT                          pDriverObj,\r
628         IN                              PDEVICE_OBJECT                          pPdo );\r
629 \r
630 static NTSTATUS\r
631 hca_start(\r
632         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
633         IN                              IRP* const                                      p_irp, \r
634                 OUT                     cl_irp_action_t* const          p_action );\r
635 \r
636 static NTSTATUS\r
637 hca_query_stop(\r
638         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
639         IN                              IRP* const                                      p_irp, \r
640                 OUT                     cl_irp_action_t* const          p_action );\r
641 \r
642 static NTSTATUS\r
643 hca_stop(\r
644         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
645         IN                              IRP* const                                      p_irp, \r
646                 OUT                     cl_irp_action_t* const          p_action );\r
647 \r
648 static NTSTATUS\r
649 hca_cancel_stop(\r
650         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
651         IN                              IRP* const                                      p_irp, \r
652                 OUT                     cl_irp_action_t* const          p_action );\r
653 \r
654 static NTSTATUS\r
655 hca_query_remove(\r
656         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
657         IN                              IRP* const                                      p_irp, \r
658                 OUT                     cl_irp_action_t* const          p_action );\r
659 \r
660 static void\r
661 hca_release_resources(\r
662         IN                              DEVICE_OBJECT* const            p_dev_obj );\r
663 \r
664 static NTSTATUS\r
665 hca_cancel_remove(\r
666         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
667         IN                              IRP* const                                      p_irp, \r
668                 OUT                     cl_irp_action_t* const          p_action );\r
669 \r
670 static NTSTATUS\r
671 hca_surprise_remove(\r
672         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
673         IN                              IRP* const                                      p_irp, \r
674                 OUT                     cl_irp_action_t* const          p_action );\r
675 \r
676 static NTSTATUS\r
677 hca_query_capabilities(\r
678         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
679         IN                              IRP* const                                      p_irp, \r
680                 OUT                     cl_irp_action_t* const          p_action );\r
681 \r
682 static NTSTATUS\r
683 hca_query_interface(\r
684         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
685         IN                              IRP* const                                      p_irp, \r
686                 OUT                     cl_irp_action_t* const          p_action );\r
687 \r
688 static NTSTATUS\r
689 hca_query_pnp_state(\r
690         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
691         IN                              IRP* const                                      p_irp, \r
692                 OUT                     cl_irp_action_t* const          p_action );\r
693 \r
694 static NTSTATUS\r
695 hca_query_bus_relations(\r
696         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
697         IN                              IRP* const                                      p_irp, \r
698                 OUT                     cl_irp_action_t* const          p_action );\r
699 \r
700 static NTSTATUS\r
701 hca_query_removal_relations(\r
702         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
703         IN                              IRP* const                                      p_irp, \r
704                 OUT                     cl_irp_action_t* const          p_action );\r
705 \r
706 static NTSTATUS\r
707 hca_query_power(\r
708         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
709         IN                              IRP* const                                      p_irp,\r
710                 OUT                     cl_irp_action_t* const          p_action );\r
711 \r
712 static NTSTATUS\r
713 hca_set_power(\r
714         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
715         IN                              IRP* const                                      p_irp, \r
716                 OUT                     cl_irp_action_t* const          p_action );\r
717 \r
718 static ci_interface_t*\r
719 __alloc_hca_ifc(\r
720         IN                              FDO_DEVICE_DATA* const          p_fdo );\r
721 \r
722 static NTSTATUS\r
723 __get_ci_interface(\r
724         IN                              DEVICE_OBJECT* const            p_dev_obj );\r
725 \r
726 \r
727 \r
728 \r
729 NTSTATUS\r
730 hca_add_device(\r
731         IN                              PDRIVER_OBJECT                          pDriverObj,\r
732         IN                              PDEVICE_OBJECT                          pPdo )\r
733 {\r
734         NTSTATUS                        status;\r
735         DEVICE_OBJECT           *p_dev_obj, *pNextDevObj;\r
736         PFDO_DEVICE_DATA        p_fdo;\r
737 \r
738         HCA_ENTER(HCA_DBG_PNP);\r
739 \r
740         /*\r
741          * Create the device so that we have a device extension to store stuff in.\r
742          */\r
743         status = IoCreateDevice( pDriverObj, sizeof(FDO_DEVICE_DATA),\r
744                 NULL, FILE_DEVICE_INFINIBAND, FILE_DEVICE_SECURE_OPEN,\r
745                 FALSE, &p_dev_obj );\r
746         if( !NT_SUCCESS( status ) )\r
747         {\r
748                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
749                         ("IoCreateDevice returned 0x%08X.\n", status));\r
750                 return status;\r
751         }\r
752 \r
753         p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
754         cl_memclr( p_fdo, sizeof(FDO_DEVICE_DATA) );\r
755         cl_spinlock_init( &p_fdo->uctx_lock );\r
756         cl_qlist_init( &p_fdo->uctx_list );\r
757         atomic_set(&p_fdo->usecnt, 0);\r
758 \r
759         /* Attach to the device stack. */\r
760         pNextDevObj = IoAttachDeviceToDeviceStack( p_dev_obj, pPdo );\r
761         if( !pNextDevObj )\r
762         {\r
763                 //cl_event_destroy( &p_fdo->mutex );\r
764                 IoDeleteDevice( p_dev_obj );\r
765                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
766                         ("IoAttachDeviceToDeviceStack failed.\n"));\r
767                 return STATUS_NO_SUCH_DEVICE;\r
768         }\r
769 \r
770         /* Inititalize the complib extension. */\r
771         cl_init_pnp_po_ext( p_dev_obj, pNextDevObj, pPdo, CL_DBG_PNP | CL_DBG_ERROR,\r
772                 &vfptrHcaPnp, NULL );\r
773 \r
774         p_fdo->state = HCA_ADDED;\r
775 \r
776         HCA_EXIT(HCA_DBG_PNP);\r
777         return status;\r
778 }\r
779 \r
780 static void\r
781 __put_ifc(\r
782                 IN      PINTERFACE              p_ifc )\r
783 {\r
784         HCA_ENTER( HCA_DBG_PNP );\r
785         p_ifc->InterfaceDereference( p_ifc->Context );\r
786         HCA_EXIT( HCA_DBG_PNP );\r
787 }\r
788 \r
789 /* Forwards the request to the HCA's PDO. */\r
790 static NTSTATUS\r
791 __get_ifc(\r
792         IN                              DEVICE_OBJECT* const            pDevObj,\r
793         IN              const   GUID* const                                     pGuid,\r
794         IN                              USHORT                                          size,\r
795         IN                              USHORT                                          Version,\r
796         IN OUT                  PVOID                                           InterfaceSpecificData,\r
797                 OUT                     PINTERFACE                                      pBusIfc )\r
798 {\r
799         NTSTATUS                        status;\r
800         IRP                                     *pIrp;\r
801         IO_STATUS_BLOCK         ioStatus;\r
802         IO_STACK_LOCATION       *pIoStack;\r
803         DEVICE_OBJECT           *pDev;\r
804         KEVENT                          event;\r
805 \r
806         HCA_ENTER( HCA_DBG_PNP );\r
807 \r
808         CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
809 \r
810         pDev = IoGetAttachedDeviceReference( pDevObj );\r
811 \r
812         KeInitializeEvent( &event, NotificationEvent, FALSE );\r
813 \r
814         /* Build the IRP for the HCA. */\r
815         pIrp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, pDev,\r
816                 NULL, 0, NULL, &event, &ioStatus );\r
817         if( !pIrp )\r
818         {\r
819                 ObDereferenceObject( pDev );\r
820                 HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, \r
821                         ("IoBuildSynchronousFsdRequest failed.\n"));\r
822                 return STATUS_INSUFFICIENT_RESOURCES;\r
823         }\r
824 \r
825         /* Copy the request query parameters. */\r
826         pIoStack = IoGetNextIrpStackLocation( pIrp );\r
827         pIoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;\r
828         pIoStack->Parameters.QueryInterface.Size = size;\r
829         pIoStack->Parameters.QueryInterface.Version = Version;\r
830         pIoStack->Parameters.QueryInterface.InterfaceType = pGuid;\r
831         pIoStack->Parameters.QueryInterface.Interface = (INTERFACE*)pBusIfc;\r
832         pIoStack->Parameters.QueryInterface.InterfaceSpecificData = InterfaceSpecificData;\r
833 \r
834         pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;\r
835 \r
836         /* Send the IRP. */\r
837         status = IoCallDriver( pDev, pIrp );\r
838         if( status == STATUS_PENDING )\r
839         {\r
840                 KeWaitForSingleObject( &event, Executive, KernelMode,\r
841                         FALSE, NULL );\r
842 \r
843                 status = ioStatus.Status;\r
844         }\r
845         ObDereferenceObject( pDev );\r
846 \r
847         HCA_EXIT( HCA_DBG_PNP );\r
848         return status;\r
849 }\r
850 \r
851 static ci_interface_t*\r
852 __alloc_hca_ifc(\r
853         IN                              PFDO_DEVICE_DATA const          p_fdo )\r
854 {\r
855         ci_interface_t  *pIfc;\r
856 \r
857         HCA_ENTER( HCA_DBG_PNP );\r
858 \r
859         pIfc = (ci_interface_t*)ExAllocatePoolWithTag( PagedPool,\r
860                 sizeof(ci_interface_t), MT_TAG_KERNEL );\r
861         if( !pIfc )\r
862         {\r
863                 HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, \r
864                         ("Failed to allocate ci_interface_t (%d bytes).\n",\r
865                         sizeof(ci_interface_t)));\r
866                 return NULL;\r
867         }\r
868 \r
869         setup_ci_interface( p_fdo->hca.guid, !!hca_is_livefish(p_fdo), pIfc );\r
870 \r
871         pIfc->p_hca_obj = &p_fdo->hca;\r
872         pIfc->vend_id = (uint32_t)p_fdo->bus_ib_ifc.pdev->ven_id;\r
873         pIfc->dev_id = (uint16_t)p_fdo->bus_ib_ifc.pdev->dev_id;\r
874         pIfc->dev_revision = (uint16_t)p_fdo->hca.hw_ver;\r
875 \r
876         HCA_EXIT( HCA_DBG_PNP );\r
877         return pIfc;\r
878 }\r
879 \r
880 static void\r
881 __unmap_hca_memory(\r
882         IN                              PFDO_DEVICE_DATA const p_fdo )\r
883 {\r
884         struct pci_dev *pdev = p_fdo->bus_ib_ifc.pdev;\r
885         int                             i;\r
886 \r
887         HCA_ENTER( HCA_DBG_PNP );\r
888 \r
889         if ( pdev )\r
890                 for( i = 0; i < HCA_BAR_TYPE_MAX; i++ ) {\r
891                         if (pdev->bar[i].virt) {\r
892                                 MmUnmapIoSpace( pdev->bar[i].virt, pdev->bar[i].size );\r
893                                 cl_memclr( &pdev->bar[i], sizeof(hca_bar_t) );\r
894                         }\r
895                 }\r
896 \r
897         HCA_EXIT( HCA_DBG_PNP );\r
898 }\r
899 \r
900 \r
901 /* release the resources, allocated in hca_start */\r
902 static void\r
903 __hca_release_resources(\r
904         IN                              DEVICE_OBJECT* const            p_dev_obj )\r
905 {\r
906         PFDO_DEVICE_DATA                p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
907 \r
908         HCA_ENTER( HCA_DBG_PNP );\r
909 \r
910         switch( p_fdo->state )\r
911         {\r
912         case HCA_STARTED:\r
913                 /* dequeue HCA  */\r
914                 mlnx_hca_remove( &p_fdo->hca );\r
915         }\r
916 \r
917         if (p_fdo->al_sym_name.Buffer) {\r
918                 ExFreePool( p_fdo->al_sym_name.Buffer );\r
919                 p_fdo->al_sym_name.Buffer = NULL;\r
920         }\r
921         \r
922         if( p_fdo->pnp_target_entry )\r
923         {\r
924                 ASSERT( p_fdo->pnp_ifc_entry );\r
925                 IoUnregisterPlugPlayNotification( p_fdo->pnp_target_entry );\r
926                 p_fdo->pnp_target_entry = NULL;\r
927         }\r
928 \r
929         if( p_fdo->pnp_ifc_entry ) {\r
930                 IoUnregisterPlugPlayNotification( p_fdo->pnp_ifc_entry );\r
931                 p_fdo->pnp_ifc_entry = NULL;\r
932         }\r
933 \r
934         if( p_fdo->p_al_file_obj ) {\r
935                 ObDereferenceObject( p_fdo->p_al_file_obj );\r
936                 p_fdo->p_al_file_obj = NULL;\r
937         }\r
938 \r
939         // release MLX4_BUS resources\r
940         if(p_fdo->bus_ib_ifc_taken) {\r
941                 p_fdo->bus_ib_ifc_taken = FALSE;\r
942                 __put_ifc( (PINTERFACE)&p_fdo->bus_ib_ifc );\r
943         }\r
944 \r
945         // release PCI BUS resources\r
946         if(p_fdo->bus_pci_ifc_taken) {\r
947                 p_fdo->bus_pci_ifc_taken = FALSE;\r
948                 __put_ifc( (PINTERFACE)&p_fdo->bus_pci_ifc );\r
949         }\r
950 \r
951         __unmap_hca_memory( p_fdo );\r
952 \r
953         p_fdo->state = HCA_ADDED;\r
954 \r
955         HCA_EXIT( HCA_DBG_PNP );\r
956 }\r
957 \r
958 \r
959 static void\r
960 hca_release_resources(\r
961         IN                              DEVICE_OBJECT* const            p_dev_obj )\r
962 {\r
963         PFDO_DEVICE_DATA                p_fdo;\r
964         POWER_STATE             powerState;\r
965 \r
966         HCA_ENTER( HCA_DBG_PNP );\r
967 \r
968         p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
969 \r
970         /* release all the resources, allocated in hca_start */\r
971         __hca_release_resources(p_dev_obj);\r
972 \r
973         /* Notify the power manager that the device is powered down. */\r
974         p_fdo->DevicePowerState = PowerDeviceD3;\r
975         powerState.DeviceState = PowerDeviceD3;\r
976         powerState = PoSetPowerState ( p_fdo->cl_ext.p_self_do, DevicePowerState, powerState );\r
977 \r
978         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, \r
979                 ("PoSetPowerState: old state %d, new state to %d\n", \r
980                 powerState.DeviceState, p_fdo->DevicePowerState ));\r
981 \r
982         /* Clear the PnP state in case we get restarted. */\r
983         p_fdo->pnpState = 0;\r
984 \r
985         HCA_EXIT( HCA_DBG_PNP );\r
986 }\r
987 \r
988 static NTSTATUS\r
989 hca_start(\r
990         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
991         IN                              IRP* const                                      p_irp, \r
992                 OUT                     cl_irp_action_t* const          p_action )\r
993 {\r
994         int                                     err;\r
995         NTSTATUS                        status;\r
996         PFDO_DEVICE_DATA        p_fdo;\r
997         IO_STACK_LOCATION       *pIoStack;\r
998         POWER_STATE                     powerState;\r
999         BUS_INTERFACE_STANDARD  bus_pci_ifc;\r
1000 \r
1001         HCA_ENTER( HCA_DBG_PNP );\r
1002 \r
1003         p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1004 \r
1005         /* Handled on the way up. */\r
1006         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
1007         if( !NT_SUCCESS( status ) )\r
1008         {\r
1009                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1010                         ("Lower drivers failed IRP_MN_START_DEVICE (%#x).\n", status));\r
1011                 goto end;\r
1012         }\r
1013 \r
1014         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1015 \r
1016         /* get PCI BUS interface */\r
1017         status = __get_ifc( p_dev_obj, &GUID_BUS_INTERFACE_STANDARD,\r
1018                 sizeof(BUS_INTERFACE_STANDARD), 1, NULL, (PINTERFACE)&bus_pci_ifc);\r
1019         if( !NT_SUCCESS( status ) ) {\r
1020                 HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting PCI BUS interface failed: status=0x%x\n", status));\r
1021                 goto end;\r
1022         }\r
1023         RtlCopyMemory( &p_fdo->bus_pci_ifc, &bus_pci_ifc, sizeof(BUS_INTERFACE_STANDARD) );\r
1024         p_fdo->bus_pci_ifc_taken = TRUE;\r
1025         \r
1026         /* get MLX4_BUS IB interface */\r
1027         status = __get_ifc( p_dev_obj, &MLX4_BUS_IB_INTERFACE_GUID,\r
1028                 sizeof(MLX4_BUS_IB_INTERFACE), MLX4_BUS_IB_INTERFACE_VERSION, NULL, (PINTERFACE)&p_fdo->bus_ib_ifc);\r
1029         if( !NT_SUCCESS( status ) ) {\r
1030                 HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting MLX4 BUS interface failed: status=0x%x\n", status));\r
1031                 goto end;\r
1032         }\r
1033         p_fdo->bus_ib_ifc_taken = TRUE;\r
1034         p_fdo->bus_ib_ifc.p_ibdev->x.p_fdo = p_fdo;\r
1035         \r
1036         InitializeListHead(&p_fdo->hca.event_list);\r
1037         KeInitializeSpinLock(&p_fdo->hca.event_list_lock);\r
1038 \r
1039         /* get node GUID */\r
1040         err = __get_dev_info( p_fdo, &p_fdo->hca.guid, &p_fdo->hca.hw_ver );\r
1041         if (err) {\r
1042 \r
1043                 HCA_PRINT(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,\r
1044                         ("can't get guid - ib_query_device() failed (%08X)\n", err ));\r
1045                 //TODO: no cleanup on error\r
1046                 return STATUS_INSUFFICIENT_RESOURCES;\r
1047         }\r
1048 \r
1049         /* queue HCA  */\r
1050         mlnx_hca_insert( &p_fdo->hca );\r
1051 \r
1052         /*\r
1053          * Change the state since the PnP callback can happen\r
1054          * before the callback returns.\r
1055          */\r
1056         p_fdo->state = HCA_STARTED;\r
1057         \r
1058         /* We get started fully powered. */\r
1059         p_fdo->DevicePowerState = PowerDeviceD0;\r
1060         powerState.DeviceState = PowerDeviceD0;\r
1061         powerState = PoSetPowerState ( p_fdo->cl_ext.p_self_do, DevicePowerState, powerState );\r
1062         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, \r
1063                 ("PoSetPowerState: old state %d, new state to %d\n", \r
1064                 powerState.DeviceState, p_fdo->DevicePowerState ));\r
1065 \r
1066 end:\r
1067         HCA_EXIT( HCA_DBG_PNP );\r
1068         return status;\r
1069 }\r
1070 \r
1071 static NTSTATUS\r
1072 hca_query_stop(\r
1073         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1074         IN                              IRP* const                                      p_irp, \r
1075                 OUT                     cl_irp_action_t* const          p_action )\r
1076 {\r
1077         /* All kernel clients will get notified through the device hierarchy. */\r
1078 \r
1079         /* TODO: set a flag to fail creation of any new IB resources. */\r
1080         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1081 }\r
1082 \r
1083 \r
1084 static NTSTATUS\r
1085 hca_stop(\r
1086         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1087         IN                              IRP* const                                      p_irp, \r
1088                 OUT                     cl_irp_action_t* const          p_action )\r
1089 {\r
1090         /*\r
1091          * Must disable everything.  Complib framework will\r
1092          * call ReleaseResources handler.\r
1093          */\r
1094         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1095 }\r
1096 \r
1097 \r
1098 static NTSTATUS\r
1099 hca_cancel_stop(\r
1100         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1101         IN                              IRP* const                                      p_irp, \r
1102                 OUT                     cl_irp_action_t* const          p_action )\r
1103 {\r
1104         /* Handled on the way up. */\r
1105         return cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
1106 }\r
1107 \r
1108 \r
1109 static NTSTATUS\r
1110 hca_query_remove(\r
1111         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1112         IN                              IRP* const                                      p_irp, \r
1113                 OUT                     cl_irp_action_t* const          p_action )\r
1114 {\r
1115         PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1116         if (atomic_read(&p_fdo->usecnt)) {\r
1117                 cl_dbg_out( "MTHCA: Can't get unloaded. %d applications are still in work\n", p_fdo->usecnt);\r
1118                 p_irp->IoStatus.Status = STATUS_UNSUCCESSFUL;\r
1119                 return cl_irp_complete( p_dev_obj, p_irp, p_action );\r
1120         }\r
1121         /* TODO: set a flag to fail creation of any new IB resources. */\r
1122         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1123 }\r
1124 \r
1125 \r
1126 static NTSTATUS\r
1127 hca_cancel_remove(\r
1128         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1129         IN                              IRP* const                                      p_irp, \r
1130                 OUT                     cl_irp_action_t* const          p_action )\r
1131 {\r
1132         /* Handled on the way up. */\r
1133         return cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
1134 }\r
1135 \r
1136 \r
1137 static NTSTATUS\r
1138 hca_surprise_remove(\r
1139         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1140         IN                              IRP* const                                      p_irp, \r
1141                 OUT                     cl_irp_action_t* const          p_action )\r
1142 {\r
1143         /*\r
1144          * TODO: Set state so that all further requests\r
1145          * automatically succeed/fail as needed.\r
1146          */\r
1147         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1148 }\r
1149 \r
1150 \r
1151 static NTSTATUS\r
1152 hca_query_capabilities(\r
1153         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1154         IN                              IRP* const                                      p_irp, \r
1155                 OUT                     cl_irp_action_t* const          p_action )\r
1156 {\r
1157         NTSTATUS                        status;\r
1158         PFDO_DEVICE_DATA        p_fdo;\r
1159         IO_STACK_LOCATION       *pIoStack;\r
1160         DEVICE_CAPABILITIES     *pCaps;\r
1161 \r
1162         HCA_ENTER( HCA_DBG_PNP );\r
1163 \r
1164         p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1165 \r
1166         /* Process on the way up. */\r
1167         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
1168         if( !NT_SUCCESS( status ) )\r
1169         {\r
1170                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1171                         ("cl_do_sync_pnp returned %08X.\n", status));\r
1172                 return status;\r
1173         }\r
1174 \r
1175         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1176         pCaps = pIoStack->Parameters.DeviceCapabilities.Capabilities;\r
1177 \r
1178         /*\r
1179          * Store the device power mapping into our extension since we're\r
1180          * the power policy owner.  The mapping is used when handling\r
1181          * IRP_MN_SET_POWER IRPs.\r
1182          */\r
1183         cl_memcpy(\r
1184                 p_fdo->DevicePower, pCaps->DeviceState, sizeof(p_fdo->DevicePower) );\r
1185 \r
1186         if( pCaps->DeviceD1 )\r
1187         {\r
1188                 HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP,\r
1189                         ("WARNING: Device reports support for DeviceD1 power state.\n"));\r
1190                 pCaps->DeviceD1 = FALSE;\r
1191         }\r
1192 \r
1193         if( pCaps->DeviceD2 )\r
1194         {\r
1195                 HCA_PRINT( TRACE_LEVEL_WARNING,HCA_DBG_PNP,\r
1196                         ("WARNING: Device reports support for DeviceD2 power state.\n"));\r
1197                 pCaps->DeviceD2 = FALSE;\r
1198         }\r
1199 \r
1200         if( pCaps->SystemWake != PowerSystemUnspecified )\r
1201         {\r
1202                 HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP,\r
1203                         ("WARNING: Device reports support for system wake.\n"));\r
1204                 pCaps->SystemWake = PowerSystemUnspecified;\r
1205         }\r
1206 \r
1207         if( pCaps->DeviceWake != PowerDeviceUnspecified )\r
1208         {\r
1209                 HCA_PRINT( TRACE_LEVEL_WARNING, HCA_DBG_PNP,\r
1210                         ("WARNING: Device reports support for device wake.\n"));\r
1211                 pCaps->DeviceWake = PowerDeviceUnspecified;\r
1212         }\r
1213 \r
1214         HCA_EXIT( HCA_DBG_PNP );\r
1215         return status;\r
1216 }\r
1217 \r
1218 static void\r
1219 __ref_ifc(\r
1220         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
1221 {\r
1222         PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1223 \r
1224         HCA_ENTER( HCA_DBG_PNP );\r
1225 \r
1226         cl_atomic_inc( &p_fdo->n_hca_ifc_ref );\r
1227         ObReferenceObject( p_dev_obj );\r
1228 \r
1229         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1230                 ("MLX4_HCA: CA_guid %I64x, hca_ifc_ref %d\n",\r
1231                 p_fdo->hca.guid, p_fdo->n_hca_ifc_ref) );\r
1232 \r
1233         HCA_EXIT( HCA_DBG_PNP );\r
1234 }\r
1235 \r
1236 static void\r
1237 __deref_ifc(\r
1238         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
1239 {\r
1240         PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1241 \r
1242         HCA_ENTER( HCA_DBG_PNP );\r
1243 \r
1244         cl_atomic_dec( &p_fdo->n_hca_ifc_ref );\r
1245         ObDereferenceObject( p_dev_obj );\r
1246 \r
1247         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1248                 ("MLX4_HCA: CA_guid %I64x, hca_ifc_ref %d\n",\r
1249                 p_fdo->hca.guid, p_fdo->n_hca_ifc_ref) );\r
1250 \r
1251         HCA_EXIT( HCA_DBG_PNP );\r
1252 }\r
1253 \r
1254 static NTSTATUS\r
1255 __query_ci_ifc(\r
1256         IN                                      DEVICE_OBJECT* const            p_dev_obj,\r
1257         IN                                      IO_STACK_LOCATION* const        p_io_stack )\r
1258 {\r
1259         RDMA_INTERFACE_VERBS    *p_ifc;\r
1260         PFDO_DEVICE_DATA                p_fdo;\r
1261         ci_interface_t                  *p_hca_ifc;\r
1262         NTSTATUS                                status;\r
1263         UINT8                                   version;\r
1264 \r
1265         HCA_ENTER( HCA_DBG_PNP );\r
1266 \r
1267         version = VerbsVersionMajor(p_io_stack->Parameters.QueryInterface.Version);\r
1268         if(  version > VERBS_MAJOR_VER )\r
1269         {\r
1270                 status = STATUS_NOT_SUPPORTED;\r
1271                 goto exit;\r
1272         }\r
1273 \r
1274         if( p_io_stack->Parameters.QueryInterface.Size < sizeof(RDMA_INTERFACE_VERBS) )\r
1275         {\r
1276                 status = STATUS_BUFFER_TOO_SMALL;\r
1277                 goto exit;\r
1278         }\r
1279 \r
1280         p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1281         p_hca_ifc = __alloc_hca_ifc( p_fdo );\r
1282         if( !p_hca_ifc )\r
1283         {\r
1284                 status = STATUS_NO_MEMORY;\r
1285                 goto exit;\r
1286         }\r
1287 \r
1288         p_ifc = (RDMA_INTERFACE_VERBS *) p_io_stack->Parameters.QueryInterface.Interface;\r
1289 \r
1290         p_ifc->InterfaceHeader.Size = sizeof(RDMA_INTERFACE_VERBS);\r
1291         p_ifc->InterfaceHeader.Version = VerbsVersion(VERBS_MAJOR_VER, VERBS_MINOR_VER);\r
1292         p_ifc->InterfaceHeader.Context = p_dev_obj;\r
1293         p_ifc->InterfaceHeader.InterfaceReference = __ref_ifc;\r
1294         p_ifc->InterfaceHeader.InterfaceDereference = __deref_ifc;\r
1295         p_ifc->Verbs = *p_hca_ifc;\r
1296 \r
1297         /* take the reference before returning. */\r
1298         __ref_ifc( p_dev_obj );\r
1299 \r
1300         ExFreePool( p_hca_ifc );\r
1301         status = STATUS_SUCCESS;\r
1302 \r
1303 exit:\r
1304         HCA_EXIT( HCA_DBG_PNP );\r
1305         return status;\r
1306 }\r
1307 \r
1308 \r
1309 static NTSTATUS\r
1310 hca_query_interface(\r
1311         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1312         IN                              IRP* const                                      p_irp, \r
1313                 OUT                     cl_irp_action_t* const          p_action )\r
1314 {\r
1315         NTSTATUS                        status;\r
1316         IO_STACK_LOCATION       *p_io_stack;\r
1317 \r
1318         HCA_ENTER( HCA_DBG_PNP );\r
1319 \r
1320 #pragma warning( push, 3 )\r
1321         PAGED_CODE();\r
1322 #pragma warning( pop )\r
1323 \r
1324         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1325         \r
1326         /* Compare requested GUID with our supported interface GUIDs. */\r
1327         if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
1328                 &GUID_RDMA_INTERFACE_VERBS ) )\r
1329         {\r
1330                 status = __query_ci_ifc( p_dev_obj, p_io_stack );\r
1331                 *p_action = IrpComplete;\r
1332         }\r
1333         else\r
1334         {\r
1335                 status = p_irp->IoStatus.Status;\r
1336                 *p_action = IrpSkip;\r
1337         }\r
1338 \r
1339         HCA_EXIT( HCA_DBG_PNP );\r
1340         return status;\r
1341 }\r
1342 \r
1343 \r
1344 static NTSTATUS\r
1345 hca_query_pnp_state(\r
1346         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1347         IN                              IRP* const                                      p_irp, \r
1348                 OUT                     cl_irp_action_t* const          p_action )\r
1349 {\r
1350         PFDO_DEVICE_DATA                p_fdo;\r
1351 \r
1352         HCA_ENTER( HCA_DBG_PNP );\r
1353 \r
1354         p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1355 \r
1356         p_irp->IoStatus.Information |= p_fdo->pnpState;\r
1357 \r
1358         *p_action = IrpSkip;\r
1359 \r
1360         HCA_EXIT( HCA_DBG_PNP );\r
1361         return STATUS_SUCCESS;;\r
1362 }\r
1363 \r
1364 static NTSTATUS\r
1365 hca_query_power(\r
1366         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1367         IN                              IRP* const                                      p_irp,\r
1368                 OUT                     cl_irp_action_t* const          p_action )\r
1369 {\r
1370         NTSTATUS                        status = STATUS_SUCCESS;\r
1371         IO_STACK_LOCATION       *pIoStack;\r
1372 \r
1373         HCA_ENTER(HCA_DBG_PO);\r
1374 \r
1375         UNUSED_PARAM( p_dev_obj );\r
1376 \r
1377         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1378 \r
1379         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1380                 ("QUERY_POWER for FDO %p: type %s, state %d, action %d, IRQL %d, IRP %p\n",\r
1381                 p_dev_obj, \r
1382                 (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
1383                 pIoStack->Parameters.Power.State.DeviceState, \r
1384                 pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql(), p_irp ));\r
1385 \r
1386         switch( pIoStack->Parameters.Power.Type )\r
1387         {\r
1388         case SystemPowerState:\r
1389                 /* Fail any requests to hibernate or sleep the system. */\r
1390                 switch( pIoStack->Parameters.Power.State.SystemState )\r
1391                 {\r
1392                         case PowerSystemSleeping1:      // STANDBY support\r
1393                         case PowerSystemHibernate:\r
1394                         {\r
1395                                 PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1396                                 if (atomic_read(&p_fdo->usecnt)) \r
1397                                         status = STATUS_UNSUCCESSFUL;\r
1398                                 break;\r
1399                         }\r
1400 \r
1401                         case PowerSystemWorking:\r
1402                         case PowerSystemShutdown:\r
1403                                 break;\r
1404 \r
1405                         default:\r
1406                                 status = STATUS_NOT_SUPPORTED;\r
1407                 }\r
1408                 break;\r
1409 \r
1410         case DevicePowerState:\r
1411                 /* Fail any query for low power states. */\r
1412                 switch( pIoStack->Parameters.Power.State.DeviceState )\r
1413                 {\r
1414                 case PowerDeviceD0:\r
1415                 case PowerDeviceD3:\r
1416                         /* We only support fully powered or off power states. */\r
1417                         break;\r
1418 \r
1419                 default:\r
1420                         status = STATUS_NOT_SUPPORTED;\r
1421                 }\r
1422                 break;\r
1423         }\r
1424 \r
1425         if( status == STATUS_SUCCESS )\r
1426                 *p_action = IrpSkip;\r
1427         else\r
1428                 *p_action = IrpComplete;\r
1429 \r
1430         HCA_EXIT( HCA_DBG_PO );\r
1431         return status;\r
1432 }\r
1433 \r
1434 \r
1435 static void\r
1436 __RequestPowerCompletion(\r
1437         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1438         IN                              UCHAR                                           minorFunction,\r
1439         IN                              POWER_STATE                                     powerState,\r
1440         IN                              void                                            *context,\r
1441         IN                              IO_STATUS_BLOCK                         *pIoStatus )\r
1442 {\r
1443         IRP                                     *p_irp;\r
1444         cl_pnp_po_ext_t         *p_fdo;\r
1445 \r
1446         HCA_ENTER( HCA_DBG_PO );\r
1447 \r
1448         UNUSED_PARAM( minorFunction );\r
1449         UNUSED_PARAM( powerState );\r
1450 \r
1451         p_irp = (IRP*)context;\r
1452         p_fdo = (cl_pnp_po_ext_t*)p_dev_obj->DeviceExtension;\r
1453 \r
1454         /* Propagate the device IRP status to the system IRP status. */\r
1455         p_irp->IoStatus.Status = pIoStatus->Status;\r
1456 \r
1457         /* Continue Power IRP processing. */\r
1458         PoStartNextPowerIrp( p_irp );\r
1459         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1460         IoReleaseRemoveLock( &p_fdo->remove_lock, p_irp );\r
1461         HCA_EXIT( HCA_DBG_PO );\r
1462 }\r
1463 \r
1464 \r
1465 /*NOTE: Completion routines must NEVER be pageable. */\r
1466 static NTSTATUS\r
1467 __SystemPowerCompletion(\r
1468         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1469         IN                              IRP                                                     *p_irp,\r
1470         IN                              void                                            *context )\r
1471 {\r
1472         NTSTATUS                        status;\r
1473         POWER_STATE                     state;\r
1474         PFDO_DEVICE_DATA        p_fdo;\r
1475         IO_STACK_LOCATION       *pIoStack;\r
1476 \r
1477         HCA_ENTER( HCA_DBG_PO );\r
1478 \r
1479         UNUSED_PARAM( context );\r
1480 \r
1481         p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1482         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1483 \r
1484         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1485         {\r
1486                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
1487                         ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n",\r
1488                         p_irp->IoStatus.Status));\r
1489                 status = STATUS_SUCCESS;\r
1490                 PoStartNextPowerIrp( p_irp );\r
1491                 goto release;\r
1492         }\r
1493 \r
1494         state.DeviceState = \r
1495                 p_fdo->DevicePower[pIoStack->Parameters.Power.State.SystemState];\r
1496 \r
1497         /*\r
1498          * Send a device power IRP to our devnode.  Using our device object will\r
1499          * only work on win2k and other NT based systems.\r
1500          */\r
1501         status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
1502                 __RequestPowerCompletion, p_irp, NULL );\r
1503 \r
1504         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1505                 ("PoRequestPowerIrp: SET_POWER 'PowerDeviceD%d', status %#x\n", \r
1506                 state.DeviceState - 1, status ));\r
1507 \r
1508         if( status != STATUS_PENDING ) {\r
1509                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO,\r
1510                         ("PoRequestPowerIrp returned %08x.\n", status));\r
1511                 p_irp->IoStatus.Status = status;        /* Propagate the failure. */\r
1512                 PoStartNextPowerIrp( p_irp );\r
1513                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1514                 goto release;\r
1515         }\r
1516 \r
1517         status = STATUS_MORE_PROCESSING_REQUIRED;\r
1518         goto exit;\r
1519 \r
1520 release:        \r
1521         IoReleaseRemoveLock( &p_fdo->cl_ext.remove_lock, p_irp );\r
1522 exit:\r
1523         HCA_EXIT( HCA_DBG_PO );\r
1524         return status;\r
1525 }\r
1526 \r
1527 \r
1528 /* Work item callback to handle DevicePowerD0 IRPs at passive level. */\r
1529 static void\r
1530 __DevicePowerUpCompletionWorkItem(\r
1531         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1532         IN                              void*                                           context )\r
1533 {\r
1534         int                                     err;\r
1535         NTSTATUS                        status;\r
1536         IO_STACK_LOCATION       *pIoStack;\r
1537         PFDO_DEVICE_DATA        p_fdo;\r
1538         IRP                                     *p_irp;\r
1539         POWER_STATE powerState;\r
1540 \r
1541         HCA_ENTER( HCA_DBG_PO );\r
1542 \r
1543         p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1544         p_irp = (IRP*)context;\r
1545         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1546 \r
1547         IoFreeWorkItem( p_fdo->pPoWorkItem );\r
1548         p_fdo->pPoWorkItem = NULL;\r
1549 \r
1550         /* restart the HCA */\r
1551         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1552                 ("***** Restart the HCA, IRQL %d\n", KeGetCurrentIrql()));\r
1553 \r
1554         /* get MLX4_BUS IB interface */\r
1555         status = __get_ifc( p_dev_obj, &MLX4_BUS_IB_INTERFACE_GUID,\r
1556                 sizeof(MLX4_BUS_IB_INTERFACE), MLX4_BUS_IB_INTERFACE_VERSION, NULL, (PINTERFACE)&p_fdo->bus_ib_ifc);\r
1557         if( !NT_SUCCESS( status ) ) {\r
1558                 HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting MLX4 BUS interface failed: status=0x%x\n", status));\r
1559                 goto err_hca_reg;\r
1560         }\r
1561         p_fdo->bus_ib_ifc_taken = TRUE;\r
1562         p_fdo->bus_ib_ifc.p_ibdev->x.p_fdo = p_fdo;\r
1563 \r
1564         /* get node GUID */\r
1565         err = __get_dev_info( p_fdo, &p_fdo->hca.guid, &p_fdo->hca.hw_ver );\r
1566         if (err) {\r
1567 \r
1568                 HCA_PRINT(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,\r
1569                         ("can't get guid - ib_query_device() failed (%08X)\n", err ));\r
1570                 //TODO: no cleanup on error\r
1571                 goto err_hca_reg;\r
1572         }\r
1573 \r
1574         p_fdo->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState;\r
1575         powerState = PoSetPowerState( p_dev_obj, DevicePowerState,\r
1576                 pIoStack->Parameters.Power.State );\r
1577 \r
1578         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1579                 ("PoSetPowerState: old state %d, new state to %d\n", \r
1580                 powerState.DeviceState, p_fdo->DevicePowerState ));\r
1581 \r
1582         goto exit;\r
1583 \r
1584 err_hca_reg:\r
1585         /* Flag device as having failed. */\r
1586         p_fdo->pnpState |= PNP_DEVICE_FAILED;\r
1587         IoInvalidateDeviceState( p_fdo->cl_ext.p_pdo );\r
1588 exit:\r
1589         PoStartNextPowerIrp( p_irp );\r
1590         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1591         IoReleaseRemoveLock( &p_fdo->cl_ext.remove_lock, p_irp );\r
1592         HCA_EXIT( HCA_DBG_PO );\r
1593 }\r
1594 \r
1595 /*NOTE: Completion routines must NEVER be pageable. */\r
1596 static NTSTATUS\r
1597 __DevicePowerUpCompletion(\r
1598         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1599         IN                              IRP                                                     *p_irp,\r
1600         IN                              void                                            *context )\r
1601 {\r
1602         NTSTATUS                        status = STATUS_SUCCESS;\r
1603         PFDO_DEVICE_DATA        p_fdo;\r
1604         IO_STACK_LOCATION       *pIoStack;\r
1605 \r
1606         HCA_ENTER( HCA_DBG_PO );\r
1607 \r
1608         UNUSED_PARAM( context );\r
1609 \r
1610         p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1611         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1612 \r
1613         if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) {\r
1614                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
1615                         ("IRP_MN_SET_POWER for device failed by lower driver with %08x.\n",\r
1616                         p_irp->IoStatus.Status));\r
1617                 status =  STATUS_SUCCESS;\r
1618                 PoStartNextPowerIrp( p_irp );\r
1619                 goto release;\r
1620         }\r
1621 \r
1622         /* Process in a work item - mthca_start blocks. */\r
1623         ASSERT( !p_fdo->pPoWorkItem );\r
1624         p_fdo->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1625         if( !p_fdo->pPoWorkItem ) {\r
1626                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
1627                         ("Failed to allocate work item.\n" ));\r
1628                 status = STATUS_SUCCESS;\r
1629                 p_fdo->pnpState |= PNP_DEVICE_FAILED;\r
1630                 IoInvalidateDeviceState( p_fdo->cl_ext.p_pdo );\r
1631                 PoStartNextPowerIrp( p_irp );\r
1632                 goto release;\r
1633         }\r
1634 \r
1635         /* Process in work item callback. */\r
1636         IoMarkIrpPending( p_irp );\r
1637         IoQueueWorkItem( p_fdo->pPoWorkItem, \r
1638                 __DevicePowerUpCompletionWorkItem, DelayedWorkQueue, p_irp );\r
1639         status = STATUS_MORE_PROCESSING_REQUIRED;\r
1640         goto exit;\r
1641 \r
1642 release:        \r
1643         IoReleaseRemoveLock( &p_fdo->cl_ext.remove_lock, p_irp );\r
1644 exit:   \r
1645         HCA_EXIT( HCA_DBG_PO );\r
1646         return status;\r
1647 }\r
1648 \r
1649 static NTSTATUS __DevicePowerDownWorkItemCompletion(\r
1650         IN                              DEVICE_OBJECT   *p_dev_obj,\r
1651         IN                              IRP                             *p_irp,\r
1652         IN                              void                            *context )\r
1653 {\r
1654         PFDO_DEVICE_DATA  p_fdo  = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1655         UNUSED_PARAM( context );\r
1656 \r
1657         HCA_ENTER( HCA_DBG_PO );\r
1658 \r
1659         PoStartNextPowerIrp( p_irp );\r
1660         IoReleaseRemoveLock( &p_fdo->cl_ext.remove_lock, p_irp );\r
1661 \r
1662         HCA_EXIT( HCA_DBG_PO );\r
1663         return STATUS_SUCCESS;\r
1664 }\r
1665 \r
1666 /* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
1667 static void\r
1668 __DevicePowerDownWorkItem(\r
1669         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1670         IN                              void*                                           context )\r
1671 {\r
1672         IO_STACK_LOCATION       *pIoStack;\r
1673         PFDO_DEVICE_DATA        p_fdo;\r
1674         IRP                                     *p_irp;\r
1675         POWER_STATE powerState;\r
1676 \r
1677         HCA_ENTER( HCA_DBG_PO );\r
1678 \r
1679         p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1680         p_irp = (IRP*)context;\r
1681         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1682 \r
1683         IoFreeWorkItem( p_fdo->pPoWorkItem );\r
1684         p_fdo->pPoWorkItem = NULL;\r
1685 \r
1686         p_fdo->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState;\r
1687         powerState = PoSetPowerState( p_dev_obj, DevicePowerState,\r
1688                 pIoStack->Parameters.Power.State );\r
1689 \r
1690         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1691                 ("PoSetPowerState: old state %d, new state to %d, IRQL %d\n", \r
1692                 powerState.DeviceState, p_fdo->DevicePowerState, KeGetCurrentIrql() ));\r
1693 \r
1694         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1695                 ("***** Remove the HCA \n"));\r
1696 \r
1697         // release MLX4_BUS resources\r
1698         if(p_fdo->bus_ib_ifc_taken) {\r
1699                 p_fdo->bus_ib_ifc_taken = FALSE;\r
1700                 __put_ifc( (PINTERFACE)&p_fdo->bus_ib_ifc );\r
1701         }\r
1702 \r
1703         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1704 #pragma warning( push, 3 )\r
1705         IoSetCompletionRoutine( p_irp, __DevicePowerDownWorkItemCompletion,\r
1706                 NULL, TRUE, TRUE, TRUE );\r
1707 #pragma warning( pop )\r
1708         PoCallDriver( p_fdo->cl_ext.p_next_do, p_irp );\r
1709 \r
1710         HCA_EXIT( HCA_DBG_PO );\r
1711 }\r
1712 \r
1713 \r
1714 static NTSTATUS\r
1715 hca_set_power(\r
1716         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1717         IN                              IRP* const                                      p_irp,\r
1718                 OUT                     cl_irp_action_t* const          p_action )\r
1719 {\r
1720         NTSTATUS                        status;\r
1721         IO_STACK_LOCATION       *pIoStack;\r
1722         PFDO_DEVICE_DATA        p_fdo;\r
1723 \r
1724         HCA_ENTER( HCA_DBG_PO );\r
1725 \r
1726         p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
1727         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1728 \r
1729         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1730                 ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d, IRQL %d \n",\r
1731                 p_dev_obj, p_fdo,\r
1732                 (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
1733                 pIoStack->Parameters.Power.State.DeviceState, \r
1734                 pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql() ));\r
1735 \r
1736         switch( pIoStack->Parameters.Power.Type )\r
1737         {\r
1738         case SystemPowerState:\r
1739                 p_fdo->SystemPowerState = pIoStack->Parameters.Power.State.SystemState;\r
1740                 \r
1741                 /*\r
1742                  * Process on the way up the stack.  We cannot block since the \r
1743                  * power dispatch function can be called at elevated IRQL if the\r
1744                  * device is in a paging/hibernation/crash dump path.\r
1745                  */\r
1746                 IoMarkIrpPending( p_irp );\r
1747                 IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1748 #pragma warning( push, 3 )\r
1749                 IoSetCompletionRoutine( p_irp, __SystemPowerCompletion, NULL, \r
1750                         TRUE, TRUE, TRUE );\r
1751 #pragma warning( pop )\r
1752                 PoCallDriver( p_fdo->cl_ext.p_next_do, p_irp );\r
1753 \r
1754                 *p_action = IrpDoNothing;\r
1755                 status = STATUS_PENDING;\r
1756                 break;\r
1757 \r
1758         case DevicePowerState:\r
1759                 IoMarkIrpPending( p_irp );\r
1760                 if( pIoStack->Parameters.Power.State.DeviceState == PowerDeviceD0 && \r
1761                         p_fdo->SystemPowerState == PowerSystemWorking)\r
1762                 { /* power up */\r
1763                         /* If we're already powered up, just pass down. */\r
1764                         if( p_fdo->DevicePowerState == PowerDeviceD0 )\r
1765                         {\r
1766                                 status = STATUS_SUCCESS;\r
1767                                 *p_action = IrpIgnore;\r
1768                                 break;\r
1769                         }\r
1770 \r
1771                         /* Process in I/O completion callback. */\r
1772                         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1773 #pragma warning( push, 3 )\r
1774                         IoSetCompletionRoutine( p_irp, __DevicePowerUpCompletion, NULL, \r
1775                                 TRUE, TRUE, TRUE );\r
1776 #pragma warning( pop )\r
1777                         PoCallDriver( p_fdo->cl_ext.p_next_do, p_irp );\r
1778                 }\r
1779                 else\r
1780                 { /* power down */\r
1781 \r
1782                         /* Process in a work item - deregister_ca and HcaDeinit block. */\r
1783                         ASSERT( !p_fdo->pPoWorkItem );\r
1784                         p_fdo->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1785                         if( !p_fdo->pPoWorkItem )\r
1786                         {\r
1787                                 status = STATUS_INSUFFICIENT_RESOURCES;\r
1788                                 break;\r
1789                         }\r
1790 \r
1791                         /* Process in work item callback. */\r
1792                         IoQueueWorkItem(\r
1793                                 p_fdo->pPoWorkItem, __DevicePowerDownWorkItem, DelayedWorkQueue, p_irp );\r
1794                 }\r
1795                 *p_action = IrpDoNothing;\r
1796                 status = STATUS_PENDING;\r
1797                 break;\r
1798 \r
1799         default:\r
1800                 /* Pass down and let the PDO driver handle it. */\r
1801                 *p_action = IrpIgnore;\r
1802                 status = STATUS_SUCCESS;\r
1803                 break;\r
1804         }\r
1805 \r
1806         if( !NT_SUCCESS( status ) )\r
1807                 *p_action = IrpComplete;\r
1808 \r
1809         HCA_EXIT( HCA_DBG_PNP );\r
1810         return status;\r
1811 }\r
1812 \r
1813 void\r
1814 hca_init_vfptr( void )\r
1815 {\r
1816         vfptrHcaPnp.identity = "MLX4_HCA driver";\r
1817         vfptrHcaPnp.pfn_start = hca_start;\r
1818         vfptrHcaPnp.pfn_query_stop = hca_query_stop;\r
1819         vfptrHcaPnp.pfn_stop = hca_stop;\r
1820         vfptrHcaPnp.pfn_cancel_stop = hca_cancel_stop;\r
1821         vfptrHcaPnp.pfn_query_remove = hca_query_remove;\r
1822         vfptrHcaPnp.pfn_release_resources = hca_release_resources;\r
1823         vfptrHcaPnp.pfn_remove = cl_do_remove;\r
1824         vfptrHcaPnp.pfn_cancel_remove = hca_cancel_remove;\r
1825         vfptrHcaPnp.pfn_surprise_remove = hca_surprise_remove;\r
1826         vfptrHcaPnp.pfn_query_capabilities = hca_query_capabilities;\r
1827         vfptrHcaPnp.pfn_query_pnp_state = hca_query_pnp_state;\r
1828         vfptrHcaPnp.pfn_filter_res_req = cl_irp_skip;\r
1829         vfptrHcaPnp.pfn_dev_usage_notification = cl_do_sync_pnp;\r
1830         vfptrHcaPnp.pfn_query_bus_relations = cl_irp_ignore;\r
1831         vfptrHcaPnp.pfn_query_ejection_relations = cl_irp_ignore;\r
1832         vfptrHcaPnp.pfn_query_removal_relations = cl_irp_ignore;\r
1833         vfptrHcaPnp.pfn_query_target_relations = cl_irp_ignore;\r
1834         vfptrHcaPnp.pfn_unknown = cl_irp_ignore;\r
1835         vfptrHcaPnp.pfn_query_resources = cl_irp_ignore;\r
1836         vfptrHcaPnp.pfn_query_res_req = cl_irp_ignore;\r
1837         vfptrHcaPnp.pfn_query_bus_info = cl_irp_ignore;\r
1838         vfptrHcaPnp.pfn_query_interface = hca_query_interface;\r
1839         vfptrHcaPnp.pfn_read_config = cl_irp_ignore;\r
1840         vfptrHcaPnp.pfn_write_config = cl_irp_ignore;\r
1841         vfptrHcaPnp.pfn_eject = cl_irp_ignore;\r
1842         vfptrHcaPnp.pfn_set_lock = cl_irp_ignore;\r
1843         vfptrHcaPnp.pfn_query_power = hca_query_power;\r
1844         vfptrHcaPnp.pfn_set_power = hca_set_power;\r
1845         vfptrHcaPnp.pfn_power_sequence = cl_irp_ignore;\r
1846         vfptrHcaPnp.pfn_wait_wake = cl_irp_ignore;\r
1847 }\r
1848 \r
1849 static NTSTATUS\r
1850 __read_registry(\r
1851         IN                              UNICODE_STRING* const   p_registry_path )\r
1852 {\r
1853         NTSTATUS                                        status;\r
1854         /* Remember the terminating entry in the table below. */\r
1855         RTL_QUERY_REGISTRY_TABLE        table[3];\r
1856 \r
1857         HCA_ENTER( HCA_DBG_PNP );\r
1858 \r
1859         RtlInitUnicodeString( &g_param_path, NULL );\r
1860         g_param_path.MaximumLength = p_registry_path->Length + \r
1861                 sizeof(L"\\Parameters");\r
1862         g_param_path.Buffer = cl_zalloc( g_param_path.MaximumLength );\r
1863         if( !g_param_path.Buffer )\r
1864         {\r
1865                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1866                         ("Failed to allocate parameters path buffer.\n"));\r
1867                 return STATUS_INSUFFICIENT_RESOURCES;\r
1868         }\r
1869 \r
1870         RtlAppendUnicodeStringToString( &g_param_path, p_registry_path );\r
1871         RtlAppendUnicodeToString( &g_param_path, L"\\Parameters" );\r
1872 \r
1873         /*\r
1874          * Clear the table.  This clears all the query callback pointers,\r
1875          * and sets up the terminating table entry.\r
1876          */\r
1877         cl_memclr( table, sizeof(table) );\r
1878 \r
1879         /* Setup the table entries. */\r
1880         table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
1881         table[0].Name = L"DebugLevel";\r
1882         table[0].EntryContext = &g.DebugPrintLevel;\r
1883         table[0].DefaultType = REG_DWORD;\r
1884         table[0].DefaultData = &g.DebugPrintLevel;\r
1885         table[0].DefaultLength = sizeof(ULONG);\r
1886 \r
1887         \r
1888         table[1].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
1889         table[1].Name = L"DebugFlags";\r
1890         table[1].EntryContext = &g.DebugPrintFlags;\r
1891         table[1].DefaultType = REG_DWORD;\r
1892         table[1].DefaultData = &g.DebugPrintFlags;\r
1893         table[1].DefaultLength = sizeof(ULONG);\r
1894 \r
1895 \r
1896         /* Have at it! */\r
1897         status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
1898                 g_param_path.Buffer, table, NULL, NULL );\r
1899 \r
1900         HCA_EXIT( HCA_DBG_PNP );\r
1901         return status;\r
1902 }\r
1903 \r
1904 static void\r
1905 hca_drv_unload(\r
1906         IN                              PDRIVER_OBJECT                  p_driver_obj )\r
1907 {\r
1908         HCA_ENTER( HCA_DBG_PNP );\r
1909 \r
1910         UNUSED_PARAM( p_driver_obj );\r
1911 \r
1912         cl_free( g_param_path.Buffer );\r
1913         \r
1914         HCA_EXIT( HCA_DBG_PNP );\r
1915 #if defined(EVENT_TRACING)\r
1916         WPP_CLEANUP(p_driver_obj);\r
1917 #endif\r
1918 \r
1919 }\r
1920 \r
1921 static NTSTATUS\r
1922 hca_sysctl(\r
1923         IN                              PDEVICE_OBJECT                          p_dev_obj,\r
1924         IN                              PIRP                                            p_irp )\r
1925 {\r
1926         NTSTATUS                status;\r
1927         PFDO_DEVICE_DATA        p_fdo;\r
1928 \r
1929         HCA_ENTER( HCA_DBG_PNP );\r
1930 \r
1931         p_fdo = p_dev_obj->DeviceExtension;\r
1932 \r
1933         IoSkipCurrentIrpStackLocation( p_irp );\r
1934         status = IoCallDriver( p_fdo->cl_ext.p_next_do, p_irp );\r
1935 \r
1936         HCA_EXIT( HCA_DBG_PNP );\r
1937         return status;\r
1938 }\r
1939 \r
1940 \r
1941 NTSTATUS\r
1942 DriverEntry(\r
1943         IN                              PDRIVER_OBJECT                  p_driver_obj,\r
1944         IN                              PUNICODE_STRING                 p_registry_path )\r
1945 {\r
1946         NTSTATUS                        status;\r
1947 #if defined(EVENT_TRACING)\r
1948         WPP_INIT_TRACING(p_driver_obj ,p_registry_path);\r
1949 #endif\r
1950         // global initializations\r
1951         g.DebugPrintLevel = TRACE_LEVEL_VERBOSE;\r
1952         g.DebugPrintFlags = 0xffff;\r
1953 \r
1954         HCA_ENTER( HCA_DBG_PNP );\r
1955 \r
1956         status = mlnx_hcas_init();\r
1957         if( status  != STATUS_SUCCESS ) {\r
1958                 HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,\r
1959                         ("mlnx_hcas_init returned %#x.\n", status));\r
1960                 goto end;\r
1961         }\r
1962 \r
1963         status = __read_registry( p_registry_path );\r
1964         if( !NT_SUCCESS( status ) )\r
1965         {\r
1966                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1967                         ("__read_registry_path returned 0x%X.\n", status));\r
1968                 return status;\r
1969         }\r
1970 \r
1971         /*leo:  init function table */\r
1972         hca_init_vfptr();\r
1973         \r
1974         p_driver_obj->MajorFunction[IRP_MJ_PNP] = cl_pnp;\r
1975         p_driver_obj->MajorFunction[IRP_MJ_POWER] = cl_power;\r
1976         p_driver_obj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = hca_sysctl;\r
1977         p_driver_obj->DriverUnload = hca_drv_unload;\r
1978         p_driver_obj->DriverExtension->AddDevice = hca_add_device;\r
1979 \r
1980 end:\r
1981         HCA_EXIT( HCA_DBG_PNP );\r
1982         return STATUS_SUCCESS;\r
1983 }\r
1984 \r
1985 #endif\r