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