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