[MTHCA] 1. feature: the driver will now enter a simulated "livefish" mode in case...
[mirror/winof/.git] / hw / mthca / kernel / hca_pnp.c
1 /* BEGIN_ICS_COPYRIGHT ****************************************\r
2 ** END_ICS_COPYRIGHT   ****************************************/\r
3 \r
4 /*\r
5         $Revision: 1.1 $\r
6 */\r
7 \r
8 \r
9 /*\r
10  * Provides the driver entry points for the Tavor VPD.\r
11  */\r
12 \r
13 #include "hca_driver.h"\r
14 #include "mthca_dev.h"\r
15 \r
16 #if defined(EVENT_TRACING)\r
17 #ifdef offsetof\r
18 #undef offsetof\r
19 #endif\r
20 #include "hca_pnp.tmh"\r
21 #endif\r
22 #include "mthca.h"\r
23 #include <initguid.h>\r
24 #include <wdmguid.h>\r
25 \r
26 extern const char *mthca_version;\r
27 \r
28 static NTSTATUS\r
29 hca_start(\r
30         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
31         IN                              IRP* const                                      p_irp, \r
32                 OUT                     cl_irp_action_t* const          p_action );\r
33 \r
34 static NTSTATUS\r
35 hca_query_stop(\r
36         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
37         IN                              IRP* const                                      p_irp, \r
38                 OUT                     cl_irp_action_t* const          p_action );\r
39 \r
40 static NTSTATUS\r
41 hca_stop(\r
42         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
43         IN                              IRP* const                                      p_irp, \r
44                 OUT                     cl_irp_action_t* const          p_action );\r
45 \r
46 static NTSTATUS\r
47 hca_cancel_stop(\r
48         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
49         IN                              IRP* const                                      p_irp, \r
50                 OUT                     cl_irp_action_t* const          p_action );\r
51 \r
52 static NTSTATUS\r
53 hca_query_remove(\r
54         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
55         IN                              IRP* const                                      p_irp, \r
56                 OUT                     cl_irp_action_t* const          p_action );\r
57 \r
58 static void\r
59 hca_release_resources(\r
60         IN                              DEVICE_OBJECT* const            p_dev_obj );\r
61 \r
62 static NTSTATUS\r
63 hca_cancel_remove(\r
64         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
65         IN                              IRP* const                                      p_irp, \r
66                 OUT                     cl_irp_action_t* const          p_action );\r
67 \r
68 static NTSTATUS\r
69 hca_surprise_remove(\r
70         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
71         IN                              IRP* const                                      p_irp, \r
72                 OUT                     cl_irp_action_t* const          p_action );\r
73 \r
74 static NTSTATUS\r
75 hca_query_capabilities(\r
76         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
77         IN                              IRP* const                                      p_irp, \r
78                 OUT                     cl_irp_action_t* const          p_action );\r
79 \r
80 static NTSTATUS\r
81 hca_query_pnp_state(\r
82         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
83         IN                              IRP* const                                      p_irp, \r
84                 OUT                     cl_irp_action_t* const          p_action );\r
85 \r
86 static NTSTATUS\r
87 hca_query_bus_relations(\r
88         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
89         IN                              IRP* const                                      p_irp, \r
90                 OUT                     cl_irp_action_t* const          p_action );\r
91 \r
92 static NTSTATUS\r
93 hca_query_removal_relations(\r
94         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
95         IN                              IRP* const                                      p_irp, \r
96                 OUT                     cl_irp_action_t* const          p_action );\r
97 \r
98 static NTSTATUS\r
99 hca_query_power(\r
100         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
101         IN                              IRP* const                                      p_irp,\r
102                 OUT                     cl_irp_action_t* const          p_action );\r
103 \r
104 static NTSTATUS\r
105 hca_set_power(\r
106         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
107         IN                              IRP* const                                      p_irp, \r
108                 OUT                     cl_irp_action_t* const          p_action );\r
109 \r
110 static ci_interface_t*\r
111 __alloc_hca_ifc(\r
112         IN                              hca_dev_ext_t* const            p_ext );\r
113 \r
114 static NTSTATUS\r
115 __get_ci_interface(\r
116         IN                              DEVICE_OBJECT* const            p_dev_obj );\r
117 \r
118 static void\r
119 __hca_deregister(\r
120         IN                              hca_dev_ext_t                   *p_ext );\r
121 \r
122 static NTSTATUS\r
123 __hca_register(\r
124         IN                              DEVICE_OBJECT                           *p_dev_obj );\r
125 \r
126 static NTSTATUS\r
127 __pnp_notify_target(\r
128         IN                              void                                            *pNotifyStruct,\r
129         IN                              void                                            *context );\r
130 \r
131 static NTSTATUS\r
132 __pnp_notify_ifc(\r
133         IN                              void                                            *pNotifyStruct,\r
134         IN                              void                                            *context );\r
135 \r
136 \r
137 #ifdef ALLOC_PRAGMA\r
138 #pragma alloc_text (PAGE, hca_add_device)\r
139 #pragma alloc_text (PAGE, hca_start)\r
140 #pragma alloc_text (PAGE, hca_query_stop)\r
141 #pragma alloc_text (PAGE, hca_stop)\r
142 #pragma alloc_text (PAGE, hca_cancel_stop)\r
143 #pragma alloc_text (PAGE, hca_query_remove)\r
144 #pragma alloc_text (PAGE, hca_release_resources)\r
145 #pragma alloc_text (PAGE, hca_cancel_remove)\r
146 #pragma alloc_text (PAGE, hca_surprise_remove)\r
147 #pragma alloc_text (PAGE, hca_query_capabilities)\r
148 #pragma alloc_text (PAGE, hca_query_pnp_state)\r
149 #pragma alloc_text (PAGE, hca_query_bus_relations)\r
150 #pragma alloc_text (PAGE, hca_query_removal_relations)\r
151 #pragma alloc_text (PAGE, hca_set_power)\r
152 #pragma alloc_text (PAGE, __alloc_hca_ifc)\r
153 #pragma alloc_text (PAGE, __get_ci_interface)\r
154 #pragma alloc_text (PAGE, __hca_register)\r
155 #pragma alloc_text (PAGE, __pnp_notify_target)\r
156 #pragma alloc_text (PAGE, __pnp_notify_ifc)\r
157 #endif\r
158 \r
159 \r
160 static cl_vfptr_pnp_po_t        vfptrHcaPnp;\r
161 \r
162 \r
163 void\r
164 hca_init_vfptr( void )\r
165 {\r
166         vfptrHcaPnp.identity = "HCA driver";\r
167         vfptrHcaPnp.pfn_start = hca_start;\r
168         vfptrHcaPnp.pfn_query_stop = hca_query_stop;\r
169         vfptrHcaPnp.pfn_stop = hca_stop;\r
170         vfptrHcaPnp.pfn_cancel_stop = hca_cancel_stop;\r
171         vfptrHcaPnp.pfn_query_remove = hca_query_remove;\r
172         vfptrHcaPnp.pfn_release_resources = hca_release_resources;\r
173         vfptrHcaPnp.pfn_remove = cl_do_remove;\r
174         vfptrHcaPnp.pfn_cancel_remove = hca_cancel_remove;\r
175         vfptrHcaPnp.pfn_surprise_remove = hca_surprise_remove;\r
176         vfptrHcaPnp.pfn_query_capabilities = hca_query_capabilities;\r
177         vfptrHcaPnp.pfn_query_pnp_state = hca_query_pnp_state;\r
178         vfptrHcaPnp.pfn_filter_res_req = cl_irp_skip;\r
179         vfptrHcaPnp.pfn_dev_usage_notification = cl_do_sync_pnp;\r
180         vfptrHcaPnp.pfn_query_bus_relations = hca_query_bus_relations;\r
181         vfptrHcaPnp.pfn_query_ejection_relations = cl_irp_ignore;\r
182         vfptrHcaPnp.pfn_query_removal_relations = hca_query_removal_relations;\r
183         vfptrHcaPnp.pfn_query_target_relations = cl_irp_ignore;\r
184         vfptrHcaPnp.pfn_unknown = cl_irp_ignore;\r
185         vfptrHcaPnp.pfn_query_resources = cl_irp_ignore;\r
186         vfptrHcaPnp.pfn_query_res_req = cl_irp_ignore;\r
187         vfptrHcaPnp.pfn_query_bus_info = cl_irp_ignore;\r
188         vfptrHcaPnp.pfn_query_interface = cl_irp_ignore;\r
189         vfptrHcaPnp.pfn_read_config = cl_irp_ignore;\r
190         vfptrHcaPnp.pfn_write_config = cl_irp_ignore;\r
191         vfptrHcaPnp.pfn_eject = cl_irp_ignore;\r
192         vfptrHcaPnp.pfn_set_lock = cl_irp_ignore;\r
193         vfptrHcaPnp.pfn_query_power = hca_query_power;\r
194         vfptrHcaPnp.pfn_set_power = hca_set_power;\r
195         vfptrHcaPnp.pfn_power_sequence = cl_irp_ignore;\r
196         vfptrHcaPnp.pfn_wait_wake = cl_irp_ignore;\r
197 }\r
198 \r
199 \r
200 NTSTATUS\r
201 hca_add_device(\r
202         IN                              PDRIVER_OBJECT                          pDriverObj,\r
203         IN                              PDEVICE_OBJECT                          pPdo )\r
204 {\r
205         NTSTATUS                        status;\r
206         DEVICE_OBJECT           *p_dev_obj, *pNextDevObj;\r
207         hca_dev_ext_t           *p_ext;\r
208 \r
209         HCA_ENTER(HCA_DBG_PNP);\r
210 \r
211         /*\r
212          * Create the device so that we have a device extension to store stuff in.\r
213          */\r
214         status = IoCreateDevice( pDriverObj, sizeof(hca_dev_ext_t),\r
215                 NULL, FILE_DEVICE_INFINIBAND, FILE_DEVICE_SECURE_OPEN,\r
216                 FALSE, &p_dev_obj );\r
217         if( !NT_SUCCESS( status ) )\r
218         {\r
219                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
220                         ("IoCreateDevice returned 0x%08X.\n", status));\r
221                 return status;\r
222         }\r
223 \r
224         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
225         cl_memclr( p_ext, sizeof(hca_dev_ext_t) );\r
226         cl_spinlock_init( &p_ext->uctx_lock );\r
227         cl_qlist_init( &p_ext->uctx_list );\r
228         atomic_set(&p_ext->usecnt, 0);\r
229 \r
230         /* Attach to the device stack. */\r
231         pNextDevObj = IoAttachDeviceToDeviceStack( p_dev_obj, pPdo );\r
232         if( !pNextDevObj )\r
233         {\r
234                 //cl_event_destroy( &p_ext->mutex );\r
235                 IoDeleteDevice( p_dev_obj );\r
236                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
237                         ("IoAttachDeviceToDeviceStack failed.\n"));\r
238                 return STATUS_NO_SUCH_DEVICE;\r
239         }\r
240 \r
241         /* Inititalize the complib extension. */\r
242         cl_init_pnp_po_ext( p_dev_obj, pNextDevObj, pPdo, 0,\r
243                 &vfptrHcaPnp, NULL );\r
244 \r
245         p_ext->state = HCA_ADDED;\r
246 \r
247         HCA_EXIT(HCA_DBG_PNP);\r
248         return status;\r
249 }\r
250 \r
251 \r
252 static NTSTATUS\r
253 __get_ci_interface(\r
254         IN                                      DEVICE_OBJECT* const    p_dev_obj )\r
255 {\r
256         NTSTATUS                        status;\r
257         IRP                                     *p_irp;\r
258         hca_dev_ext_t           *p_ext;\r
259         IO_STATUS_BLOCK         ioStatus;\r
260         IO_STACK_LOCATION       *pIoStack;\r
261         KEVENT                          event;\r
262 \r
263         HCA_ENTER( HCA_DBG_PNP );\r
264 \r
265         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
266 \r
267         KeInitializeEvent( &event, NotificationEvent, FALSE );\r
268 \r
269         /* Query for the verbs interface. */\r
270         p_irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, p_ext->p_al_dev,\r
271                 NULL, 0, NULL, &event, &ioStatus );\r
272         if( !p_irp )\r
273         {\r
274                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
275                         ("IoBuildSynchronousFsdRequest failed.\n"));\r
276                 return STATUS_INSUFFICIENT_RESOURCES;\r
277         }\r
278 \r
279         /* Format the IRP. */\r
280         pIoStack = IoGetNextIrpStackLocation( p_irp );\r
281         pIoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;\r
282         pIoStack->Parameters.QueryInterface.Version = IB_CI_INTERFACE_VERSION;\r
283         pIoStack->Parameters.QueryInterface.Size = sizeof(ib_ci_ifc_t);\r
284         pIoStack->Parameters.QueryInterface.Interface = \r
285                 (INTERFACE*)&p_ext->ci_ifc;\r
286         pIoStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;\r
287         pIoStack->Parameters.QueryInterface.InterfaceType = \r
288                 &GUID_IB_CI_INTERFACE;\r
289         p_irp->IoStatus.Status = STATUS_NOT_SUPPORTED;\r
290 \r
291         /* Send the IRP. */\r
292         status = IoCallDriver( p_ext->p_al_dev, p_irp );\r
293         if( status == STATUS_PENDING )\r
294         {\r
295                 KeWaitForSingleObject( &event, Executive, KernelMode, \r
296                         FALSE, NULL );\r
297 \r
298                 status = ioStatus.Status;\r
299         }\r
300 \r
301         if( !NT_SUCCESS( status ) )\r
302         {\r
303                 HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, \r
304                         ("Query interface for verbs returned %08x.\n", status));\r
305                 return status;\r
306         }\r
307 \r
308         HCA_EXIT( HCA_DBG_PNP );\r
309         return status;\r
310 }\r
311 \r
312 \r
313 static NTSTATUS\r
314 __pnp_notify_target(\r
315         IN                              void                                            *pNotifyStruct,\r
316         IN                              void                                            *context )\r
317 {\r
318         NTSTATUS                                                        status = STATUS_SUCCESS;\r
319         DEVICE_OBJECT                                           *p_dev_obj;\r
320         hca_dev_ext_t                                           *p_ext;\r
321         TARGET_DEVICE_REMOVAL_NOTIFICATION      *pNotify;\r
322 \r
323         HCA_ENTER( HCA_DBG_PNP );\r
324 \r
325         pNotify = (TARGET_DEVICE_REMOVAL_NOTIFICATION*)pNotifyStruct;\r
326         p_dev_obj = (DEVICE_OBJECT*)context;\r
327         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
328 \r
329         if( IsEqualGUID( &pNotify->Event, &GUID_TARGET_DEVICE_QUERY_REMOVE ) )\r
330         {\r
331                 if ( p_ext->state == HCA_REGISTERED) {\r
332                         /* Release AL's CI interface. */\r
333                         p_ext->ci_ifc.wdm.InterfaceDereference( p_ext->ci_ifc.wdm.Context );\r
334                         p_ext->state = HCA_IFC_DEREFERENCED;\r
335                 }\r
336 \r
337                 /* Release AL's file object so that it can unload. */\r
338                 CL_ASSERT( p_ext->p_al_dev );\r
339                 CL_ASSERT( p_ext->p_al_file_obj );\r
340                 CL_ASSERT( p_ext->p_al_file_obj == pNotify->FileObject );\r
341                 if( p_ext->p_al_file_obj ) {\r
342                         ObDereferenceObject( p_ext->p_al_file_obj );\r
343                         p_ext->p_al_file_obj = NULL;\r
344                         p_ext->p_al_dev = NULL;\r
345                 }\r
346         }\r
347         else if( IsEqualGUID( &pNotify->Event, \r
348                 &GUID_TARGET_DEVICE_REMOVE_COMPLETE ) )\r
349         {\r
350                 if (p_ext->ci_ifc.deregister_ca) {\r
351                         /* Notify AL that the CA is being removed. */\r
352                         p_ext->ci_ifc.deregister_ca( p_ext->hca.guid );\r
353                         p_ext->ci_ifc.deregister_ca = NULL;\r
354                 }\r
355 \r
356                 if ( p_ext->state == HCA_REGISTERED) {\r
357                         /* Release AL's CI interface. */\r
358                         p_ext->ci_ifc.wdm.InterfaceDereference( p_ext->ci_ifc.wdm.Context );\r
359                 }\r
360                 p_ext->state = HCA_STARTED;\r
361 \r
362                 /* Release AL's file object so that it can unload. */\r
363                 if( p_ext->p_al_file_obj )\r
364                 {\r
365                         ObDereferenceObject( p_ext->p_al_file_obj );\r
366                         p_ext->p_al_file_obj = NULL;\r
367                         p_ext->p_al_dev = NULL;\r
368                 }\r
369 \r
370                 /* Cancel our target device change registration. */\r
371                 if (p_ext->pnp_target_entry) {\r
372                         IoUnregisterPlugPlayNotification( p_ext->pnp_target_entry );\r
373                         p_ext->pnp_target_entry = NULL;\r
374                 }\r
375 \r
376         }\r
377         else if( IsEqualGUID( &pNotify->Event, \r
378                 &GUID_TARGET_DEVICE_REMOVE_CANCELLED ) )\r
379         {\r
380                 /* Cancel our target device change registration. */\r
381                 if (p_ext->pnp_target_entry) {\r
382                         IoUnregisterPlugPlayNotification( p_ext->pnp_target_entry );\r
383                         p_ext->pnp_target_entry = NULL;\r
384                 }\r
385 \r
386                 /* Get the device object pointer for the AL. */\r
387                 CL_ASSERT( !p_ext->p_al_file_obj );\r
388                 CL_ASSERT( !p_ext->p_al_dev );\r
389                 /* Get the AL device object. */\r
390                 HCA_PRINT( TRACE_LEVEL_INFORMATION      ,HCA_DBG_SHIM  ,("Calling IoGetDeviceObjectPointer.\n"));\r
391                 status = IoGetDeviceObjectPointer( &p_ext->al_sym_name,\r
392                         FILE_ALL_ACCESS, &p_ext->p_al_file_obj, &p_ext->p_al_dev );\r
393                 if( !NT_SUCCESS( status ) )\r
394                 {\r
395                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_SHIM, \r
396                                 ("IoGetDeviceObjectPointer returned %08x.\n", status ));\r
397                         return STATUS_SUCCESS;\r
398                 }\r
399 \r
400                 /* Register for removal notification of the IB Fabric root device. */\r
401                 status = IoRegisterPlugPlayNotification( \r
402                         EventCategoryTargetDeviceChange, 0, p_ext->p_al_file_obj, \r
403                         p_dev_obj->DriverObject, __pnp_notify_target, p_dev_obj, \r
404                         &p_ext->pnp_target_entry );\r
405                 if( !NT_SUCCESS( status ) )\r
406                 {\r
407                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
408                                 ("IoRegisterPlugPlayNotification returned %08x.\n", status));\r
409                         return status;\r
410                 }\r
411 \r
412                 CL_ASSERT( p_ext->state == HCA_IFC_DEREFERENCED );\r
413                 if ( p_ext->state == HCA_IFC_DEREFERENCED) {\r
414                         /* Release AL's CI interface. */\r
415                         p_ext->ci_ifc.wdm.InterfaceReference( p_ext->ci_ifc.wdm.Context );\r
416                         p_ext->state = HCA_REGISTERED;\r
417                 }\r
418         }\r
419 \r
420         HCA_EXIT( HCA_DBG_PNP );\r
421         return status;\r
422 }\r
423 \r
424 \r
425 static ci_interface_t*\r
426 __alloc_hca_ifc(\r
427         IN                              hca_dev_ext_t* const            p_ext )\r
428 {\r
429         ci_interface_t  *pIfc;\r
430 \r
431         HCA_ENTER( HCA_DBG_PNP );\r
432 \r
433         pIfc =\r
434                 (ci_interface_t*)ExAllocatePool( PagedPool, sizeof(ci_interface_t) );\r
435         if( !pIfc )\r
436         {\r
437                 HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, \r
438                         ("Failed to allocate ci_interface_t (%d bytes).\n",\r
439                         sizeof(ci_interface_t)));\r
440                 return NULL;\r
441         }\r
442 \r
443         setup_ci_interface( p_ext->hca.guid,\r
444                 !!mthca_is_livefish(p_ext->hca.mdev),\r
445                 pIfc );\r
446 \r
447         pIfc->p_hca_dev = p_ext->cl_ext.p_pdo;\r
448         pIfc->vend_id = (uint32_t)p_ext->hcaConfig.VendorID;\r
449         pIfc->dev_id = (uint16_t)p_ext->hcaConfig.DeviceID;\r
450         pIfc->dev_revision = (uint16_t)p_ext->hca.hw_ver;\r
451 \r
452         HCA_EXIT( HCA_DBG_PNP );\r
453         return pIfc;\r
454 }\r
455 \r
456 static void\r
457 __hca_deregister(\r
458         IN                              hca_dev_ext_t                   *p_ext )\r
459 {\r
460         HCA_ENTER( HCA_DBG_PNP );\r
461         \r
462         if ( p_ext->state == HCA_REGISTERED) {\r
463                 if (p_ext->ci_ifc.deregister_ca) {\r
464                         /* Notify AL that the CA is being removed. */\r
465                         p_ext->ci_ifc.deregister_ca( p_ext->hca.guid );\r
466                         p_ext->ci_ifc.deregister_ca = NULL;\r
467                         /* Release AL's CI interface. */\r
468                         p_ext->ci_ifc.wdm.InterfaceDereference( p_ext->ci_ifc.wdm.Context );\r
469                         p_ext->state = HCA_STARTED;\r
470                 }\r
471         }\r
472 \r
473         HCA_EXIT( HCA_DBG_PNP );\r
474 }\r
475 \r
476 static NTSTATUS\r
477 __hca_register(\r
478         IN                              DEVICE_OBJECT                           *p_dev_obj )\r
479 {\r
480         hca_dev_ext_t                   *p_ext;\r
481         NTSTATUS                                status;\r
482         ib_api_status_t                 ib_status;\r
483         ci_interface_t                  *p_hca_ifc;\r
484 \r
485         HCA_ENTER( HCA_DBG_PNP );\r
486         \r
487         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
488 \r
489         ASSERT( p_ext->state == HCA_STARTED );\r
490         ASSERT( p_ext->p_al_dev );\r
491 \r
492         /* Get the AL's lower interface. */\r
493         status = __get_ci_interface( p_dev_obj );\r
494         if( !NT_SUCCESS( status ) )\r
495         {\r
496                 HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_SHIM, \r
497                         ("__get_ci_interface returned %08x.\n", status));\r
498                 return status;\r
499         }\r
500 \r
501         /* Allocate and populate our HCA interface structure. */\r
502         p_hca_ifc = __alloc_hca_ifc( p_ext );\r
503         if( !p_hca_ifc )\r
504         {\r
505                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM  ,("__alloc_hca_ifc failed.\n"));\r
506                 return STATUS_NO_MEMORY;\r
507         }\r
508 \r
509         /* Notify AL that we're available... */\r
510         ib_status = p_ext->ci_ifc.register_ca( p_hca_ifc );\r
511         ExFreePool( p_hca_ifc );\r
512         if( ib_status != IB_SUCCESS )\r
513         {\r
514                 p_ext->ci_ifc.wdm.InterfaceDereference( p_ext->ci_ifc.wdm.Context );\r
515                 return STATUS_INSUFFICIENT_RESOURCES;\r
516         }\r
517 \r
518         p_ext->state = HCA_REGISTERED;\r
519         return STATUS_SUCCESS;\r
520 }\r
521 \r
522 \r
523 static NTSTATUS\r
524 __pnp_notify_ifc(\r
525         IN                              void                                            *pNotifyStruct,\r
526         IN                              void                                            *context )\r
527 {\r
528         NTSTATUS                                                                status = STATUS_SUCCESS;\r
529         DEVICE_OBJECT                                                   *p_dev_obj;\r
530         hca_dev_ext_t                                                   *p_ext;\r
531         DEVICE_INTERFACE_CHANGE_NOTIFICATION    *pNotify;\r
532 \r
533         HCA_ENTER( HCA_DBG_PNP );\r
534 \r
535         pNotify = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)pNotifyStruct;\r
536         p_dev_obj = (DEVICE_OBJECT*)context;\r
537         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
538 \r
539         if( !IsEqualGUID( &pNotify->Event, &GUID_DEVICE_INTERFACE_ARRIVAL ) )\r
540                 goto done;\r
541 \r
542         /*\r
543          * Sanity check.  We should only be getting notifications of the \r
544          * CI interface exported by AL.\r
545          */\r
546         ASSERT( \r
547                 IsEqualGUID( &pNotify->InterfaceClassGuid, &GUID_IB_CI_INTERFACE ) );\r
548 \r
549         if( p_ext->state != HCA_STARTED )\r
550         {\r
551                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_PNP  ,("Invalid state: %d\n", p_ext->state));\r
552                 goto done;\r
553         }\r
554 \r
555         /* save symbolic name of IBAL for a case of cancelled IBAL removal */\r
556         if (!p_ext->al_sym_name.Buffer) {\r
557                 p_ext->al_sym_name.Length = pNotify->SymbolicLinkName->Length;\r
558                 p_ext->al_sym_name.MaximumLength = pNotify->SymbolicLinkName->MaximumLength;\r
559                 p_ext->al_sym_name.Buffer = ExAllocatePool( NonPagedPool, \r
560                         p_ext->al_sym_name.MaximumLength * sizeof(wchar_t) );\r
561                 if (!p_ext->al_sym_name.Buffer)\r
562                 {\r
563                         HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_PNP  ,("allocation of sym IBAL name failed.\n"));\r
564                         goto done;\r
565                 }\r
566                 RtlCopyUnicodeString( &p_ext->al_sym_name, pNotify->SymbolicLinkName );\r
567         }\r
568 \r
569         ASSERT( !p_ext->p_al_dev );\r
570         ASSERT( !p_ext->p_al_file_obj );\r
571 \r
572         /* Get the AL device object. */\r
573         HCA_PRINT( TRACE_LEVEL_INFORMATION  ,HCA_DBG_PNP  ,("Calling IoGetDeviceObjectPointer.\n"));\r
574         status = IoGetDeviceObjectPointer( pNotify->SymbolicLinkName,\r
575                 FILE_ALL_ACCESS, &p_ext->p_al_file_obj, &p_ext->p_al_dev );\r
576         if( !NT_SUCCESS( status ) )\r
577         {\r
578                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
579                         ("IoGetDeviceObjectPointer returned %08x.\n", status ));\r
580                 goto done;\r
581         }\r
582 \r
583         /* Register for removal notification of the IB Fabric root device. */\r
584         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, \r
585                 ("Registering for target notifications.\n"));\r
586         status = IoRegisterPlugPlayNotification( \r
587                 EventCategoryTargetDeviceChange, 0, p_ext->p_al_file_obj, \r
588                 p_dev_obj->DriverObject, __pnp_notify_target, p_dev_obj, \r
589                 &p_ext->pnp_target_entry );\r
590         if( !NT_SUCCESS( status ) )\r
591         {\r
592                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
593                         ("IoRegisterPlugPlayNotification returned %08x.\n", status));\r
594                 goto err_reg_notify;\r
595         }\r
596 \r
597         status = __hca_register( p_dev_obj );\r
598         if( !NT_SUCCESS( status ) )\r
599         {\r
600                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
601                         ("__get_ci_interface returned %08x.\n", status));\r
602                 goto err_reg_hca;\r
603         }\r
604         goto done;\r
605         \r
606 err_reg_hca:\r
607         IoUnregisterPlugPlayNotification( p_ext->pnp_target_entry );\r
608         p_ext->pnp_target_entry = NULL;\r
609 err_reg_notify:\r
610         ObDereferenceObject( p_ext->p_al_file_obj );\r
611         p_ext->p_al_file_obj = NULL;\r
612         p_ext->p_al_dev = NULL;\r
613 done:\r
614         HCA_EXIT( HCA_DBG_PNP );\r
615         return status;\r
616 }\r
617 \r
618 \r
619 /*\r
620  * Walk the resource lists and store the information.  The write-only\r
621  * flag is not set for the UAR region, so it is indistinguishable from the\r
622  * DDR region since both are prefetchable.  The code here assumes that the\r
623  * resources get handed in order - HCR, UAR, DDR.\r
624  *      - Configuration Space: not prefetchable, read/write\r
625  *      - UAR space: prefetchable, write only.\r
626  *      - DDR: prefetchable, read/write.\r
627  */\r
628 static NTSTATUS\r
629 __SetupHcaResources(\r
630         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
631         IN                              CM_RESOURCE_LIST* const         pHcaResList,\r
632         IN                              CM_RESOURCE_LIST* const         pHostResList )\r
633 {\r
634         NTSTATUS                                                status = STATUS_SUCCESS;\r
635         hca_dev_ext_t                                   *p_ext;\r
636         USHORT                                                  i;\r
637         hca_bar_type_t                                  type = HCA_BAR_TYPE_HCR;\r
638 \r
639         CM_PARTIAL_RESOURCE_DESCRIPTOR  *pHcaRes, *pHostRes;\r
640 \r
641         HCA_ENTER( HCA_DBG_PNP );\r
642 \r
643         // there will be no resources for "livefish" (PCI memory controller mode)\r
644         if (!pHcaResList || !pHostResList)\r
645                 goto done;\r
646                 \r
647         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
648 \r
649         // store the bus number for reset of Tavor\r
650         p_ext->bus_number = pHostResList->List[0].BusNumber;\r
651         \r
652         for( i = 0; i < pHostResList->List[0].PartialResourceList.Count; i++ )\r
653         {\r
654                 pHcaRes =\r
655                         &pHcaResList->List[0].PartialResourceList.PartialDescriptors[i];\r
656                 pHostRes = \r
657                         &pHostResList->List[0].PartialResourceList.PartialDescriptors[i];\r
658 \r
659 \r
660                 /*\r
661                  * Save the interrupt information so that we can power the device\r
662                  * up and down.  Since the device will lose state when powered down\r
663                  * we have to fully disable it.  Note that we can leave memory mapped\r
664                  * resources in place when powered down as the resource assignments\r
665                  * won't change.  However, we must disconnect our interrupt, and\r
666                  * reconnect it when powering up.\r
667                  */\r
668                 if( pHcaRes->Type == CmResourceTypeInterrupt )\r
669                 {\r
670                         p_ext->interruptInfo = *pHostRes;\r
671                         continue;\r
672                 }\r
673                 \r
674                 if( pHcaRes->Type != CmResourceTypeMemory )\r
675                         continue;\r
676 \r
677                 /*\r
678                  * Sanity check that our assumption on how resources\r
679                  * are reported hold.\r
680                  */\r
681                 if( type == HCA_BAR_TYPE_HCR &&\r
682                         (pHcaRes->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE) )\r
683                 {\r
684                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
685                                 ("First memory resource is prefetchable - expected HCR.\n"));\r
686                         status = STATUS_UNSUCCESSFUL;\r
687                         break;\r
688                 }\r
689 \r
690                 p_ext->bar[type].phys = pHcaRes->u.Memory.Start.QuadPart;\r
691                 p_ext->bar[type].size = pHcaRes->u.Memory.Length;\r
692 #ifdef MAP_ALL_HCA_MEMORY               \r
693                 /*leo: no need to map all the resources */\r
694                 p_ext->bar[type].virt = MmMapIoSpace( pHostRes->u.Memory.Start,\r
695                         pHostRes->u.Memory.Length, MmNonCached );\r
696                 if( !p_ext->bar[type].virt )\r
697                 {\r
698                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
699                                 ("Failed to map memory resource type %d\n", type));\r
700                         status = STATUS_UNSUCCESSFUL;\r
701                         break;\r
702                 }\r
703 #else           \r
704                 p_ext->bar[type].virt = NULL;\r
705 #endif          \r
706 \r
707                 type++;\r
708         }\r
709 \r
710         if( type == HCA_BAR_TYPE_DDR)\r
711         {\r
712                 p_ext->hca_hidden = 1;\r
713         }\r
714         else \r
715         if( type != HCA_BAR_TYPE_MAX )\r
716         {\r
717                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM  ,("Failed to map all memory resources.\n"));\r
718                 status = STATUS_UNSUCCESSFUL;\r
719         }\r
720 \r
721         if( p_ext->interruptInfo.Type != CmResourceTypeInterrupt )\r
722         {\r
723                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM  ,("No interrupt resource.\n"));\r
724                 status = STATUS_UNSUCCESSFUL;\r
725         }\r
726 \r
727 done:\r
728         HCA_EXIT( HCA_DBG_PNP );\r
729         return status;\r
730 }\r
731 \r
732 \r
733 static void\r
734 __UnmapHcaMemoryResources(\r
735         IN                              DEVICE_OBJECT* const            p_dev_obj )\r
736 {\r
737         hca_dev_ext_t           *p_ext;\r
738         USHORT                          i;\r
739 \r
740         HCA_ENTER( HCA_DBG_PNP );\r
741 \r
742         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
743 \r
744         for( i = 0; i < HCA_BAR_TYPE_MAX; i++ )\r
745         {\r
746                 if( p_ext->bar[i].virt )\r
747                 {\r
748                         MmUnmapIoSpace( p_ext->bar[i].virt, p_ext->bar[i].size );\r
749                         cl_memclr( &p_ext->bar[i], sizeof(hca_bar_t) );\r
750                 }\r
751         }\r
752 \r
753         HCA_EXIT( HCA_DBG_PNP );\r
754 }\r
755 \r
756 \r
757 static int mthca_get_livefish_info(struct mthca_dev *mdev, __be64 *node_guid, u32 *hw_id)\r
758 {\r
759         *node_guid = cl_hton64((uint64_t)(ULONG_PTR)mdev);\r
760         mdev->ib_dev.node_guid = *node_guid;\r
761         *hw_id = 0;\r
762         return 0;\r
763 }\r
764 \r
765 static NTSTATUS\r
766 hca_start(\r
767         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
768         IN                              IRP* const                                      p_irp, \r
769                 OUT                     cl_irp_action_t* const          p_action )\r
770 {\r
771         NTSTATUS                        status;\r
772         hca_dev_ext_t           *p_ext;\r
773         IO_STACK_LOCATION       *pIoStack;\r
774         POWER_STATE                     powerState;\r
775         DEVICE_DESCRIPTION      devDesc;\r
776 \r
777         HCA_ENTER( HCA_DBG_PNP );\r
778 \r
779         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
780 \r
781         /* Handled on the way up. */\r
782         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
783         if( !NT_SUCCESS( status ) )\r
784         {\r
785                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
786                         ("Lower drivers failed IRP_MN_START_DEVICE.\n"));\r
787                 return status;\r
788         }\r
789 \r
790         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
791 \r
792         /*\r
793          * Walk the resource lists and store the information.  The write-only\r
794          * flag is not set for the UAR region, so it is indistinguishable from the\r
795          * DDR region since both are prefetchable.  The code here assumes that the\r
796          * resources get handed in order - HCR, UAR, DDR.\r
797          *      - Configuration Space: not prefetchable, read/write\r
798          *      - UAR space: prefetchable, write only.\r
799          *      - DDR: prefetchable, read/write.\r
800          */\r
801         status = __SetupHcaResources( p_dev_obj,\r
802                 pIoStack->Parameters.StartDevice.AllocatedResources,\r
803                 pIoStack->Parameters.StartDevice.AllocatedResourcesTranslated );\r
804         if( !NT_SUCCESS( status ) )\r
805         {\r
806                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
807                         ("__ProcessResources returned %08X.\n", status));\r
808                 return status;\r
809         }\r
810         \r
811         /* save PCI bus i/f, PCI configuration info and enable device */\r
812         hca_enable_pci( p_dev_obj, &p_ext->hcaBusIfc, &p_ext->hcaConfig );\r
813 \r
814         /*\r
815          * Get the DMA adapter representing the HCA so we can\r
816          * allocate common buffers.\r
817          */\r
818         RtlZeroMemory( &devDesc, sizeof(devDesc) );\r
819         devDesc.Version = DEVICE_DESCRIPTION_VERSION2;\r
820         devDesc.Master = TRUE;\r
821         devDesc.ScatterGather = TRUE;\r
822         devDesc.Dma32BitAddresses = TRUE;\r
823         devDesc.Dma64BitAddresses = TRUE;\r
824         devDesc.InterfaceType = PCIBus;\r
825 \r
826         // get the adapter object\r
827         // 0x80000000 is a threshold, that's why - 1\r
828         devDesc.MaximumLength = 0x80000000 - 1;\r
829         p_ext->p_dma_adapter = IoGetDmaAdapter(\r
830                 p_ext->cl_ext.p_pdo, &devDesc, &p_ext->n_map_regs );\r
831         if( !p_ext->p_dma_adapter )\r
832         {\r
833                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
834                         ("Failed to get DMA_ADAPTER for HCA.\n"));\r
835                 return STATUS_INSUFFICIENT_RESOURCES;\r
836         }\r
837 \r
838         /* Initialize the HCA now. */\r
839         status = mthca_init_one( p_ext );\r
840         if( !NT_SUCCESS( status ) )\r
841         {\r
842                 //TODO: no cleanup on error\r
843                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
844                         ("mthca_init_one returned %08X\n", status));\r
845                 return status;\r
846         }\r
847 \r
848         /*leo: get node GUID */\r
849         {\r
850                 int err;\r
851                 if (mthca_is_livefish(p_ext->hca.mdev)) \r
852                         err = mthca_get_livefish_info( p_ext->hca.mdev, &p_ext->hca.guid, &p_ext->hca.hw_ver );\r
853                 else\r
854                         err = mthca_get_dev_info( p_ext->hca.mdev, &p_ext->hca.guid, &p_ext->hca.hw_ver );\r
855                 if (err) {\r\r
856                         //TODO: no cleanup on error\r
857                         HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, \r
858                                 ("can't get guid - mthca_query_port()"));\r
859                         return STATUS_INSUFFICIENT_RESOURCES;\r
860                 }\r
861         }\r
862 \r
863         /* queue HCA  */\r
864         mlnx_hca_insert( &p_ext->hca );\r
865 \r
866         /*\r
867          * Change the state since the PnP callback can happen\r
868          * before the callback returns.\r
869          */\r
870         p_ext->state = HCA_STARTED;\r
871         \r
872         /* Register for interface arrival of the IB_AL device. */\r
873         status = IoRegisterPlugPlayNotification(\r
874                 EventCategoryDeviceInterfaceChange,\r
875                 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,\r
876                 (void*)&GUID_IB_CI_INTERFACE, p_dev_obj->DriverObject,\r
877                 __pnp_notify_ifc, p_dev_obj, &p_ext->pnp_ifc_entry );\r
878         if( !NT_SUCCESS( status ) )\r
879         {\r
880                 p_ext->state = HCA_ADDED;\r
881                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP,\r
882                         ("IoRegisterPlugPlayNotification returned %08x.\n", status));\r
883         }\r
884 \r
885         /* We get started fully powered. */\r
886         p_ext->PowerState = PowerDeviceD0;\r
887         powerState.DeviceState = PowerDeviceD0;\r
888         PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState );\r
889 \r
890         {\r
891                 struct mthca_dev *mdev = p_ext->hca.mdev;\r
892                 HCA_PRINT_EV(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,\r
893                         ("Ven %x Dev %d Hw %x Fw %d.%d.%d Drv %s (%s)", \r
894                         (unsigned)p_ext->hcaConfig.VendorID, (unsigned)p_ext->hcaConfig.DeviceID,\r
895                         p_ext->hca.hw_ver,      (int) (mdev->fw_ver >> 32),\r
896                         (int) (mdev->fw_ver >> 16) & 0xffff, (int) (mdev->fw_ver & 0xffff),\r
897                         DRV_VERSION, DRV_RELDATE\r
898                         ));\r
899                 HCA_PRINT_EV(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,\r
900                         ("Flags %s%s%s%s%s%s%s\n", \r
901                         (mdev->mthca_flags & MTHCA_FLAG_LIVEFISH) ? "Flash Recovery Mode:" : "",\r
902                         (mdev->mthca_flags & MTHCA_FLAG_MEMFREE) ? "MemFree:" : "",\r
903                         (mdev->mthca_flags & MTHCA_FLAG_NO_LAM) ? "NoLam:" : "",\r
904                         (mdev->mthca_flags & MTHCA_FLAG_FMR) ? "Fmr:" : "",\r
905                         (mdev->mthca_flags & MTHCA_FLAG_SRQ) ? "Srq:" : "",\r
906                         (mdev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN) ? "HideDdr:" : "",\r
907                         (mdev->mthca_flags & MTHCA_FLAG_PCIE) ? "PciEx:" : ""\r
908                         ));\r
909         }\r
910 \r
911         HCA_EXIT( HCA_DBG_PNP );\r
912         return status;\r
913 }\r
914 \r
915 \r
916 /* release the resources, allocated in hca_start */\r
917 static void\r
918 __hca_release_resources(\r
919         IN                              DEVICE_OBJECT* const            p_dev_obj )\r
920 {\r
921         hca_dev_ext_t           *p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
922 \r
923         HCA_ENTER( HCA_DBG_PNP );\r
924 \r
925         switch( p_ext->state )\r
926         {\r
927         case HCA_REGISTERED:\r
928                 __hca_deregister( p_ext );\r
929 \r
930                 /* Fall through. */\r
931         case HCA_STARTED:\r
932                 /* dequeue HCA  */\r
933                 mlnx_hca_remove( &p_ext->hca );\r
934         }\r
935 \r
936         if (p_ext->al_sym_name.Buffer) {\r
937                 ExFreePool( p_ext->al_sym_name.Buffer );\r
938                 p_ext->al_sym_name.Buffer = NULL;\r
939         }\r
940         \r
941         if( p_ext->pnp_target_entry )\r
942         {\r
943                 ASSERT( p_ext->pnp_ifc_entry );\r
944                 IoUnregisterPlugPlayNotification( p_ext->pnp_target_entry );\r
945                 p_ext->pnp_target_entry = NULL;\r
946         }\r
947 \r
948         if( p_ext->pnp_ifc_entry ) {\r
949                 IoUnregisterPlugPlayNotification( p_ext->pnp_ifc_entry );\r
950                 p_ext->pnp_ifc_entry = NULL;\r
951         }\r
952 \r
953         if( p_ext->p_al_file_obj ) {\r
954                 ObDereferenceObject( p_ext->p_al_file_obj );\r
955                 p_ext->p_al_file_obj = NULL;\r
956         }\r
957 \r
958         mthca_remove_one( p_ext );\r
959 \r
960         if( p_ext->p_dma_adapter ) {\r
961                 p_ext->p_dma_adapter->DmaOperations->PutDmaAdapter( p_ext->p_dma_adapter );\r
962                 p_ext->p_dma_adapter = NULL;\r
963         }\r
964 \r
965         hca_disable_pci( &p_ext->hcaBusIfc );\r
966 \r
967         //cl_event_destroy( &p_ext->mutex );\r
968         __UnmapHcaMemoryResources( p_dev_obj );\r
969 \r
970         p_ext->state = HCA_ADDED;\r
971 \r
972         HCA_EXIT( HCA_DBG_PNP );\r
973 }\r
974 \r
975 \r
976 static void\r
977 hca_release_resources(\r
978         IN                              DEVICE_OBJECT* const            p_dev_obj )\r
979 {\r
980         hca_dev_ext_t           *p_ext;\r
981         POWER_STATE                     powerState;\r
982 \r
983         HCA_ENTER( HCA_DBG_PNP );\r
984 \r
985         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
986 \r
987         /* release all the resources, allocated in hca_start */\r
988         __hca_release_resources(p_dev_obj);\r
989 \r
990         /* Notify the power manager that the device is powered down. */\r
991         powerState.DeviceState = PowerDeviceD3;\r
992         PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState );\r
993 \r
994         /* Clear the PnP state in case we get restarted. */\r
995         p_ext->pnpState = 0;\r
996 \r
997         HCA_EXIT( HCA_DBG_PNP );\r
998 }\r
999 \r
1000 \r
1001 static NTSTATUS\r
1002 hca_query_removal_relations(\r
1003         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1004         IN                                      IRP* const                              p_irp, \r
1005                 OUT                             cl_irp_action_t* const  p_action )\r
1006 {\r
1007         NTSTATUS        status;\r
1008         hca_dev_ext_t   *p_ext;\r
1009 \r
1010         HCA_ENTER( HCA_DBG_PNP );\r
1011 \r
1012         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1013 \r
1014         if( p_ext->state == HCA_REGISTERED )\r
1015         {\r
1016                 status = p_ext->ci_ifc.get_relations( p_ext->hca.guid, p_irp );\r
1017                 if( !NT_SUCCESS( status ) )\r
1018                 {\r
1019                         *p_action = IrpComplete;\r
1020                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1021                                 ("AL get_relations returned %08x.\n", status));\r
1022                         return status;\r
1023                 }\r
1024         }\r
1025 \r
1026         *p_action = IrpPassDown;\r
1027         HCA_EXIT( HCA_DBG_PNP );\r
1028         return STATUS_SUCCESS;\r
1029 }\r
1030 \r
1031 \r
1032 static NTSTATUS\r
1033 hca_query_bus_relations(\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         NTSTATUS                        status;\r
1039         DEVICE_RELATIONS        *p_rel;\r
1040         hca_dev_ext_t   *p_ext;\r
1041 \r
1042         HCA_ENTER( HCA_DBG_PNP );\r
1043 \r
1044         p_ext = p_dev_obj->DeviceExtension;\r
1045 \r
1046         //cl_event_wait_on( &p_ext->mutex, EVENT_NO_TIMEOUT, FALSE );\r
1047         if( p_ext->state == HCA_REGISTERED )\r
1048         {\r
1049                 status = p_ext->ci_ifc.get_relations( p_ext->hca.guid, p_irp );\r
1050                 if( !NT_SUCCESS( status ) )\r
1051                 {\r
1052                         //cl_event_signal( &p_ext->mutex );\r
1053                         *p_action = IrpComplete;\r
1054                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1055                                 ("AL get_relations returned %08x.\n", status));\r
1056                         return status;\r
1057                 }\r
1058         }\r
1059         else\r
1060         {\r
1061                 status = cl_alloc_relations( p_irp, 1 );\r
1062                 if( !NT_SUCCESS( status ) )\r
1063                 {\r
1064                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1065                                 ("cl_alloc_relations returned %08x.\n", status));\r
1066                         return status;\r
1067                 }\r
1068 \r
1069                 p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
1070                 p_rel->Count = 0;\r
1071                 p_rel->Objects[0] = NULL;\r
1072         }\r
1073 \r
1074         //cl_event_signal( &p_ext->mutex );\r
1075 \r
1076         *p_action = IrpPassDown;\r
1077         HCA_EXIT( HCA_DBG_PNP );\r
1078         return STATUS_SUCCESS;\r
1079 }\r
1080 \r
1081 \r
1082 static NTSTATUS\r
1083 hca_query_stop(\r
1084         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1085         IN                              IRP* const                                      p_irp, \r
1086                 OUT                     cl_irp_action_t* const          p_action )\r
1087 {\r
1088         /* All kernel clients will get notified through the device hierarchy. */\r
1089 \r
1090         /* TODO: set a flag to fail creation of any new IB resources. */\r
1091         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1092 }\r
1093 \r
1094 \r
1095 static NTSTATUS\r
1096 hca_stop(\r
1097         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1098         IN                              IRP* const                                      p_irp, \r
1099                 OUT                     cl_irp_action_t* const          p_action )\r
1100 {\r
1101         /*\r
1102          * Must disable everything.  Complib framework will\r
1103          * call ReleaseResources handler.\r
1104          */\r
1105         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1106 }\r
1107 \r
1108 \r
1109 static NTSTATUS\r
1110 hca_cancel_stop(\r
1111         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1112         IN                              IRP* const                                      p_irp, \r
1113                 OUT                     cl_irp_action_t* const          p_action )\r
1114 {\r
1115         /* Handled on the way up. */\r
1116         return cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
1117 }\r
1118 \r
1119 \r
1120 static NTSTATUS\r
1121 hca_query_remove(\r
1122         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1123         IN                              IRP* const                                      p_irp, \r
1124                 OUT                     cl_irp_action_t* const          p_action )\r
1125 {\r
1126         hca_dev_ext_t*p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1127         if (atomic_read(&p_ext->usecnt)) {\r
1128                 p_irp->IoStatus.Status = STATUS_UNSUCCESSFUL;\r
1129                 return cl_irp_complete( p_dev_obj, p_irp, p_action );\r
1130         }\r
1131         /* TODO: set a flag to fail creation of any new IB resources. */\r
1132         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1133 }\r
1134 \r
1135 \r
1136 static NTSTATUS\r
1137 hca_cancel_remove(\r
1138         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1139         IN                              IRP* const                                      p_irp, \r
1140                 OUT                     cl_irp_action_t* const          p_action )\r
1141 {\r
1142         /* Handled on the way up. */\r
1143         return cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
1144 }\r
1145 \r
1146 \r
1147 static NTSTATUS\r
1148 hca_surprise_remove(\r
1149         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1150         IN                              IRP* const                                      p_irp, \r
1151                 OUT                     cl_irp_action_t* const          p_action )\r
1152 {\r
1153         /*\r
1154          * TODO: Set state so that all further requests\r
1155          * automatically succeed/fail as needed.\r
1156          */\r
1157         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1158 }\r
1159 \r
1160 \r
1161 static NTSTATUS\r
1162 hca_query_capabilities(\r
1163         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1164         IN                              IRP* const                                      p_irp, \r
1165                 OUT                     cl_irp_action_t* const          p_action )\r
1166 {\r
1167         NTSTATUS                        status;\r
1168         hca_dev_ext_t           *p_ext;\r
1169         IO_STACK_LOCATION       *pIoStack;\r
1170         DEVICE_CAPABILITIES     *pCaps;\r
1171 \r
1172         HCA_ENTER( HCA_DBG_PNP );\r
1173 \r
1174         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1175 \r
1176         /* Process on the way up. */\r
1177         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
1178         if( !NT_SUCCESS( status ) )\r
1179         {\r
1180                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1181                         ("cl_do_sync_pnp returned %08X.\n", status));\r
1182                 return status;\r
1183         }\r
1184 \r
1185         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1186         pCaps = pIoStack->Parameters.DeviceCapabilities.Capabilities;\r
1187 \r
1188         /*\r
1189          * Store the device power mapping into our extension since we're\r
1190          * the power policy owner.  The mapping is used when handling\r
1191          * IRP_MN_SET_POWER IRPs.\r
1192          */\r
1193         cl_memcpy(\r
1194                 p_ext->DevicePower, pCaps->DeviceState, sizeof(p_ext->DevicePower) );\r
1195 \r
1196         if( pCaps->DeviceD1 )\r
1197         {\r
1198                 HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP,\r
1199                         ("WARNING: Device reports support for DeviceD1 power state.\n"));\r
1200                 pCaps->DeviceD1 = FALSE;\r
1201         }\r
1202 \r
1203         if( pCaps->DeviceD2 )\r
1204         {\r
1205                 HCA_PRINT( TRACE_LEVEL_WARNING,HCA_DBG_PNP,\r
1206                         ("WARNING: Device reports support for DeviceD2 power state.\n"));\r
1207                 pCaps->DeviceD2 = FALSE;\r
1208         }\r
1209 \r
1210         if( pCaps->SystemWake != PowerSystemUnspecified )\r
1211         {\r
1212                 HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP,\r
1213                         ("WARNING: Device reports support for system wake.\n"));\r
1214                 pCaps->SystemWake = PowerSystemUnspecified;\r
1215         }\r
1216 \r
1217         if( pCaps->DeviceWake != PowerDeviceUnspecified )\r
1218         {\r
1219                 HCA_PRINT( TRACE_LEVEL_WARNING, HCA_DBG_PNP,\r
1220                         ("WARNING: Device reports support for device wake.\n"));\r
1221                 pCaps->DeviceWake = PowerDeviceUnspecified;\r
1222         }\r
1223 \r
1224         HCA_EXIT( HCA_DBG_PNP );\r
1225         return status;\r
1226 }\r
1227 \r
1228 \r
1229 static NTSTATUS\r
1230 hca_query_pnp_state(\r
1231         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1232         IN                              IRP* const                                      p_irp, \r
1233                 OUT                     cl_irp_action_t* const          p_action )\r
1234 {\r
1235         hca_dev_ext_t           *p_ext;\r
1236 \r
1237         HCA_ENTER( HCA_DBG_PNP );\r
1238 \r
1239         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1240 \r
1241         p_irp->IoStatus.Information |= p_ext->pnpState;\r
1242 \r
1243         *p_action = IrpSkip;\r
1244 \r
1245         HCA_EXIT( HCA_DBG_PNP );\r
1246         return STATUS_SUCCESS;;\r
1247 }\r
1248 \r
1249 \r
1250 static NTSTATUS\r
1251 hca_query_power(\r
1252         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1253         IN                              IRP* const                                      p_irp,\r
1254                 OUT                     cl_irp_action_t* const          p_action )\r
1255 {\r
1256         NTSTATUS                        status = STATUS_SUCCESS;\r
1257         IO_STACK_LOCATION       *pIoStack;\r
1258 \r
1259         HCA_ENTER(HCA_DBG_PO);\r
1260 \r
1261         UNUSED_PARAM( p_dev_obj );\r
1262 \r
1263         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1264 \r
1265         switch( pIoStack->Parameters.Power.Type )\r
1266         {\r
1267         case SystemPowerState:\r
1268                 /* Fail any requests to hibernate or sleep the system. */\r
1269                 switch( pIoStack->Parameters.Power.State.SystemState )\r
1270                 {\r
1271                         case PowerSystemWorking:\r
1272                         case PowerSystemShutdown:\r
1273                                 /* We only support fully working and shutdown system states. */\r
1274                                 break;\r
1275 \r
1276                         default:\r
1277                                 status = STATUS_NOT_SUPPORTED;\r
1278                 }\r
1279                 break;\r
1280 \r
1281         case DevicePowerState:\r
1282                 /* Fail any query for low power states. */\r
1283                 switch( pIoStack->Parameters.Power.State.DeviceState )\r
1284                 {\r
1285                 case PowerDeviceD0:\r
1286                 case PowerDeviceD3:\r
1287                         /* We only support fully powered or off power states. */\r
1288                         break;\r
1289 \r
1290                 default:\r
1291                         status = STATUS_NOT_SUPPORTED;\r
1292                 }\r
1293                 break;\r
1294         }\r
1295 \r
1296         if( status == STATUS_NOT_SUPPORTED )\r
1297                 *p_action = IrpComplete;\r
1298         else\r
1299                 *p_action = IrpSkip;\r
1300 \r
1301         HCA_EXIT( HCA_DBG_PO );\r
1302         return status;\r
1303 }\r
1304 \r
1305 \r
1306 static void\r
1307 __RequestPowerCompletion(\r
1308         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1309         IN                              UCHAR                                           minorFunction,\r
1310         IN                              POWER_STATE                                     powerState,\r
1311         IN                              void                                            *context,\r
1312         IN                              IO_STATUS_BLOCK                         *pIoStatus )\r
1313 {\r
1314         IRP                                     *p_irp;\r
1315         cl_pnp_po_ext_t         *p_ext;\r
1316 \r
1317         HCA_ENTER( HCA_DBG_PO );\r
1318 \r
1319         UNUSED_PARAM( minorFunction );\r
1320         UNUSED_PARAM( powerState );\r
1321 \r
1322         p_irp = (IRP*)context;\r
1323         p_ext = (cl_pnp_po_ext_t*)p_dev_obj->DeviceExtension;\r
1324 \r
1325         /* Propagate the device IRP status to the system IRP status. */\r
1326         p_irp->IoStatus.Status = pIoStatus->Status;\r
1327 \r
1328         /* Continue Power IRP processing. */\r
1329         PoStartNextPowerIrp( p_irp );\r
1330         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1331         IoReleaseRemoveLock( &p_ext->remove_lock, p_irp );\r
1332         HCA_EXIT( HCA_DBG_PO );\r
1333 }\r
1334 \r
1335 \r
1336 /*NOTE: Completion routines must NEVER be pageable. */\r
1337 static NTSTATUS\r
1338 __SystemPowerCompletion(\r
1339         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1340         IN                              IRP                                                     *p_irp,\r
1341         IN                              void                                            *context )\r
1342 {\r
1343         NTSTATUS                        status;\r
1344         POWER_STATE                     state;\r
1345         hca_dev_ext_t           *p_ext;\r
1346         IO_STACK_LOCATION       *pIoStack;\r
1347 \r
1348         HCA_ENTER( HCA_DBG_PNP );\r
1349 \r
1350         UNUSED_PARAM( context );\r
1351 \r
1352         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1353         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1354 \r
1355         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1356         {\r
1357                 PoStartNextPowerIrp( p_irp );\r
1358                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1359                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1360                         ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n",\r
1361                         p_irp->IoStatus.Status));\r
1362                 return STATUS_SUCCESS;\r
1363         }\r
1364 \r
1365         state.DeviceState = \r
1366                 p_ext->DevicePower[pIoStack->Parameters.Power.State.SystemState];\r
1367 \r
1368         /*\r
1369          * Send a device power IRP to our devnode.  Using our device object will\r
1370          * only work on win2k and other NT based systems.\r
1371          */\r
1372         status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
1373                 __RequestPowerCompletion, p_irp, NULL );\r
1374 \r
1375         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1376         {\r
1377                 PoStartNextPowerIrp( p_irp );\r
1378                 /* Propagate the failure. */\r
1379                 p_irp->IoStatus.Status = status;\r
1380                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1381                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1382                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP,\r
1383                         ("PoRequestPowerIrp returned %08x.\n", status));\r
1384         }\r
1385 \r
1386         HCA_EXIT( HCA_DBG_PNP );\r
1387         return STATUS_MORE_PROCESSING_REQUIRED;\r
1388 }\r
1389 \r
1390 \r
1391 /* Work item callback to handle DevicePowerD0 IRPs at passive level. */\r
1392 static void\r
1393 __PowerUpCb(\r
1394         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1395         IN                              void*                                           context )\r
1396 {\r
1397         NTSTATUS                        status;\r
1398         IO_STACK_LOCATION       *pIoStack;\r
1399         hca_dev_ext_t           *p_ext;\r
1400         IRP                                     *p_irp;\r
1401 \r
1402         HCA_ENTER( HCA_DBG_PO );\r
1403 \r
1404         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1405         p_irp = (IRP*)context;\r
1406         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1407 \r
1408         IoFreeWorkItem( p_ext->pPoWorkItem );\r
1409         p_ext->pPoWorkItem = NULL;\r
1410 \r
1411         /* restart the HCA */\r
1412         status = mthca_init_one( p_ext );\r
1413         if( !NT_SUCCESS( status ) )\r
1414                 goto done;\r
1415 \r
1416         if( p_ext->p_al_dev )\r
1417                 status = __hca_register( p_dev_obj );\r
1418 \r
1419 done:\r
1420         if( !NT_SUCCESS( status ) )\r
1421         {\r
1422                 /* Flag device as having failed. */\r
1423                 p_ext->pnpState |= PNP_DEVICE_FAILED;\r
1424                 IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1425         }\r
1426 \r
1427         PoStartNextPowerIrp( p_irp );\r
1428         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1429         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1430 \r
1431         HCA_EXIT( HCA_DBG_PO );\r
1432 }\r
1433 \r
1434 \r
1435 /*NOTE: Completion routines must NEVER be pageable. */\r
1436 static NTSTATUS\r
1437 __DevicePowerCompletion(\r
1438         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1439         IN                              IRP                                                     *p_irp,\r
1440         IN                              void                                            *context )\r
1441 {\r
1442         NTSTATUS                        status = STATUS_SUCCESS;\r
1443         hca_dev_ext_t           *p_ext;\r
1444         IO_STACK_LOCATION       *pIoStack;\r
1445         KIRQL irql = KeGetCurrentIrql(  );\r
1446         \r
1447         \r
1448 \r
1449         HCA_ENTER( HCA_DBG_PO );\r
1450 \r
1451         UNUSED_PARAM( context );\r
1452 \r
1453         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1454         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1455 \r
1456         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1457         {\r
1458                 PoStartNextPowerIrp( p_irp );\r
1459                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1460                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1461                         ("IRP_MN_SET_POWER for device failed by lower driver with %08x.\n",\r
1462                         p_irp->IoStatus.Status));\r
1463                 return STATUS_SUCCESS;\r
1464         }\r
1465 \r
1466         p_ext->PowerState = pIoStack->Parameters.Power.State.DeviceState;\r
1467         PoSetPowerState( p_dev_obj, DevicePowerState,\r
1468                 pIoStack->Parameters.Power.State );\r
1469 \r
1470         if (irql > PASSIVE_LEVEL) {\r
1471                 /* Process in a work item - mthca_start blocks. */\r
1472                 ASSERT( !p_ext->pPoWorkItem );\r
1473                 p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1474                 if( !p_ext->pPoWorkItem )\r
1475                 {\r
1476                         IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1477 \r
1478                         PoStartNextPowerIrp( p_irp );\r
1479                         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1480 \r
1481                         return STATUS_SUCCESS;\r
1482                 }\r
1483 \r
1484                 /* Process in work item callback. */\r
1485                 IoMarkIrpPending( p_irp );\r
1486                 IoQueueWorkItem( p_ext->pPoWorkItem, __PowerUpCb, DelayedWorkQueue, p_irp );\r
1487         }\r
1488         else {\r
1489 \r
1490                 /* restart the HCA */\r
1491                 status = mthca_init_one( p_ext );\r
1492                 if( !NT_SUCCESS( status ) )\r
1493                         goto done;\r
1494 \r
1495                 if( p_ext->p_al_dev )\r
1496                         status = __hca_register( p_dev_obj );\r
1497         }\r
1498 \r
1499 done:\r
1500         if( !NT_SUCCESS( status ) )\r
1501                 IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1502 \r
1503         PoStartNextPowerIrp( p_irp );\r
1504         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1505 \r
1506         HCA_EXIT( HCA_DBG_PO );\r
1507         return STATUS_MORE_PROCESSING_REQUIRED;\r
1508 }\r
1509 \r
1510 static NTSTATUS __DeviceDownCbCompletion(\r
1511         IN                              DEVICE_OBJECT   *p_dev_obj,\r
1512         IN                              IRP                             *p_irp,\r
1513         IN                              void                            *context )\r
1514 {\r
1515         hca_dev_ext_t  *p_ext  = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1516         UNUSED_PARAM( context );\r
1517 \r
1518         PoStartNextPowerIrp( p_irp );\r
1519         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1520         return STATUS_SUCCESS;\r
1521 }\r
1522 \r
1523 /* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
1524 static void\r
1525 __PowerDownCb(\r
1526         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1527         IN                              void*                                           context )\r
1528 {\r
1529         IO_STACK_LOCATION       *pIoStack;\r
1530         hca_dev_ext_t           *p_ext;\r
1531         IRP                                     *p_irp;\r
1532 \r
1533         HCA_ENTER( HCA_DBG_PO );\r
1534 \r
1535         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1536         p_irp = (IRP*)context;\r
1537         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1538 \r
1539         IoFreeWorkItem( p_ext->pPoWorkItem );\r
1540         p_ext->pPoWorkItem = NULL;\r
1541 \r
1542         PoSetPowerState( p_dev_obj, DevicePowerState,\r
1543                 pIoStack->Parameters.Power.State );\r
1544 \r
1545         __hca_deregister( p_ext );\r
1546         mthca_remove_one( p_ext );\r
1547 \r
1548         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1549 #pragma warning( push, 3 )\r
1550         IoSetCompletionRoutine( p_irp, __DeviceDownCbCompletion,\r
1551                 NULL, TRUE, TRUE, TRUE );\r
1552 #pragma warning( pop )\r
1553         PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1554 \r
1555         HCA_EXIT( HCA_DBG_PO );\r
1556 }\r
1557 \r
1558 \r
1559 static NTSTATUS\r
1560 hca_set_power(\r
1561         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1562         IN                              IRP* const                                      p_irp,\r
1563                 OUT                     cl_irp_action_t* const          p_action )\r
1564 {\r
1565         NTSTATUS                        status;\r
1566         IO_STACK_LOCATION       *pIoStack;\r
1567         hca_dev_ext_t           *p_ext;\r
1568 \r
1569         HCA_ENTER( HCA_DBG_PO );\r
1570 \r
1571         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1572         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1573 \r
1574         switch( pIoStack->Parameters.Power.Type )\r
1575         {\r
1576         case SystemPowerState:\r
1577                 /*\r
1578                  * Process on the way up the stack.  We cannot block since the \r
1579                  * power dispatch function can be called at elevated IRQL if the\r
1580                  * device is in a paging/hibernation/crash dump path.\r
1581                  */\r
1582                 IoMarkIrpPending( p_irp );\r
1583                 IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1584 #pragma warning( push, 3 )\r
1585                 IoSetCompletionRoutine( p_irp, __SystemPowerCompletion, NULL, \r
1586                         TRUE, TRUE, TRUE );\r
1587 #pragma warning( pop )\r
1588                 PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1589 \r
1590                 *p_action = IrpDoNothing;\r
1591                 status = STATUS_PENDING;\r
1592                 break;\r
1593 \r
1594         case DevicePowerState:\r
1595                 IoMarkIrpPending( p_irp );\r
1596                 if( pIoStack->Parameters.Power.State.DeviceState == PowerDeviceD0 )\r
1597                 {\r
1598                         /* If we're already powered up, just pass down. */\r
1599                         if( p_ext->PowerState == PowerDeviceD0 )\r
1600                         {\r
1601                                 status = STATUS_SUCCESS;\r
1602                                 *p_action = IrpIgnore;\r
1603                                 break;\r
1604                         }\r
1605 \r
1606                         /* Process in I/O completion callback. */\r
1607                         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1608 #pragma warning( push, 3 )\r
1609                         IoSetCompletionRoutine( p_irp, __DevicePowerCompletion, NULL, \r
1610                                 TRUE, TRUE, TRUE );\r
1611 #pragma warning( pop )\r
1612                         PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1613                 }\r
1614                 else\r
1615                 {\r
1616                         /* Process in a work item - deregister_ca and HcaDeinit block. */\r
1617                         ASSERT( !p_ext->pPoWorkItem );\r
1618                         p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1619                         if( !p_ext->pPoWorkItem )\r
1620                         {\r
1621                                 status = STATUS_INSUFFICIENT_RESOURCES;\r
1622                                 break;\r
1623                         }\r
1624 \r
1625                         /* Process in work item callback. */\r
1626                         IoMarkIrpPending( p_irp );\r
1627                         IoQueueWorkItem(\r
1628                                 p_ext->pPoWorkItem, __PowerDownCb, DelayedWorkQueue, p_irp );\r
1629                 }\r
1630                 *p_action = IrpDoNothing;\r
1631                 status = STATUS_PENDING;\r
1632                 break;\r
1633 \r
1634         default:\r
1635                 /* Pass down and let the PDO driver handle it. */\r
1636                 *p_action = IrpIgnore;\r
1637                 status = STATUS_SUCCESS;\r
1638                 break;\r
1639         }\r
1640 \r
1641         if( !NT_SUCCESS( status ) )\r
1642                 *p_action = IrpComplete;\r
1643 \r
1644         HCA_EXIT( HCA_DBG_PNP );\r
1645         return status;\r
1646 }\r
1647 \r
1648 static void\r
1649 __reregister_hca_cb(\r
1650         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1651         IN                              void*                                           context )\r
1652 {\r
1653 #define SLEEP_TIME              100000  // 100 msec\r
1654 #define POLL_TRIES              20              // to wait for 2 sec\r
1655         int i;\r
1656         NTSTATUS                        status;\r
1657         LARGE_INTEGER  interval;\r
1658         hca_dev_ext_t           *p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1659         PIO_WORKITEM            pPoWorkItem = (PIO_WORKITEM)context;\r
1660 \r
1661         HCA_ENTER( HCA_DBG_PO );\r
1662 \r
1663         IoFreeWorkItem( pPoWorkItem );\r
1664 \r
1665         /* wait SLEEP_TIME_USEC usec for application to exit */\r
1666         interval.QuadPart = (-10) * SLEEP_TIME;\r
1667         KeDelayExecutionThread( KernelMode, FALSE, &interval );\r
1668         for (i=0; p_ext->usecnt && i < POLL_TRIES; ++i) {\r
1669                 KeDelayExecutionThread( KernelMode, FALSE, &interval );\r
1670         }\r
1671 \r
1672         if (!p_ext->usecnt) {\r
1673                 /* reregister HCA */\r
1674                  __hca_deregister( p_ext );\r
1675 \r
1676                 if( p_ext->p_al_dev ) {\r
1677                         status = __hca_register( p_dev_obj );\r
1678                         if( !NT_SUCCESS( status ) ) {\r
1679                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1680                                         ("__hca_register returned 0x%08X.\n", status));\r
1681                         }\r
1682                 }\r
1683         }\r
1684 \r
1685         HCA_EXIT( HCA_DBG_PO );\r
1686 }\r
1687 \r
1688 \r
1689 void reregister_hca( hca_dev_ext_t *p_ext )\r
1690 {\r
1691         DEVICE_OBJECT *p_dev_obj = (DEVICE_OBJECT *)p_ext->cl_ext.p_self_do;\r
1692         PIO_WORKITEM pPoWorkItem;\r
1693 \r
1694         /* Process in a work item - deregister_ca and HcaDeinit block. */\r
1695         pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1696         if( pPoWorkItem ) \r
1697                 IoQueueWorkItem( pPoWorkItem, __reregister_hca_cb, \r
1698                         DelayedWorkQueue, pPoWorkItem );\r
1699         \r
1700 }\r
1701 \r