81643697a6f1723908c7caf060efa6646ff327d2
[mirror/winof/.git] / core / bus / kernel / bus_iou_mgr.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.\r
4  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\r
8  *     Redistribution and use in source and binary forms, with or\r
9  *     without modification, are permitted provided that the following\r
10  *     conditions are met:\r
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\r
16  *      - Redistributions in binary form must reproduce the above\r
17  *        copyright notice, this list of conditions and the following\r
18  *        disclaimer in the documentation and/or other materials\r
19  *        provided with the distribution.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
25  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
26  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
28  * SOFTWARE.\r
29  *\r
30  * $Id$\r
31  */\r
32 \r
33 \r
34 #include <iba/ib_types.h>\r
35 #include <complib/cl_async_proc.h>\r
36 #include <complib/cl_bus_ifc.h>\r
37 #include "ib_common.h"\r
38 #include "al_ca.h"\r
39 #include "al_mgr.h"\r
40 #include "bus_pnp.h"\r
41 #include "bus_iou_mgr.h"\r
42 #include <initguid.h>\r
43 #include <wdmguid.h>\r
44 #include "iba/iou_ifc.h"\r
45 \r
46 \r
47 /* {5A9649F4-0101-4a7c-8337-796C48082DA2} */\r
48 DEFINE_GUID(GUID_BUS_TYPE_IBA, \r
49 0x5a9649f4, 0x101, 0x4a7c, 0x83, 0x37, 0x79, 0x6c, 0x48, 0x8, 0x2d, 0xa2);\r
50 \r
51 \r
52 /*\r
53  * Size of device descriptions, in the format:\r
54  *      IBA\VxxxxxxPxxxxxxxxvxxxxxxxx\r
55  */\r
56 #define IOU_DEV_ID_SIZE         sizeof(L"IBA\\VxxxxxxPxxxxvxxxxxxxx")\r
57 #define IOU_DEV_ID_STRING1      L"IBA\\V%06xP%04hxv%08x"\r
58 #define IOU_DEV_ID_STRING2      L"IBA\\V%06xP%04hx"\r
59 #define IOU_HW_ID_SIZE          \\r
60         sizeof(L"IBA\\VxxxxxxPxxxxvxxxxxxxx\0IBA\\VxxxxxxPxxxx\0\0")\r
61 #define IOU_COMPAT_ID           L"IBA\\IB_IOU\0\0"\r
62 #define IOU_LOCATION_SIZE       \\r
63         sizeof(L"Chassis 0xxxxxxxxxxxxxxxxx, Slot xx")\r
64 \r
65 /*\r
66  * Device extension for IOU PDOs.\r
67  */\r
68 typedef struct _bus_iou_ext\r
69 {\r
70         bus_pdo_ext_t                   pdo;\r
71 \r
72         net64_t                                 chassis_guid;\r
73         uint8_t                                 slot;\r
74         net64_t                                 guid;\r
75         net32_t                                 vend_id;\r
76         net16_t                                 dev_id;\r
77         net32_t                                 revision;\r
78         char                                    desc[IB_NODE_DESCRIPTION_SIZE + 1];\r
79 \r
80         /* Number of references on the upper interface. */\r
81         atomic32_t                              n_ifc_ref;\r
82 \r
83 }       bus_iou_ext_t;\r
84 \r
85 \r
86 typedef struct _iou_pnp_context\r
87 {\r
88         bus_filter_t    *p_bus_filter;\r
89         void                    *p_pdo_ext;\r
90 \r
91 }       iou_pnp_ctx_t;\r
92 \r
93 \r
94 /*\r
95  * Function prototypes.\r
96  */\r
97 void\r
98 destroying_iou_mgr(\r
99         IN                              cl_obj_t*                                       p_obj );\r
100 \r
101 void\r
102 free_iou_mgr(\r
103         IN                              cl_obj_t*                                       p_obj );\r
104 \r
105 ib_api_status_t\r
106 bus_reg_iou_pnp(\r
107         IN                              bus_filter_t*                           p_bfi );\r
108 \r
109 ib_api_status_t\r
110 iou_mgr_pnp_cb(\r
111         IN                              ib_pnp_rec_t*                           p_pnp_rec );\r
112 \r
113 ib_api_status_t\r
114 iou_mgr_iou_add(\r
115         IN                              ib_pnp_iou_rec_t*                       p_pnp_rec );\r
116 \r
117 void\r
118 iou_mgr_iou_remove(\r
119         IN                              ib_pnp_iou_rec_t*                       p_pnp_rec );\r
120 \r
121 static NTSTATUS\r
122 iou_start(\r
123         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
124         IN                              IRP* const                                      p_irp, \r
125                 OUT                     cl_irp_action_t* const          p_action );\r
126 \r
127 static NTSTATUS\r
128 iou_query_remove(\r
129         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
130         IN                              IRP* const                                      p_irp, \r
131                 OUT                     cl_irp_action_t* const          p_action );\r
132 \r
133 static void\r
134 iou_release_resources(\r
135         IN                              DEVICE_OBJECT* const            p_dev_obj );\r
136 \r
137 static NTSTATUS\r
138 iou_remove(\r
139         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
140         IN                              IRP* const                                      p_irp, \r
141                 OUT                     cl_irp_action_t* const          p_action );\r
142 \r
143 static NTSTATUS\r
144 iou_surprise_remove(\r
145         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
146         IN                              IRP* const                                      p_irp, \r
147                 OUT                     cl_irp_action_t* const          p_action );\r
148 \r
149 static NTSTATUS\r
150 iou_query_capabilities(\r
151         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
152         IN                              IRP* const                                      p_irp, \r
153                 OUT                     cl_irp_action_t* const          p_action );\r
154 \r
155 static NTSTATUS\r
156 iou_query_target_relations(\r
157         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
158         IN                              IRP* const                                      p_irp, \r
159                 OUT                     cl_irp_action_t* const          p_action );\r
160 \r
161 static NTSTATUS\r
162 iou_query_device_id(\r
163         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
164         IN                              IRP* const                                      p_irp );\r
165 \r
166 static NTSTATUS\r
167 iou_query_hardware_ids(\r
168         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
169         IN                              IRP* const                                      p_irp );\r
170 \r
171 static NTSTATUS\r
172 iou_query_compatible_ids(\r
173         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
174         IN                              IRP* const                                      p_irp );\r
175 \r
176 static NTSTATUS\r
177 iou_query_unique_id(\r
178         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
179         IN                              IRP* const                                      p_irp );\r
180 \r
181 static NTSTATUS\r
182 iou_query_description(\r
183         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
184         IN                              IRP* const                                      p_irp );\r
185 \r
186 static NTSTATUS\r
187 iou_query_location(\r
188         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
189         IN                              IRP* const                                      p_irp );\r
190 \r
191 static NTSTATUS\r
192 iou_query_bus_info(\r
193         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
194         IN                              IRP* const                                      p_irp, \r
195                 OUT                     cl_irp_action_t* const          p_action );\r
196 \r
197 static NTSTATUS\r
198 iou_query_interface(\r
199         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
200         IN                              IRP* const                                      p_irp, \r
201                 OUT                     cl_irp_action_t* const          p_action );\r
202 \r
203 static NTSTATUS\r
204 iou_set_power(\r
205         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
206         IN                              IRP* const                                      p_irp,\r
207                 OUT                     cl_irp_action_t* const          p_action );\r
208 \r
209 \r
210 \r
211 /*\r
212  * Global virtual function pointer tables shared between all \r
213  * instances of Port PDOs.\r
214  */\r
215 static const cl_vfptr_pnp_po_t          vfptr_iou_pnp = {\r
216         "IB IOU",\r
217         iou_start,\r
218         cl_irp_succeed,\r
219         cl_irp_succeed,\r
220         cl_irp_succeed,\r
221         iou_query_remove,\r
222         iou_release_resources,\r
223         iou_remove,\r
224         cl_irp_succeed,\r
225         iou_surprise_remove,\r
226         iou_query_capabilities,\r
227         cl_irp_complete,\r
228         cl_irp_complete,\r
229         cl_irp_succeed,\r
230         cl_irp_complete,\r
231         cl_irp_complete,\r
232         cl_irp_complete,\r
233         iou_query_target_relations,\r
234         cl_irp_complete,\r
235         cl_irp_complete,\r
236         cl_irp_complete,\r
237         iou_query_bus_info,\r
238         iou_query_interface,\r
239         cl_irp_complete,\r
240         cl_irp_complete,\r
241         cl_irp_complete,\r
242         cl_irp_complete,\r
243         cl_irp_succeed,                         // QueryPower\r
244         iou_set_power,                          // SetPower\r
245         cl_irp_unsupported,                     // PowerSequence\r
246         cl_irp_unsupported                      // WaitWake\r
247 };\r
248 \r
249 \r
250 static const cl_vfptr_query_txt_t               vfptr_iou_query_txt = {\r
251         iou_query_device_id,\r
252         iou_query_hardware_ids,\r
253         iou_query_compatible_ids,\r
254         iou_query_unique_id,\r
255         iou_query_description,\r
256         iou_query_location\r
257 };\r
258 \r
259 \r
260 /*\r
261  * Create the AL load service.\r
262  */\r
263 ib_api_status_t\r
264 create_iou_mgr(\r
265         IN                              bus_filter_t*                           p_bfi )\r
266 {\r
267         ib_api_status_t         status;\r
268         cl_status_t                     cl_status;\r
269         iou_mgr_t                       *gp_iou_mgr;\r
270 \r
271         BUS_ENTER( BUS_DBG_PNP );\r
272 \r
273         CL_ASSERT( p_bfi->p_iou_mgr == NULL );\r
274 \r
275         gp_iou_mgr = cl_zalloc( sizeof(iou_mgr_t) );\r
276         if( !gp_iou_mgr )\r
277         {\r
278                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
279                         ("Failed to allocate IOU manager.\n") );\r
280                 return IB_INSUFFICIENT_MEMORY;\r
281         }\r
282         p_bfi->p_iou_mgr = gp_iou_mgr;\r
283 \r
284         /* Construct the load service. */\r
285         cl_obj_construct( &gp_iou_mgr->obj, AL_OBJ_TYPE_LOADER );\r
286 \r
287         p_bfi->p_iou_mgr_obj = &p_bfi->p_iou_mgr->obj; // save for destroy & free\r
288 \r
289         cl_mutex_construct( &gp_iou_mgr->pdo_mutex );\r
290         cl_qlist_init( &gp_iou_mgr->iou_list );\r
291 \r
292         cl_status = cl_mutex_init( &gp_iou_mgr->pdo_mutex );\r
293         if( cl_status != CL_SUCCESS )\r
294         {\r
295                 free_iou_mgr( &gp_iou_mgr->obj );\r
296                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
297                         ("cl_mutex_init returned %#x.\n", cl_status) );\r
298                 return ib_convert_cl_status( cl_status );\r
299         }\r
300 \r
301         /* Initialize the load service object. */\r
302         cl_status = cl_obj_init( &gp_iou_mgr->obj, CL_DESTROY_SYNC,\r
303                                                          destroying_iou_mgr, NULL, free_iou_mgr );\r
304         if( cl_status != CL_SUCCESS )\r
305         {\r
306                 free_iou_mgr( &gp_iou_mgr->obj );\r
307                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
308                         ("cl_obj_init returned %#x.\n", cl_status) );\r
309                 return ib_convert_cl_status( cl_status );\r
310         }\r
311 \r
312         /* Register for IOU PnP events. */\r
313         status = bus_reg_iou_pnp( p_bfi );\r
314         if( status != IB_SUCCESS )\r
315         {\r
316                 free_iou_mgr( &gp_iou_mgr->obj );\r
317                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
318                         ("bus_reg_iou_pnp returned %s.\n", ib_get_err_str(status)) );\r
319                 return status;\r
320         }\r
321 \r
322         BUS_EXIT( BUS_DBG_PNP );\r
323         return IB_SUCCESS;\r
324 }\r
325 \r
326 \r
327 /*\r
328  * Pre-destroy the load service.\r
329  */\r
330 void\r
331 destroying_iou_mgr(\r
332         IN                              cl_obj_t*                                       p_obj )\r
333 {\r
334         ib_api_status_t                 status;\r
335         bus_filter_t                    *p_bfi;\r
336         iou_mgr_t                               *gp_iou_mgr;\r
337 \r
338         BUS_ENTER( BUS_DBG_PNP );\r
339 \r
340         CL_ASSERT( p_obj );\r
341         p_bfi = get_bfi_by_obj( BFI_IOU_MGR_OBJ, p_obj );\r
342         if (p_bfi == NULL) {\r
343                 BUS_PRINT(BUS_DBG_PNP, ("Failed to find p_bfi by obj %p?\n", p_obj));\r
344                 return;\r
345         }\r
346         gp_iou_mgr = p_bfi->p_iou_mgr;\r
347 \r
348         BUS_PRINT(BUS_DBG_PNP, ("%s obj %p iou_mgr %p iou_mgr_obj %p\n",\r
349                                                         p_bfi->whoami, p_obj,gp_iou_mgr,&gp_iou_mgr->obj));\r
350 \r
351         CL_ASSERT( gp_iou_mgr == PARENT_STRUCT( p_obj, iou_mgr_t, obj ) );\r
352 \r
353         /* Deregister for iou PnP events. */\r
354         if( get_bfi_count() == 1 && bus_globals.h_pnp_iou )\r
355         {\r
356                 status = ib_dereg_pnp( bus_globals.h_pnp_iou, NULL );\r
357                 bus_globals.h_pnp_iou = NULL;\r
358                 CL_ASSERT( status == IB_SUCCESS );\r
359         }\r
360         cl_obj_deref( p_bfi->p_iou_mgr_obj );\r
361 \r
362         BUS_EXIT( BUS_DBG_PNP );\r
363 }\r
364 \r
365 \r
366 /*\r
367  * Free the load service.\r
368  */\r
369 void\r
370 free_iou_mgr(\r
371         IN                              cl_obj_t*                                       p_obj )\r
372 {\r
373         bus_pdo_ext_t   *p_ext;\r
374         cl_list_item_t  *p_list_item;\r
375         bus_filter_t    *p_bfi;\r
376         iou_mgr_t               *gp_iou_mgr;\r
377 \r
378         BUS_ENTER( BUS_DBG_PNP );\r
379 \r
380         CL_ASSERT( p_obj );\r
381         p_bfi = get_bfi_by_obj( BFI_IOU_MGR_OBJ, p_obj );\r
382         if ( p_bfi == NULL ) {\r
383                 BUS_TRACE( BUS_DBG_ERROR, ("Unable to get p_bfi iou_obj %p?\n", p_obj) );\r
384                 return;\r
385         }\r
386         gp_iou_mgr = p_bfi->p_iou_mgr;\r
387         if ( !gp_iou_mgr ) {\r
388                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("%s <null> IOU mgr?\n",p_bfi->whoami) );\r
389                 // if create fails & then free is called, p_bfi->p_iou_mgr == NULL\r
390                 return;\r
391         }\r
392 \r
393         CL_ASSERT( gp_iou_mgr == PARENT_STRUCT( p_obj, iou_mgr_t, obj ) );\r
394 \r
395         BUS_PRINT( BUS_DBG_PNP, ("%s Mark all IOU PDOs as no longer present\n",\r
396                                                                 p_bfi->whoami));\r
397         /*\r
398          * Mark all IOU PDOs as no longer present.  This will cause them\r
399          * to be removed when they process the IRP_MN_REMOVE_DEVICE.\r
400          */\r
401         p_list_item = cl_qlist_remove_head( &gp_iou_mgr->iou_list );\r
402         while( p_list_item != cl_qlist_end( &gp_iou_mgr->iou_list ) )\r
403         {\r
404                 p_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
405                 p_list_item = cl_qlist_remove_head( &gp_iou_mgr->iou_list );\r
406                 if( p_ext->cl_ext.pnp_state == SurpriseRemoved )\r
407                 {\r
408                         CL_ASSERT( !p_ext->b_present );\r
409                         p_ext->b_reported_missing = TRUE;\r
410                         BUS_TRACE( BUS_DBG_PNP,\r
411                                         ("%s Surprise-remove %s: ext %p, present %d, missing %d\n",\r
412                                                 p_bfi->whoami,\r
413                                                 p_ext->cl_ext.vfptr_pnp_po->identity, p_ext,\r
414                                                 p_ext->b_present, p_ext->b_reported_missing ) );\r
415                         continue;\r
416                 }\r
417 \r
418                 if( p_ext->h_ca )\r
419                 {\r
420                         /* Invalidate bus relations for the HCA. */\r
421                         IoInvalidateDeviceRelations(\r
422                                 p_ext->h_ca->p_hca_dev, BusRelations );\r
423 \r
424                         /* Release the reference on the CA object. */\r
425                         deref_al_obj( &p_ext->h_ca->obj );\r
426                 }\r
427 \r
428                 BUS_TRACE( BUS_DBG_PNP, ("Deleted device %s %s: PDO %p, ext %p\n",\r
429                                         p_bfi->whoami, p_ext->cl_ext.vfptr_pnp_po->identity,\r
430                                         p_ext->cl_ext.p_self_do, p_ext ) );\r
431 \r
432                 IoDeleteDevice( p_ext->cl_ext.p_self_do );\r
433         }\r
434 \r
435         cl_mutex_destroy( &gp_iou_mgr->pdo_mutex );\r
436         cl_obj_deinit( p_obj );\r
437         cl_free( gp_iou_mgr );\r
438 \r
439         p_bfi->p_iou_mgr = NULL;\r
440         p_bfi->p_iou_mgr_obj = NULL;\r
441 \r
442         BUS_EXIT( BUS_DBG_PNP );\r
443 }\r
444 \r
445 \r
446 /*\r
447  * Register the load service for the given PnP class events.\r
448  */\r
449 ib_api_status_t\r
450 bus_reg_iou_pnp( IN bus_filter_t *p_bfi )\r
451 {\r
452         ib_pnp_req_t                    pnp_req;\r
453         ib_api_status_t                 status = IB_SUCCESS;\r
454         boolean_t                               need_pnp_reg = FALSE;\r
455 \r
456         /* only need to register for IOU PNP events once.\r
457          * do not hold mutex over pnp_reg() call as callback which needs mutex\r
458          * could occur.\r
459          */\r
460         if ( !bus_globals.h_pnp_iou )\r
461         {\r
462                 lock_control_event();\r
463                 if ( !bus_globals.h_pnp_iou )\r
464                 {\r
465                         bus_globals.h_pnp_iou = (ib_pnp_handle_t)1; /* block others */ \r
466                         need_pnp_reg = TRUE;\r
467                 }\r
468                 unlock_control_event();\r
469 \r
470                 if ( need_pnp_reg )\r
471                 {\r
472                         cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) );\r
473                         pnp_req.pnp_class       = IB_PNP_IOU | IB_PNP_FLAG_REG_SYNC;\r
474                         pnp_req.pnp_context = NULL;\r
475                         pnp_req.pfn_pnp_cb      = iou_mgr_pnp_cb;\r
476 \r
477                         status = ib_reg_pnp( gh_al, &pnp_req, &bus_globals.h_pnp_iou );\r
478                 }\r
479         }\r
480 \r
481         if ( status == IB_SUCCESS )\r
482         {\r
483                 /* Reference the load service on behalf of the ib_reg_pnp call. */\r
484                 cl_obj_ref( p_bfi->p_iou_mgr_obj );\r
485         }\r
486 \r
487         return status;\r
488 }\r
489 \r
490 \r
491 /*\r
492  * Load service PnP event callback.\r
493  */\r
494 ib_api_status_t\r
495 iou_mgr_pnp_cb(\r
496         IN                              ib_pnp_rec_t*                           p_pnp_rec )\r
497 {\r
498         ib_api_status_t         status=IB_SUCCESS;\r
499 \r
500         BUS_ENTER( BUS_DBG_PNP );\r
501 \r
502         CL_ASSERT( p_pnp_rec );\r
503 \r
504         switch( p_pnp_rec->pnp_event )\r
505         {\r
506         case IB_PNP_IOU_ADD:\r
507                 status = iou_mgr_iou_add( (ib_pnp_iou_rec_t*)p_pnp_rec );\r
508                 break;\r
509 \r
510         case IB_PNP_IOU_REMOVE:\r
511                 iou_mgr_iou_remove( (ib_pnp_iou_rec_t*)p_pnp_rec );\r
512                 break;\r
513 \r
514         default:\r
515                 BUS_PRINT( BUS_DBG_PNP, ("Unhandled PNP Event %s\n",\r
516                                         ib_get_pnp_event_str(p_pnp_rec->pnp_event) ));\r
517                 break;\r
518         }\r
519         BUS_EXIT( BUS_DBG_PNP );\r
520         return status;\r
521 }\r
522 \r
523 \r
524 /*\r
525  * Called to get child relations for the bus root.\r
526  */\r
527 NTSTATUS\r
528 iou_mgr_get_bus_relations(\r
529         IN              const   net64_t                                         ca_guid,\r
530         IN                              IRP* const                                      p_irp )\r
531 {\r
532         NTSTATUS                        status;\r
533         bus_filter_t            *p_bfi;\r
534         iou_mgr_t                       *gp_iou_mgr;\r
535         DEVICE_RELATIONS        *p_rel;\r
536 \r
537         BUS_ENTER( BUS_DBG_PNP );\r
538 \r
539         BUS_PRINT(BUS_DBG_PNP, ("CA_guid %I64x\n",ca_guid));\r
540 \r
541         /* special case guid == 0 - walk all bus filter instances */\r
542         if ( ca_guid == 0ULL ) {\r
543                 for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++) {\r
544                         gp_iou_mgr = p_bfi->p_iou_mgr;\r
545                         if ( !gp_iou_mgr )\r
546                                 continue;\r
547                         cl_mutex_acquire( &gp_iou_mgr->pdo_mutex );\r
548                         status = bus_get_relations( &gp_iou_mgr->iou_list, ca_guid, p_irp );\r
549                         cl_mutex_release( &gp_iou_mgr->pdo_mutex );\r
550                 }\r
551                 p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
552                 if ( p_rel ) {\r
553                         BUS_PRINT(BUS_DBG_PNP, ("CA_guid 0 Reports %d relations\n", p_rel->Count));\r
554                 }\r
555                 BUS_EXIT( BUS_DBG_PNP );\r
556                 return STATUS_SUCCESS;\r
557         }\r
558 \r
559         p_bfi = get_bfi_by_ca_guid(ca_guid);\r
560         if (p_bfi == NULL) {\r
561                 BUS_TRACE_EXIT(BUS_DBG_PNP,\r
562                                                                 ("NULL p_bfi from ca_guid %I64x ?\n",ca_guid));\r
563                 return STATUS_UNSUCCESSFUL;\r
564         }\r
565         gp_iou_mgr = p_bfi->p_iou_mgr;\r
566 \r
567         BUS_PRINT(BUS_DBG_PNP, ("%s for ca_guid %I64x iou_mgr %p\n",\r
568                                                         p_bfi->whoami, ca_guid, gp_iou_mgr) );\r
569         if (!gp_iou_mgr)\r
570                 return STATUS_NO_SUCH_DEVICE;\r
571 \r
572         cl_mutex_acquire( &gp_iou_mgr->pdo_mutex );\r
573         status = bus_get_relations( &gp_iou_mgr->iou_list, ca_guid, p_irp );\r
574         cl_mutex_release( &gp_iou_mgr->pdo_mutex );\r
575 \r
576         BUS_EXIT( BUS_DBG_PNP );\r
577         return status;\r
578 }\r
579 \r
580 \r
581 static ib_api_status_t\r
582 __iou_was_hibernated(\r
583         IN                              ib_pnp_iou_rec_t*                       p_pnp_rec,\r
584         IN                              bus_filter_t*                           p_bfi )\r
585 {\r
586         ib_api_status_t status;\r
587         cl_list_item_t  *p_list_item;\r
588         bus_iou_ext_t   *p_iou_ext;\r
589         bus_pdo_ext_t   *p_pdo_ext = NULL;\r
590         size_t                  n_devs = 0;\r
591         iou_mgr_t               *gp_iou_mgr = p_bfi->p_iou_mgr;\r
592         cl_qlist_t              *p_pdo_list = &gp_iou_mgr->iou_list;\r
593         iou_pnp_ctx_t   *p_ctx = p_pnp_rec->pnp_rec.context;\r
594 \r
595         BUS_ENTER( BUS_DBG_PNP );\r
596         \r
597         cl_mutex_acquire( &gp_iou_mgr->pdo_mutex );\r
598         \r
599         /* Count the number of child devices. */\r
600         for( p_list_item = cl_qlist_head( p_pdo_list );\r
601                 p_list_item != cl_qlist_end( p_pdo_list );\r
602                 p_list_item = cl_qlist_next( p_list_item ) )\r
603         {\r
604                 p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
605                 p_iou_ext = (bus_iou_ext_t*)p_pdo_ext;\r
606 \r
607                 /* TODO: maybe we need more search patterns like vend_id, dev_id ... */\r
608                 if( p_pdo_ext->b_present && p_pdo_ext->b_hibernating &&\r
609                         (p_iou_ext->guid == p_pnp_rec->pnp_rec.guid) )\r
610                 {\r
611                         n_devs++;\r
612                         break;\r
613                 }\r
614 \r
615                 BUS_TRACE( BUS_DBG_PNP, ("%s Skipped PDO for %s: PDO %p, ext %p, "\r
616                         "present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
617                         p_bfi->whoami,\r
618                         p_pdo_ext->cl_ext.vfptr_pnp_po->identity,\r
619                         p_pdo_ext->cl_ext.p_self_do, \r
620                         p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
621                         p_pdo_ext->b_hibernating, p_iou_ext->guid ) );\r
622         }\r
623 \r
624         if (n_devs)\r
625         {\r
626                 /* Take a reference on the parent HCA. */\r
627                 p_pdo_ext->h_ca = acquire_ca( p_pnp_rec->ca_guid );\r
628                 if( !p_pdo_ext->h_ca )\r
629                 {\r
630                         BUS_TRACE( BUS_DBG_ERROR,\r
631                                 ("acquire_ca failed to find CA by guid %I64x\n",\r
632                                 p_pnp_rec->ca_guid ) );\r
633                         status = IB_INVALID_GUID;\r
634                 }\r
635                 else \r
636                 {\r
637                         p_pdo_ext->b_hibernating = FALSE;\r
638                         p_ctx->p_pdo_ext = p_pdo_ext; // for iou_mgr_iou_remove()\r
639 \r
640                         status = IB_SUCCESS;\r
641                         p_iou_ext = (bus_iou_ext_t*)p_pdo_ext;\r
642                         BUS_TRACE( BUS_DBG_PNP, ("%s Found PDO for %s: PDO %p, ext %p, "\r
643                                 "present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
644                                 p_bfi->whoami,\r
645                                 p_pdo_ext->cl_ext.vfptr_pnp_po->identity,\r
646                                 p_pdo_ext->cl_ext.p_self_do, \r
647                                 p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
648                                 p_pdo_ext->b_hibernating, p_iou_ext->guid ) );\r
649                 }\r
650         }\r
651         else \r
652         {\r
653                 BUS_TRACE( BUS_DBG_PNP, ("%s Failed to find PDO for guid %I64x\n",\r
654                                                                 p_bfi->whoami, p_pnp_rec->pnp_rec.guid ) );\r
655                 status = IB_NOT_FOUND;\r
656         }\r
657 \r
658         cl_mutex_release( &gp_iou_mgr->pdo_mutex );\r
659 \r
660         BUS_EXIT( BUS_DBG_PNP );\r
661         return status;\r
662 }\r
663 \r
664 ib_api_status_t\r
665 iou_mgr_iou_add(\r
666         IN                              ib_pnp_iou_rec_t*                       p_pnp_rec )\r
667 {\r
668         NTSTATUS                status;\r
669         DEVICE_OBJECT   *p_pdo;\r
670         bus_iou_ext_t   *p_iou_ext;\r
671         bus_filter_t    *p_bfi;\r
672         iou_mgr_t               *gp_iou_mgr;\r
673         iou_pnp_ctx_t   *p_ctx = p_pnp_rec->pnp_rec.context;\r
674 \r
675         BUS_ENTER( BUS_DBG_PNP );\r
676 \r
677         p_bfi = get_bfi_by_ca_guid( p_pnp_rec->ca_guid );\r
678         if ( !p_bfi ) {\r
679                 BUS_TRACE_EXIT( BUS_DBG_PNP,("NULL p_bfi? ca_guid 0x%I64x\n",\r
680                                                                         p_pnp_rec->ca_guid ) );\r
681                 return IB_ERROR;\r
682         }\r
683 \r
684         if ( !p_ctx ) {\r
685                 /*\r
686                  * Allocate a PNP context for this object. pnp_rec.context is object\r
687                  * unique.\r
688                  */\r
689                 p_ctx = cl_zalloc( sizeof(*p_ctx) );\r
690                 if( !p_ctx )\r
691                 {\r
692                         BUS_TRACE_EXIT(BUS_DBG_PNP, ("%s ca_guid %I64x iou_guid(%I64x) "\r
693                                         "BAD alloc for PNP context\n", p_bfi->whoami,\r
694                                         p_bfi->ca_guid, p_pnp_rec->guid ));\r
695 \r
696                         return IB_ERROR;\r
697                 }\r
698                 p_ctx->p_bus_filter = p_bfi;\r
699                 p_pnp_rec->pnp_rec.context = p_ctx;\r
700 \r
701                 BUS_PRINT(BUS_DBG_PNP,\r
702                                         ("%s ca_guid %I64x iou_guid(%I64x) ALLOC p_ctx @ %p\n",\r
703                                         p_bfi->whoami, p_bfi->ca_guid, p_pnp_rec->guid,p_ctx));\r
704         }\r
705         gp_iou_mgr = p_bfi->p_iou_mgr;\r
706 \r
707         /* Upon hibernating the computer IB_BUS driver doesn't remove PDO, but\r
708            marks with a flag. So we first try to find an existing PDO for this port,\r
709            marked with this flag. If it was found, we turn off the flag and use\r
710            this PDO */\r
711         status = __iou_was_hibernated( p_pnp_rec, p_bfi );\r
712         if( status != IB_NOT_FOUND )\r
713         {\r
714                 BUS_EXIT( BUS_DBG_PNP );\r
715                 return status;\r
716         }\r
717 \r
718         /* Create the PDO for the new port device. */\r
719         status = IoCreateDevice( bus_globals.p_driver_obj, sizeof(bus_iou_ext_t),\r
720                                                          NULL, FILE_DEVICE_CONTROLLER, \r
721                                                          FILE_DEVICE_SECURE_OPEN |\r
722                                                                                         FILE_AUTOGENERATED_DEVICE_NAME,\r
723                                                          FALSE, &p_pdo );\r
724 \r
725         if( !NT_SUCCESS( status ) )\r
726         {\r
727                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
728                         ("IoCreateDevice returned %08x.\n", status) );\r
729                 return IB_ERROR;\r
730         }\r
731 \r
732         p_iou_ext = p_pdo->DeviceExtension;\r
733         memset( p_iou_ext, 0, sizeof(bus_iou_ext_t) );\r
734 \r
735         /* Initialize the device extension. */\r
736         cl_init_pnp_po_ext( p_pdo, NULL, p_pdo, bus_globals.dbg_lvl,\r
737                                                 &vfptr_iou_pnp, &vfptr_iou_query_txt );\r
738 \r
739         /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */\r
740         p_pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;\r
741         \r
742         p_iou_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0;\r
743         p_iou_ext->pdo.p_parent_ext = p_bfi->p_bus_ext;\r
744         p_iou_ext->pdo.b_present = TRUE;\r
745         p_iou_ext->pdo.b_reported_missing = FALSE;\r
746 \r
747         BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n",\r
748                 p_iou_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_iou_ext,\r
749                 p_iou_ext->pdo.b_present, p_iou_ext->pdo.b_reported_missing ) );\r
750 \r
751         p_iou_ext->guid = p_pnp_rec->guid;\r
752         p_iou_ext->chassis_guid = p_pnp_rec->chassis_guid;\r
753         p_iou_ext->slot = p_pnp_rec->slot;\r
754         p_iou_ext->vend_id = cl_ntoh32( p_pnp_rec->vend_id );\r
755         if( p_iou_ext->vend_id == 0x00066a )\r
756                 p_iou_ext->dev_id = (net16_t)(p_pnp_rec->pnp_rec.guid >> 32) & 0x00FF;\r
757         else\r
758                 p_iou_ext->dev_id = cl_ntoh16( p_pnp_rec->dev_id );\r
759         p_iou_ext->revision = cl_ntoh32( p_pnp_rec->revision );\r
760         cl_memcpy( p_iou_ext->desc, p_pnp_rec->desc,\r
761                 IB_NODE_DESCRIPTION_SIZE + 1 );\r
762         p_iou_ext->n_ifc_ref = 0;\r
763 \r
764         /* Cache the CA GUID. */\r
765         p_iou_ext->pdo.ca_guid = p_pnp_rec->ca_guid;\r
766 \r
767         /* Take a reference on the parent HCA. */\r
768         p_iou_ext->pdo.h_ca = acquire_ca( p_pnp_rec->ca_guid );\r
769         if( !p_iou_ext->pdo.h_ca )\r
770         {\r
771                 IoDeleteDevice( p_pdo );\r
772                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("acquire_ca failed to find CA.\n") );\r
773                 return IB_INVALID_GUID;\r
774         }\r
775 \r
776         /* Store the device extension in the PDO list for future queries. */\r
777         cl_mutex_acquire( &gp_iou_mgr->pdo_mutex );\r
778         cl_qlist_insert_tail( &gp_iou_mgr->iou_list, &p_iou_ext->pdo.list_item );\r
779         cl_mutex_release( &gp_iou_mgr->pdo_mutex );\r
780 \r
781         /*\r
782          * Set the context of the PNP event.  The context is passed in for future\r
783          * events on the same port.\r
784          */\r
785         /* if not set in iou_was_hibernated(), set now */\r
786         if ( !p_ctx->p_pdo_ext )\r
787                 p_ctx->p_pdo_ext = p_iou_ext;\r
788 \r
789         /* Tell the PnP Manager to rescan for the HCA's bus relations. */\r
790         IoInvalidateDeviceRelations(\r
791                         p_iou_ext->pdo.h_ca->p_hca_dev, BusRelations );\r
792 \r
793         /* Invalidate removal relations for the bus driver. */\r
794         IoInvalidateDeviceRelations(\r
795                 p_bfi->p_bus_ext->cl_ext.p_pdo, RemovalRelations );\r
796 \r
797         BUS_EXIT( BUS_DBG_PNP );\r
798 \r
799         return IB_SUCCESS;\r
800 }\r
801 \r
802 \r
803 void\r
804 iou_mgr_iou_remove(\r
805         IN                              ib_pnp_iou_rec_t*                       p_pnp_rec )\r
806 {\r
807         bus_pdo_ext_t   *p_ext;\r
808         iou_mgr_t               *gp_iou_mgr;\r
809         bus_filter_t    *p_bfi;\r
810         iou_pnp_ctx_t   *p_ctx = p_pnp_rec->pnp_rec.context;\r
811 \r
812         BUS_ENTER( BUS_DBG_PNP );\r
813 \r
814         if ( !p_ctx ) {\r
815                 BUS_EXIT( BUS_DBG_PNP );\r
816                 return;\r
817         }\r
818 \r
819         CL_ASSERT( p_ctx->p_bus_filter->magic == BFI_MAGIC );\r
820         p_bfi = p_ctx->p_bus_filter;\r
821         CL_ASSERT( p_bfi );\r
822 \r
823         BUS_PRINT(BUS_DBG_PNP,("%s ca_guid 0x%I64x iou_mgr %p\n",\r
824                                 p_bfi->whoami, p_bfi->ca_guid, p_bfi->p_iou_mgr));\r
825 \r
826         /* fdo_release_resources() has destroyed the IOU mgr, all that needs to be\r
827          * done is cleanup the PNP IOU context; one per port.\r
828          */\r
829         if ( p_bfi->ca_guid == 0ULL || !p_bfi->p_iou_mgr ) {\r
830                 cl_free( p_ctx );\r
831                 p_pnp_rec->pnp_rec.context = NULL;\r
832                 BUS_EXIT( BUS_DBG_PNP );\r
833                 return;\r
834         }\r
835 \r
836         gp_iou_mgr = p_bfi->p_iou_mgr;\r
837 \r
838         /* Within the PNP record's context is the IOU extension; see\r
839          * was_hibernated().\r
840          */\r
841         p_ext = p_ctx->p_pdo_ext;\r
842         CL_ASSERT( p_ext );\r
843 \r
844         if (p_bfi != p_ext->p_parent_ext->bus_filter) {\r
845                 BUS_PRINT(BUS_DBG_PNP,\r
846                         ("p_bfi(%p) != p_ext->bus_filter(%p) line %d file %s\n",\r
847                         p_bfi,p_ext->p_parent_ext->bus_filter, __LINE__,__FILE__));\r
848                 CL_ASSERT (p_bfi == p_ext->p_parent_ext->bus_filter);\r
849         }\r
850 \r
851         /*\r
852          * Flag the port PDO as no longer being present.  We have to wait until\r
853          * the PnP manager removes it to clean up.  However, we do release the\r
854          * reference on the CA object in order to allow the removal of the HCA\r
855          * to proceed should it occur before the port's PDO is cleaned up.\r
856          */\r
857         cl_mutex_acquire( &gp_iou_mgr->pdo_mutex );\r
858         if ( !p_ext->h_ca )\r
859         {\r
860                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("NULL h_ca? p_ext %p\n", p_ext ) );\r
861                 return;\r
862         }\r
863 \r
864         if( p_ext->b_hibernating )\r
865         {\r
866                 BUS_TRACE( BUS_DBG_PNP, ("%s Skip port removing for %s: PDO %p ext %p "\r
867                         "present %d missing %d hibernating %d\n",\r
868                         p_bfi->whoami,\r
869                         p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do,\r
870                         p_ext, p_ext->b_present, \r
871                         p_ext->b_reported_missing, p_ext->b_hibernating ) );\r
872                 goto hca_deref;\r
873         }\r
874 \r
875         p_ext->b_present = FALSE;\r
876         p_ext->b_reported_missing = TRUE;\r
877 \r
878         BUS_TRACE( BUS_DBG_PNP, ("%s %s: ext %p, present %d, missing %d .\n",\r
879                                 p_bfi->whoami,\r
880                                 p_ext->cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->b_present,\r
881                                 p_ext->b_reported_missing ) );\r
882 \r
883         /* Invalidate removal relations for the bus driver. */\r
884         IoInvalidateDeviceRelations(\r
885                 p_bfi->p_bus_ext->cl_ext.p_pdo, RemovalRelations );\r
886 \r
887         /* Invalidate bus relations for the HCA. */\r
888         IoInvalidateDeviceRelations(\r
889                 p_ext->h_ca->p_hca_dev, BusRelations );\r
890 \r
891 hca_deref:\r
892         /* free PNP context */\r
893         cl_free( p_ctx );\r
894         p_pnp_rec->pnp_rec.context = NULL;\r
895 \r
896         deref_al_obj( &p_ext->h_ca->obj );\r
897         p_ext->h_ca = NULL;\r
898 \r
899         cl_mutex_release( &gp_iou_mgr->pdo_mutex );\r
900 \r
901         BUS_EXIT( BUS_DBG_PNP );\r
902 }\r
903 \r
904 \r
905 static NTSTATUS\r
906 iou_start(\r
907         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
908         IN                                      IRP* const                              p_irp, \r
909                 OUT                             cl_irp_action_t* const  p_action )\r
910 {\r
911         bus_pdo_ext_t   *p_ext;\r
912 \r
913         BUS_ENTER( BUS_DBG_PNP );\r
914 \r
915         UNUSED_PARAM( p_irp );\r
916 \r
917         p_ext = p_dev_obj->DeviceExtension;\r
918 \r
919         /* Notify the Power Manager that the device is started. */\r
920         PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
921 \r
922         *p_action = IrpComplete;\r
923         BUS_EXIT( BUS_DBG_PNP );\r
924         return STATUS_SUCCESS;\r
925 }\r
926 \r
927 \r
928 static NTSTATUS\r
929 iou_query_remove(\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         bus_iou_ext_t   *p_ext;\r
935 \r
936         BUS_ENTER( BUS_DBG_PNP );\r
937 \r
938         UNUSED_PARAM( p_irp );\r
939 \r
940         p_ext = p_dev_obj->DeviceExtension;\r
941 \r
942         *p_action = IrpComplete;\r
943         if( p_ext->n_ifc_ref )\r
944         {\r
945                 /*\r
946                  * Our interface is still being held by someone.\r
947                  * Rollback the PnP state that was changed in the complib handler.\r
948                  */\r
949                 cl_rollback_pnp_state( &p_ext->pdo.cl_ext );\r
950 \r
951                 /* Fail the query. */\r
952                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Failing IRP_MN_QUERY_REMOVE_DEVICE:\n"\r
953                         "\tInterface has %d reference\n", p_ext->n_ifc_ref ) );\r
954                 return STATUS_UNSUCCESSFUL;\r
955         }\r
956 \r
957         BUS_EXIT( BUS_DBG_PNP );\r
958         return STATUS_SUCCESS;\r
959 }\r
960 \r
961 \r
962 static void\r
963 iou_release_resources(\r
964         IN                                      DEVICE_OBJECT* const    p_dev_obj )\r
965 {\r
966         bus_iou_ext_t   *p_ext;\r
967         POWER_STATE             po_state;\r
968         iou_mgr_t               *gp_iou_mgr;\r
969 \r
970         BUS_ENTER( BUS_DBG_PNP );\r
971 \r
972         p_ext = p_dev_obj->DeviceExtension;\r
973         gp_iou_mgr = p_ext->pdo.p_parent_ext->bus_filter->p_iou_mgr;\r
974 \r
975         /* Remove this PDO from its list. */\r
976         cl_mutex_acquire( &gp_iou_mgr->pdo_mutex );\r
977         BUS_TRACE( BUS_DBG_PNP, ("Removing IOU from list.\n") );\r
978         cl_qlist_remove_item( &gp_iou_mgr->iou_list, &p_ext->pdo.list_item );\r
979         cl_mutex_release( &gp_iou_mgr->pdo_mutex );\r
980         po_state.DeviceState = PowerDeviceD3;\r
981         PoSetPowerState( p_ext->pdo.cl_ext.p_pdo, DevicePowerState, po_state );\r
982 \r
983         BUS_EXIT( BUS_DBG_PNP );\r
984 }\r
985 \r
986 \r
987 static NTSTATUS\r
988 iou_remove(\r
989         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
990         IN                                      IRP* const                              p_irp, \r
991                 OUT                             cl_irp_action_t* const  p_action )\r
992 {\r
993         bus_iou_ext_t   *p_ext;\r
994 \r
995         BUS_ENTER( BUS_DBG_PNP );\r
996 \r
997         p_ext = p_dev_obj->DeviceExtension;\r
998 \r
999         if( p_ext->pdo.b_present )\r
1000         {\r
1001                 CL_ASSERT( p_ext->pdo.cl_ext.pnp_state != NotStarted );\r
1002                 CL_ASSERT( !p_ext->pdo.b_reported_missing );\r
1003                 /* Reset the state to NotStarted.  CompLib set it to Deleted. */\r
1004                 cl_set_pnp_state( &p_ext->pdo.cl_ext, NotStarted );\r
1005                 /* Don't delete the device.  It may simply be disabled. */\r
1006                 *p_action = IrpComplete;\r
1007                 BUS_TRACE_EXIT( BUS_DBG_PNP,\r
1008                                 ("Device %s still present: PDO %p, ext %p\n",\r
1009                                 p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_dev_obj, p_ext) );\r
1010                 return STATUS_SUCCESS;\r
1011         }\r
1012 \r
1013         if( !p_ext->pdo.b_reported_missing )\r
1014         {\r
1015                 /* Reset the state to RemovePending.  Complib set it to Deleted. */\r
1016                 cl_rollback_pnp_state( &p_ext->pdo.cl_ext );\r
1017                 *p_action = IrpComplete;\r
1018                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device not reported missing yet.\n") );\r
1019                 return STATUS_SUCCESS;\r
1020         }\r
1021 \r
1022         /* Wait for all I/O operations to complete. */\r
1023         IoReleaseRemoveLockAndWait( &p_ext->pdo.cl_ext.remove_lock, p_irp );\r
1024 \r
1025         /* Release resources if it was not done yet. */\r
1026         if( p_ext->pdo.cl_ext.last_pnp_state != SurpriseRemoved )\r
1027                 p_ext->pdo.cl_ext.vfptr_pnp_po->pfn_release_resources( p_dev_obj );\r
1028 \r
1029         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
1030         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1031 \r
1032         IoDeleteDevice( p_dev_obj );\r
1033 \r
1034         *p_action = IrpDoNothing;\r
1035         BUS_EXIT( BUS_DBG_PNP );\r
1036         return STATUS_SUCCESS;\r
1037 }\r
1038 \r
1039 \r
1040 static NTSTATUS\r
1041 iou_surprise_remove(\r
1042         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1043         IN                              IRP* const                                      p_irp, \r
1044                 OUT                     cl_irp_action_t* const          p_action )\r
1045 {\r
1046         bus_iou_ext_t   *p_ext;\r
1047 \r
1048         BUS_ENTER( BUS_DBG_PNP );\r
1049 \r
1050         UNUSED_PARAM( p_irp );\r
1051 \r
1052         p_ext = p_dev_obj->DeviceExtension;\r
1053         p_ext->pdo.b_present = FALSE;\r
1054         p_ext->pdo.b_reported_missing = TRUE;\r
1055 \r
1056         BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n",\r
1057                                 p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext,\r
1058                                 p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) );\r
1059 \r
1060         *p_action = IrpComplete;\r
1061 \r
1062         BUS_EXIT( BUS_DBG_PNP );\r
1063         return STATUS_SUCCESS;\r
1064 }\r
1065 \r
1066 \r
1067 static NTSTATUS\r
1068 iou_query_capabilities(\r
1069         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1070         IN                                      IRP* const                              p_irp, \r
1071                 OUT                             cl_irp_action_t* const  p_action )\r
1072 {\r
1073         DEVICE_CAPABILITIES             *p_caps;\r
1074         IO_STACK_LOCATION               *p_io_stack;\r
1075 \r
1076         BUS_ENTER( BUS_DBG_PNP );\r
1077 \r
1078         UNUSED_PARAM( p_dev_obj );\r
1079 \r
1080         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1081         p_caps = p_io_stack->Parameters.DeviceCapabilities.Capabilities;\r
1082 \r
1083         p_caps->DeviceD1 = FALSE;\r
1084         p_caps->DeviceD2 = FALSE;\r
1085         p_caps->LockSupported = FALSE;\r
1086         p_caps->EjectSupported = FALSE;\r
1087         p_caps->Removable = TRUE;\r
1088         p_caps->DockDevice = FALSE;\r
1089         p_caps->UniqueID = TRUE;\r
1090         p_caps->SilentInstall = TRUE;\r
1091         p_caps->RawDeviceOK = FALSE;\r
1092         p_caps->SurpriseRemovalOK = FALSE;\r
1093         p_caps->WakeFromD0 = FALSE;\r
1094         p_caps->WakeFromD1 = FALSE;\r
1095         p_caps->WakeFromD2 = FALSE;\r
1096         p_caps->WakeFromD3 = FALSE;\r
1097         p_caps->HardwareDisabled = FALSE;\r
1098         p_caps->DeviceState[PowerSystemWorking] = PowerDeviceD0;\r
1099         p_caps->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;\r
1100         p_caps->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;\r
1101         p_caps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;\r
1102         p_caps->DeviceState[PowerSystemHibernate] = PowerDeviceD3;\r
1103         p_caps->DeviceState[PowerSystemShutdown] = PowerDeviceD3;\r
1104         p_caps->SystemWake = PowerSystemUnspecified;\r
1105         p_caps->DeviceWake = PowerDeviceUnspecified;\r
1106         p_caps->D1Latency = 0;\r
1107         p_caps->D2Latency = 0;\r
1108         p_caps->D3Latency = 0;\r
1109 \r
1110         *p_action = IrpComplete;\r
1111         BUS_EXIT( BUS_DBG_PNP );\r
1112         return STATUS_SUCCESS;\r
1113 }\r
1114 \r
1115 \r
1116 static NTSTATUS\r
1117 iou_query_target_relations(\r
1118         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1119         IN                                      IRP* const                              p_irp, \r
1120                 OUT                             cl_irp_action_t* const  p_action )\r
1121 {\r
1122         NTSTATUS                        status;\r
1123         DEVICE_RELATIONS        *p_rel;\r
1124 \r
1125         BUS_ENTER( BUS_DBG_PNP );\r
1126 \r
1127         *p_action = IrpComplete;\r
1128 \r
1129         status = cl_alloc_relations( p_irp, 1 );\r
1130         if( !NT_SUCCESS( status ) )\r
1131         {\r
1132                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1133                         ("cl_alloc_relations returned 0x%08x.\n", status) );\r
1134                 return status;\r
1135         }\r
1136 \r
1137         p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
1138         p_rel->Count = 1;\r
1139         p_rel->Objects[0] = p_dev_obj;\r
1140 \r
1141         ObReferenceObject( p_dev_obj );\r
1142 \r
1143         BUS_EXIT( BUS_DBG_PNP );\r
1144         return status;\r
1145 }\r
1146 \r
1147 \r
1148 static NTSTATUS\r
1149 iou_query_device_id(\r
1150         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1151                 OUT                             IRP* const                              p_irp )\r
1152 {\r
1153         NTSTATUS                        status;\r
1154         bus_iou_ext_t           *p_ext;\r
1155         WCHAR                           *p_string;\r
1156 \r
1157         BUS_ENTER( BUS_DBG_PNP );\r
1158 \r
1159         p_ext = (bus_iou_ext_t*)p_dev_obj->DeviceExtension;\r
1160         if( !p_ext->pdo.b_present )\r
1161         {\r
1162                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1163                 return STATUS_NO_SUCH_DEVICE;\r
1164         }\r
1165 \r
1166         /* Device ID is "IBA\SID_<sid> where <sid> is the IPoIB Service ID. */\r
1167         p_string = ExAllocatePoolWithTag( PagedPool, IOU_DEV_ID_SIZE, 'didq' );\r
1168         if( !p_string )\r
1169         {\r
1170                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
1171                         ("Failed to allocate device ID buffer (%d bytes).\n",\r
1172                         IOU_DEV_ID_SIZE) );\r
1173                 return STATUS_INSUFFICIENT_RESOURCES;\r
1174         }\r
1175 \r
1176         status =\r
1177                 RtlStringCbPrintfW( p_string, IOU_DEV_ID_SIZE, IOU_DEV_ID_STRING1,\r
1178                         p_ext->vend_id, p_ext->dev_id, p_ext->revision );\r
1179         if( !NT_SUCCESS( status ) )\r
1180         {\r
1181                 ExFreePool( p_string );\r
1182                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1183                         ("Failed to format device ID string.\n") );\r
1184                 return status;\r
1185         }\r
1186         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1187 \r
1188         BUS_EXIT( BUS_DBG_PNP );\r
1189         return STATUS_SUCCESS;\r
1190 }\r
1191 \r
1192 \r
1193 static NTSTATUS\r
1194 iou_query_hardware_ids(\r
1195         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1196                 OUT                             IRP* const                              p_irp )\r
1197 {\r
1198         NTSTATUS                        status;\r
1199         bus_iou_ext_t           *p_ext;\r
1200         WCHAR                           *p_string, *p_start;\r
1201         size_t                          size;\r
1202 \r
1203         BUS_ENTER( BUS_DBG_PNP );\r
1204 \r
1205         p_ext = (bus_iou_ext_t*)p_dev_obj->DeviceExtension;\r
1206         if( !p_ext->pdo.b_present )\r
1207         {\r
1208                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1209                 return STATUS_NO_SUCH_DEVICE;\r
1210         }\r
1211 \r
1212         p_string = ExAllocatePoolWithTag( PagedPool, IOU_HW_ID_SIZE, 'dihq' );\r
1213         if( !p_string )\r
1214         {\r
1215                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
1216                         ("Failed to allocate hardware ID buffer (%d bytes).\n",\r
1217                         IOU_HW_ID_SIZE) );\r
1218                 return STATUS_INSUFFICIENT_RESOURCES;\r
1219         }\r
1220 \r
1221         p_start = p_string;\r
1222         size = IOU_HW_ID_SIZE;\r
1223         /* Fill in the first HW ID. */\r
1224         status = RtlStringCbPrintfExW( p_start, size, &p_start, &size,\r
1225                 STRSAFE_FILL_BEHIND_NULL | STRSAFE_NO_TRUNCATION, IOU_DEV_ID_STRING1,\r
1226                 p_ext->vend_id, p_ext->dev_id, p_ext->revision );\r
1227         if( !NT_SUCCESS( status ) )\r
1228         {\r
1229                 ExFreePool( p_string );\r
1230                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1231                         ("Failed to format device ID string.\n") );\r
1232                 return status;\r
1233         }\r
1234         /* Fill in the second HW ID. */\r
1235         CL_ASSERT( *p_start == L'\0' );\r
1236         p_start++;\r
1237         size -= sizeof(WCHAR);\r
1238         status = RtlStringCbPrintfExW( p_start, size, NULL, NULL,\r
1239                 STRSAFE_FILL_BEHIND_NULL | STRSAFE_NO_TRUNCATION, IOU_DEV_ID_STRING2,\r
1240                 p_ext->vend_id, p_ext->dev_id );\r
1241         if( !NT_SUCCESS( status ) )\r
1242         {\r
1243                 ExFreePool( p_string );\r
1244                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1245                         ("Failed to format device ID string.\n") );\r
1246                 return status;\r
1247         }\r
1248         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1249 \r
1250         BUS_EXIT( BUS_DBG_PNP );\r
1251         return STATUS_SUCCESS;\r
1252 }\r
1253 \r
1254 \r
1255 static NTSTATUS\r
1256 iou_query_compatible_ids(\r
1257         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1258                 OUT                             IRP* const                              p_irp )\r
1259 {\r
1260         WCHAR                           *p_string;\r
1261 \r
1262         BUS_ENTER( BUS_DBG_PNP );\r
1263 \r
1264         UNUSED_PARAM( p_dev_obj );\r
1265 \r
1266         p_string = ExAllocatePoolWithTag( PagedPool, sizeof(IOU_COMPAT_ID), 'dicq' );\r
1267         if( !p_string )\r
1268         {\r
1269                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
1270                         ("Failed to allocate compatible ID buffer (%d bytes).\n",\r
1271                         IOU_HW_ID_SIZE) );\r
1272                 return STATUS_INSUFFICIENT_RESOURCES;\r
1273         }\r
1274 \r
1275         cl_memcpy( p_string, IOU_COMPAT_ID, sizeof(IOU_COMPAT_ID) );\r
1276         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1277 \r
1278         BUS_EXIT( BUS_DBG_PNP );\r
1279         return STATUS_SUCCESS;\r
1280 }\r
1281 \r
1282 \r
1283 static NTSTATUS\r
1284 iou_query_unique_id(\r
1285         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1286                 OUT                             IRP* const                              p_irp )\r
1287 {\r
1288         NTSTATUS                        status;\r
1289         WCHAR                           *p_string;\r
1290         bus_iou_ext_t           *p_ext;\r
1291 \r
1292         BUS_ENTER( BUS_DBG_PNP );\r
1293         \r
1294         p_ext = p_dev_obj->DeviceExtension;\r
1295         if( !p_ext->pdo.b_present )\r
1296         {\r
1297                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1298                 return STATUS_NO_SUCH_DEVICE;\r
1299         }\r
1300 \r
1301         /* The instance ID is the port GUID. */\r
1302         p_string = ExAllocatePoolWithTag( PagedPool, sizeof(WCHAR) * 33, 'diuq' );\r
1303         if( !p_string )\r
1304         {\r
1305                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
1306                         ("Failed to allocate instance ID buffer (%d bytes).\n",\r
1307                         sizeof(WCHAR) * 17) );\r
1308                 return STATUS_NO_MEMORY;\r
1309         }\r
1310 \r
1311         status = RtlStringCchPrintfW( p_string, 33, L"%016I64x%016I64x",\r
1312                 p_ext->guid, p_ext->pdo.ca_guid );\r
1313         if( !NT_SUCCESS( status ) )\r
1314         {\r
1315                 CL_ASSERT( NT_SUCCESS( status ) );\r
1316                 ExFreePool( p_string );\r
1317                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1318                         ("RtlStringCchPrintfW returned %08x.\n", status) );\r
1319                 return status;\r
1320         }\r
1321 \r
1322         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1323 \r
1324         BUS_EXIT( BUS_DBG_PNP );\r
1325         return STATUS_SUCCESS;\r
1326 }\r
1327 \r
1328 \r
1329 static NTSTATUS\r
1330 iou_query_description(\r
1331         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1332                 OUT                             IRP* const                              p_irp )\r
1333 {\r
1334         NTSTATUS                        status;\r
1335         WCHAR                           *p_string;\r
1336         bus_iou_ext_t           *p_ext;\r
1337 \r
1338         BUS_ENTER( BUS_DBG_PNP );\r
1339         \r
1340         p_ext = p_dev_obj->DeviceExtension;\r
1341         if( !p_ext->pdo.b_present )\r
1342         {\r
1343                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1344                 return STATUS_NO_SUCH_DEVICE;\r
1345         }\r
1346 \r
1347         /* The instance ID is the port GUID. */\r
1348         p_string = ExAllocatePoolWithTag( PagedPool,\r
1349                                                                           sizeof(WCHAR) * sizeof(p_ext->desc),\r
1350                                                                           'sedq' );\r
1351         if( !p_string )\r
1352         {\r
1353                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
1354                         ("Failed to allocate device description buffer (%d bytes).\n",\r
1355                         sizeof(WCHAR) * sizeof(p_ext->desc)) );\r
1356                 return STATUS_INSUFFICIENT_RESOURCES;\r
1357         }\r
1358 \r
1359         status = RtlStringCchPrintfW( p_string, sizeof(p_ext->desc),\r
1360                 L"%S", p_ext->desc );\r
1361         if( !NT_SUCCESS( status ) )\r
1362         {\r
1363                 CL_ASSERT( NT_SUCCESS( status ) );\r
1364                 ExFreePool( p_string );\r
1365                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1366                         ("RtlStringCchPrintfW returned %08x.\n", status) );\r
1367                 return status;\r
1368         }\r
1369         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1370 \r
1371         BUS_EXIT( BUS_DBG_PNP );\r
1372         return STATUS_SUCCESS;\r
1373 }\r
1374 \r
1375 \r
1376 static NTSTATUS\r
1377 iou_query_location(\r
1378         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1379                 OUT                             IRP* const                              p_irp )\r
1380 {\r
1381         NTSTATUS                        status;\r
1382         bus_iou_ext_t           *p_ext;\r
1383         WCHAR                           *p_string;\r
1384 \r
1385         BUS_ENTER( BUS_DBG_PNP );\r
1386 \r
1387         p_ext = (bus_iou_ext_t*)p_dev_obj->DeviceExtension;\r
1388         if( !p_ext->pdo.b_present )\r
1389         {\r
1390                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1391                 return STATUS_NO_SUCH_DEVICE;\r
1392         }\r
1393 \r
1394         p_string = ExAllocatePoolWithTag( PagedPool, IOU_LOCATION_SIZE, 'colq' );\r
1395         if( !p_string )\r
1396         {\r
1397                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
1398                         ("Failed to allocate location buffer (%d bytes).\n",\r
1399                         IOU_LOCATION_SIZE) );\r
1400                 return STATUS_INSUFFICIENT_RESOURCES;\r
1401         }\r
1402 \r
1403         status = RtlStringCbPrintfW( p_string, IOU_LOCATION_SIZE,\r
1404                 L"Chassis 0x%016I64x, Slot %d", p_ext->chassis_guid, p_ext->slot );\r
1405         if( !NT_SUCCESS( status ) )\r
1406         {\r
1407                 ExFreePool( p_string );\r
1408                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1409                         ("Failed to format device ID string.\n") );\r
1410                 return status;\r
1411         }\r
1412         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1413 \r
1414         BUS_EXIT( BUS_DBG_PNP );\r
1415         return STATUS_SUCCESS;\r
1416 }\r
1417 \r
1418 \r
1419 static NTSTATUS\r
1420 iou_query_bus_info(\r
1421         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1422         IN                                      IRP* const                              p_irp, \r
1423                 OUT                             cl_irp_action_t* const  p_action )\r
1424 {\r
1425         PNP_BUS_INFORMATION     *p_bus_info;\r
1426 \r
1427         BUS_ENTER( BUS_DBG_PNP );\r
1428 \r
1429         UNUSED_PARAM( p_dev_obj );\r
1430 \r
1431         *p_action = IrpComplete;\r
1432 \r
1433         p_bus_info = ExAllocatePoolWithTag( PagedPool, sizeof(PNP_BUS_INFORMATION), 'subq' );\r
1434         if( !p_bus_info )\r
1435         {\r
1436                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1437                         ("Failed to allocate PNP_BUS_INFORMATION (%d bytes).\n",\r
1438                         sizeof(PNP_BUS_INFORMATION)) );\r
1439                 return STATUS_INSUFFICIENT_RESOURCES;\r
1440         }\r
1441 \r
1442         p_bus_info->BusTypeGuid = GUID_BUS_TYPE_IBA;\r
1443         //TODO: Memory from Intel - storage miniport would not stay loaded unless\r
1444         //TODO: bus type was PCI.  Look here if SRP is having problems staying\r
1445         //TODO: loaded.\r
1446         p_bus_info->LegacyBusType = PNPBus;\r
1447         p_bus_info->BusNumber = 0;\r
1448 \r
1449         p_irp->IoStatus.Information = (ULONG_PTR)p_bus_info;\r
1450         BUS_EXIT( BUS_DBG_PNP );\r
1451         return STATUS_SUCCESS;\r
1452 }\r
1453 \r
1454 \r
1455 static NTSTATUS\r
1456 iou_query_iou_ifc(\r
1457         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1458         IN                              IO_STACK_LOCATION* const        p_io_stack )\r
1459 {\r
1460         NTSTATUS                                status;\r
1461         ib_al_ifc_t                             *p_ifc;\r
1462         ib_al_ifc_data_t                *p_ifc_data;\r
1463         iou_ifc_data_t                  *p_iou_data;\r
1464         bus_iou_ext_t                   *p_ext;\r
1465         const GUID                              *p_guid;\r
1466 \r
1467         BUS_ENTER( BUS_DBG_PNP );\r
1468 \r
1469         CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
1470 \r
1471         p_ext = p_dev_obj->DeviceExtension;\r
1472 \r
1473         /* Get the interface. */\r
1474         status = cl_fwd_query_ifc(\r
1475                 p_ext->pdo.p_parent_ext->cl_ext.p_self_do, p_io_stack );\r
1476         if( !NT_SUCCESS( status ) )\r
1477         {\r
1478                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1479                         ("Failed to forward interface query: %08X\n", status) );\r
1480                 return status;\r
1481         }\r
1482 \r
1483         if( !p_io_stack->Parameters.QueryInterface.InterfaceSpecificData )\r
1484         {\r
1485                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("No interface specific data!\n") );\r
1486                 return status;\r
1487         }\r
1488 \r
1489         p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
1490 \r
1491         p_ifc_data = (ib_al_ifc_data_t*)\r
1492                 p_io_stack->Parameters.QueryInterface.InterfaceSpecificData;\r
1493         p_guid = p_ifc_data->type;\r
1494         if( !IsEqualGUID( p_guid, &GUID_IOU_INTERFACE_DATA ) )\r
1495         {\r
1496                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Unsupported interface data: \n\t"\r
1497                         "0x%08x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x,"\r
1498                         "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x.\n",\r
1499                         p_guid->Data1, p_guid->Data2, p_guid->Data3,\r
1500                         p_guid->Data4[0], p_guid->Data4[1], p_guid->Data4[2],\r
1501                         p_guid->Data4[3], p_guid->Data4[4], p_guid->Data4[5],\r
1502                         p_guid->Data4[6], p_guid->Data4[7]) );\r
1503                 return status;\r
1504         }\r
1505 \r
1506         if( p_ifc_data->version != IOU_INTERFACE_DATA_VERSION )\r
1507         {\r
1508                 p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context );\r
1509                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1510                         ("Unsupported version %d, expected %d\n",\r
1511                         p_ifc_data->version, IOU_INTERFACE_DATA_VERSION) );\r
1512                 return STATUS_NOT_SUPPORTED;\r
1513         }\r
1514 \r
1515         ASSERT( p_ifc_data->p_data );\r
1516 \r
1517         if( p_ifc_data->size != sizeof(iou_ifc_data_t) )\r
1518         {\r
1519                 p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context );\r
1520                 BUS_TRACE_EXIT( BUS_DBG_PNP,\r
1521                         ("Buffer too small (%d given, %d required).\n",\r
1522                         p_ifc_data->size,\r
1523                         sizeof(iou_ifc_data_t)) );\r
1524                 return STATUS_BUFFER_TOO_SMALL;\r
1525         }\r
1526 \r
1527         /* Set the interface data. */\r
1528         p_iou_data = (iou_ifc_data_t*)p_ifc_data->p_data;\r
1529 \r
1530         p_iou_data->ca_guid = p_ext->pdo.ca_guid;\r
1531         p_iou_data->chassis_guid = p_ext->chassis_guid;\r
1532         p_iou_data->slot = p_ext->slot;\r
1533         p_iou_data->guid = p_ext->guid;\r
1534 \r
1535         BUS_EXIT( BUS_DBG_PNP );\r
1536         return STATUS_SUCCESS;\r
1537 }\r
1538 \r
1539 \r
1540 static NTSTATUS\r
1541 iou_query_interface(\r
1542         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1543         IN                                      IRP* const                              p_irp, \r
1544                 OUT                             cl_irp_action_t* const  p_action )\r
1545 {\r
1546         bus_pdo_ext_t           *p_ext;\r
1547         NTSTATUS                        status;\r
1548         IO_STACK_LOCATION       *p_io_stack;\r
1549 \r
1550         BUS_ENTER( BUS_DBG_PNP );\r
1551 \r
1552         CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
1553 \r
1554         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1555         \r
1556         /* Bottom of the stack - IRP must be completed. */\r
1557         *p_action = IrpComplete;\r
1558 \r
1559         /* Compare requested GUID with our supported interface GUIDs. */\r
1560         if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
1561                 &GUID_IB_AL_INTERFACE ) )\r
1562         {\r
1563                 status = iou_query_iou_ifc( p_dev_obj, p_io_stack );\r
1564         }\r
1565         else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
1566                 &GUID_BUS_INTERFACE_STANDARD ) )\r
1567         {\r
1568                 p_ext = p_dev_obj->DeviceExtension;\r
1569                 if( !p_ext->h_ca ||\r
1570                         !p_ext->b_present ||\r
1571                         !p_ext->h_ca->p_hca_dev ||\r
1572                         p_ext->b_reported_missing )\r
1573                 {\r
1574                         return STATUS_NO_SUCH_DEVICE;\r
1575                 }\r
1576 \r
1577 \r
1578                 status = cl_fwd_query_ifc(\r
1579                         p_ext->h_ca->p_hca_dev, p_io_stack );\r
1580         }\r
1581         else\r
1582         {\r
1583                 status = p_irp->IoStatus.Status;\r
1584         }\r
1585 \r
1586         BUS_EXIT( BUS_DBG_PNP );\r
1587         return status;\r
1588 }\r
1589 \r
1590 \r
1591 \r
1592 /* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
1593 static void\r
1594 __HibernateUpWorkItem(\r
1595         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1596         IN                              void*                                           context )\r
1597 {\r
1598         IO_STACK_LOCATION       *p_io_stack;\r
1599         bus_pdo_ext_t           *p_ext;\r
1600         IRP                                     *p_irp;\r
1601         POWER_STATE powerState;\r
1602 \r
1603         BUS_ENTER( BUS_DBG_POWER );\r
1604 \r
1605         p_ext = (bus_pdo_ext_t*)p_dev_obj->DeviceExtension;\r
1606         p_irp = (IRP*)context;\r
1607         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1608 \r
1609         IoFreeWorkItem( p_ext->p_po_work_item );\r
1610         p_ext->p_po_work_item = NULL;\r
1611 \r
1612         while (!p_ext->h_ca) {\r
1613                 BUS_TRACE( BUS_DBG_PNP, ("Waiting for the end of HCA registration ... \n"));\r
1614                 cl_thread_suspend( 200 );       /* suspend for 200 ms */\r
1615         }\r
1616 \r
1617         p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
1618         powerState = PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
1619 \r
1620         BUS_TRACE( BUS_DBG_POWER, \r
1621                 ("PoSetPowerState: old state %d, new state to %d\n", \r
1622                 powerState.DeviceState, p_ext->dev_po_state ));\r
1623 \r
1624         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
1625         PoStartNextPowerIrp( p_irp );\r
1626         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1627         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1628 \r
1629         BUS_EXIT( BUS_DBG_POWER );\r
1630 }\r
1631 \r
1632 /*\r
1633  * The PDOs created by the IB Bus driver are software devices.  As such,\r
1634  * all power states are supported.  It is left to the HCA power policy \r
1635  * owner to handle which states can be supported by the HCA.\r
1636  */\r
1637 static NTSTATUS\r
1638 iou_set_power(\r
1639         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1640         IN                              IRP* const                                      p_irp,\r
1641                 OUT                     cl_irp_action_t* const          p_action )\r
1642 {\r
1643         NTSTATUS                        status = STATUS_SUCCESS;\r
1644         IO_STACK_LOCATION       *p_io_stack;\r
1645         bus_pdo_ext_t           *p_ext;\r
1646 \r
1647         BUS_ENTER( BUS_DBG_POWER );\r
1648 \r
1649         p_ext = p_dev_obj->DeviceExtension;\r
1650         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1651 \r
1652         BUS_TRACE( BUS_DBG_POWER, \r
1653                 ("SET_POWER for PDO %p (ext %p): type %s, state %d, action %d \n",\r
1654                 p_dev_obj, p_ext,\r
1655                 (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
1656                 p_io_stack->Parameters.Power.State.DeviceState, \r
1657                 p_io_stack->Parameters.Power.ShutdownType ));\r
1658 \r
1659         if ((p_io_stack->Parameters.Power.Type == SystemPowerState) &&\r
1660                 (p_io_stack->Parameters.Power.State.SystemState ==PowerSystemHibernate ||\r
1661                 p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 ))\r
1662         {\r
1663                 BUS_TRACE( BUS_DBG_POWER, ("Setting b_hibernating flag for PDO %p \n", p_dev_obj));\r
1664                 p_ext->b_hibernating = TRUE;\r
1665         }\r
1666 \r
1667         if( p_io_stack->Parameters.Power.Type == DevicePowerState )\r
1668         {\r
1669                 /* after hibernation PDO is not ready for work. we need to wait for finishing of the HCA registration */\r
1670                 if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && p_ext->b_hibernating)\r
1671                 {\r
1672                         /* Process in a work item - deregister_ca and HcaDeinit block. */\r
1673                         ASSERT( !p_ext->p_po_work_item );\r
1674                         p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj );\r
1675                         if( !p_ext->p_po_work_item )\r
1676                                 status = STATUS_INSUFFICIENT_RESOURCES;\r
1677                         else {\r
1678                                 /* Process in work item callback. */\r
1679                                 IoMarkIrpPending( p_irp );\r
1680                                 IoQueueWorkItem(\r
1681                                         p_ext->p_po_work_item, __HibernateUpWorkItem, DelayedWorkQueue, p_irp );\r
1682                                 *p_action = IrpDoNothing;\r
1683                                 BUS_EXIT( BUS_DBG_POWER );\r
1684                                 return STATUS_PENDING;\r
1685                         }\r
1686                 }\r
1687 \r
1688                 /* Notify the power manager. */\r
1689                 p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
1690                 PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
1691         }\r
1692 \r
1693         *p_action = IrpComplete;\r
1694         BUS_EXIT( BUS_DBG_POWER );\r
1695         return STATUS_SUCCESS;\r
1696 }\r