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