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