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