054086a67ac05b4d783267ae96e8471f7a3ae49d
[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 #include <rdma\verbs.h>\r
16 \r
17 #if defined(EVENT_TRACING)\r
18 #ifdef offsetof\r
19 #undef offsetof\r
20 #endif\r
21 #include "hca_pnp.tmh"\r
22 #endif\r
23 #include "mthca.h"\r
24 #include <initguid.h>\r
25 #include <wdmguid.h>\r
26 \r
27 extern const char *mthca_version;\r
28 hca_dev_ext_t *g_ext = NULL;\r
29 \r
30 static NTSTATUS\r
31 hca_start(\r
32         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
33         IN                              IRP* const                                      p_irp, \r
34                 OUT                     cl_irp_action_t* const          p_action );\r
35 \r
36 static NTSTATUS\r
37 hca_query_stop(\r
38         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
39         IN                              IRP* const                                      p_irp, \r
40                 OUT                     cl_irp_action_t* const          p_action );\r
41 \r
42 static NTSTATUS\r
43 hca_stop(\r
44         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
45         IN                              IRP* const                                      p_irp, \r
46                 OUT                     cl_irp_action_t* const          p_action );\r
47 \r
48 static NTSTATUS\r
49 hca_cancel_stop(\r
50         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
51         IN                              IRP* const                                      p_irp, \r
52                 OUT                     cl_irp_action_t* const          p_action );\r
53 \r
54 static NTSTATUS\r
55 hca_query_remove(\r
56         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
57         IN                              IRP* const                                      p_irp, \r
58                 OUT                     cl_irp_action_t* const          p_action );\r
59 \r
60 static void\r
61 hca_release_resources(\r
62         IN                              DEVICE_OBJECT* const            p_dev_obj );\r
63 \r
64 static NTSTATUS\r
65 hca_cancel_remove(\r
66         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
67         IN                              IRP* const                                      p_irp, \r
68                 OUT                     cl_irp_action_t* const          p_action );\r
69 \r
70 static NTSTATUS\r
71 hca_surprise_remove(\r
72         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
73         IN                              IRP* const                                      p_irp, \r
74                 OUT                     cl_irp_action_t* const          p_action );\r
75 \r
76 static NTSTATUS\r
77 hca_query_capabilities(\r
78         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
79         IN                              IRP* const                                      p_irp, \r
80                 OUT                     cl_irp_action_t* const          p_action );\r
81 \r
82 static NTSTATUS\r
83 hca_query_pnp_state(\r
84         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
85         IN                              IRP* const                                      p_irp, \r
86                 OUT                     cl_irp_action_t* const          p_action );\r
87 \r
88 static NTSTATUS\r
89 hca_query_bus_relations(\r
90         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
91         IN                              IRP* const                                      p_irp, \r
92                 OUT                     cl_irp_action_t* const          p_action );\r
93 \r
94 static NTSTATUS\r
95 hca_query_removal_relations(\r
96         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
97         IN                              IRP* const                                      p_irp, \r
98                 OUT                     cl_irp_action_t* const          p_action );\r
99 \r
100 static NTSTATUS\r
101 hca_query_power(\r
102         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
103         IN                              IRP* const                                      p_irp,\r
104                 OUT                     cl_irp_action_t* const          p_action );\r
105 \r
106 static NTSTATUS\r
107 hca_set_power(\r
108         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
109         IN                              IRP* const                                      p_irp, \r
110                 OUT                     cl_irp_action_t* const          p_action );\r
111 \r
112 static ci_interface_t*\r
113 __alloc_hca_ifc(\r
114         IN                              hca_dev_ext_t* const            p_ext );\r
115 \r
116 static NTSTATUS\r
117 hca_query_interface(\r
118         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
119         IN                              IRP* const                                      p_irp, \r
120                 OUT                     cl_irp_action_t* const          p_action );\r
121 \r
122 static NTSTATUS\r
123 __get_ci_interface(\r
124         IN                              DEVICE_OBJECT* const            p_dev_obj );\r
125 \r
126 \r
127 \r
128 static cl_vfptr_pnp_po_t        vfptrHcaPnp;\r
129 \r
130 \r
131 void\r
132 hca_init_vfptr( void )\r
133 {\r
134         vfptrHcaPnp.identity = "HCA driver";\r
135         vfptrHcaPnp.pfn_start = hca_start;\r
136         vfptrHcaPnp.pfn_query_stop = hca_query_stop;\r
137         vfptrHcaPnp.pfn_stop = hca_stop;\r
138         vfptrHcaPnp.pfn_cancel_stop = hca_cancel_stop;\r
139         vfptrHcaPnp.pfn_query_remove = hca_query_remove;\r
140         vfptrHcaPnp.pfn_release_resources = hca_release_resources;\r
141         vfptrHcaPnp.pfn_remove = cl_do_remove;\r
142         vfptrHcaPnp.pfn_cancel_remove = hca_cancel_remove;\r
143         vfptrHcaPnp.pfn_surprise_remove = hca_surprise_remove;\r
144         vfptrHcaPnp.pfn_query_capabilities = hca_query_capabilities;\r
145         vfptrHcaPnp.pfn_query_pnp_state = hca_query_pnp_state;\r
146         vfptrHcaPnp.pfn_filter_res_req = cl_irp_skip;\r
147         vfptrHcaPnp.pfn_dev_usage_notification = cl_do_sync_pnp;\r
148         vfptrHcaPnp.pfn_query_bus_relations = cl_irp_ignore;\r
149         vfptrHcaPnp.pfn_query_ejection_relations = cl_irp_ignore;\r
150         vfptrHcaPnp.pfn_query_removal_relations = cl_irp_ignore;\r
151         vfptrHcaPnp.pfn_query_target_relations = cl_irp_ignore;\r
152         vfptrHcaPnp.pfn_unknown = cl_irp_ignore;\r
153         vfptrHcaPnp.pfn_query_resources = cl_irp_ignore;\r
154         vfptrHcaPnp.pfn_query_res_req = cl_irp_ignore;\r
155         vfptrHcaPnp.pfn_query_bus_info = cl_irp_ignore;\r
156         vfptrHcaPnp.pfn_query_interface = hca_query_interface;\r
157         vfptrHcaPnp.pfn_read_config = cl_irp_ignore;\r
158         vfptrHcaPnp.pfn_write_config = cl_irp_ignore;\r
159         vfptrHcaPnp.pfn_eject = cl_irp_ignore;\r
160         vfptrHcaPnp.pfn_set_lock = cl_irp_ignore;\r
161         vfptrHcaPnp.pfn_query_power = hca_query_power;\r
162         vfptrHcaPnp.pfn_set_power = hca_set_power;\r
163         vfptrHcaPnp.pfn_power_sequence = cl_irp_ignore;\r
164         vfptrHcaPnp.pfn_wait_wake = cl_irp_ignore;\r
165 }\r
166 \r
167 \r
168 NTSTATUS\r
169 hca_add_device(\r
170         IN                              PDRIVER_OBJECT                          pDriverObj,\r
171         IN                              PDEVICE_OBJECT                          pPdo )\r
172 {\r
173         NTSTATUS                        status;\r
174         DEVICE_OBJECT           *p_dev_obj, *pNextDevObj;\r
175         hca_dev_ext_t           *p_ext;\r
176 \r
177         HCA_ENTER(HCA_DBG_PNP);\r
178 \r
179         /*\r
180          * Create the device so that we have a device extension to store stuff in.\r
181          */\r
182         status = IoCreateDevice( pDriverObj, sizeof(hca_dev_ext_t),\r
183                 NULL, FILE_DEVICE_INFINIBAND, FILE_DEVICE_SECURE_OPEN,\r
184                 FALSE, &p_dev_obj );\r
185         if( !NT_SUCCESS( status ) )\r
186         {\r
187                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
188                         ("IoCreateDevice returned 0x%08X.\n", status));\r
189                 return status;\r
190         }\r
191 \r
192         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
193         if (!g_ext)\r
194                 g_ext = p_ext;\r
195         cl_memclr( p_ext, sizeof(hca_dev_ext_t) );\r
196         cl_spinlock_init( &p_ext->uctx_lock );\r
197         cl_qlist_init( &p_ext->uctx_list );\r
198         atomic_set(&p_ext->usecnt, 0);\r
199 \r
200         /* Attach to the device stack. */\r
201         pNextDevObj = IoAttachDeviceToDeviceStack( p_dev_obj, pPdo );\r
202         if( !pNextDevObj )\r
203         {\r
204                 //cl_event_destroy( &p_ext->mutex );\r
205                 IoDeleteDevice( p_dev_obj );\r
206                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
207                         ("IoAttachDeviceToDeviceStack failed.\n"));\r
208                 return STATUS_NO_SUCH_DEVICE;\r
209         }\r
210 \r
211         /* Inititalize the complib extension. */\r
212         cl_init_pnp_po_ext( p_dev_obj, pNextDevObj, pPdo, CL_DBG_PNP | CL_DBG_ERROR,\r
213                 &vfptrHcaPnp, NULL );\r
214 \r
215         p_ext->state = HCA_ADDED;\r
216 \r
217         HCA_EXIT(HCA_DBG_PNP);\r
218         return status;\r
219 }\r
220 \r
221 \r
222 static ci_interface_t*\r
223 __alloc_hca_ifc(\r
224         IN                              hca_dev_ext_t* const            p_ext )\r
225 {\r
226         ci_interface_t  *pIfc;\r
227 \r
228         HCA_ENTER( HCA_DBG_PNP );\r
229 \r
230         pIfc = (ci_interface_t*)ExAllocatePoolWithTag( PagedPool,\r
231                                                                                                    sizeof(ci_interface_t),\r
232                                                                                                    'pnpa' );\r
233         if( !pIfc )\r
234         {\r
235                 HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, \r
236                         ("Failed to allocate ci_interface_t (%d bytes).\n",\r
237                         sizeof(ci_interface_t)));\r
238                 return NULL;\r
239         }\r
240 \r
241         setup_ci_interface( p_ext->hca.guid,\r
242                 !!mthca_is_livefish(p_ext->hca.mdev),\r
243                 pIfc );\r
244 \r
245         pIfc->p_hca_obj = &p_ext->hca.hob;\r
246         pIfc->vend_id = (uint32_t)p_ext->hcaConfig.VendorID;\r
247         pIfc->dev_id = (uint16_t)p_ext->hcaConfig.DeviceID;\r
248         pIfc->dev_revision = (uint16_t)p_ext->hca.hw_ver;\r
249 \r
250         HCA_EXIT( HCA_DBG_PNP );\r
251         return pIfc;\r
252 }\r
253 \r
254 \r
255 /*\r
256  * Walk the resource lists and store the information.  The write-only\r
257  * flag is not set for the UAR region, so it is indistinguishable from the\r
258  * DDR region since both are prefetchable.  The code here assumes that the\r
259  * resources get handed in order - HCR, UAR, DDR.\r
260  *      - Configuration Space: not prefetchable, read/write\r
261  *      - UAR space: prefetchable, write only.\r
262  *      - DDR: prefetchable, read/write.\r
263  */\r
264 static NTSTATUS\r
265 __SetupHcaResources(\r
266         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
267         IN                              CM_RESOURCE_LIST* const         pHcaResList,\r
268         IN                              CM_RESOURCE_LIST* const         pHostResList )\r
269 {\r
270         NTSTATUS                                                status = STATUS_SUCCESS;\r
271         hca_dev_ext_t                                   *p_ext;\r
272         USHORT                                                  i;\r
273         hca_bar_type_t                                  type = HCA_BAR_TYPE_HCR;\r
274 \r
275         CM_PARTIAL_RESOURCE_DESCRIPTOR  *pHcaRes, *pHostRes;\r
276 \r
277         HCA_ENTER( HCA_DBG_PNP );\r
278 \r
279         // there will be no resources for "livefish" (PCI memory controller mode)\r
280         if (!pHcaResList || !pHostResList)\r
281                 goto done;\r
282                 \r
283         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
284 \r
285         // store the bus number for reset of Tavor\r
286         p_ext->bus_number = pHostResList->List[0].BusNumber;\r
287         \r
288         for( i = 0; i < pHostResList->List[0].PartialResourceList.Count; i++ )\r
289         {\r
290                 pHcaRes =\r
291                         &pHcaResList->List[0].PartialResourceList.PartialDescriptors[i];\r
292                 pHostRes = \r
293                         &pHostResList->List[0].PartialResourceList.PartialDescriptors[i];\r
294 \r
295 \r
296                 /*\r
297                  * Save the interrupt information so that we can power the device\r
298                  * up and down.  Since the device will lose state when powered down\r
299                  * we have to fully disable it.  Note that we can leave memory mapped\r
300                  * resources in place when powered down as the resource assignments\r
301                  * won't change.  However, we must disconnect our interrupt, and\r
302                  * reconnect it when powering up.\r
303                  */\r
304                 if( pHcaRes->Type == CmResourceTypeInterrupt )\r
305                 {\r
306                         p_ext->interruptInfo = *pHostRes;\r
307             if ( g_processor_affinity == 0xFFFFFFFF ) \r
308                         {\r
309                                 /* \r
310                                  * Calculate the mask of the last processor\r
311                                  */\r
312                                 KAFFINITY               n_active_processors_bitmask;\r
313                                 uint32_t                last_processor_mask = 0 , tmp_processor_mask = 1;\r
314                                 \r
315                                 n_active_processors_bitmask = KeQueryActiveProcessors();\r
316                 while ( tmp_processor_mask & n_active_processors_bitmask )\r
317                                 {\r
318                                                 last_processor_mask = tmp_processor_mask;\r
319                                                 tmp_processor_mask = tmp_processor_mask << 1;\r
320                                 }\r
321                                 p_ext->interruptInfo.u.Interrupt.Affinity = last_processor_mask; \r
322                         }\r
323                         else if (g_processor_affinity != 0) \r
324                         {\r
325                                 p_ext->interruptInfo.u.Interrupt.Affinity = g_processor_affinity;                               \r
326                         }\r
327                         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP,("Set Interrupt affinity to : 0x%08X\n",\r
328                                          (int)p_ext->interruptInfo.u.Interrupt.Affinity ));\r
329 \r
330                         continue;\r
331                 }\r
332                 \r
333                 if( pHcaRes->Type != CmResourceTypeMemory )\r
334                         continue;\r
335 \r
336                 /*\r
337                  * Sanity check that our assumption on how resources\r
338                  * are reported hold.\r
339                  */\r
340                 if( type == HCA_BAR_TYPE_HCR &&\r
341                         (pHcaRes->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE) )\r
342                 {\r
343                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
344                                 ("First memory resource is prefetchable - expected HCR.\n"));\r
345                         status = STATUS_UNSUCCESSFUL;\r
346                         break;\r
347                 }\r
348 \r
349                 p_ext->bar[type].phys = pHcaRes->u.Memory.Start.QuadPart;\r
350                 p_ext->bar[type].size = pHcaRes->u.Memory.Length;\r
351 #ifdef MAP_ALL_HCA_MEMORY               \r
352                 /*leo: no need to map all the resources */\r
353                 p_ext->bar[type].virt = MmMapIoSpace( pHostRes->u.Memory.Start,\r
354                         pHostRes->u.Memory.Length, MmNonCached );\r
355                 if( !p_ext->bar[type].virt )\r
356                 {\r
357                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
358                                 ("Failed to map memory resource type %d\n", type));\r
359                         status = STATUS_UNSUCCESSFUL;\r
360                         break;\r
361                 }\r
362 #else           \r
363                 p_ext->bar[type].virt = NULL;\r
364 #endif          \r
365 \r
366                 type++;\r
367         }\r
368 \r
369         if( type == HCA_BAR_TYPE_DDR)\r
370         {\r
371                 p_ext->hca_hidden = 1;\r
372         }\r
373         else \r
374         if( type != HCA_BAR_TYPE_MAX )\r
375         {\r
376                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM  ,("Failed to map all memory resources.\n"));\r
377                 status = STATUS_UNSUCCESSFUL;\r
378         }\r
379 \r
380         if( p_ext->interruptInfo.Type != CmResourceTypeInterrupt )\r
381         {\r
382                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM  ,("No interrupt resource.\n"));\r
383                 status = STATUS_UNSUCCESSFUL;\r
384         }\r
385 \r
386 done:\r
387         HCA_EXIT( HCA_DBG_PNP );\r
388         return status;\r
389 }\r
390 \r
391 \r
392 static void\r
393 __UnmapHcaMemoryResources(\r
394         IN                              DEVICE_OBJECT* const            p_dev_obj )\r
395 {\r
396         hca_dev_ext_t           *p_ext;\r
397         USHORT                          i;\r
398 \r
399         HCA_ENTER( HCA_DBG_PNP );\r
400 \r
401         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
402 \r
403         for( i = 0; i < HCA_BAR_TYPE_MAX; i++ )\r
404         {\r
405                 if( p_ext->bar[i].virt )\r
406                 {\r
407                         MmUnmapIoSpace( p_ext->bar[i].virt, p_ext->bar[i].size );\r
408                         cl_memclr( &p_ext->bar[i], sizeof(hca_bar_t) );\r
409                 }\r
410         }\r
411 \r
412         HCA_EXIT( HCA_DBG_PNP );\r
413 }\r
414 \r
415 \r
416 static int mthca_get_livefish_info(struct mthca_dev *mdev, __be64 *node_guid, u32 *hw_id)\r
417 {\r
418         *node_guid = cl_hton64((uint64_t)(ULONG_PTR)mdev);\r
419         mdev->ib_dev.node_guid = *node_guid;\r
420         *hw_id = 0;\r
421         return 0;\r
422 }\r
423 \r
424 static NTSTATUS\r
425 hca_start(\r
426         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
427         IN                              IRP* const                                      p_irp, \r
428                 OUT                     cl_irp_action_t* const          p_action )\r
429 {\r
430         NTSTATUS                        status;\r
431         hca_dev_ext_t           *p_ext;\r
432         IO_STACK_LOCATION       *pIoStack;\r
433         POWER_STATE                     powerState;\r
434         DEVICE_DESCRIPTION      devDesc;\r
435 \r
436         HCA_ENTER( HCA_DBG_PNP );\r
437 \r
438         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
439 \r
440         /* Handled on the way up. */\r
441         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
442         if( !NT_SUCCESS( status ) )\r
443         {\r
444                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
445                         ("Lower drivers failed IRP_MN_START_DEVICE (%#x).\n", status));\r
446                 return status;\r
447         }\r
448 \r
449         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
450 \r
451         /*\r
452          * Walk the resource lists and store the information.  The write-only\r
453          * flag is not set for the UAR region, so it is indistinguishable from the\r
454          * DDR region since both are prefetchable.  The code here assumes that the\r
455          * resources get handed in order - HCR, UAR, DDR.\r
456          *      - Configuration Space: not prefetchable, read/write\r
457          *      - UAR space: prefetchable, write only.\r
458          *      - DDR: prefetchable, read/write.\r
459          */\r
460         status = __SetupHcaResources( p_dev_obj,\r
461                 pIoStack->Parameters.StartDevice.AllocatedResources,\r
462                 pIoStack->Parameters.StartDevice.AllocatedResourcesTranslated );\r
463         if( !NT_SUCCESS( status ) )\r
464         {\r
465                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
466                         ("__ProcessResources returned %08X.\n", status));\r
467                 return status;\r
468         }\r
469         \r
470         /* save PCI bus i/f, PCI configuration info and enable device */\r
471         hca_enable_pci( p_dev_obj, &p_ext->hcaBusIfc, &p_ext->hcaConfig );\r
472 \r
473         /*\r
474          * Get the DMA adapter representing the HCA so we can\r
475          * allocate common buffers.\r
476          */\r
477         RtlZeroMemory( &devDesc, sizeof(devDesc) );\r
478         devDesc.Version = DEVICE_DESCRIPTION_VERSION2;\r
479         devDesc.Master = TRUE;\r
480         devDesc.ScatterGather = TRUE;\r
481         devDesc.Dma32BitAddresses = TRUE;\r
482         devDesc.Dma64BitAddresses = TRUE;\r
483         devDesc.InterfaceType = PCIBus;\r
484 \r
485         // get the adapter object\r
486         // 0x80000000 is a threshold, that's why - 1\r
487         devDesc.MaximumLength = 0x80000000 - 1;\r
488         p_ext->p_dma_adapter = IoGetDmaAdapter(\r
489                 p_ext->cl_ext.p_pdo, &devDesc, &p_ext->n_map_regs );\r
490         if( !p_ext->p_dma_adapter )\r
491         {\r
492                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
493                         ("Failed to get DMA_ADAPTER for HCA.\n"));\r
494                 return STATUS_INSUFFICIENT_RESOURCES;\r
495         }\r
496 \r
497         /* Initialize the HCA now. */\r
498         status = mthca_init_one( p_ext );\r
499         if( !NT_SUCCESS( status ) )\r
500         {\r
501                 //TODO: no cleanup on error\r
502                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
503                         ("mthca_init_one returned %08X\n", status));\r
504                 return status;\r
505         }\r
506 \r
507         /*leo: get node GUID */\r
508         {\r
509                 int err;\r
510                 if (mthca_is_livefish(p_ext->hca.mdev)) \r
511                         err = mthca_get_livefish_info( p_ext->hca.mdev, &p_ext->hca.guid, &p_ext->hca.hw_ver );\r
512                 else\r
513                         err = mthca_get_dev_info( p_ext->hca.mdev, &p_ext->hca.guid, &p_ext->hca.hw_ver );\r
514 \r
515                 if (err) {\r
516 \r
517                         //TODO: no cleanup on error\r
518                         HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, \r
519                                 ("can't get guid - mthca_query_port()"));\r
520                         return STATUS_INSUFFICIENT_RESOURCES;\r
521                 }\r
522         }\r
523 \r
524         /* queue HCA  */\r
525         mlnx_hca_insert( &p_ext->hca );\r
526 \r
527         /*\r
528          * Change the state since the PnP callback can happen\r
529          * before the callback returns.\r
530          */\r
531         p_ext->state = HCA_STARTED;\r
532         \r
533         /* We get started fully powered. */\r
534         p_ext->DevicePowerState = PowerDeviceD0;\r
535         powerState.DeviceState = PowerDeviceD0;\r
536         powerState = PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState );\r
537         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, \r
538                 ("PoSetPowerState: old state %d, new state to %d\n", \r
539                 powerState.DeviceState, p_ext->DevicePowerState ));\r
540 \r
541 \r
542         {\r
543                 struct mthca_dev *mdev = p_ext->hca.mdev;\r
544                 HCA_PRINT_EV(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,\r
545                         ("Ven %x Dev %d Hw %x Fw %d.%d.%d Drv %s (%s)", \r
546                         (unsigned)p_ext->hcaConfig.VendorID, (unsigned)p_ext->hcaConfig.DeviceID,\r
547                         p_ext->hca.hw_ver,      (int) (mdev->fw_ver >> 32),\r
548                         (int) (mdev->fw_ver >> 16) & 0xffff, (int) (mdev->fw_ver & 0xffff),\r
549                         DRV_VERSION, DRV_RELDATE\r
550                         ));\r
551                 HCA_PRINT_EV(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,\r
552                         ("Flags %s%s%s%s%s%s%s\n", \r
553                         (mdev->mthca_flags & MTHCA_FLAG_LIVEFISH) ? "Flash Recovery Mode:" : "",\r
554                         (mdev->mthca_flags & MTHCA_FLAG_MEMFREE) ? "MemFree:" : "",\r
555                         (mdev->mthca_flags & MTHCA_FLAG_NO_LAM) ? "NoLam:" : "",\r
556                         (mdev->mthca_flags & MTHCA_FLAG_FMR) ? "Fmr:" : "",\r
557                         (mdev->mthca_flags & MTHCA_FLAG_SRQ) ? "Srq:" : "",\r
558                         (mdev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN) ? "HideDdr:" : "",\r
559                         (mdev->mthca_flags & MTHCA_FLAG_PCIE) ? "PciEx:" : ""\r
560                         ));\r
561         }\r
562 \r
563         HCA_EXIT( HCA_DBG_PNP );\r
564         return status;\r
565 }\r
566 \r
567 \r
568 /* release the resources, allocated in hca_start */\r
569 static void\r
570 __hca_release_resources(\r
571         IN                              DEVICE_OBJECT* const            p_dev_obj )\r
572 {\r
573         hca_dev_ext_t           *p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
574 \r
575         HCA_ENTER( HCA_DBG_PNP );\r
576 \r
577         switch( p_ext->state )\r
578         {\r
579         case HCA_STARTED:\r
580                 /* dequeue HCA  */\r
581                 mlnx_hca_remove( &p_ext->hca );\r
582         }\r
583 \r
584         if (p_ext->al_sym_name.Buffer) {\r
585                 ExFreePool( p_ext->al_sym_name.Buffer );\r
586                 p_ext->al_sym_name.Buffer = NULL;\r
587         }\r
588         \r
589         if( p_ext->pnp_target_entry )\r
590         {\r
591                 ASSERT( p_ext->pnp_ifc_entry );\r
592                 IoUnregisterPlugPlayNotification( p_ext->pnp_target_entry );\r
593                 p_ext->pnp_target_entry = NULL;\r
594         }\r
595 \r
596         if( p_ext->pnp_ifc_entry ) {\r
597                 IoUnregisterPlugPlayNotification( p_ext->pnp_ifc_entry );\r
598                 p_ext->pnp_ifc_entry = NULL;\r
599         }\r
600 \r
601         if( p_ext->p_al_file_obj ) {\r
602                 ObDereferenceObject( p_ext->p_al_file_obj );\r
603                 p_ext->p_al_file_obj = NULL;\r
604         }\r
605 \r
606         mthca_remove_one( p_ext );\r
607 \r
608         if( p_ext->p_dma_adapter ) {\r
609                 p_ext->p_dma_adapter->DmaOperations->PutDmaAdapter( p_ext->p_dma_adapter );\r
610                 p_ext->p_dma_adapter = NULL;\r
611         }\r
612 \r
613         hca_disable_pci( &p_ext->hcaBusIfc );\r
614 \r
615         //cl_event_destroy( &p_ext->mutex );\r
616         __UnmapHcaMemoryResources( p_dev_obj );\r
617 \r
618         p_ext->state = HCA_ADDED;\r
619 \r
620         HCA_EXIT( HCA_DBG_PNP );\r
621 }\r
622 \r
623 \r
624 static void\r
625 hca_release_resources(\r
626         IN                              DEVICE_OBJECT* const            p_dev_obj )\r
627 {\r
628         hca_dev_ext_t           *p_ext;\r
629         POWER_STATE             powerState;\r
630 \r
631         HCA_ENTER( HCA_DBG_PNP );\r
632 \r
633         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
634 \r
635         /* release all the resources, allocated in hca_start */\r
636         __hca_release_resources(p_dev_obj);\r
637 \r
638         /* Notify the power manager that the device is powered down. */\r
639         p_ext->DevicePowerState = PowerDeviceD3;\r
640         powerState.DeviceState = PowerDeviceD3;\r
641         powerState = PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState );\r
642 \r
643         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, \r
644                 ("PoSetPowerState: old state %d, new state to %d\n", \r
645                 powerState.DeviceState, p_ext->DevicePowerState ));\r
646 \r
647 \r
648         /* Clear the PnP state in case we get restarted. */\r
649         p_ext->pnpState = 0;\r
650 \r
651         HCA_EXIT( HCA_DBG_PNP );\r
652 }\r
653 \r
654 \r
655 static NTSTATUS\r
656 hca_query_stop(\r
657         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
658         IN                              IRP* const                                      p_irp, \r
659                 OUT                     cl_irp_action_t* const          p_action )\r
660 {\r
661         /* All kernel clients will get notified through the device hierarchy. */\r
662 \r
663         /* TODO: set a flag to fail creation of any new IB resources. */\r
664         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
665 }\r
666 \r
667 \r
668 static NTSTATUS\r
669 hca_stop(\r
670         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
671         IN                              IRP* const                                      p_irp, \r
672                 OUT                     cl_irp_action_t* const          p_action )\r
673 {\r
674         /*\r
675          * Must disable everything.  Complib framework will\r
676          * call ReleaseResources handler.\r
677          */\r
678         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
679 }\r
680 \r
681 \r
682 static NTSTATUS\r
683 hca_cancel_stop(\r
684         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
685         IN                              IRP* const                                      p_irp, \r
686                 OUT                     cl_irp_action_t* const          p_action )\r
687 {\r
688         /* Handled on the way up. */\r
689         return cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
690 }\r
691 \r
692 \r
693 static NTSTATUS\r
694 hca_query_remove(\r
695         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
696         IN                              IRP* const                                      p_irp, \r
697                 OUT                     cl_irp_action_t* const          p_action )\r
698 {\r
699         hca_dev_ext_t*p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
700         if (atomic_read(&p_ext->usecnt)) {\r
701                 cl_dbg_out( "MTHCA: Can't get unloaded. %d applications are still in work\n", p_ext->usecnt);\r
702                 p_irp->IoStatus.Status = STATUS_UNSUCCESSFUL;\r
703                 return cl_irp_complete( p_dev_obj, p_irp, p_action );\r
704         }\r
705         /* TODO: set a flag to fail creation of any new IB resources. */\r
706         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
707 }\r
708 \r
709 \r
710 static NTSTATUS\r
711 hca_cancel_remove(\r
712         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
713         IN                              IRP* const                                      p_irp, \r
714                 OUT                     cl_irp_action_t* const          p_action )\r
715 {\r
716         /* Handled on the way up. */\r
717         return cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
718 }\r
719 \r
720 \r
721 static NTSTATUS\r
722 hca_surprise_remove(\r
723         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
724         IN                              IRP* const                                      p_irp, \r
725                 OUT                     cl_irp_action_t* const          p_action )\r
726 {\r
727         /*\r
728          * TODO: Set state so that all further requests\r
729          * automatically succeed/fail as needed.\r
730          */\r
731         return cl_irp_skip( p_dev_obj, p_irp, p_action );\r
732 }\r
733 \r
734 \r
735 static NTSTATUS\r
736 hca_query_capabilities(\r
737         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
738         IN                              IRP* const                                      p_irp, \r
739                 OUT                     cl_irp_action_t* const          p_action )\r
740 {\r
741         NTSTATUS                        status;\r
742         hca_dev_ext_t           *p_ext;\r
743         IO_STACK_LOCATION       *pIoStack;\r
744         DEVICE_CAPABILITIES     *pCaps;\r
745 \r
746         HCA_ENTER( HCA_DBG_PNP );\r
747 \r
748         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
749 \r
750         /* Process on the way up. */\r
751         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
752         if( !NT_SUCCESS( status ) )\r
753         {\r
754                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
755                         ("cl_do_sync_pnp returned %08X.\n", status));\r
756                 return status;\r
757         }\r
758 \r
759         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
760         pCaps = pIoStack->Parameters.DeviceCapabilities.Capabilities;\r
761 \r
762         /*\r
763          * Store the device power mapping into our extension since we're\r
764          * the power policy owner.  The mapping is used when handling\r
765          * IRP_MN_SET_POWER IRPs.\r
766          */\r
767         cl_memcpy(\r
768                 p_ext->DevicePower, pCaps->DeviceState, sizeof(p_ext->DevicePower) );\r
769 \r
770         if( pCaps->DeviceD1 )\r
771         {\r
772                 HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP,\r
773                         ("WARNING: Device reports support for DeviceD1 power state.\n"));\r
774                 pCaps->DeviceD1 = FALSE;\r
775         }\r
776 \r
777         if( pCaps->DeviceD2 )\r
778         {\r
779                 HCA_PRINT( TRACE_LEVEL_WARNING,HCA_DBG_PNP,\r
780                         ("WARNING: Device reports support for DeviceD2 power state.\n"));\r
781                 pCaps->DeviceD2 = FALSE;\r
782         }\r
783 \r
784         if( pCaps->SystemWake != PowerSystemUnspecified )\r
785         {\r
786                 HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP,\r
787                         ("WARNING: Device reports support for system wake.\n"));\r
788                 pCaps->SystemWake = PowerSystemUnspecified;\r
789         }\r
790 \r
791         if( pCaps->DeviceWake != PowerDeviceUnspecified )\r
792         {\r
793                 HCA_PRINT( TRACE_LEVEL_WARNING, HCA_DBG_PNP,\r
794                         ("WARNING: Device reports support for device wake.\n"));\r
795                 pCaps->DeviceWake = PowerDeviceUnspecified;\r
796         }\r
797 \r
798         HCA_EXIT( HCA_DBG_PNP );\r
799         return status;\r
800 }\r
801 \r
802 static void\r
803 __ref_ifc(\r
804         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
805 {\r
806         hca_dev_ext_t   *p_ext  = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
807 \r
808         HCA_ENTER( HCA_DBG_PNP );\r
809 \r
810         cl_atomic_inc( &p_ext->n_hca_ifc_ref );\r
811         ObReferenceObject( p_dev_obj );\r
812 \r
813         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
814                 ("MTHCA: CA_guid %I64x, hca_ifc_ref %d\n",\r
815                 p_ext->hca.guid, p_ext->n_hca_ifc_ref) );\r
816 \r
817         HCA_EXIT( HCA_DBG_PNP );\r
818 }\r
819 \r
820 static void\r
821 __deref_ifc(\r
822         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
823 {\r
824         hca_dev_ext_t   *p_ext  = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
825 \r
826         HCA_ENTER( HCA_DBG_PNP );\r
827 \r
828         cl_atomic_dec( &p_ext->n_hca_ifc_ref );\r
829         ObDereferenceObject( p_dev_obj );\r
830 \r
831         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
832                 ("MTHCA: CA_guid %I64x, hca_ifc_ref %d\n",\r
833                 p_ext->hca.guid, p_ext->n_hca_ifc_ref) );\r
834 \r
835         HCA_EXIT( HCA_DBG_PNP );\r
836 }\r
837 \r
838 static NTSTATUS\r
839 __query_ci_ifc(\r
840         IN                                      DEVICE_OBJECT* const            p_dev_obj,\r
841         IN                                      IO_STACK_LOCATION* const        p_io_stack )\r
842 {\r
843         RDMA_INTERFACE_VERBS    *p_ifc;\r
844         hca_dev_ext_t                   *p_ext;\r
845         ci_interface_t                  *p_hca_ifc;\r
846         NTSTATUS                                status;\r
847         UINT8                                   version;\r
848 \r
849         HCA_ENTER( HCA_DBG_PNP );\r
850 \r
851         version = VerbsVersionMajor(p_io_stack->Parameters.QueryInterface.Version);\r
852         if(  version > VERBS_MAJOR_VER )\r
853         {\r
854                 status = STATUS_NOT_SUPPORTED;\r
855                 goto exit;\r
856         }\r
857 \r
858         if( p_io_stack->Parameters.QueryInterface.Size < sizeof(RDMA_INTERFACE_VERBS) )\r
859         {\r
860                 status = STATUS_BUFFER_TOO_SMALL;\r
861                 goto exit;\r
862         }\r
863 \r
864         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
865         p_hca_ifc = __alloc_hca_ifc( p_ext );\r
866         if( !p_hca_ifc )\r
867         {\r
868                 status = STATUS_NO_MEMORY;\r
869                 goto exit;\r
870         }\r
871 \r
872         p_ifc = (RDMA_INTERFACE_VERBS *) p_io_stack->Parameters.QueryInterface.Interface;\r
873 \r
874         p_ifc->InterfaceHeader.Size = sizeof(RDMA_INTERFACE_VERBS);\r
875         p_ifc->InterfaceHeader.Version = VerbsVersion(VERBS_MAJOR_VER, VERBS_MINOR_VER);\r
876         p_ifc->InterfaceHeader.Context = p_dev_obj;\r
877         p_ifc->InterfaceHeader.InterfaceReference = __ref_ifc;\r
878         p_ifc->InterfaceHeader.InterfaceDereference = __deref_ifc;\r
879         p_ifc->Verbs = *p_hca_ifc;\r
880 \r
881         /* take the reference before returning. */\r
882         __ref_ifc( p_dev_obj );\r
883 \r
884         ExFreePool( p_hca_ifc );\r
885         status = STATUS_SUCCESS;\r
886 \r
887 exit:\r
888         HCA_EXIT( HCA_DBG_PNP );\r
889         return status;\r
890 }\r
891 \r
892 \r
893 static NTSTATUS\r
894 hca_query_interface(\r
895         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
896         IN                              IRP* const                                      p_irp, \r
897                 OUT                     cl_irp_action_t* const          p_action )\r
898 {\r
899         NTSTATUS                        status;\r
900         IO_STACK_LOCATION       *p_io_stack;\r
901 \r
902         HCA_ENTER( HCA_DBG_PNP );\r
903 \r
904 #pragma warning( push, 3 )\r
905         PAGED_CODE();\r
906 #pragma warning( pop )\r
907 \r
908         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
909         \r
910         /* Compare requested GUID with our supported interface GUIDs. */\r
911         if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
912                 &GUID_RDMA_INTERFACE_VERBS ) )\r
913         {\r
914                 status = __query_ci_ifc( p_dev_obj, p_io_stack );\r
915                 *p_action = IrpComplete;\r
916         }\r
917         else\r
918         {\r
919                 status = p_irp->IoStatus.Status;\r
920                 *p_action = IrpSkip;\r
921         }\r
922 \r
923         HCA_EXIT( HCA_DBG_PNP );\r
924         return status;\r
925 }\r
926 \r
927 \r
928 static NTSTATUS\r
929 hca_query_pnp_state(\r
930         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
931         IN                              IRP* const                                      p_irp, \r
932                 OUT                     cl_irp_action_t* const          p_action )\r
933 {\r
934         hca_dev_ext_t           *p_ext;\r
935 \r
936         HCA_ENTER( HCA_DBG_PNP );\r
937 \r
938         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
939 \r
940         p_irp->IoStatus.Information |= p_ext->pnpState;\r
941 \r
942         *p_action = IrpSkip;\r
943 \r
944         HCA_EXIT( HCA_DBG_PNP );\r
945         return STATUS_SUCCESS;;\r
946 }\r
947 \r
948 static NTSTATUS\r
949 hca_query_power(\r
950         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
951         IN                              IRP* const                                      p_irp,\r
952                 OUT                     cl_irp_action_t* const          p_action )\r
953 {\r
954         NTSTATUS                        status = STATUS_SUCCESS;\r
955         IO_STACK_LOCATION       *pIoStack;\r
956 \r
957         HCA_ENTER(HCA_DBG_PO);\r
958 \r
959         UNUSED_PARAM( p_dev_obj );\r
960 \r
961         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
962 \r
963         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
964                 ("QUERY_POWER for FDO %p: type %s, state %d, action %d, IRQL %d, IRP %p\n",\r
965                 p_dev_obj, \r
966                 (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
967                 pIoStack->Parameters.Power.State.DeviceState, \r
968                 pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql(), p_irp ));\r
969 \r
970         switch( pIoStack->Parameters.Power.Type )\r
971         {\r
972         case SystemPowerState:\r
973                 /* Fail any requests to hibernate or sleep the system. */\r
974                 switch( pIoStack->Parameters.Power.State.SystemState )\r
975                 {\r
976                         case PowerSystemSleeping1:      // STANDBY support\r
977                         case PowerSystemHibernate:\r
978                         {\r
979                                 hca_dev_ext_t*p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
980                                 if (atomic_read(&p_ext->usecnt)) \r
981                                         status = STATUS_UNSUCCESSFUL;\r
982                                 break;\r
983                         }\r
984 \r
985                         case PowerSystemWorking:\r
986                         case PowerSystemShutdown:\r
987                                 break;\r
988 \r
989                         default:\r
990                                 status = STATUS_NOT_SUPPORTED;\r
991                 }\r
992                 break;\r
993 \r
994         case DevicePowerState:\r
995                 /* Fail any query for low power states. */\r
996                 switch( pIoStack->Parameters.Power.State.DeviceState )\r
997                 {\r
998                 case PowerDeviceD0:\r
999                 case PowerDeviceD3:\r
1000                         /* We only support fully powered or off power states. */\r
1001                         break;\r
1002 \r
1003                 default:\r
1004                         status = STATUS_NOT_SUPPORTED;\r
1005                 }\r
1006                 break;\r
1007         }\r
1008 \r
1009         if( status == STATUS_SUCCESS )\r
1010                 *p_action = IrpSkip;\r
1011         else\r
1012                 *p_action = IrpComplete;\r
1013 \r
1014         HCA_EXIT( HCA_DBG_PO );\r
1015         return status;\r
1016 }\r
1017 \r
1018 \r
1019 static void\r
1020 __RequestPowerCompletion(\r
1021         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1022         IN                              UCHAR                                           minorFunction,\r
1023         IN                              POWER_STATE                                     powerState,\r
1024         IN                              void                                            *context,\r
1025         IN                              IO_STATUS_BLOCK                         *pIoStatus )\r
1026 {\r
1027         IRP                                     *p_irp;\r
1028         cl_pnp_po_ext_t         *p_ext;\r
1029 \r
1030         HCA_ENTER( HCA_DBG_PO );\r
1031 \r
1032         UNUSED_PARAM( minorFunction );\r
1033         UNUSED_PARAM( powerState );\r
1034 \r
1035         p_irp = (IRP*)context;\r
1036         p_ext = (cl_pnp_po_ext_t*)p_dev_obj->DeviceExtension;\r
1037 \r
1038         /* Propagate the device IRP status to the system IRP status. */\r
1039         p_irp->IoStatus.Status = pIoStatus->Status;\r
1040 \r
1041         /* Continue Power IRP processing. */\r
1042         PoStartNextPowerIrp( p_irp );\r
1043         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1044         IoReleaseRemoveLock( &p_ext->remove_lock, p_irp );\r
1045         HCA_EXIT( HCA_DBG_PO );\r
1046 }\r
1047 \r
1048 \r
1049 /*NOTE: Completion routines must NEVER be pageable. */\r
1050 static NTSTATUS\r
1051 __SystemPowerCompletion(\r
1052         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1053         IN                              IRP                                                     *p_irp,\r
1054         IN                              void                                            *context )\r
1055 {\r
1056         NTSTATUS                        status;\r
1057         POWER_STATE                     state;\r
1058         hca_dev_ext_t           *p_ext;\r
1059         IO_STACK_LOCATION       *pIoStack;\r
1060 \r
1061         HCA_ENTER( HCA_DBG_PO );\r
1062 \r
1063         UNUSED_PARAM( context );\r
1064 \r
1065         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1066         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1067 \r
1068         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1069         {\r
1070                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
1071                         ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n",\r
1072                         p_irp->IoStatus.Status));\r
1073                 status = STATUS_SUCCESS;\r
1074                 PoStartNextPowerIrp( p_irp );\r
1075                 goto release;\r
1076         }\r
1077 \r
1078         state.DeviceState = \r
1079                 p_ext->DevicePower[pIoStack->Parameters.Power.State.SystemState];\r
1080 \r
1081         /*\r
1082          * Send a device power IRP to our devnode.  Using our device object will\r
1083          * only work on win2k and other NT based systems.\r
1084          */\r
1085         status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
1086                 __RequestPowerCompletion, p_irp, NULL );\r
1087 \r
1088         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1089                 ("PoRequestPowerIrp: SET_POWER 'PowerDeviceD%d', status %#x\n", \r
1090                 state.DeviceState - 1, status ));\r
1091 \r
1092         if( status != STATUS_PENDING ) {\r
1093                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO,\r
1094                         ("PoRequestPowerIrp returned %08x.\n", status));\r
1095                 p_irp->IoStatus.Status = status;        /* Propagate the failure. */\r
1096                 PoStartNextPowerIrp( p_irp );\r
1097                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1098                 goto release;\r
1099         }\r
1100 \r
1101         status = STATUS_MORE_PROCESSING_REQUIRED;\r
1102         goto exit;\r
1103 \r
1104 release:        \r
1105         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1106 exit:\r
1107         HCA_EXIT( HCA_DBG_PO );\r
1108         return status;\r
1109 }\r
1110 \r
1111 \r
1112 /* Work item callback to handle DevicePowerD0 IRPs at passive level. */\r
1113 static void\r
1114 __DevicePowerUpCompletionWorkItem(\r
1115         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1116         IN                              void*                                           context )\r
1117 {\r
1118         NTSTATUS                        status;\r
1119         IO_STACK_LOCATION       *pIoStack;\r
1120         hca_dev_ext_t           *p_ext;\r
1121         IRP                                     *p_irp;\r
1122         POWER_STATE powerState;\r
1123 \r
1124         HCA_ENTER( HCA_DBG_PO );\r
1125 \r
1126         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1127         p_irp = (IRP*)context;\r
1128         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1129 \r
1130         IoFreeWorkItem( p_ext->pPoWorkItem );\r
1131         p_ext->pPoWorkItem = NULL;\r
1132 \r
1133         /* restart the HCA */\r
1134         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1135                 ("***** Restart the HCA, IRQL %d\n", KeGetCurrentIrql()));\r
1136 \r
1137         status = mthca_init_one( p_ext );\r
1138         if( !NT_SUCCESS( status ) ) {\r
1139                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
1140                         ("!!! mthca_init_one failed (%#x) \n", status));\r
1141                 goto err_mthca_init;\r
1142         }\r
1143 \r
1144         p_ext->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState;\r
1145         powerState = PoSetPowerState( p_dev_obj, DevicePowerState,\r
1146                 pIoStack->Parameters.Power.State );\r
1147 \r
1148         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1149                 ("PoSetPowerState: old state %d, new state to %d\n", \r
1150                 powerState.DeviceState, p_ext->DevicePowerState ));\r
1151 \r
1152         goto exit;\r
1153 \r
1154 err_mthca_init:\r
1155         /* Flag device as having failed. */\r
1156         p_ext->pnpState |= PNP_DEVICE_FAILED;\r
1157         IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1158 exit:\r
1159         PoStartNextPowerIrp( p_irp );\r
1160         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1161         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1162         HCA_EXIT( HCA_DBG_PO );\r
1163 }\r
1164 \r
1165 /*NOTE: Completion routines must NEVER be pageable. */\r
1166 static NTSTATUS\r
1167 __DevicePowerUpCompletion(\r
1168         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1169         IN                              IRP                                                     *p_irp,\r
1170         IN                              void                                            *context )\r
1171 {\r
1172         NTSTATUS                        status = STATUS_SUCCESS;\r
1173         hca_dev_ext_t           *p_ext;\r
1174         IO_STACK_LOCATION       *pIoStack;\r
1175 \r
1176         HCA_ENTER( HCA_DBG_PO );\r
1177 \r
1178         UNUSED_PARAM( context );\r
1179 \r
1180         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1181         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1182 \r
1183         if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) {\r
1184                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
1185                         ("IRP_MN_SET_POWER for device failed by lower driver with %08x.\n",\r
1186                         p_irp->IoStatus.Status));\r
1187                 status =  STATUS_SUCCESS;\r
1188                 PoStartNextPowerIrp( p_irp );\r
1189                 goto release;\r
1190         }\r
1191 \r
1192         /* Process in a work item - mthca_start blocks. */\r
1193         ASSERT( !p_ext->pPoWorkItem );\r
1194         p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1195         if( !p_ext->pPoWorkItem ) {\r
1196                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
1197                         ("Failed to allocate work item.\n" ));\r
1198                 status = STATUS_SUCCESS;\r
1199                 p_ext->pnpState |= PNP_DEVICE_FAILED;\r
1200                 IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1201                 PoStartNextPowerIrp( p_irp );\r
1202                 goto release;\r
1203         }\r
1204 \r
1205         /* Process in work item callback. */\r
1206         IoMarkIrpPending( p_irp );\r
1207         IoQueueWorkItem( p_ext->pPoWorkItem, \r
1208                 __DevicePowerUpCompletionWorkItem, DelayedWorkQueue, p_irp );\r
1209         status = STATUS_MORE_PROCESSING_REQUIRED;\r
1210         goto exit;\r
1211 \r
1212 release:        \r
1213         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1214 exit:   \r
1215         HCA_EXIT( HCA_DBG_PO );\r
1216         return status;\r
1217 }\r
1218 \r
1219 static NTSTATUS __DevicePowerDownWorkItemCompletion(\r
1220         IN                              DEVICE_OBJECT   *p_dev_obj,\r
1221         IN                              IRP                             *p_irp,\r
1222         IN                              void                            *context )\r
1223 {\r
1224         hca_dev_ext_t  *p_ext  = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1225         UNUSED_PARAM( context );\r
1226 \r
1227         HCA_ENTER( HCA_DBG_PO );\r
1228 \r
1229         PoStartNextPowerIrp( p_irp );\r
1230         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1231 \r
1232         HCA_EXIT( HCA_DBG_PO );\r
1233         return STATUS_SUCCESS;\r
1234 }\r
1235 \r
1236 /* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
1237 static void\r
1238 __DevicePowerDownWorkItem(\r
1239         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1240         IN                              void*                                           context )\r
1241 {\r
1242         IO_STACK_LOCATION       *pIoStack;\r
1243         hca_dev_ext_t           *p_ext;\r
1244         IRP                                     *p_irp;\r
1245         POWER_STATE powerState;\r
1246 \r
1247         HCA_ENTER( HCA_DBG_PO );\r
1248 \r
1249         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1250         p_irp = (IRP*)context;\r
1251         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1252 \r
1253         IoFreeWorkItem( p_ext->pPoWorkItem );\r
1254         p_ext->pPoWorkItem = NULL;\r
1255 \r
1256         p_ext->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState;\r
1257         powerState = PoSetPowerState( p_dev_obj, DevicePowerState,\r
1258                 pIoStack->Parameters.Power.State );\r
1259 \r
1260         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1261                 ("PoSetPowerState: old state %d, new state to %d, IRQL %d\n", \r
1262                 powerState.DeviceState, p_ext->DevicePowerState, KeGetCurrentIrql() ));\r
1263 \r
1264         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1265                 ("***** Remove the HCA \n"));\r
1266 \r
1267         mthca_remove_one( p_ext );\r
1268 \r
1269         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1270 #pragma warning( push, 3 )\r
1271         IoSetCompletionRoutine( p_irp, __DevicePowerDownWorkItemCompletion,\r
1272                 NULL, TRUE, TRUE, TRUE );\r
1273 #pragma warning( pop )\r
1274         PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1275 \r
1276         HCA_EXIT( HCA_DBG_PO );\r
1277 }\r
1278 \r
1279 \r
1280 static NTSTATUS\r
1281 hca_set_power(\r
1282         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1283         IN                              IRP* const                                      p_irp,\r
1284                 OUT                     cl_irp_action_t* const          p_action )\r
1285 {\r
1286         NTSTATUS                        status;\r
1287         IO_STACK_LOCATION       *pIoStack;\r
1288         hca_dev_ext_t           *p_ext;\r
1289 \r
1290         HCA_ENTER( HCA_DBG_PO );\r
1291 \r
1292         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1293         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1294 \r
1295         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1296                 ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d, IRQL %d \n",\r
1297                 p_dev_obj, p_ext,\r
1298                 (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
1299                 pIoStack->Parameters.Power.State.DeviceState, \r
1300                 pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql() ));\r
1301 \r
1302         switch( pIoStack->Parameters.Power.Type )\r
1303         {\r
1304         case SystemPowerState:\r
1305                 p_ext->SystemPowerState = pIoStack->Parameters.Power.State.SystemState;\r
1306                 \r
1307                 /*\r
1308                  * Process on the way up the stack.  We cannot block since the \r
1309                  * power dispatch function can be called at elevated IRQL if the\r
1310                  * device is in a paging/hibernation/crash dump path.\r
1311                  */\r
1312                 IoMarkIrpPending( p_irp );\r
1313                 IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1314 #pragma warning( push, 3 )\r
1315                 IoSetCompletionRoutine( p_irp, __SystemPowerCompletion, NULL, \r
1316                         TRUE, TRUE, TRUE );\r
1317 #pragma warning( pop )\r
1318                 PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1319 \r
1320                 *p_action = IrpDoNothing;\r
1321                 status = STATUS_PENDING;\r
1322                 break;\r
1323 \r
1324         case DevicePowerState:\r
1325                 IoMarkIrpPending( p_irp );\r
1326                 if( pIoStack->Parameters.Power.State.DeviceState == PowerDeviceD0 && \r
1327                         p_ext->SystemPowerState == PowerSystemWorking)\r
1328                 { /* power up */\r
1329                         /* If we're already powered up, just pass down. */\r
1330                         if( p_ext->DevicePowerState == PowerDeviceD0 )\r
1331                         {\r
1332                                 status = STATUS_SUCCESS;\r
1333                                 *p_action = IrpIgnore;\r
1334                                 break;\r
1335                         }\r
1336 \r
1337                         /* Process in I/O completion callback. */\r
1338                         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1339 #pragma warning( push, 3 )\r
1340                         IoSetCompletionRoutine( p_irp, __DevicePowerUpCompletion, NULL, \r
1341                                 TRUE, TRUE, TRUE );\r
1342 #pragma warning( pop )\r
1343                         PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1344                 }\r
1345                 else\r
1346                 { /* power down */\r
1347 \r
1348                         /* Process in a work item - deregister_ca and HcaDeinit block. */\r
1349                         ASSERT( !p_ext->pPoWorkItem );\r
1350                         p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1351                         if( !p_ext->pPoWorkItem )\r
1352                         {\r
1353                                 status = STATUS_INSUFFICIENT_RESOURCES;\r
1354                                 break;\r
1355                         }\r
1356 \r
1357                         /* Process in work item callback. */\r
1358                         IoQueueWorkItem(\r
1359                                 p_ext->pPoWorkItem, __DevicePowerDownWorkItem, DelayedWorkQueue, p_irp );\r
1360                 }\r
1361                 *p_action = IrpDoNothing;\r
1362                 status = STATUS_PENDING;\r
1363                 break;\r
1364 \r
1365         default:\r
1366                 /* Pass down and let the PDO driver handle it. */\r
1367                 *p_action = IrpIgnore;\r
1368                 status = STATUS_SUCCESS;\r
1369                 break;\r
1370         }\r
1371 \r
1372         if( !NT_SUCCESS( status ) )\r
1373                 *p_action = IrpComplete;\r
1374 \r
1375         HCA_EXIT( HCA_DBG_PNP );\r
1376         return status;\r
1377 }\r
1378 \r
1379 \r