[MTHCA, IBAL] added FMR support; [MTHCA] 1. fixed (and now works) "livefish" support;
[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         // there will be no resources for "livefish" (PCI memory controller mode)\r
580         if (!pHcaResList || !pHostResList)\r
581                 goto done;\r
582                 \r
583         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
584 \r
585         ASSERT( pHostResList->List[0].PartialResourceList.Version == 1 );\r
586         ASSERT( pHostResList->List[0].PartialResourceList.Revision == 1 );\r
587 \r
588         // store the bus number for reset of Tavor\r
589         p_ext->bus_number = pHostResList->List[0].BusNumber;\r
590         \r
591         for( i = 0; i < pHostResList->List[0].PartialResourceList.Count; i++ )\r
592         {\r
593                 pHcaRes =\r
594                         &pHcaResList->List[0].PartialResourceList.PartialDescriptors[i];\r
595                 pHostRes = \r
596                         &pHostResList->List[0].PartialResourceList.PartialDescriptors[i];\r
597 \r
598 \r
599                 /*\r
600                  * Save the interrupt information so that we can power the device\r
601                  * up and down.  Since the device will lose state when powered down\r
602                  * we have to fully disable it.  Note that we can leave memory mapped\r
603                  * resources in place when powered down as the resource assignments\r
604                  * won't change.  However, we must disconnect our interrupt, and\r
605                  * reconnect it when powering up.\r
606                  */\r
607                 if( pHcaRes->Type == CmResourceTypeInterrupt )\r
608                 {\r
609                         p_ext->interruptInfo = *pHostRes;\r
610                         continue;\r
611                 }\r
612                 \r
613                 if( pHcaRes->Type != CmResourceTypeMemory )\r
614                         continue;\r
615 \r
616                 /*\r
617                  * Sanity check that our assumption on how resources\r
618                  * are reported hold.\r
619                  */\r
620                 if( type == HCA_BAR_TYPE_HCR &&\r
621                         (pHcaRes->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE) )\r
622                 {\r
623                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
624                                 ("First memory resource is prefetchable - expected HCR.\n"));\r
625                         status = STATUS_UNSUCCESSFUL;\r
626                         break;\r
627                 }\r
628 \r
629                 p_ext->bar[type].phys = pHcaRes->u.Memory.Start.QuadPart;\r
630                 p_ext->bar[type].size = pHcaRes->u.Memory.Length;\r
631 #ifdef MAP_ALL_HCA_MEMORY               \r
632                 /*leo: no need to map all the resources */\r
633                 p_ext->bar[type].virt = MmMapIoSpace( pHostRes->u.Memory.Start,\r
634                         pHostRes->u.Memory.Length, MmNonCached );\r
635                 if( !p_ext->bar[type].virt )\r
636                 {\r
637                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
638                                 ("Failed to map memory resource type %d\n", type));\r
639                         status = STATUS_UNSUCCESSFUL;\r
640                         break;\r
641                 }\r
642 #else           \r
643                 p_ext->bar[type].virt = NULL;\r
644 #endif          \r
645 \r
646                 type++;\r
647         }\r
648 \r
649         if( type == HCA_BAR_TYPE_DDR)\r
650         {\r
651                 p_ext->hca_hidden = 1;\r
652         }\r
653         else \r
654         if( type != HCA_BAR_TYPE_MAX )\r
655         {\r
656                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM  ,("Failed to map all memory resources.\n"));\r
657                 status = STATUS_UNSUCCESSFUL;\r
658         }\r
659 \r
660         if( p_ext->interruptInfo.Type != CmResourceTypeInterrupt )\r
661         {\r
662                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM  ,("No interrupt resource.\n"));\r
663                 status = STATUS_UNSUCCESSFUL;\r
664         }\r
665 \r
666 done:\r
667         HCA_EXIT( HCA_DBG_PNP );\r
668         return status;\r
669 }\r
670 \r
671 \r
672 static void\r
673 __UnmapHcaMemoryResources(\r
674         IN                              DEVICE_OBJECT* const            p_dev_obj )\r
675 {\r
676         hca_dev_ext_t           *p_ext;\r
677         USHORT                          i;\r
678 \r
679         HCA_ENTER( HCA_DBG_PNP );\r
680 \r
681         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
682 \r
683         for( i = 0; i < HCA_BAR_TYPE_MAX; i++ )\r
684         {\r
685                 if( p_ext->bar[i].virt )\r
686                 {\r
687                         MmUnmapIoSpace( p_ext->bar[i].virt, p_ext->bar[i].size );\r
688                         cl_memclr( &p_ext->bar[i], sizeof(hca_bar_t) );\r
689                 }\r
690         }\r
691 \r
692         HCA_EXIT( HCA_DBG_PNP );\r
693 }\r
694 \r
695 \r
696 static int mthca_get_livefish_info(struct mthca_dev *mdev, __be64 *node_guid, u32 *hw_id)\r
697 {\r
698         *node_guid = cl_hton64((uint64_t)(ULONG_PTR)mdev);\r
699         mdev->ib_dev.node_guid = *node_guid;\r
700         *hw_id = 0;\r
701         return 0;\r
702 }\r
703 \r
704 static NTSTATUS\r
705 hca_start(\r
706         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
707         IN                              IRP* const                                      p_irp, \r
708                 OUT                     cl_irp_action_t* const          p_action )\r
709 {\r
710         NTSTATUS                        status;\r
711         hca_dev_ext_t           *p_ext;\r
712         IO_STACK_LOCATION       *pIoStack;\r
713         POWER_STATE                     powerState;\r
714         DEVICE_DESCRIPTION      devDesc;\r
715 \r
716         HCA_ENTER( HCA_DBG_PNP );\r
717 \r
718         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
719 \r
720         /* Handled on the way up. */\r
721         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
722         if( !NT_SUCCESS( status ) )\r
723         {\r
724                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
725                         ("Lower drivers failed IRP_MN_START_DEVICE.\n"));\r
726                 return status;\r
727         }\r
728 \r
729         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
730 \r
731         /*\r
732          * Walk the resource lists and store the information.  The write-only\r
733          * flag is not set for the UAR region, so it is indistinguishable from the\r
734          * DDR region since both are prefetchable.  The code here assumes that the\r
735          * resources get handed in order - HCR, UAR, DDR.\r
736          *      - Configuration Space: not prefetchable, read/write\r
737          *      - UAR space: prefetchable, write only.\r
738          *      - DDR: prefetchable, read/write.\r
739          */\r
740         status = __SetupHcaResources( p_dev_obj,\r
741                 pIoStack->Parameters.StartDevice.AllocatedResources,\r
742                 pIoStack->Parameters.StartDevice.AllocatedResourcesTranslated );\r
743         if( !NT_SUCCESS( status ) )\r
744         {\r
745                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
746                         ("__ProcessResources returned %08X.\n", status));\r
747                 return status;\r
748         }\r
749         \r
750         /* save PCI bus i/f, PCI configuration info and enable device */\r
751         hca_enable_pci( p_dev_obj, &p_ext->hcaBusIfc, &p_ext->hcaConfig );\r
752 \r
753         /*\r
754          * Get the DMA adapter representing the HCA so we can\r
755          * allocate common buffers.\r
756          */\r
757         RtlZeroMemory( &devDesc, sizeof(devDesc) );\r
758         devDesc.Version = DEVICE_DESCRIPTION_VERSION2;\r
759         devDesc.Master = TRUE;\r
760         devDesc.ScatterGather = TRUE;\r
761         devDesc.Dma32BitAddresses = TRUE;\r
762         devDesc.Dma64BitAddresses = TRUE;\r
763         devDesc.InterfaceType = PCIBus;\r
764 \r
765         // get the adapter object\r
766         // 0x80000000 is a threshold, that's why - 1\r
767         devDesc.MaximumLength = 0x80000000 - 1;\r
768         p_ext->p_dma_adapter = IoGetDmaAdapter(\r
769                 p_ext->cl_ext.p_pdo, &devDesc, &p_ext->n_map_regs );\r
770         if( !p_ext->p_dma_adapter )\r
771         {\r
772                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
773                         ("Failed to get DMA_ADAPTER for HCA.\n"));\r
774                 return STATUS_INSUFFICIENT_RESOURCES;\r
775         }\r
776 \r
777         /* Initialize the HCA now. */\r
778         status = mthca_init_one( p_ext );\r
779         if( !NT_SUCCESS( status ) )\r
780         {\r
781                 //TODO: no cleanup on error\r
782                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
783                         ("mthca_init_one returned %08X\n", status));\r
784                 return status;\r
785         }\r
786 \r
787         /*leo: get node GUID */\r
788         {\r
789                 int err;\r
790                 if (mthca_is_livefish(p_ext->hca.mdev)) \r
791                         err = mthca_get_livefish_info( p_ext->hca.mdev, &p_ext->hca.guid, &p_ext->hca.hw_ver );\r
792                 else\r
793                         err = mthca_get_dev_info( p_ext->hca.mdev, &p_ext->hca.guid, &p_ext->hca.hw_ver );\r
794                 if (err) {\r\r
795                         //TODO: no cleanup on error\r
796                         HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, \r
797                                 ("can't get guid - mthca_query_port()"));\r
798                         return STATUS_INSUFFICIENT_RESOURCES;\r
799                 }\r
800         }\r
801 \r
802         /* queue HCA  */\r
803         mlnx_hca_insert( &p_ext->hca );\r
804 \r
805         /*\r
806          * Change the state since the PnP callback can happen\r
807          * before the callback returns.\r
808          */\r
809         p_ext->state = HCA_STARTED;\r
810         \r
811         /* Register for interface arrival of the IB_AL device. */\r
812         status = IoRegisterPlugPlayNotification(\r
813                 EventCategoryDeviceInterfaceChange,\r
814                 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,\r
815                 (void*)&GUID_IB_CI_INTERFACE, p_dev_obj->DriverObject,\r
816                 __pnp_notify_ifc, p_dev_obj, &p_ext->pnp_ifc_entry );\r
817         if( !NT_SUCCESS( status ) )\r
818         {\r
819                 p_ext->state = HCA_ADDED;\r
820                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP,\r
821                         ("IoRegisterPlugPlayNotification returned %08x.\n", status));\r
822         }\r
823 \r
824         /* We get started fully powered. */\r
825         p_ext->PowerState = PowerDeviceD0;\r
826         powerState.DeviceState = PowerDeviceD0;\r
827         PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState );\r
828 \r
829         {\r
830                 struct mthca_dev *mdev = p_ext->hca.mdev;\r
831                 HCA_PRINT_EV(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,\r
832                         ("Ven %d Dev %d Hw %x Fw %d.%d.%d Drv %s (%s) Flg %s%s%s\n", \r
833                         (unsigned)p_ext->hcaConfig.VendorID, (unsigned)p_ext->hcaConfig.DeviceID,\r
834                         p_ext->hca.hw_ver,      (int) (mdev->fw_ver >> 32),\r
835                         (int) (mdev->fw_ver >> 16) & 0xffff, (int) (mdev->fw_ver & 0xffff),\r
836                         DRV_VERSION, DRV_RELDATE,\r
837                         (mdev->mthca_flags & MTHCA_FLAG_MEMFREE) ? "M:" : "",\r
838                         (mdev->mthca_flags & MTHCA_FLAG_PCIE) ? "E:" : "",\r
839                         (mdev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN) ? "H" : ""\r
840                         ));\r
841         }\r
842 \r
843         HCA_EXIT( HCA_DBG_PNP );\r
844         return status;\r
845 }\r
846 \r
847 \r
848 /* release the resources, allocated in hca_start */\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 = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
854 \r
855         HCA_ENTER( HCA_DBG_PNP );\r
856 \r
857         if( p_ext->state == HCA_REGISTERED )\r
858         {\r
859                 CL_ASSERT( p_ext->ci_ifc.deregister_ca );\r
860                 CL_ASSERT( p_ext->p_al_dev );\r
861                 CL_ASSERT( p_ext->p_al_file_obj );\r
862                 /* Notify AL that the CA is being removed. */\r
863                 p_ext->ci_ifc.deregister_ca( p_ext->hca.guid );\r
864                 /* Release AL's CI interface. */\r
865                 p_ext->ci_ifc.wdm.InterfaceDereference( p_ext->ci_ifc.wdm.Context );\r
866                 p_ext->state = HCA_STARTED;\r
867         }\r
868 \r
869         /* dequeue HCA  */\r
870         mlnx_hca_remove( &p_ext->hca );\r
871 \r
872         if( p_ext->pnp_target_entry )\r
873         {\r
874                 ASSERT( p_ext->pnp_ifc_entry );\r
875                 IoUnregisterPlugPlayNotification( p_ext->pnp_target_entry );\r
876                 p_ext->pnp_target_entry = NULL;\r
877         }\r
878 \r
879         if( p_ext->pnp_ifc_entry ) {\r
880                 IoUnregisterPlugPlayNotification( p_ext->pnp_ifc_entry );\r
881                 p_ext->pnp_ifc_entry = NULL;\r
882         }\r
883 \r
884         if( p_ext->p_al_file_obj ) {\r
885                 ObDereferenceObject( p_ext->p_al_file_obj );\r
886                 p_ext->p_al_file_obj = NULL;\r
887         }\r
888 \r
889         mthca_remove_one( p_ext );\r
890 \r
891         if( p_ext->p_dma_adapter ) {\r
892                 p_ext->p_dma_adapter->DmaOperations->PutDmaAdapter( p_ext->p_dma_adapter );\r
893                 p_ext->p_dma_adapter = NULL;\r
894         }\r
895 \r
896         hca_disable_pci( &p_ext->hcaBusIfc );\r
897 \r
898         //cl_event_destroy( &p_ext->mutex );\r
899         __UnmapHcaMemoryResources( p_dev_obj );\r
900 \r
901         p_ext->state = HCA_ADDED;\r
902 \r
903         HCA_EXIT( HCA_DBG_PNP );\r
904 }\r
905 \r
906 \r
907 static void\r
908 hca_release_resources(\r
909         IN                              DEVICE_OBJECT* const            p_dev_obj )\r
910 {\r
911         hca_dev_ext_t           *p_ext;\r
912         POWER_STATE                     powerState;\r
913 \r
914         HCA_ENTER( HCA_DBG_PNP );\r
915 \r
916         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
917 \r
918         /* release all the resources, allocated in hca_start */\r
919         __hca_release_resources(p_dev_obj);\r
920 \r
921         /* Notify the power manager that the device is powered down. */\r
922         powerState.DeviceState = PowerDeviceD3;\r
923         PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState );\r
924 \r
925         /* Clear the PnP state in case we get restarted. */\r
926         p_ext->pnpState = 0;\r
927 \r
928         HCA_EXIT( HCA_DBG_PNP );\r
929 }\r
930 \r
931 \r
932 static NTSTATUS\r
933 hca_query_removal_relations(\r
934         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
935         IN                                      IRP* const                              p_irp, \r
936                 OUT                             cl_irp_action_t* const  p_action )\r
937 {\r
938         NTSTATUS        status;\r
939         hca_dev_ext_t   *p_ext;\r
940 \r
941         HCA_ENTER( HCA_DBG_PNP );\r
942 \r
943         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
944 \r
945         if( p_ext->state == HCA_REGISTERED )\r
946         {\r
947                 status = p_ext->ci_ifc.get_relations( p_ext->hca.guid, p_irp );\r
948                 if( !NT_SUCCESS( status ) )\r
949                 {\r
950                         *p_action = IrpComplete;\r
951                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
952                                 ("AL get_relations returned %08x.\n", status));\r
953                         return status;\r
954                 }\r
955         }\r
956 \r
957         *p_action = IrpPassDown;\r
958         HCA_EXIT( HCA_DBG_PNP );\r
959         return STATUS_SUCCESS;\r
960 }\r
961 \r
962 \r
963 static NTSTATUS\r
964 hca_query_bus_relations(\r
965         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
966         IN                                      IRP* const                              p_irp, \r
967                 OUT                             cl_irp_action_t* const  p_action )\r
968 {\r
969         NTSTATUS                        status;\r
970         DEVICE_RELATIONS        *p_rel;\r
971         hca_dev_ext_t   *p_ext;\r
972 \r
973         HCA_ENTER( HCA_DBG_PNP );\r
974 \r
975         p_ext = p_dev_obj->DeviceExtension;\r
976 \r
977         //cl_event_wait_on( &p_ext->mutex, EVENT_NO_TIMEOUT, FALSE );\r
978         if( p_ext->state == HCA_REGISTERED )\r
979         {\r
980                 status = p_ext->ci_ifc.get_relations( p_ext->hca.guid, p_irp );\r
981                 if( !NT_SUCCESS( status ) )\r
982                 {\r
983                         //cl_event_signal( &p_ext->mutex );\r
984                         *p_action = IrpComplete;\r
985                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
986                                 ("AL get_relations returned %08x.\n", status));\r
987                         return status;\r
988                 }\r
989         }\r
990         else\r
991         {\r
992                 status = cl_alloc_relations( p_irp, 1 );\r
993                 if( !NT_SUCCESS( status ) )\r
994                 {\r
995                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
996                                 ("cl_alloc_relations returned %08x.\n", status));\r
997                         return status;\r
998                 }\r
999 \r
1000                 p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
1001                 p_rel->Count = 0;\r
1002                 p_rel->Objects[0] = NULL;\r
1003         }\r
1004 \r
1005         //cl_event_signal( &p_ext->mutex );\r
1006 \r
1007         *p_action = IrpPassDown;\r
1008         HCA_EXIT( HCA_DBG_PNP );\r
1009         return STATUS_SUCCESS;\r
1010 }\r
1011 \r
1012 \r
1013 static NTSTATUS\r
1014 hca_query_stop(\r
1015         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1016         IN                              IRP* const                                      p_irp, \r
1017                 OUT                     cl_irp_action_t* const          p_action )\r
1018 {\r
1019         /* All kernel clients will get notified through the device hierarchy. */\r
1020 \r
1021         /* TODO: set a flag to fail creation of any new IB resources. */\r
1022         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1023 }\r
1024 \r
1025 \r
1026 static NTSTATUS\r
1027 hca_stop(\r
1028         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1029         IN                              IRP* const                                      p_irp, \r
1030                 OUT                     cl_irp_action_t* const          p_action )\r
1031 {\r
1032         /*\r
1033          * Must disable everything.  Complib framework will\r
1034          * call ReleaseResources handler.\r
1035          */\r
1036         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1037 }\r
1038 \r
1039 \r
1040 static NTSTATUS\r
1041 hca_cancel_stop(\r
1042         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1043         IN                              IRP* const                                      p_irp, \r
1044                 OUT                     cl_irp_action_t* const          p_action )\r
1045 {\r
1046         /* Handled on the way up. */\r
1047         return cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
1048 }\r
1049 \r
1050 \r
1051 static NTSTATUS\r
1052 hca_query_remove(\r
1053         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1054         IN                              IRP* const                                      p_irp, \r
1055                 OUT                     cl_irp_action_t* const          p_action )\r
1056 {\r
1057         /* Query remove always succeeds. */\r
1058         /* TODO: set a flag to fail creation of any new IB resources. */\r
1059         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
1060 }\r
1061 \r
1062 \r
1063 static NTSTATUS\r
1064 hca_cancel_remove(\r
1065         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1066         IN                              IRP* const                                      p_irp, \r
1067                 OUT                     cl_irp_action_t* const          p_action )\r
1068 {\r
1069         /* Handled on the way up. */\r
1070         return cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
1071 }\r
1072 \r
1073 \r
1074 static NTSTATUS\r
1075 hca_surprise_remove(\r
1076         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1077         IN                              IRP* const                                      p_irp, \r
1078                 OUT                     cl_irp_action_t* const          p_action )\r
1079 {\r
1080         /*\r
1081          * TODO: Set state so that all further requests\r
1082          * automatically succeed/fail as needed.\r
1083          */\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_query_capabilities(\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         NTSTATUS                        status;\r
1095         hca_dev_ext_t           *p_ext;\r
1096         IO_STACK_LOCATION       *pIoStack;\r
1097         DEVICE_CAPABILITIES     *pCaps;\r
1098 \r
1099         HCA_ENTER( HCA_DBG_PNP );\r
1100 \r
1101         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1102 \r
1103         /* Process on the way up. */\r
1104         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
1105         if( !NT_SUCCESS( status ) )\r
1106         {\r
1107                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1108                         ("cl_do_sync_pnp returned %08X.\n", status));\r
1109                 return status;\r
1110         }\r
1111 \r
1112         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1113         pCaps = pIoStack->Parameters.DeviceCapabilities.Capabilities;\r
1114 \r
1115         /*\r
1116          * Store the device power mapping into our extension since we're\r
1117          * the power policy owner.  The mapping is used when handling\r
1118          * IRP_MN_SET_POWER IRPs.\r
1119          */\r
1120         cl_memcpy(\r
1121                 p_ext->DevicePower, pCaps->DeviceState, sizeof(p_ext->DevicePower) );\r
1122 \r
1123         if( pCaps->DeviceD1 )\r
1124         {\r
1125                 HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP,\r
1126                         ("WARNING: Device reports support for DeviceD1 power state.\n"));\r
1127                 pCaps->DeviceD1 = FALSE;\r
1128         }\r
1129 \r
1130         if( pCaps->DeviceD2 )\r
1131         {\r
1132                 HCA_PRINT( TRACE_LEVEL_WARNING,HCA_DBG_PNP,\r
1133                         ("WARNING: Device reports support for DeviceD2 power state.\n"));\r
1134                 pCaps->DeviceD2 = FALSE;\r
1135         }\r
1136 \r
1137         if( pCaps->SystemWake != PowerSystemUnspecified )\r
1138         {\r
1139                 HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP,\r
1140                         ("WARNING: Device reports support for system wake.\n"));\r
1141                 pCaps->SystemWake = PowerSystemUnspecified;\r
1142         }\r
1143 \r
1144         if( pCaps->DeviceWake != PowerDeviceUnspecified )\r
1145         {\r
1146                 HCA_PRINT( TRACE_LEVEL_WARNING, HCA_DBG_PNP,\r
1147                         ("WARNING: Device reports support for device wake.\n"));\r
1148                 pCaps->DeviceWake = PowerDeviceUnspecified;\r
1149         }\r
1150 \r
1151         HCA_EXIT( HCA_DBG_PNP );\r
1152         return status;\r
1153 }\r
1154 \r
1155 \r
1156 static NTSTATUS\r
1157 hca_query_pnp_state(\r
1158         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1159         IN                              IRP* const                                      p_irp, \r
1160                 OUT                     cl_irp_action_t* const          p_action )\r
1161 {\r
1162         hca_dev_ext_t           *p_ext;\r
1163 \r
1164         HCA_ENTER( HCA_DBG_PNP );\r
1165 \r
1166         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1167 \r
1168         p_irp->IoStatus.Information |= p_ext->pnpState;\r
1169 \r
1170         *p_action = IrpSkip;\r
1171 \r
1172         HCA_EXIT( HCA_DBG_PNP );\r
1173         return STATUS_SUCCESS;;\r
1174 }\r
1175 \r
1176 \r
1177 static NTSTATUS\r
1178 hca_query_power(\r
1179         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1180         IN                              IRP* const                                      p_irp,\r
1181                 OUT                     cl_irp_action_t* const          p_action )\r
1182 {\r
1183         NTSTATUS                        status = STATUS_SUCCESS;\r
1184         IO_STACK_LOCATION       *pIoStack;\r
1185 \r
1186         HCA_ENTER(HCA_DBG_PO);\r
1187 \r
1188         UNUSED_PARAM( p_dev_obj );\r
1189 \r
1190         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1191 \r
1192         switch( pIoStack->Parameters.Power.Type )\r
1193         {\r
1194         case SystemPowerState:\r
1195                 /* Fail any requests to hibernate or sleep the system. */\r
1196                 switch( pIoStack->Parameters.Power.State.SystemState )\r
1197                 {\r
1198                         case PowerSystemWorking:\r
1199                         case PowerSystemShutdown:\r
1200                                 /* We only support fully working and shutdown system states. */\r
1201                                 break;\r
1202 \r
1203                         default:\r
1204                                 status = STATUS_NOT_SUPPORTED;\r
1205                 }\r
1206                 break;\r
1207 \r
1208         case DevicePowerState:\r
1209                 /* Fail any query for low power states. */\r
1210                 switch( pIoStack->Parameters.Power.State.DeviceState )\r
1211                 {\r
1212                 case PowerDeviceD0:\r
1213                 case PowerDeviceD3:\r
1214                         /* We only support fully powered or off power states. */\r
1215                         break;\r
1216 \r
1217                 default:\r
1218                         status = STATUS_NOT_SUPPORTED;\r
1219                 }\r
1220                 break;\r
1221         }\r
1222 \r
1223         if( status == STATUS_NOT_SUPPORTED )\r
1224                 *p_action = IrpComplete;\r
1225         else\r
1226                 *p_action = IrpSkip;\r
1227 \r
1228         HCA_EXIT( HCA_DBG_PO );\r
1229         return status;\r
1230 }\r
1231 \r
1232 \r
1233 static void\r
1234 __RequestPowerCompletion(\r
1235         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1236         IN                              UCHAR                                           minorFunction,\r
1237         IN                              POWER_STATE                                     powerState,\r
1238         IN                              void                                            *context,\r
1239         IN                              IO_STATUS_BLOCK                         *pIoStatus )\r
1240 {\r
1241         IRP                                     *p_irp;\r
1242         cl_pnp_po_ext_t         *p_ext;\r
1243 \r
1244         HCA_ENTER( HCA_DBG_PO );\r
1245 \r
1246         UNUSED_PARAM( minorFunction );\r
1247         UNUSED_PARAM( powerState );\r
1248 \r
1249         p_irp = (IRP*)context;\r
1250         p_ext = (cl_pnp_po_ext_t*)p_dev_obj->DeviceExtension;\r
1251 \r
1252         /* Propagate the device IRP status to the system IRP status. */\r
1253         p_irp->IoStatus.Status = pIoStatus->Status;\r
1254 \r
1255         /* Continue Power IRP processing. */\r
1256         PoStartNextPowerIrp( p_irp );\r
1257         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1258         IoReleaseRemoveLock( &p_ext->remove_lock, p_irp );\r
1259         HCA_EXIT( HCA_DBG_PO );\r
1260 }\r
1261 \r
1262 \r
1263 /*NOTE: Completion routines must NEVER be pageable. */\r
1264 static NTSTATUS\r
1265 __SystemPowerCompletion(\r
1266         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1267         IN                              IRP                                                     *p_irp,\r
1268         IN                              void                                            *context )\r
1269 {\r
1270         NTSTATUS                        status;\r
1271         POWER_STATE                     state;\r
1272         hca_dev_ext_t           *p_ext;\r
1273         IO_STACK_LOCATION       *pIoStack;\r
1274 \r
1275         HCA_ENTER( HCA_DBG_PNP );\r
1276 \r
1277         UNUSED_PARAM( context );\r
1278 \r
1279         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1280         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1281 \r
1282         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1283         {\r
1284                 PoStartNextPowerIrp( p_irp );\r
1285                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1286                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1287                         ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n",\r
1288                         p_irp->IoStatus.Status));\r
1289                 return STATUS_SUCCESS;\r
1290         }\r
1291 \r
1292         state.DeviceState = \r
1293                 p_ext->DevicePower[pIoStack->Parameters.Power.State.SystemState];\r
1294 \r
1295         /*\r
1296          * Send a device power IRP to our devnode.  Using our device object will\r
1297          * only work on win2k and other NT based systems.\r
1298          */\r
1299         status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
1300                 __RequestPowerCompletion, p_irp, NULL );\r
1301 \r
1302         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1303         {\r
1304                 PoStartNextPowerIrp( p_irp );\r
1305                 /* Propagate the failure. */\r
1306                 p_irp->IoStatus.Status = status;\r
1307                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1308                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1309                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP,\r
1310                         ("PoRequestPowerIrp returned %08x.\n", status));\r
1311         }\r
1312 \r
1313         HCA_EXIT( HCA_DBG_PNP );\r
1314         return STATUS_MORE_PROCESSING_REQUIRED;\r
1315 }\r
1316 \r
1317 \r
1318 /* Work item callback to handle DevicePowerD0 IRPs at passive level. */\r
1319 static void\r
1320 __PowerUpCb(\r
1321         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1322         IN                              void*                                           context )\r
1323 {\r
1324         NTSTATUS                        status;\r
1325         IO_STACK_LOCATION       *pIoStack;\r
1326         hca_dev_ext_t           *p_ext;\r
1327         IRP                                     *p_irp;\r
1328 \r
1329         HCA_ENTER( HCA_DBG_PO );\r
1330 \r
1331         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1332         p_irp = (IRP*)context;\r
1333         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1334 \r
1335         IoFreeWorkItem( p_ext->pPoWorkItem );\r
1336         p_ext->pPoWorkItem = NULL;\r
1337 \r
1338         /* restart the HCA */\r
1339         status = mthca_init_one( p_ext );\r
1340         if( !NT_SUCCESS( status ) )\r
1341                 goto done;\r
1342 \r
1343         if( p_ext->p_al_dev )\r
1344                 status = __hca_register( p_dev_obj );\r
1345 \r
1346 done:\r
1347         if( !NT_SUCCESS( status ) )\r
1348         {\r
1349                 /* Flag device as having failed. */\r
1350                 p_ext->pnpState |= PNP_DEVICE_FAILED;\r
1351                 IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1352         }\r
1353 \r
1354         PoStartNextPowerIrp( p_irp );\r
1355         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1356         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1357 \r
1358         HCA_EXIT( HCA_DBG_PO );\r
1359 }\r
1360 \r
1361 \r
1362 /*NOTE: Completion routines must NEVER be pageable. */\r
1363 static NTSTATUS\r
1364 __DevicePowerCompletion(\r
1365         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1366         IN                              IRP                                                     *p_irp,\r
1367         IN                              void                                            *context )\r
1368 {\r
1369         NTSTATUS                        status = STATUS_SUCCESS;\r
1370         hca_dev_ext_t           *p_ext;\r
1371         IO_STACK_LOCATION       *pIoStack;\r
1372         KIRQL irql = KeGetCurrentIrql(  );\r
1373         \r
1374         \r
1375 \r
1376         HCA_ENTER( HCA_DBG_PO );\r
1377 \r
1378         UNUSED_PARAM( context );\r
1379 \r
1380         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1381         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1382 \r
1383         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1384         {\r
1385                 PoStartNextPowerIrp( p_irp );\r
1386                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1387                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
1388                         ("IRP_MN_SET_POWER for device failed by lower driver with %08x.\n",\r
1389                         p_irp->IoStatus.Status));\r
1390                 return STATUS_SUCCESS;\r
1391         }\r
1392 \r
1393         p_ext->PowerState = pIoStack->Parameters.Power.State.DeviceState;\r
1394         PoSetPowerState( p_dev_obj, DevicePowerState,\r
1395                 pIoStack->Parameters.Power.State );\r
1396 \r
1397         if (irql > PASSIVE_LEVEL) {\r
1398                 /* Process in a work item - mthca_start blocks. */\r
1399                 ASSERT( !p_ext->pPoWorkItem );\r
1400                 p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1401                 if( !p_ext->pPoWorkItem )\r
1402                 {\r
1403                         IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1404 \r
1405                         PoStartNextPowerIrp( p_irp );\r
1406                         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1407 \r
1408                         return STATUS_SUCCESS;\r
1409                 }\r
1410 \r
1411                 /* Process in work item callback. */\r
1412                 IoMarkIrpPending( p_irp );\r
1413                 IoQueueWorkItem( p_ext->pPoWorkItem, __PowerUpCb, DelayedWorkQueue, p_irp );\r
1414         }\r
1415         else {\r
1416 \r
1417                 /* restart the HCA */\r
1418                 status = mthca_init_one( p_ext );\r
1419                 if( !NT_SUCCESS( status ) )\r
1420                         goto done;\r
1421 \r
1422                 if( p_ext->p_al_dev )\r
1423                         status = __hca_register( p_dev_obj );\r
1424         }\r
1425 \r
1426 done:\r
1427         if( !NT_SUCCESS( status ) )\r
1428                 IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1429 \r
1430         PoStartNextPowerIrp( p_irp );\r
1431         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1432 \r
1433         HCA_EXIT( HCA_DBG_PO );\r
1434         return STATUS_MORE_PROCESSING_REQUIRED;\r
1435 }\r
1436 \r
1437 \r
1438 /* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
1439 static void\r
1440 __PowerDownCb(\r
1441         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1442         IN                              void*                                           context )\r
1443 {\r
1444         IO_STACK_LOCATION       *pIoStack;\r
1445         hca_dev_ext_t           *p_ext;\r
1446         IRP                                     *p_irp;\r
1447 \r
1448         HCA_ENTER( HCA_DBG_PO );\r
1449 \r
1450         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1451         p_irp = (IRP*)context;\r
1452         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1453 \r
1454         IoFreeWorkItem( p_ext->pPoWorkItem );\r
1455         p_ext->pPoWorkItem = NULL;\r
1456 \r
1457         PoSetPowerState( p_dev_obj, DevicePowerState,\r
1458                 pIoStack->Parameters.Power.State );\r
1459 \r
1460         if( p_ext->state == HCA_REGISTERED )\r
1461         {\r
1462                 CL_ASSERT( p_ext->ci_ifc.deregister_ca );\r
1463                 CL_ASSERT( p_ext->p_al_dev );\r
1464                 CL_ASSERT( p_ext->p_al_file_obj );\r
1465                 /* Notify AL that the CA is being removed. */\r
1466                 p_ext->ci_ifc.deregister_ca( p_ext->hca.guid );\r
1467                 /* Release AL's CI interface. */\r
1468                 p_ext->ci_ifc.wdm.InterfaceDereference( p_ext->ci_ifc.wdm.Context );\r
1469                 p_ext->state = HCA_STARTED;\r
1470         }\r
1471 \r
1472         mthca_remove_one( p_ext );\r
1473 \r
1474         IoSkipCurrentIrpStackLocation( p_irp );\r
1475         PoStartNextPowerIrp( p_irp );\r
1476         PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1477         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1478 \r
1479         HCA_EXIT( HCA_DBG_PO );\r
1480 }\r
1481 \r
1482 \r
1483 static NTSTATUS\r
1484 hca_set_power(\r
1485         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1486         IN                              IRP* const                                      p_irp,\r
1487                 OUT                     cl_irp_action_t* const          p_action )\r
1488 {\r
1489         NTSTATUS                        status;\r
1490         IO_STACK_LOCATION       *pIoStack;\r
1491         hca_dev_ext_t           *p_ext;\r
1492 \r
1493         HCA_ENTER( HCA_DBG_PO );\r
1494 \r
1495         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1496         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1497 \r
1498         switch( pIoStack->Parameters.Power.Type )\r
1499         {\r
1500         case SystemPowerState:\r
1501                 /*\r
1502                  * Process on the way up the stack.  We cannot block since the \r
1503                  * power dispatch function can be called at elevated IRQL if the\r
1504                  * device is in a paging/hibernation/crash dump path.\r
1505                  */\r
1506                 IoMarkIrpPending( p_irp );\r
1507                 IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1508 #pragma warning( push, 3 )\r
1509                 IoSetCompletionRoutine( p_irp, __SystemPowerCompletion, NULL, \r
1510                         TRUE, TRUE, TRUE );\r
1511 #pragma warning( pop )\r
1512                 PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1513 \r
1514                 *p_action = IrpDoNothing;\r
1515                 status = STATUS_PENDING;\r
1516                 break;\r
1517 \r
1518         case DevicePowerState:\r
1519                 IoMarkIrpPending( p_irp );\r
1520                 if( pIoStack->Parameters.Power.State.DeviceState == PowerDeviceD0 )\r
1521                 {\r
1522                         /* If we're already powered up, just pass down. */\r
1523                         if( p_ext->PowerState == PowerDeviceD0 )\r
1524                         {\r
1525                                 status = STATUS_SUCCESS;\r
1526                                 *p_action = IrpIgnore;\r
1527                                 break;\r
1528                         }\r
1529 \r
1530                         /* Process in I/O completion callback. */\r
1531                         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1532 #pragma warning( push, 3 )\r
1533                         IoSetCompletionRoutine( p_irp, __DevicePowerCompletion, NULL, \r
1534                                 TRUE, TRUE, TRUE );\r
1535 #pragma warning( pop )\r
1536                         PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1537                 }\r
1538                 else\r
1539                 {\r
1540                         /* Process in a work item - deregister_ca and HcaDeinit block. */\r
1541                         ASSERT( !p_ext->pPoWorkItem );\r
1542                         p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1543                         if( !p_ext->pPoWorkItem )\r
1544                         {\r
1545                                 status = STATUS_INSUFFICIENT_RESOURCES;\r
1546                                 break;\r
1547                         }\r
1548 \r
1549                         /* Process in work item callback. */\r
1550                         IoMarkIrpPending( p_irp );\r
1551                         IoQueueWorkItem(\r
1552                                 p_ext->pPoWorkItem, __PowerDownCb, DelayedWorkQueue, p_irp );\r
1553                 }\r
1554                 *p_action = IrpDoNothing;\r
1555                 status = STATUS_PENDING;\r
1556                 break;\r
1557 \r
1558         default:\r
1559                 /* Pass down and let the PDO driver handle it. */\r
1560                 *p_action = IrpIgnore;\r
1561                 status = STATUS_SUCCESS;\r
1562                 break;\r
1563         }\r
1564 \r
1565         if( !NT_SUCCESS( status ) )\r
1566                 *p_action = IrpComplete;\r
1567 \r
1568         HCA_EXIT( HCA_DBG_PNP );\r
1569         return status;\r
1570 }\r