[MTHCA] mthca_provider.c - prevent dereference of <NULL> mdev or mdev->ext
[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_dev = p_ext->cl_ext.p_pdo;\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         p_ifc->p_hca_obj = &p_ext->hca.hob;\r
881 \r
882         /* take the reference before returning. */\r
883         __ref_ifc( p_dev_obj );\r
884 \r
885         ExFreePool( p_hca_ifc );\r
886         status = STATUS_SUCCESS;\r
887 \r
888 exit:\r
889         HCA_EXIT( HCA_DBG_PNP );\r
890         return status;\r
891 }\r
892 \r
893 \r
894 static NTSTATUS\r
895 hca_query_interface(\r
896         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
897         IN                              IRP* const                                      p_irp, \r
898                 OUT                     cl_irp_action_t* const          p_action )\r
899 {\r
900         NTSTATUS                        status;\r
901         IO_STACK_LOCATION       *p_io_stack;\r
902 \r
903         HCA_ENTER( HCA_DBG_PNP );\r
904 \r
905 #pragma warning( push, 3 )\r
906         PAGED_CODE();\r
907 #pragma warning( pop )\r
908 \r
909         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
910         \r
911         /* Compare requested GUID with our supported interface GUIDs. */\r
912         if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
913                 &GUID_RDMA_INTERFACE_VERBS ) )\r
914         {\r
915                 status = __query_ci_ifc( p_dev_obj, p_io_stack );\r
916                 *p_action = IrpComplete;\r
917         }\r
918         else\r
919         {\r
920                 status = p_irp->IoStatus.Status;\r
921                 *p_action = IrpSkip;\r
922         }\r
923 \r
924         HCA_EXIT( HCA_DBG_PNP );\r
925         return status;\r
926 }\r
927 \r
928 \r
929 static NTSTATUS\r
930 hca_query_pnp_state(\r
931         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
932         IN                              IRP* const                                      p_irp, \r
933                 OUT                     cl_irp_action_t* const          p_action )\r
934 {\r
935         hca_dev_ext_t           *p_ext;\r
936 \r
937         HCA_ENTER( HCA_DBG_PNP );\r
938 \r
939         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
940 \r
941         p_irp->IoStatus.Information |= p_ext->pnpState;\r
942 \r
943         *p_action = IrpSkip;\r
944 \r
945         HCA_EXIT( HCA_DBG_PNP );\r
946         return STATUS_SUCCESS;;\r
947 }\r
948 \r
949 static NTSTATUS\r
950 hca_query_power(\r
951         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
952         IN                              IRP* const                                      p_irp,\r
953                 OUT                     cl_irp_action_t* const          p_action )\r
954 {\r
955         NTSTATUS                        status = STATUS_SUCCESS;\r
956         IO_STACK_LOCATION       *pIoStack;\r
957 \r
958         HCA_ENTER(HCA_DBG_PO);\r
959 \r
960         UNUSED_PARAM( p_dev_obj );\r
961 \r
962         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
963 \r
964         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
965                 ("QUERY_POWER for FDO %p: type %s, state %d, action %d, IRQL %d, IRP %p\n",\r
966                 p_dev_obj, \r
967                 (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
968                 pIoStack->Parameters.Power.State.DeviceState, \r
969                 pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql(), p_irp ));\r
970 \r
971         switch( pIoStack->Parameters.Power.Type )\r
972         {\r
973         case SystemPowerState:\r
974                 /* Fail any requests to hibernate or sleep the system. */\r
975                 switch( pIoStack->Parameters.Power.State.SystemState )\r
976                 {\r
977                         case PowerSystemSleeping1:      // STANDBY support\r
978                         case PowerSystemHibernate:\r
979                         {\r
980                                 hca_dev_ext_t*p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
981                                 if (atomic_read(&p_ext->usecnt)) \r
982                                         status = STATUS_UNSUCCESSFUL;\r
983                                 break;\r
984                         }\r
985 \r
986                         case PowerSystemWorking:\r
987                         case PowerSystemShutdown:\r
988                                 break;\r
989 \r
990                         default:\r
991                                 status = STATUS_NOT_SUPPORTED;\r
992                 }\r
993                 break;\r
994 \r
995         case DevicePowerState:\r
996                 /* Fail any query for low power states. */\r
997                 switch( pIoStack->Parameters.Power.State.DeviceState )\r
998                 {\r
999                 case PowerDeviceD0:\r
1000                 case PowerDeviceD3:\r
1001                         /* We only support fully powered or off power states. */\r
1002                         break;\r
1003 \r
1004                 default:\r
1005                         status = STATUS_NOT_SUPPORTED;\r
1006                 }\r
1007                 break;\r
1008         }\r
1009 \r
1010         if( status == STATUS_SUCCESS )\r
1011                 *p_action = IrpSkip;\r
1012         else\r
1013                 *p_action = IrpComplete;\r
1014 \r
1015         HCA_EXIT( HCA_DBG_PO );\r
1016         return status;\r
1017 }\r
1018 \r
1019 \r
1020 static void\r
1021 __RequestPowerCompletion(\r
1022         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1023         IN                              UCHAR                                           minorFunction,\r
1024         IN                              POWER_STATE                                     powerState,\r
1025         IN                              void                                            *context,\r
1026         IN                              IO_STATUS_BLOCK                         *pIoStatus )\r
1027 {\r
1028         IRP                                     *p_irp;\r
1029         cl_pnp_po_ext_t         *p_ext;\r
1030 \r
1031         HCA_ENTER( HCA_DBG_PO );\r
1032 \r
1033         UNUSED_PARAM( minorFunction );\r
1034         UNUSED_PARAM( powerState );\r
1035 \r
1036         p_irp = (IRP*)context;\r
1037         p_ext = (cl_pnp_po_ext_t*)p_dev_obj->DeviceExtension;\r
1038 \r
1039         /* Propagate the device IRP status to the system IRP status. */\r
1040         p_irp->IoStatus.Status = pIoStatus->Status;\r
1041 \r
1042         /* Continue Power IRP processing. */\r
1043         PoStartNextPowerIrp( p_irp );\r
1044         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1045         IoReleaseRemoveLock( &p_ext->remove_lock, p_irp );\r
1046         HCA_EXIT( HCA_DBG_PO );\r
1047 }\r
1048 \r
1049 \r
1050 /*NOTE: Completion routines must NEVER be pageable. */\r
1051 static NTSTATUS\r
1052 __SystemPowerCompletion(\r
1053         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1054         IN                              IRP                                                     *p_irp,\r
1055         IN                              void                                            *context )\r
1056 {\r
1057         NTSTATUS                        status;\r
1058         POWER_STATE                     state;\r
1059         hca_dev_ext_t           *p_ext;\r
1060         IO_STACK_LOCATION       *pIoStack;\r
1061 \r
1062         HCA_ENTER( HCA_DBG_PO );\r
1063 \r
1064         UNUSED_PARAM( context );\r
1065 \r
1066         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1067         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1068 \r
1069         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1070         {\r
1071                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
1072                         ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n",\r
1073                         p_irp->IoStatus.Status));\r
1074                 status = STATUS_SUCCESS;\r
1075                 PoStartNextPowerIrp( p_irp );\r
1076                 goto release;\r
1077         }\r
1078 \r
1079         state.DeviceState = \r
1080                 p_ext->DevicePower[pIoStack->Parameters.Power.State.SystemState];\r
1081 \r
1082         /*\r
1083          * Send a device power IRP to our devnode.  Using our device object will\r
1084          * only work on win2k and other NT based systems.\r
1085          */\r
1086         status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
1087                 __RequestPowerCompletion, p_irp, NULL );\r
1088 \r
1089         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1090                 ("PoRequestPowerIrp: SET_POWER 'PowerDeviceD%d', status %#x\n", \r
1091                 state.DeviceState - 1, status ));\r
1092 \r
1093         if( status != STATUS_PENDING ) {\r
1094                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO,\r
1095                         ("PoRequestPowerIrp returned %08x.\n", status));\r
1096                 p_irp->IoStatus.Status = status;        /* Propagate the failure. */\r
1097                 PoStartNextPowerIrp( p_irp );\r
1098                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1099                 goto release;\r
1100         }\r
1101 \r
1102         status = STATUS_MORE_PROCESSING_REQUIRED;\r
1103         goto exit;\r
1104 \r
1105 release:        \r
1106         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1107 exit:\r
1108         HCA_EXIT( HCA_DBG_PO );\r
1109         return status;\r
1110 }\r
1111 \r
1112 \r
1113 /* Work item callback to handle DevicePowerD0 IRPs at passive level. */\r
1114 static void\r
1115 __DevicePowerUpCompletionWorkItem(\r
1116         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1117         IN                              void*                                           context )\r
1118 {\r
1119         NTSTATUS                        status;\r
1120         IO_STACK_LOCATION       *pIoStack;\r
1121         hca_dev_ext_t           *p_ext;\r
1122         IRP                                     *p_irp;\r
1123         POWER_STATE powerState;\r
1124 \r
1125         HCA_ENTER( HCA_DBG_PO );\r
1126 \r
1127         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1128         p_irp = (IRP*)context;\r
1129         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1130 \r
1131         IoFreeWorkItem( p_ext->pPoWorkItem );\r
1132         p_ext->pPoWorkItem = NULL;\r
1133 \r
1134         /* restart the HCA */\r
1135         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1136                 ("***** Restart the HCA, IRQL %d\n", KeGetCurrentIrql()));\r
1137 \r
1138         status = mthca_init_one( p_ext );\r
1139         if( !NT_SUCCESS( status ) ) {\r
1140                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
1141                         ("!!! mthca_init_one failed (%#x) \n", status));\r
1142                 goto err_mthca_init;\r
1143         }\r
1144 \r
1145         p_ext->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState;\r
1146         powerState = PoSetPowerState( p_dev_obj, DevicePowerState,\r
1147                 pIoStack->Parameters.Power.State );\r
1148 \r
1149         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1150                 ("PoSetPowerState: old state %d, new state to %d\n", \r
1151                 powerState.DeviceState, p_ext->DevicePowerState ));\r
1152 \r
1153         goto exit;\r
1154 \r
1155 err_mthca_init:\r
1156         /* Flag device as having failed. */\r
1157         p_ext->pnpState |= PNP_DEVICE_FAILED;\r
1158         IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1159 exit:\r
1160         PoStartNextPowerIrp( p_irp );\r
1161         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1162         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1163         HCA_EXIT( HCA_DBG_PO );\r
1164 }\r
1165 \r
1166 /*NOTE: Completion routines must NEVER be pageable. */\r
1167 static NTSTATUS\r
1168 __DevicePowerUpCompletion(\r
1169         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1170         IN                              IRP                                                     *p_irp,\r
1171         IN                              void                                            *context )\r
1172 {\r
1173         NTSTATUS                        status = STATUS_SUCCESS;\r
1174         hca_dev_ext_t           *p_ext;\r
1175         IO_STACK_LOCATION       *pIoStack;\r
1176 \r
1177         HCA_ENTER( HCA_DBG_PO );\r
1178 \r
1179         UNUSED_PARAM( context );\r
1180 \r
1181         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1182         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1183 \r
1184         if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) {\r
1185                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
1186                         ("IRP_MN_SET_POWER for device failed by lower driver with %08x.\n",\r
1187                         p_irp->IoStatus.Status));\r
1188                 status =  STATUS_SUCCESS;\r
1189                 PoStartNextPowerIrp( p_irp );\r
1190                 goto release;\r
1191         }\r
1192 \r
1193         /* Process in a work item - mthca_start blocks. */\r
1194         ASSERT( !p_ext->pPoWorkItem );\r
1195         p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1196         if( !p_ext->pPoWorkItem ) {\r
1197                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, \r
1198                         ("Failed to allocate work item.\n" ));\r
1199                 status = STATUS_SUCCESS;\r
1200                 p_ext->pnpState |= PNP_DEVICE_FAILED;\r
1201                 IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
1202                 PoStartNextPowerIrp( p_irp );\r
1203                 goto release;\r
1204         }\r
1205 \r
1206         /* Process in work item callback. */\r
1207         IoMarkIrpPending( p_irp );\r
1208         IoQueueWorkItem( p_ext->pPoWorkItem, \r
1209                 __DevicePowerUpCompletionWorkItem, DelayedWorkQueue, p_irp );\r
1210         status = STATUS_MORE_PROCESSING_REQUIRED;\r
1211         goto exit;\r
1212 \r
1213 release:        \r
1214         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1215 exit:   \r
1216         HCA_EXIT( HCA_DBG_PO );\r
1217         return status;\r
1218 }\r
1219 \r
1220 static NTSTATUS __DevicePowerDownWorkItemCompletion(\r
1221         IN                              DEVICE_OBJECT   *p_dev_obj,\r
1222         IN                              IRP                             *p_irp,\r
1223         IN                              void                            *context )\r
1224 {\r
1225         hca_dev_ext_t  *p_ext  = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1226         UNUSED_PARAM( context );\r
1227 \r
1228         HCA_ENTER( HCA_DBG_PO );\r
1229 \r
1230         PoStartNextPowerIrp( p_irp );\r
1231         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1232 \r
1233         HCA_EXIT( HCA_DBG_PO );\r
1234         return STATUS_SUCCESS;\r
1235 }\r
1236 \r
1237 /* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
1238 static void\r
1239 __DevicePowerDownWorkItem(\r
1240         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1241         IN                              void*                                           context )\r
1242 {\r
1243         IO_STACK_LOCATION       *pIoStack;\r
1244         hca_dev_ext_t           *p_ext;\r
1245         IRP                                     *p_irp;\r
1246         POWER_STATE powerState;\r
1247 \r
1248         HCA_ENTER( HCA_DBG_PO );\r
1249 \r
1250         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1251         p_irp = (IRP*)context;\r
1252         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1253 \r
1254         IoFreeWorkItem( p_ext->pPoWorkItem );\r
1255         p_ext->pPoWorkItem = NULL;\r
1256 \r
1257         p_ext->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState;\r
1258         powerState = PoSetPowerState( p_dev_obj, DevicePowerState,\r
1259                 pIoStack->Parameters.Power.State );\r
1260 \r
1261         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1262                 ("PoSetPowerState: old state %d, new state to %d, IRQL %d\n", \r
1263                 powerState.DeviceState, p_ext->DevicePowerState, KeGetCurrentIrql() ));\r
1264 \r
1265         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1266                 ("***** Remove the HCA \n"));\r
1267 \r
1268         mthca_remove_one( p_ext );\r
1269 \r
1270         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1271 #pragma warning( push, 3 )\r
1272         IoSetCompletionRoutine( p_irp, __DevicePowerDownWorkItemCompletion,\r
1273                 NULL, TRUE, TRUE, TRUE );\r
1274 #pragma warning( pop )\r
1275         PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1276 \r
1277         HCA_EXIT( HCA_DBG_PO );\r
1278 }\r
1279 \r
1280 \r
1281 static NTSTATUS\r
1282 hca_set_power(\r
1283         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1284         IN                              IRP* const                                      p_irp,\r
1285                 OUT                     cl_irp_action_t* const          p_action )\r
1286 {\r
1287         NTSTATUS                        status;\r
1288         IO_STACK_LOCATION       *pIoStack;\r
1289         hca_dev_ext_t           *p_ext;\r
1290 \r
1291         HCA_ENTER( HCA_DBG_PO );\r
1292 \r
1293         p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
1294         pIoStack = IoGetCurrentIrpStackLocation( p_irp );\r
1295 \r
1296         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
1297                 ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d, IRQL %d \n",\r
1298                 p_dev_obj, p_ext,\r
1299                 (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
1300                 pIoStack->Parameters.Power.State.DeviceState, \r
1301                 pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql() ));\r
1302 \r
1303         switch( pIoStack->Parameters.Power.Type )\r
1304         {\r
1305         case SystemPowerState:\r
1306                 p_ext->SystemPowerState = pIoStack->Parameters.Power.State.SystemState;\r
1307                 \r
1308                 /*\r
1309                  * Process on the way up the stack.  We cannot block since the \r
1310                  * power dispatch function can be called at elevated IRQL if the\r
1311                  * device is in a paging/hibernation/crash dump path.\r
1312                  */\r
1313                 IoMarkIrpPending( p_irp );\r
1314                 IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1315 #pragma warning( push, 3 )\r
1316                 IoSetCompletionRoutine( p_irp, __SystemPowerCompletion, NULL, \r
1317                         TRUE, TRUE, TRUE );\r
1318 #pragma warning( pop )\r
1319                 PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1320 \r
1321                 *p_action = IrpDoNothing;\r
1322                 status = STATUS_PENDING;\r
1323                 break;\r
1324 \r
1325         case DevicePowerState:\r
1326                 IoMarkIrpPending( p_irp );\r
1327                 if( pIoStack->Parameters.Power.State.DeviceState == PowerDeviceD0 && \r
1328                         p_ext->SystemPowerState == PowerSystemWorking)\r
1329                 { /* power up */\r
1330                         /* If we're already powered up, just pass down. */\r
1331                         if( p_ext->DevicePowerState == PowerDeviceD0 )\r
1332                         {\r
1333                                 status = STATUS_SUCCESS;\r
1334                                 *p_action = IrpIgnore;\r
1335                                 break;\r
1336                         }\r
1337 \r
1338                         /* Process in I/O completion callback. */\r
1339                         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1340 #pragma warning( push, 3 )\r
1341                         IoSetCompletionRoutine( p_irp, __DevicePowerUpCompletion, NULL, \r
1342                                 TRUE, TRUE, TRUE );\r
1343 #pragma warning( pop )\r
1344                         PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1345                 }\r
1346                 else\r
1347                 { /* power down */\r
1348 \r
1349                         /* Process in a work item - deregister_ca and HcaDeinit block. */\r
1350                         ASSERT( !p_ext->pPoWorkItem );\r
1351                         p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj );\r
1352                         if( !p_ext->pPoWorkItem )\r
1353                         {\r
1354                                 status = STATUS_INSUFFICIENT_RESOURCES;\r
1355                                 break;\r
1356                         }\r
1357 \r
1358                         /* Process in work item callback. */\r
1359                         IoQueueWorkItem(\r
1360                                 p_ext->pPoWorkItem, __DevicePowerDownWorkItem, DelayedWorkQueue, p_irp );\r
1361                 }\r
1362                 *p_action = IrpDoNothing;\r
1363                 status = STATUS_PENDING;\r
1364                 break;\r
1365 \r
1366         default:\r
1367                 /* Pass down and let the PDO driver handle it. */\r
1368                 *p_action = IrpIgnore;\r
1369                 status = STATUS_SUCCESS;\r
1370                 break;\r
1371         }\r
1372 \r
1373         if( !NT_SUCCESS( status ) )\r
1374                 *p_action = IrpComplete;\r
1375 \r
1376         HCA_EXIT( HCA_DBG_PNP );\r
1377         return status;\r
1378 }\r
1379 \r
1380 \r