792e1e0e91b3013c84eb721b5176fd8347abaa24
[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 %d Dev %d Hw %x Fw %d.%d.%d Drv %s (%s) Flg %s%s%s\n", \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                         (mdev->mthca_flags & MTHCA_FLAG_MEMFREE) ? "M:" : "",\r
899                         (mdev->mthca_flags & MTHCA_FLAG_PCIE) ? "E:" : "",\r
900                         (mdev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN) ? "H" : ""\r
901                         ));\r
902         }\r
903 \r
904         HCA_EXIT( HCA_DBG_PNP );\r
905         return status;\r
906 }\r
907 \r
908 \r
909 /* release the resources, allocated in hca_start */\r
910 static void\r
911 __hca_release_resources(\r
912         IN                              DEVICE_OBJECT* const            p_dev_obj )\r
913 {\r
914         hca_dev_ext_t           *p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
915 \r
916         HCA_ENTER( HCA_DBG_PNP );\r
917 \r
918         switch( p_ext->state )\r
919         {\r
920         case HCA_REGISTERED:\r
921                 __hca_deregister( p_ext );\r
922 \r
923                 /* Fall through. */\r
924         case HCA_STARTED:\r
925                 /* dequeue HCA  */\r
926                 mlnx_hca_remove( &p_ext->hca );\r
927         }\r
928 \r
929         if (p_ext->al_sym_name.Buffer) {\r
930                 ExFreePool( p_ext->al_sym_name.Buffer );\r
931                 p_ext->al_sym_name.Buffer = NULL;\r
932         }\r
933         \r
934         if( p_ext->pnp_target_entry )\r
935         {\r
936                 ASSERT( p_ext->pnp_ifc_entry );\r
937                 IoUnregisterPlugPlayNotification( p_ext->pnp_target_entry );\r
938                 p_ext->pnp_target_entry = NULL;\r
939         }\r
940 \r
941         if( p_ext->pnp_ifc_entry ) {\r
942                 IoUnregisterPlugPlayNotification( p_ext->pnp_ifc_entry );\r
943                 p_ext->pnp_ifc_entry = NULL;\r
944         }\r
945 \r
946         if( p_ext->p_al_file_obj ) {\r
947                 ObDereferenceObject( p_ext->p_al_file_obj );\r
948                 p_ext->p_al_file_obj = NULL;\r
949         }\r
950 \r
951         mthca_remove_one( p_ext );\r
952 \r
953         if( p_ext->p_dma_adapter ) {\r
954                 p_ext->p_dma_adapter->DmaOperations->PutDmaAdapter( p_ext->p_dma_adapter );\r
955                 p_ext->p_dma_adapter = NULL;\r
956         }\r
957 \r
958         hca_disable_pci( &p_ext->hcaBusIfc );\r
959 \r
960         //cl_event_destroy( &p_ext->mutex );\r
961         __UnmapHcaMemoryResources( p_dev_obj );\r
962 \r
963         p_ext->state = HCA_ADDED;\r
964 \r
965         HCA_EXIT( HCA_DBG_PNP );\r
966 }\r
967 \r
968 \r
969 static void\r
970 hca_release_resources(\r
971         IN                              DEVICE_OBJECT* const            p_dev_obj )\r
972 {\r
973         hca_dev_ext_t           *p_ext;\r
974         POWER_STATE                     powerState;\r
975 \r
976         HCA_ENTER( HCA_DBG_PNP );\r
977 \r
978         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
979 \r
980         /* release all the resources, allocated in hca_start */\r
981         __hca_release_resources(p_dev_obj);\r
982 \r
983         /* Notify the power manager that the device is powered down. */\r
984         powerState.DeviceState = PowerDeviceD3;\r
985         PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState );\r
986 \r
987         /* Clear the PnP state in case we get restarted. */\r
988         p_ext->pnpState = 0;\r
989 \r
990         HCA_EXIT( HCA_DBG_PNP );\r
991 }\r
992 \r
993 \r
994 static NTSTATUS\r
995 hca_query_removal_relations(\r
996         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
997         IN                                      IRP* const                              p_irp, \r
998                 OUT                             cl_irp_action_t* const  p_action )\r
999 {\r
1000         NTSTATUS        status;\r
1001         hca_dev_ext_t   *p_ext;\r
1002 \r
1003         HCA_ENTER( HCA_DBG_PNP );\r
1004 \r
1005         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1006 \r
1007         if( p_ext->state == HCA_REGISTERED )\r
1008         {\r
1009                 status = p_ext->ci_ifc.get_relations( p_ext->hca.guid, p_irp );\r
1010                 if( !NT_SUCCESS( status ) )\r
1011                 {\r
1012                         *p_action = IrpComplete;\r
1013                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1014                                 ("AL get_relations returned %08x.\n", status));\r
1015                         return status;\r
1016                 }\r
1017         }\r
1018 \r
1019         *p_action = IrpPassDown;\r
1020         HCA_EXIT( HCA_DBG_PNP );\r
1021         return STATUS_SUCCESS;\r
1022 }\r
1023 \r
1024 \r
1025 static NTSTATUS\r
1026 hca_query_bus_relations(\r
1027         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1028         IN                                      IRP* const                              p_irp, \r
1029                 OUT                             cl_irp_action_t* const  p_action )\r
1030 {\r
1031         NTSTATUS                        status;\r
1032         DEVICE_RELATIONS        *p_rel;\r
1033         hca_dev_ext_t   *p_ext;\r
1034 \r
1035         HCA_ENTER( HCA_DBG_PNP );\r
1036 \r
1037         p_ext = p_dev_obj->DeviceExtension;\r
1038 \r
1039         //cl_event_wait_on( &p_ext->mutex, EVENT_NO_TIMEOUT, FALSE );\r
1040         if( p_ext->state == HCA_REGISTERED )\r
1041         {\r
1042                 status = p_ext->ci_ifc.get_relations( p_ext->hca.guid, p_irp );\r
1043                 if( !NT_SUCCESS( status ) )\r
1044                 {\r
1045                         //cl_event_signal( &p_ext->mutex );\r
1046                         *p_action = IrpComplete;\r
1047                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1048                                 ("AL get_relations returned %08x.\n", status));\r
1049                         return status;\r
1050                 }\r
1051         }\r
1052         else\r
1053         {\r
1054                 status = cl_alloc_relations( p_irp, 1 );\r
1055                 if( !NT_SUCCESS( status ) )\r
1056                 {\r
1057                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1058                                 ("cl_alloc_relations returned %08x.\n", status));\r
1059                         return status;\r
1060                 }\r
1061 \r
1062                 p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
1063                 p_rel->Count = 0;\r
1064                 p_rel->Objects[0] = NULL;\r
1065         }\r
1066 \r
1067         //cl_event_signal( &p_ext->mutex );\r
1068 \r
1069         *p_action = IrpPassDown;\r
1070         HCA_EXIT( HCA_DBG_PNP );\r
1071         return STATUS_SUCCESS;\r
1072 }\r
1073 \r
1074 \r
1075 static NTSTATUS\r
1076 hca_query_stop(\r
1077         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1078         IN                              IRP* const                                      p_irp, \r
1079                 OUT                     cl_irp_action_t* const          p_action )\r
1080 {\r
1081         /* All kernel clients will get notified through the device hierarchy. */\r
1082 \r
1083         /* TODO: set a flag to fail creation of any new IB resources. */\r
1084         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1085 }\r
1086 \r
1087 \r
1088 static NTSTATUS\r
1089 hca_stop(\r
1090         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1091         IN                              IRP* const                                      p_irp, \r
1092                 OUT                     cl_irp_action_t* const          p_action )\r
1093 {\r
1094         /*\r
1095          * Must disable everything.  Complib framework will\r
1096          * call ReleaseResources handler.\r
1097          */\r
1098         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1099 }\r
1100 \r
1101 \r
1102 static NTSTATUS\r
1103 hca_cancel_stop(\r
1104         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1105         IN                              IRP* const                                      p_irp, \r
1106                 OUT                     cl_irp_action_t* const          p_action )\r
1107 {\r
1108         /* Handled on the way up. */\r
1109         return cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
1110 }\r
1111 \r
1112 \r
1113 static NTSTATUS\r
1114 hca_query_remove(\r
1115         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1116         IN                              IRP* const                                      p_irp, \r
1117                 OUT                     cl_irp_action_t* const          p_action )\r
1118 {\r
1119         hca_dev_ext_t*p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1120         if (atomic_read(&p_ext->usecnt)) {\r
1121                 p_irp->IoStatus.Status = STATUS_UNSUCCESSFUL;\r
1122                 return cl_irp_complete( p_dev_obj, p_irp, p_action );\r
1123         }\r
1124         /* TODO: set a flag to fail creation of any new IB resources. */\r
1125         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1126 }\r
1127 \r
1128 \r
1129 static NTSTATUS\r
1130 hca_cancel_remove(\r
1131         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1132         IN                              IRP* const                                      p_irp, \r
1133                 OUT                     cl_irp_action_t* const          p_action )\r
1134 {\r
1135         /* Handled on the way up. */\r
1136         return cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
1137 }\r
1138 \r
1139 \r
1140 static NTSTATUS\r
1141 hca_surprise_remove(\r
1142         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1143         IN                              IRP* const                                      p_irp, \r
1144                 OUT                     cl_irp_action_t* const          p_action )\r
1145 {\r
1146         /*\r
1147          * TODO: Set state so that all further requests\r
1148          * automatically succeed/fail as needed.\r
1149          */\r
1150         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1151 }\r
1152 \r
1153 \r
1154 static NTSTATUS\r
1155 hca_query_capabilities(\r
1156         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1157         IN                              IRP* const                                      p_irp, \r
1158                 OUT                     cl_irp_action_t* const          p_action )\r
1159 {\r
1160         NTSTATUS                        status;\r
1161         hca_dev_ext_t           *p_ext;\r
1162         IO_STACK_LOCATION       *pIoStack;\r
1163         DEVICE_CAPABILITIES     *pCaps;\r
1164 \r
1165         HCA_ENTER( HCA_DBG_PNP );\r
1166 \r
1167         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1168 \r
1169         /* Process on the way up. */\r
1170         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
1171         if( !NT_SUCCESS( status ) )\r
1172         {\r
1173                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1174                         ("cl_do_sync_pnp returned %08X.\n", status));\r
1175                 return status;\r
1176         }\r
1177 \r
1178         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1179         pCaps = pIoStack->Parameters.DeviceCapabilities.Capabilities;\r
1180 \r
1181         /*\r
1182          * Store the device power mapping into our extension since we're\r
1183          * the power policy owner.  The mapping is used when handling\r
1184          * IRP_MN_SET_POWER IRPs.\r
1185          */\r
1186         cl_memcpy(\r
1187                 p_ext->DevicePower, pCaps->DeviceState, sizeof(p_ext->DevicePower) );\r
1188 \r
1189         if( pCaps->DeviceD1 )\r
1190         {\r
1191                 HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP,\r
1192                         ("WARNING: Device reports support for DeviceD1 power state.\n"));\r
1193                 pCaps->DeviceD1 = FALSE;\r
1194         }\r
1195 \r
1196         if( pCaps->DeviceD2 )\r
1197         {\r
1198                 HCA_PRINT( TRACE_LEVEL_WARNING,HCA_DBG_PNP,\r
1199                         ("WARNING: Device reports support for DeviceD2 power state.\n"));\r
1200                 pCaps->DeviceD2 = FALSE;\r
1201         }\r
1202 \r
1203         if( pCaps->SystemWake != PowerSystemUnspecified )\r
1204         {\r
1205                 HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP,\r
1206                         ("WARNING: Device reports support for system wake.\n"));\r
1207                 pCaps->SystemWake = PowerSystemUnspecified;\r
1208         }\r
1209 \r
1210         if( pCaps->DeviceWake != PowerDeviceUnspecified )\r
1211         {\r
1212                 HCA_PRINT( TRACE_LEVEL_WARNING, HCA_DBG_PNP,\r
1213                         ("WARNING: Device reports support for device wake.\n"));\r
1214                 pCaps->DeviceWake = PowerDeviceUnspecified;\r
1215         }\r
1216 \r
1217         HCA_EXIT( HCA_DBG_PNP );\r
1218         return status;\r
1219 }\r
1220 \r
1221 \r
1222 static NTSTATUS\r
1223 hca_query_pnp_state(\r
1224         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1225         IN                              IRP* const                                      p_irp, \r
1226                 OUT                     cl_irp_action_t* const          p_action )\r
1227 {\r
1228         hca_dev_ext_t           *p_ext;\r
1229 \r
1230         HCA_ENTER( HCA_DBG_PNP );\r
1231 \r
1232         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1233 \r
1234         p_irp->IoStatus.Information |= p_ext->pnpState;\r
1235 \r
1236         *p_action = IrpSkip;\r
1237 \r
1238         HCA_EXIT( HCA_DBG_PNP );\r
1239         return STATUS_SUCCESS;;\r
1240 }\r
1241 \r
1242 \r
1243 static NTSTATUS\r
1244 hca_query_power(\r
1245         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1246         IN                              IRP* const                                      p_irp,\r
1247                 OUT                     cl_irp_action_t* const          p_action )\r
1248 {\r
1249         NTSTATUS                        status = STATUS_SUCCESS;\r
1250         IO_STACK_LOCATION       *pIoStack;\r
1251 \r
1252         HCA_ENTER(HCA_DBG_PO);\r
1253 \r
1254         UNUSED_PARAM( p_dev_obj );\r
1255 \r
1256         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1257 \r
1258         switch( pIoStack->Parameters.Power.Type )\r
1259         {\r
1260         case SystemPowerState:\r
1261                 /* Fail any requests to hibernate or sleep the system. */\r
1262                 switch( pIoStack->Parameters.Power.State.SystemState )\r
1263                 {\r
1264                         case PowerSystemWorking:\r
1265                         case PowerSystemShutdown:\r
1266                                 /* We only support fully working and shutdown system states. */\r
1267                                 break;\r
1268 \r
1269                         default:\r
1270                                 status = STATUS_NOT_SUPPORTED;\r
1271                 }\r
1272                 break;\r
1273 \r
1274         case DevicePowerState:\r
1275                 /* Fail any query for low power states. */\r
1276                 switch( pIoStack->Parameters.Power.State.DeviceState )\r
1277                 {\r
1278                 case PowerDeviceD0:\r
1279                 case PowerDeviceD3:\r
1280                         /* We only support fully powered or off power states. */\r
1281                         break;\r
1282 \r
1283                 default:\r
1284                         status = STATUS_NOT_SUPPORTED;\r
1285                 }\r
1286                 break;\r
1287         }\r
1288 \r
1289         if( status == STATUS_NOT_SUPPORTED )\r
1290                 *p_action = IrpComplete;\r
1291         else\r
1292                 *p_action = IrpSkip;\r
1293 \r
1294         HCA_EXIT( HCA_DBG_PO );\r
1295         return status;\r
1296 }\r
1297 \r
1298 \r
1299 static void\r
1300 __RequestPowerCompletion(\r
1301         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1302         IN                              UCHAR                                           minorFunction,\r
1303         IN                              POWER_STATE                                     powerState,\r
1304         IN                              void                                            *context,\r
1305         IN                              IO_STATUS_BLOCK                         *pIoStatus )\r
1306 {\r
1307         IRP                                     *p_irp;\r
1308         cl_pnp_po_ext_t         *p_ext;\r
1309 \r
1310         HCA_ENTER( HCA_DBG_PO );\r
1311 \r
1312         UNUSED_PARAM( minorFunction );\r
1313         UNUSED_PARAM( powerState );\r
1314 \r
1315         p_irp = (IRP*)context;\r
1316         p_ext = (cl_pnp_po_ext_t*)p_dev_obj->DeviceExtension;\r
1317 \r
1318         /* Propagate the device IRP status to the system IRP status. */\r
1319         p_irp->IoStatus.Status = pIoStatus->Status;\r
1320 \r
1321         /* Continue Power IRP processing. */\r
1322         PoStartNextPowerIrp( p_irp );\r
1323         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1324         IoReleaseRemoveLock( &p_ext->remove_lock, p_irp );\r
1325         HCA_EXIT( HCA_DBG_PO );\r
1326 }\r
1327 \r
1328 \r
1329 /*NOTE: Completion routines must NEVER be pageable. */\r
1330 static NTSTATUS\r
1331 __SystemPowerCompletion(\r
1332         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1333         IN                              IRP                                                     *p_irp,\r
1334         IN                              void                                            *context )\r
1335 {\r
1336         NTSTATUS                        status;\r
1337         POWER_STATE                     state;\r
1338         hca_dev_ext_t           *p_ext;\r
1339         IO_STACK_LOCATION       *pIoStack;\r
1340 \r
1341         HCA_ENTER( HCA_DBG_PNP );\r
1342 \r
1343         UNUSED_PARAM( context );\r
1344 \r
1345         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1346         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1347 \r
1348         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1349         {\r
1350                 PoStartNextPowerIrp( p_irp );\r
1351                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1352                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1353                         ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n",\r
1354                         p_irp->IoStatus.Status));\r
1355                 return STATUS_SUCCESS;\r
1356         }\r
1357 \r
1358         state.DeviceState = \r
1359                 p_ext->DevicePower[pIoStack->Parameters.Power.State.SystemState];\r
1360 \r
1361         /*\r
1362          * Send a device power IRP to our devnode.  Using our device object will\r
1363          * only work on win2k and other NT based systems.\r
1364          */\r
1365         status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
1366                 __RequestPowerCompletion, p_irp, NULL );\r
1367 \r
1368         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1369         {\r
1370                 PoStartNextPowerIrp( p_irp );\r
1371                 /* Propagate the failure. */\r
1372                 p_irp->IoStatus.Status = status;\r
1373                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1374                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1375                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP,\r
1376                         ("PoRequestPowerIrp returned %08x.\n", status));\r
1377         }\r
1378 \r
1379         HCA_EXIT( HCA_DBG_PNP );\r
1380         return STATUS_MORE_PROCESSING_REQUIRED;\r
1381 }\r
1382 \r
1383 \r
1384 /* Work item callback to handle DevicePowerD0 IRPs at passive level. */\r
1385 static void\r
1386 __PowerUpCb(\r
1387         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1388         IN                              void*                                           context )\r
1389 {\r
1390         NTSTATUS                        status;\r
1391         IO_STACK_LOCATION       *pIoStack;\r
1392         hca_dev_ext_t           *p_ext;\r
1393         IRP                                     *p_irp;\r
1394 \r
1395         HCA_ENTER( HCA_DBG_PO );\r
1396 \r
1397         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1398         p_irp = (IRP*)context;\r
1399         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1400 \r
1401         IoFreeWorkItem( p_ext->pPoWorkItem );\r
1402         p_ext->pPoWorkItem = NULL;\r
1403 \r
1404         /* restart the HCA */\r
1405         status = mthca_init_one( p_ext );\r
1406         if( !NT_SUCCESS( status ) )\r
1407                 goto done;\r
1408 \r
1409         if( p_ext->p_al_dev )\r
1410                 status = __hca_register( p_dev_obj );\r
1411 \r
1412 done:\r
1413         if( !NT_SUCCESS( status ) )\r
1414         {\r
1415                 /* Flag device as having failed. */\r
1416                 p_ext->pnpState |= PNP_DEVICE_FAILED;\r
1417                 IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1418         }\r
1419 \r
1420         PoStartNextPowerIrp( p_irp );\r
1421         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1422         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1423 \r
1424         HCA_EXIT( HCA_DBG_PO );\r
1425 }\r
1426 \r
1427 \r
1428 /*NOTE: Completion routines must NEVER be pageable. */\r
1429 static NTSTATUS\r
1430 __DevicePowerCompletion(\r
1431         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1432         IN                              IRP                                                     *p_irp,\r
1433         IN                              void                                            *context )\r
1434 {\r
1435         NTSTATUS                        status = STATUS_SUCCESS;\r
1436         hca_dev_ext_t           *p_ext;\r
1437         IO_STACK_LOCATION       *pIoStack;\r
1438         KIRQL irql = KeGetCurrentIrql(  );\r
1439         \r
1440         \r
1441 \r
1442         HCA_ENTER( HCA_DBG_PO );\r
1443 \r
1444         UNUSED_PARAM( context );\r
1445 \r
1446         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1447         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1448 \r
1449         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1450         {\r
1451                 PoStartNextPowerIrp( p_irp );\r
1452                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1453                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1454                         ("IRP_MN_SET_POWER for device failed by lower driver with %08x.\n",\r
1455                         p_irp->IoStatus.Status));\r
1456                 return STATUS_SUCCESS;\r
1457         }\r
1458 \r
1459         p_ext->PowerState = pIoStack->Parameters.Power.State.DeviceState;\r
1460         PoSetPowerState( p_dev_obj, DevicePowerState,\r
1461                 pIoStack->Parameters.Power.State );\r
1462 \r
1463         if (irql > PASSIVE_LEVEL) {\r
1464                 /* Process in a work item - mthca_start blocks. */\r
1465                 ASSERT( !p_ext->pPoWorkItem );\r
1466                 p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1467                 if( !p_ext->pPoWorkItem )\r
1468                 {\r
1469                         IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1470 \r
1471                         PoStartNextPowerIrp( p_irp );\r
1472                         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1473 \r
1474                         return STATUS_SUCCESS;\r
1475                 }\r
1476 \r
1477                 /* Process in work item callback. */\r
1478                 IoMarkIrpPending( p_irp );\r
1479                 IoQueueWorkItem( p_ext->pPoWorkItem, __PowerUpCb, DelayedWorkQueue, p_irp );\r
1480         }\r
1481         else {\r
1482 \r
1483                 /* restart the HCA */\r
1484                 status = mthca_init_one( p_ext );\r
1485                 if( !NT_SUCCESS( status ) )\r
1486                         goto done;\r
1487 \r
1488                 if( p_ext->p_al_dev )\r
1489                         status = __hca_register( p_dev_obj );\r
1490         }\r
1491 \r
1492 done:\r
1493         if( !NT_SUCCESS( status ) )\r
1494                 IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1495 \r
1496         PoStartNextPowerIrp( p_irp );\r
1497         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1498 \r
1499         HCA_EXIT( HCA_DBG_PO );\r
1500         return STATUS_MORE_PROCESSING_REQUIRED;\r
1501 }\r
1502 \r
1503 static NTSTATUS __DeviceDownCbCompletion(\r
1504         IN                              DEVICE_OBJECT   *p_dev_obj,\r
1505         IN                              IRP                             *p_irp,\r
1506         IN                              void                            *context )\r
1507 {\r
1508         hca_dev_ext_t  *p_ext  = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1509         UNUSED_PARAM( context );\r
1510 \r
1511         PoStartNextPowerIrp( p_irp );\r
1512         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1513         return STATUS_SUCCESS;\r
1514 }\r
1515 \r
1516 /* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
1517 static void\r
1518 __PowerDownCb(\r
1519         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1520         IN                              void*                                           context )\r
1521 {\r
1522         IO_STACK_LOCATION       *pIoStack;\r
1523         hca_dev_ext_t           *p_ext;\r
1524         IRP                                     *p_irp;\r
1525 \r
1526         HCA_ENTER( HCA_DBG_PO );\r
1527 \r
1528         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1529         p_irp = (IRP*)context;\r
1530         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1531 \r
1532         IoFreeWorkItem( p_ext->pPoWorkItem );\r
1533         p_ext->pPoWorkItem = NULL;\r
1534 \r
1535         PoSetPowerState( p_dev_obj, DevicePowerState,\r
1536                 pIoStack->Parameters.Power.State );\r
1537 \r
1538         __hca_deregister( p_ext );\r
1539         mthca_remove_one( p_ext );\r
1540 \r
1541         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1542 #pragma warning( push, 3 )\r
1543         IoSetCompletionRoutine( p_irp, __DeviceDownCbCompletion,\r
1544                 NULL, TRUE, TRUE, TRUE );\r
1545 #pragma warning( pop )\r
1546         PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1547 \r
1548         HCA_EXIT( HCA_DBG_PO );\r
1549 }\r
1550 \r
1551 \r
1552 static NTSTATUS\r
1553 hca_set_power(\r
1554         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1555         IN                              IRP* const                                      p_irp,\r
1556                 OUT                     cl_irp_action_t* const          p_action )\r
1557 {\r
1558         NTSTATUS                        status;\r
1559         IO_STACK_LOCATION       *pIoStack;\r
1560         hca_dev_ext_t           *p_ext;\r
1561 \r
1562         HCA_ENTER( HCA_DBG_PO );\r
1563 \r
1564         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1565         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1566 \r
1567         switch( pIoStack->Parameters.Power.Type )\r
1568         {\r
1569         case SystemPowerState:\r
1570                 /*\r
1571                  * Process on the way up the stack.  We cannot block since the \r
1572                  * power dispatch function can be called at elevated IRQL if the\r
1573                  * device is in a paging/hibernation/crash dump path.\r
1574                  */\r
1575                 IoMarkIrpPending( p_irp );\r
1576                 IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1577 #pragma warning( push, 3 )\r
1578                 IoSetCompletionRoutine( p_irp, __SystemPowerCompletion, NULL, \r
1579                         TRUE, TRUE, TRUE );\r
1580 #pragma warning( pop )\r
1581                 PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1582 \r
1583                 *p_action = IrpDoNothing;\r
1584                 status = STATUS_PENDING;\r
1585                 break;\r
1586 \r
1587         case DevicePowerState:\r
1588                 IoMarkIrpPending( p_irp );\r
1589                 if( pIoStack->Parameters.Power.State.DeviceState == PowerDeviceD0 )\r
1590                 {\r
1591                         /* If we're already powered up, just pass down. */\r
1592                         if( p_ext->PowerState == PowerDeviceD0 )\r
1593                         {\r
1594                                 status = STATUS_SUCCESS;\r
1595                                 *p_action = IrpIgnore;\r
1596                                 break;\r
1597                         }\r
1598 \r
1599                         /* Process in I/O completion callback. */\r
1600                         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1601 #pragma warning( push, 3 )\r
1602                         IoSetCompletionRoutine( p_irp, __DevicePowerCompletion, NULL, \r
1603                                 TRUE, TRUE, TRUE );\r
1604 #pragma warning( pop )\r
1605                         PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1606                 }\r
1607                 else\r
1608                 {\r
1609                         /* Process in a work item - deregister_ca and HcaDeinit block. */\r
1610                         ASSERT( !p_ext->pPoWorkItem );\r
1611                         p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1612                         if( !p_ext->pPoWorkItem )\r
1613                         {\r
1614                                 status = STATUS_INSUFFICIENT_RESOURCES;\r
1615                                 break;\r
1616                         }\r
1617 \r
1618                         /* Process in work item callback. */\r
1619                         IoMarkIrpPending( p_irp );\r
1620                         IoQueueWorkItem(\r
1621                                 p_ext->pPoWorkItem, __PowerDownCb, DelayedWorkQueue, p_irp );\r
1622                 }\r
1623                 *p_action = IrpDoNothing;\r
1624                 status = STATUS_PENDING;\r
1625                 break;\r
1626 \r
1627         default:\r
1628                 /* Pass down and let the PDO driver handle it. */\r
1629                 *p_action = IrpIgnore;\r
1630                 status = STATUS_SUCCESS;\r
1631                 break;\r
1632         }\r
1633 \r
1634         if( !NT_SUCCESS( status ) )\r
1635                 *p_action = IrpComplete;\r
1636 \r
1637         HCA_EXIT( HCA_DBG_PNP );\r
1638         return status;\r
1639 }\r
1640 \r
1641 static void\r
1642 __reregister_hca_cb(\r
1643         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1644         IN                              void*                                           context )\r
1645 {\r
1646 #define SLEEP_TIME              100000  // 100 msec\r
1647 #define POLL_TRIES              20              // to wait for 2 sec\r
1648         int i;\r
1649         NTSTATUS                        status;\r
1650         LARGE_INTEGER  interval;\r
1651         hca_dev_ext_t           *p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1652         PIO_WORKITEM            pPoWorkItem = (PIO_WORKITEM)context;\r
1653 \r
1654         HCA_ENTER( HCA_DBG_PO );\r
1655 \r
1656         IoFreeWorkItem( pPoWorkItem );\r
1657 \r
1658         /* wait SLEEP_TIME_USEC usec for application to exit */\r
1659         interval.QuadPart = (-10) * SLEEP_TIME;\r
1660         KeDelayExecutionThread( KernelMode, FALSE, &interval );\r
1661         for (i=0; p_ext->usecnt && i < POLL_TRIES; ++i) {\r
1662                 KeDelayExecutionThread( KernelMode, FALSE, &interval );\r
1663         }\r
1664 \r
1665         if (!p_ext->usecnt) {\r
1666                 /* reregister HCA */\r
1667                  __hca_deregister( p_ext );\r
1668 \r
1669                 if( p_ext->p_al_dev ) {\r
1670                         status = __hca_register( p_dev_obj );\r
1671                         if( !NT_SUCCESS( status ) ) {\r
1672                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1673                                         ("__hca_register returned 0x%08X.\n", status));\r
1674                         }\r
1675                 }\r
1676         }\r
1677 \r
1678         HCA_EXIT( HCA_DBG_PO );\r
1679 }\r
1680 \r
1681 \r
1682 void reregister_hca( hca_dev_ext_t *p_ext )\r
1683 {\r
1684         DEVICE_OBJECT *p_dev_obj = (DEVICE_OBJECT *)p_ext->cl_ext.p_self_do;\r
1685         PIO_WORKITEM pPoWorkItem;\r
1686 \r
1687         /* Process in a work item - deregister_ca and HcaDeinit block. */\r
1688         pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1689         if( pPoWorkItem ) \r
1690                 IoQueueWorkItem( pPoWorkItem, __reregister_hca_cb, \r
1691                         DelayedWorkQueue, pPoWorkItem );\r
1692         \r
1693 }\r
1694 \r