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