[IBBUS] added support for creating vendor defined devices.
[mirror/winof/.git] / core / bus / kernel / bus_port_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 "bus_pnp.h"\r
39 #include "bus_port_mgr.h"\r
40 #include "al_ca.h"\r
41 #include "al_mgr.h"\r
42 #include <initguid.h>\r
43 #include <wdmguid.h>\r
44 #include "iba/ipoib_ifc.h"\r
45 #include "al_dev.h"\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  * Device extension for IPoIB port PDOs.\r
54  */\r
55 typedef struct _bus_port_ext\r
56 {\r
57         bus_pdo_ext_t                   pdo;\r
58 \r
59         port_guid_pkey_t                port_guid;\r
60         uint32_t                                n_port;\r
61 \r
62         /* Number of references on the upper interface. */\r
63         atomic32_t                              n_ifc_ref;\r
64 \r
65 }       bus_port_ext_t;\r
66 \r
67 \r
68 typedef struct _port_pnp_context\r
69 {\r
70         bus_filter_t    *p_bus_filter;\r
71         void                    *p_pdo_ext;\r
72         int                             port_num;\r
73 \r
74 }       port_pnp_ctx_t;\r
75 \r
76 \r
77 extern pkey_array_t  g_pkeys;\r
78 \r
79 /*\r
80  * Function prototypes.\r
81  */\r
82 void\r
83 destroying_port_mgr(\r
84         IN                              cl_obj_t*                                       p_obj );\r
85 \r
86 void\r
87 free_port_mgr(\r
88         IN                              cl_obj_t*                                       p_obj );\r
89 \r
90 ib_api_status_t\r
91 bus_reg_port_pnp(\r
92         IN                              bus_filter_t*                           p_bfi );\r
93 \r
94 ib_api_status_t\r
95 port_mgr_pnp_cb(\r
96         IN                              ib_pnp_rec_t*                           p_pnp_rec );\r
97 \r
98 ib_api_status_t\r
99 port_mgr_port_add(\r
100         IN                              ib_pnp_port_rec_t*                      p_pnp_rec );\r
101 \r
102 void\r
103 port_mgr_port_remove(\r
104         IN                              ib_pnp_port_rec_t*                      p_pnp_rec );\r
105 \r
106 static NTSTATUS\r
107 port_start(\r
108         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
109         IN                              IRP* const                                      p_irp,\r
110                 OUT                     cl_irp_action_t* const          p_action );\r
111 \r
112 static NTSTATUS\r
113 port_query_remove(\r
114         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
115         IN                              IRP* const                                      p_irp,\r
116                 OUT                     cl_irp_action_t* const          p_action );\r
117 \r
118 static void\r
119 port_release_resources(\r
120         IN                              DEVICE_OBJECT* const            p_dev_obj );\r
121 \r
122 static NTSTATUS\r
123 port_remove(\r
124         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
125         IN                              IRP* const                                      p_irp,\r
126                 OUT                     cl_irp_action_t* const          p_action );\r
127 \r
128 static NTSTATUS\r
129 port_surprise_remove(\r
130         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
131         IN                              IRP* const                                      p_irp,\r
132                 OUT                     cl_irp_action_t* const          p_action );\r
133 \r
134 static NTSTATUS\r
135 port_query_capabilities(\r
136         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
137         IN                              IRP* const                                      p_irp,\r
138                 OUT                     cl_irp_action_t* const          p_action );\r
139 \r
140 static NTSTATUS\r
141 port_query_target_relations(\r
142         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
143         IN                              IRP* const                                      p_irp,\r
144                 OUT                     cl_irp_action_t* const          p_action );\r
145 \r
146 static NTSTATUS\r
147 port_query_device_id(\r
148         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
149         IN                              IRP* const                                      p_irp );\r
150 \r
151 static NTSTATUS\r
152 port_query_hardware_ids(\r
153         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
154         IN                              IRP* const                                      p_irp );\r
155 \r
156 static NTSTATUS\r
157 port_query_compatible_ids(\r
158         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
159         IN                              IRP* const                                      p_irp );\r
160 \r
161 static NTSTATUS\r
162 port_query_unique_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 port_query_description(\r
168         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
169         IN                              IRP* const                                      p_irp );\r
170 \r
171 \r
172 static NTSTATUS\r
173 port_query_location(\r
174         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
175         IN                              IRP* const                                      p_irp );\r
176 \r
177 static NTSTATUS\r
178 port_query_bus_info(\r
179         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
180         IN                              IRP* const                                      p_irp,\r
181                 OUT                     cl_irp_action_t* const          p_action );\r
182 \r
183 static NTSTATUS\r
184 port_query_ipoib_ifc(\r
185         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
186         IN                              IO_STACK_LOCATION* const        p_io_stack );\r
187 \r
188 static NTSTATUS\r
189 port_query_interface(\r
190         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
191         IN                              IRP* const                                      p_irp,\r
192                 OUT                     cl_irp_action_t* const          p_action );\r
193 \r
194 static NTSTATUS\r
195 port_set_power(\r
196         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
197         IN                              IRP* const                                      p_irp,\r
198                 OUT                     cl_irp_action_t* const          p_action );\r
199 \r
200 \r
201 /* All PnP code is called at passive, so it can all be paged out. */\r
202 #ifdef ALLOC_PRAGMA\r
203 #pragma alloc_text (PAGE, port_start)\r
204 #pragma alloc_text (PAGE, port_query_remove)\r
205 #pragma alloc_text (PAGE, port_release_resources)\r
206 #pragma alloc_text (PAGE, port_remove)\r
207 #pragma alloc_text (PAGE, port_surprise_remove)\r
208 #pragma alloc_text (PAGE, port_query_capabilities)\r
209 #pragma alloc_text (PAGE, port_query_target_relations)\r
210 #pragma alloc_text (PAGE, port_query_device_id)\r
211 #pragma alloc_text (PAGE, port_query_hardware_ids)\r
212 #pragma alloc_text (PAGE, port_query_compatible_ids)\r
213 #pragma alloc_text (PAGE, port_query_unique_id)\r
214 #pragma alloc_text (PAGE, port_query_description)\r
215 #pragma alloc_text (PAGE, port_query_location)\r
216 #pragma alloc_text (PAGE, port_query_bus_info)\r
217 #pragma alloc_text (PAGE, port_query_ipoib_ifc)\r
218 #pragma alloc_text (PAGE, port_query_interface)\r
219 #pragma alloc_text (PAGE_PNP, port_set_power)\r
220 #pragma alloc_text (PAGE, port_mgr_port_add)\r
221 #pragma alloc_text (PAGE, port_mgr_port_remove)\r
222 #endif\r
223 \r
224 \r
225 /*\r
226  * Global virtual function pointer tables shared between all\r
227  * instances of Port PDOs.\r
228  */\r
229 static const cl_vfptr_pnp_po_t          vfptr_port_pnp = {\r
230         "IODEVICE",\r
231         port_start,\r
232         cl_irp_succeed,\r
233         cl_irp_succeed,\r
234         cl_irp_succeed,\r
235         port_query_remove,\r
236         port_release_resources,\r
237         port_remove,\r
238         cl_irp_succeed,\r
239         port_surprise_remove,\r
240         port_query_capabilities,\r
241         cl_irp_complete,\r
242         cl_irp_complete,\r
243         cl_irp_succeed,\r
244         cl_irp_complete,\r
245         cl_irp_complete,\r
246         cl_irp_complete,\r
247         port_query_target_relations,\r
248         cl_irp_complete,\r
249         cl_irp_complete,\r
250         cl_irp_complete,\r
251         port_query_bus_info,\r
252         port_query_interface,\r
253         cl_irp_complete,\r
254         cl_irp_complete,\r
255         cl_irp_complete,\r
256         cl_irp_complete,\r
257         cl_irp_succeed,                         // QueryPower\r
258         port_set_power,                         // SetPower\r
259         cl_irp_unsupported,                     // PowerSequence\r
260         cl_irp_unsupported                      // WaitWake\r
261 };\r
262 \r
263 \r
264 static const cl_vfptr_query_txt_t               vfptr_port_query_txt = {\r
265         port_query_device_id,\r
266         port_query_hardware_ids,\r
267         port_query_compatible_ids,\r
268         port_query_unique_id,\r
269         port_query_description,\r
270         port_query_location\r
271 };\r
272 \r
273 \r
274 \r
275 /*\r
276  * Create the AL load service.\r
277  */\r
278 ib_api_status_t\r
279 create_port_mgr(\r
280                 IN                      bus_filter_t*                           p_bfi,\r
281                 OUT                     port_mgr_t** const                      pp_port_mgr )\r
282 {\r
283         ib_api_status_t         status;\r
284         cl_status_t                     cl_status;\r
285         port_mgr_t                      *p_port_mgr;\r
286 \r
287         BUS_ENTER( BUS_DBG_PNP );\r
288 \r
289         CL_ASSERT( p_bfi->p_port_mgr == NULL );\r
290 \r
291         p_port_mgr = cl_zalloc( sizeof( port_mgr_t ) );\r
292         if( !p_port_mgr )\r
293         {\r
294                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
295                         ("Failed to allocate port manager.\n") );\r
296                 return IB_INSUFFICIENT_MEMORY;\r
297         }\r
298         p_bfi->p_port_mgr = p_port_mgr;\r
299 \r
300         /* Construct the load service. */\r
301         cl_obj_construct( &p_port_mgr->obj, AL_OBJ_TYPE_LOADER );\r
302         p_bfi->p_port_mgr_obj = &p_port_mgr->obj;\r
303         cl_mutex_construct( &p_port_mgr->pdo_mutex );\r
304         cl_qlist_init( &p_port_mgr->port_list );\r
305 \r
306         cl_status = cl_mutex_init( &p_port_mgr->pdo_mutex );\r
307         if( cl_status != CL_SUCCESS )\r
308         {\r
309                 free_port_mgr( &p_port_mgr->obj );\r
310                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
311                         ("cl_mutex_init returned %#x.\n", cl_status) );\r
312                 return ib_convert_cl_status( cl_status );\r
313         }\r
314 \r
315         /* Initialize the load service object. */\r
316         cl_status = cl_obj_init( &p_port_mgr->obj, CL_DESTROY_SYNC,\r
317                                                          destroying_port_mgr, NULL, free_port_mgr );\r
318 \r
319         if( cl_status != CL_SUCCESS )\r
320         {\r
321                 free_port_mgr( &p_port_mgr->obj );\r
322                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
323                         ("cl_obj_init returned %#x.\n", cl_status) );\r
324                 return ib_convert_cl_status( cl_status );\r
325         }\r
326 \r
327         /* Register for port PnP events */\r
328         status = bus_reg_port_pnp(p_bfi);\r
329         if( status != IB_SUCCESS )\r
330         {\r
331                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
332                         ("bus_reg_port_pnp returned %s.\n", ib_get_err_str(status)) );\r
333                 free_port_mgr( &p_port_mgr->obj );\r
334                 return status;\r
335         }\r
336 \r
337         *pp_port_mgr = p_port_mgr;\r
338 \r
339         BUS_EXIT( BUS_DBG_PNP );\r
340         return IB_SUCCESS;\r
341 }\r
342 \r
343 \r
344 /*\r
345  * Pre-destroy the load service.\r
346  */\r
347 void\r
348 destroying_port_mgr(\r
349         IN                              cl_obj_t*                                       p_obj )\r
350 {\r
351         ib_api_status_t                 status;\r
352         bus_filter_t                    *p_bfi;\r
353         port_mgr_t                              *p_port_mgr;\r
354 \r
355         BUS_ENTER( BUS_DBG_PNP );\r
356 \r
357         CL_ASSERT( p_obj );\r
358         p_bfi = get_bfi_by_obj(BFI_PORT_MGR_OBJ, p_obj);\r
359         if (p_bfi == NULL) {\r
360                 BUS_PRINT(BUS_DBG_PNP, ("Failed to find p_bfi by obj %p?\n", p_obj));\r
361                 return;\r
362         }\r
363         p_port_mgr = p_bfi->p_port_mgr;\r
364 \r
365         BUS_PRINT(BUS_DBG_PNP, ("%s obj %p port_mgr %p port_mgr_obj %p\n",\r
366                         p_bfi->whoami,p_obj,p_port_mgr, p_bfi->p_port_mgr_obj) );\r
367 \r
368         CL_ASSERT( (void*)p_bfi->p_port_mgr == (void*)p_bfi->p_port_mgr_obj );\r
369         CL_ASSERT( p_port_mgr == PARENT_STRUCT( p_obj, port_mgr_t, obj ) );\r
370 \r
371         /* Deregister for port PnP events if this is the last Port manager. */\r
372         if ( get_bfi_count() == 1 && bus_globals.h_pnp_port ) {\r
373                 status = ib_dereg_pnp( bus_globals.h_pnp_port, NULL );\r
374                 bus_globals.h_pnp_port = NULL;\r
375                 CL_ASSERT( status == IB_SUCCESS );\r
376         }\r
377         cl_obj_deref( p_bfi->p_port_mgr_obj );\r
378 \r
379         BUS_EXIT( BUS_DBG_PNP );\r
380 }\r
381 \r
382 \r
383 /*\r
384  * Free the load service.\r
385  */\r
386 void\r
387 free_port_mgr(\r
388         IN                              cl_obj_t*                                       p_obj )\r
389 {\r
390         bus_pdo_ext_t   *p_ext;\r
391         cl_list_item_t  *p_list_item;\r
392         bus_filter_t    *p_bfi;\r
393         port_mgr_t              *p_port_mgr;\r
394 \r
395         BUS_ENTER( BUS_DBG_PNP );\r
396 \r
397         CL_ASSERT( p_obj );\r
398         p_bfi = get_bfi_by_obj(BFI_PORT_MGR_OBJ, p_obj);\r
399         if (p_bfi == NULL) {\r
400                 BUS_PRINT(BUS_DBG_PNP, ("No p_bfi for port obj %p?\n", p_obj));\r
401                 return;\r
402         }\r
403         p_port_mgr = p_bfi->p_port_mgr;\r
404         if ( !p_port_mgr ) {\r
405                 // if create fails & then free is called, p_bfi->p_port_mgr == NULL\r
406                 return;\r
407         }\r
408         CL_ASSERT( p_port_mgr == PARENT_STRUCT( p_obj, port_mgr_t, obj ) );\r
409 \r
410         BUS_PRINT(BUS_DBG_PNP, ("%s obj %p port_mgr %p port_mgr_obj %p\n",\r
411                         p_bfi->whoami, p_obj,p_port_mgr,\r
412                         p_bfi->p_port_mgr_obj) );\r
413 \r
414         BUS_PRINT( BUS_DBG_PNP,\r
415                                 ("%s Mark all IPoIB PDOs no longer present\n", p_bfi->whoami));\r
416         /*\r
417          * Mark all IPoIB PDOs as no longer present.  This will cause them\r
418          * to be removed when they process the IRP_MN_REMOVE_DEVICE.\r
419          */\r
420         p_list_item = cl_qlist_remove_head( &p_port_mgr->port_list );\r
421         while( p_list_item != cl_qlist_end( &p_port_mgr->port_list ) )\r
422         {\r
423                 p_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
424                 p_list_item = cl_qlist_remove_head( &p_port_mgr->port_list );\r
425                 if( p_ext->cl_ext.pnp_state == SurpriseRemoved )\r
426                 {\r
427                         CL_ASSERT( !p_ext->b_present );\r
428                         p_ext->b_reported_missing = TRUE;\r
429                         BUS_TRACE( BUS_DBG_PNP,\r
430                                 ("%s %s: PDO %p, ext %p, present %d, missing %d .\n",\r
431                                 p_bfi->whoami,\r
432                                 p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do,\r
433                                 p_ext, p_ext->b_present, p_ext->b_reported_missing ) );\r
434                         continue;\r
435                 }\r
436                 if( p_ext->h_ca && p_ext->hca_acquired )\r
437                 {\r
438                         /* Invalidate bus relations for the HCA. */\r
439                         IoInvalidateDeviceRelations(\r
440                                 p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
441 \r
442                         /* Release the reference on the CA object. */\r
443                         deref_al_obj( &p_ext->h_ca->obj );\r
444                 }\r
445 \r
446                 BUS_TRACE( BUS_DBG_PNP, ("%s Deleted device %s: PDO %p, ext %p\n",\r
447                                         p_bfi->whoami, p_ext->cl_ext.vfptr_pnp_po->identity,\r
448                                         p_ext->cl_ext.p_self_do, p_ext ) );\r
449 \r
450                 IoDeleteDevice( p_ext->cl_ext.p_self_do );\r
451         }\r
452 \r
453         cl_mutex_destroy( &p_port_mgr->pdo_mutex );\r
454         cl_obj_deinit( p_obj );\r
455         cl_free( p_port_mgr );\r
456 \r
457         p_bfi->p_port_mgr = NULL;\r
458         p_bfi->p_port_mgr_obj = NULL;\r
459 \r
460         BUS_EXIT( BUS_DBG_PNP );\r
461 }\r
462 \r
463 \r
464 /*\r
465  * Register the load service for the given PnP class events.\r
466  */\r
467 ib_api_status_t\r
468 bus_reg_port_pnp( IN bus_filter_t *p_bfi )\r
469 {\r
470         ib_pnp_req_t                    pnp_req;\r
471         ib_api_status_t                 status = IB_SUCCESS;\r
472         boolean_t                               need_pnp_reg = FALSE;\r
473 \r
474         /* only need to register for port PNP events once.\r
475          * Do not hold mutex over pnp_reg() call as callback which needs mutex\r
476          * could occur.\r
477          */\r
478         if ( !bus_globals.h_pnp_port )\r
479         {\r
480                 lock_control_event();\r
481                 if ( !bus_globals.h_pnp_port ) {\r
482                         bus_globals.h_pnp_port = (ib_pnp_handle_t)1; /* block others */\r
483                         need_pnp_reg = TRUE;\r
484                 }\r
485                 unlock_control_event();\r
486 \r
487                 if ( need_pnp_reg )\r
488                 {\r
489                         cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) );\r
490                         pnp_req.pnp_class       = IB_PNP_PORT | IB_PNP_FLAG_REG_SYNC;\r
491                         pnp_req.pnp_context = NULL;\r
492                         pnp_req.pfn_pnp_cb      = port_mgr_pnp_cb;\r
493 \r
494                         status = ib_reg_pnp( gh_al, &pnp_req, &bus_globals.h_pnp_port );\r
495                 }\r
496         }\r
497 \r
498         if ( status == IB_SUCCESS )\r
499         {\r
500                 /* Reference this bus filter's port load service */\r
501                 cl_obj_ref( &p_bfi->p_port_mgr->obj );\r
502         }\r
503 \r
504         return status;\r
505 }\r
506 \r
507 \r
508 /*\r
509  * Load service PnP event callback.\r
510  */\r
511 ib_api_status_t\r
512 port_mgr_pnp_cb(\r
513         IN                              ib_pnp_rec_t*                           p_pnp_rec )\r
514 {\r
515         ib_api_status_t         status=IB_SUCCESS;\r
516 \r
517         BUS_ENTER( BUS_DBG_PNP );\r
518 \r
519         CL_ASSERT( p_pnp_rec );\r
520 \r
521         switch( p_pnp_rec->pnp_event )\r
522         {\r
523         case IB_PNP_PORT_ADD:\r
524                 status = port_mgr_port_add( (ib_pnp_port_rec_t*)p_pnp_rec );\r
525                 break;\r
526 \r
527         case IB_PNP_PORT_REMOVE:\r
528                 port_mgr_port_remove( (ib_pnp_port_rec_t*)p_pnp_rec );\r
529                 break;\r
530 \r
531         default:\r
532                 XBUS_PRINT( BUS_DBG_PNP, ("Unhandled PNP Event %s\n",\r
533                                         ib_get_pnp_event_str(p_pnp_rec->pnp_event) ));\r
534                 break;\r
535         }\r
536         BUS_EXIT( BUS_DBG_PNP );\r
537 \r
538         return status;\r
539 }\r
540 \r
541 \r
542 /*\r
543  * Called to get bus relations for an HCA.\r
544  */\r
545 NTSTATUS\r
546 port_mgr_get_bus_relations(\r
547         IN              const   net64_t                                         ca_guid,\r
548         IN                              IRP* const                                      p_irp )\r
549 {\r
550         NTSTATUS                        status;\r
551         bus_filter_t            *p_bfi;\r
552         port_mgr_t                      *p_port_mgr;\r
553         DEVICE_RELATIONS        *p_rel;\r
554 \r
555         BUS_ENTER( BUS_DBG_PNP );\r
556 \r
557         BUS_PRINT(BUS_DBG_PNP, ("CA_guid %I64x\n",ca_guid));\r
558 \r
559         /* special case guid == 0 - walk all bus filter instances */\r
560         if ( ca_guid == 0ULL ) {\r
561                 BUS_PRINT(BUS_DBG_PNP, ("CA_guid 0\n"));\r
562                 for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++) {\r
563                         p_port_mgr = p_bfi->p_port_mgr;\r
564                         if ( !p_port_mgr )\r
565                                 continue;\r
566                         cl_mutex_acquire( &p_port_mgr->pdo_mutex );\r
567                         status = bus_get_relations( &p_port_mgr->port_list,\r
568                                                                                 p_bfi->ca_guid,\r
569                                                                                 p_irp );\r
570                         cl_mutex_release( &p_port_mgr->pdo_mutex );\r
571                 }\r
572 \r
573                 p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
574                 if ( p_rel ) {\r
575                         BUS_PRINT(BUS_DBG_PNP, ("CA_guid 0 Reports %d\n", p_rel->Count));\r
576                 }\r
577                 BUS_EXIT( BUS_DBG_PNP );\r
578                 return STATUS_SUCCESS;\r
579         }\r
580 \r
581         p_bfi = get_bfi_by_ca_guid(ca_guid);\r
582         if (p_bfi == NULL) {\r
583                 BUS_PRINT(BUS_DBG_PNP,\r
584                         ("Null *p_bfi from ca_guid %I64x\n",ca_guid));\r
585                 BUS_EXIT( BUS_DBG_PNP );\r
586                 return STATUS_NO_SUCH_DEVICE;\r
587         }\r
588         p_port_mgr = p_bfi->p_port_mgr;\r
589 \r
590         BUS_PRINT(BUS_DBG_PNP, ("%s for ca_guid %I64x port_mgr %p\n",\r
591                                                         p_bfi->whoami, ca_guid, p_port_mgr) );\r
592         if (!p_port_mgr)\r
593                 return STATUS_NO_SUCH_DEVICE;\r
594 \r
595         cl_mutex_acquire( &p_port_mgr->pdo_mutex );\r
596         status = bus_get_relations( &p_port_mgr->port_list, ca_guid, p_irp );\r
597         cl_mutex_release( &p_port_mgr->pdo_mutex );\r
598 \r
599         BUS_EXIT( BUS_DBG_PNP );\r
600         return STATUS_SUCCESS;\r
601 }\r
602 \r
603 static ib_api_status_t\r
604 __port_was_hibernated(\r
605         IN                              ib_pnp_port_rec_t*                      p_pnp_rec,\r
606         IN                              bus_filter_t*                           p_bfi )\r
607 {\r
608         NTSTATUS                status;\r
609         cl_list_item_t  *p_list_item;\r
610         bus_port_ext_t  *p_port_ext;\r
611         bus_pdo_ext_t   *p_pdo_ext = NULL;\r
612         size_t                  n_devs = 0;\r
613         port_mgr_t              *p_port_mgr = p_bfi->p_port_mgr;\r
614         cl_qlist_t              *p_pdo_list = &p_port_mgr->port_list;\r
615         port_pnp_ctx_t  *p_ctx = p_pnp_rec->pnp_rec.context;\r
616 \r
617         BUS_ENTER( BUS_DBG_PNP );\r
618 \r
619         if ( !p_port_mgr ) {\r
620                 // if free_port_mgr has been called , p_bfi->p_port_mgr == NULL \r
621                 // this will cause crash on cl_mutex_acquire\r
622                 // (leo) i'm not sure when it happens, but i saw it happened\r
623                 status = IB_NOT_FOUND;\r
624                 goto end;\r
625         }\r
626 \r
627         cl_mutex_acquire( &p_port_mgr->pdo_mutex );\r
628         \r
629         /* Count the number of child devices. */\r
630         for( p_list_item = cl_qlist_head( p_pdo_list );\r
631                 p_list_item != cl_qlist_end( p_pdo_list );\r
632                 p_list_item = cl_qlist_next( p_list_item ) )\r
633         {\r
634                 p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
635                 p_port_ext = (bus_port_ext_t*)p_pdo_ext;\r
636         \r
637                 if( p_pdo_ext->b_present && p_pdo_ext->b_hibernating &&\r
638                         (p_port_ext->port_guid.guid == p_pnp_rec->p_port_attr->port_guid) )\r
639                 {\r
640                         n_devs++;\r
641                         break;\r
642                 }\r
643 \r
644                 BUS_TRACE( BUS_DBG_PNP, ("%s Skipped PDO for %s: PDO %p, ext %p, "\r
645                         "present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
646                         p_bfi->whoami,\r
647                         p_pdo_ext->cl_ext.vfptr_pnp_po->identity,\r
648                         p_pdo_ext->cl_ext.p_self_do, \r
649                         p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
650                         p_pdo_ext->b_hibernating, p_port_ext->port_guid.guid  ) );\r
651         }\r
652 \r
653         if (n_devs)\r
654         {\r
655                 /* Take a reference on the parent HCA. */\r
656                 p_pdo_ext->h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid );\r
657                 if( !p_pdo_ext->h_ca )\r
658                 {\r
659                         BUS_TRACE( BUS_DBG_ERROR,\r
660                                 ("%s acquire_ca failed to find CA by guid %I64x\n",\r
661                                 p_bfi->whoami, p_pnp_rec->p_ca_attr->ca_guid ) );\r
662                         status = IB_INVALID_GUID;\r
663                 }\r
664                 else \r
665                 {\r
666                         p_pdo_ext->b_hibernating = FALSE;\r
667 \r
668                         CL_ASSERT( p_ctx );\r
669                         p_ctx->p_pdo_ext = p_pdo_ext; // save for port_mgr_port_remove\r
670 \r
671                         status = IB_SUCCESS;\r
672                         p_port_ext = (bus_port_ext_t*)p_pdo_ext;\r
673                         BUS_TRACE( BUS_DBG_PNP, ("%s Found PDO for %s: PDO %p, ext %p, "\r
674                                 "present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
675                                 p_bfi->whoami,\r
676                                 p_pdo_ext->cl_ext.vfptr_pnp_po->identity,\r
677                                 p_pdo_ext->cl_ext.p_self_do, \r
678                                 p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
679                                 p_pdo_ext->b_hibernating, p_port_ext->port_guid.guid ) );\r
680                 }\r
681         }\r
682         else \r
683         {\r
684                 BUS_TRACE( BUS_DBG_PNP, ("%s Failed to find PDO for guid  %I64x .\n",\r
685                                         p_bfi->whoami, p_pnp_rec->p_ca_attr->ca_guid ) );\r
686                 status = IB_NOT_FOUND;\r
687         }\r
688 \r
689         cl_mutex_release( &p_port_mgr->pdo_mutex );\r
690 \r
691 end:\r
692         BUS_EXIT( BUS_DBG_PNP );\r
693         return status;\r
694 }\r
695 \r
696 #if DBG\r
697 \r
698 void\r
699 dump_pnp_port_rec( ib_pnp_port_rec_t*   pr )\r
700 {\r
701         BUS_PRINT( BUS_DBG_PNP, ("%s() ib_pnp_port_rec_t* @ %p\nib_pnp_rec_t*:\n",\r
702                                 __FUNCTION__,pr));\r
703 \r
704 \r
705         BUS_PRINT( BUS_DBG_PNP, ("  Event %s\n",\r
706                                 ib_get_pnp_event_str(pr->pnp_rec.pnp_event) ));\r
707 \r
708         BUS_PRINT( BUS_DBG_PNP, ("  pnp_context %p\n",pr->pnp_rec.pnp_context));\r
709         BUS_PRINT( BUS_DBG_PNP, ("  context %p\n",pr->pnp_rec.context));\r
710         BUS_PRINT( BUS_DBG_PNP, ("  guid %I64x\n",pr->pnp_rec.guid));\r
711         BUS_PRINT( BUS_DBG_PNP, ("  ca_guid %I64x\n",pr->pnp_rec.ca_guid));\r
712 \r
713         if ( !pr->p_ca_attr ) {\r
714                 BUS_PRINT( BUS_DBG_PNP, ("  NULL *p_ca_attr ?\n"));\r
715         }\r
716         else {\r
717                 BUS_PRINT( BUS_DBG_PNP, ("*p_ca_attr\n"));\r
718                 BUS_PRINT( BUS_DBG_PNP, ("  ca_guid 0x%I64x\n",\r
719                                                                 pr->p_ca_attr->ca_guid ) );\r
720         }\r
721         if ( !pr->p_port_attr ) {\r
722                 BUS_PRINT( BUS_DBG_PNP, ("  NULL *p_port_attr?\n"));\r
723         }\r
724         else {\r
725                 BUS_PRINT( BUS_DBG_PNP, ("*p_port_attr:\n"));\r
726                 BUS_PRINT( BUS_DBG_PNP, ("  port_guid 0x%I64x port_num %d\n",\r
727                                                                 pr->p_port_attr->port_guid,\r
728                                                                 pr->p_port_attr->port_num ));\r
729         }\r
730 }\r
731 \r
732 void\r
733 dump_pnp_iou_rec( ib_pnp_iou_rec_t*     pr )\r
734 {\r
735         BUS_PRINT( BUS_DBG_PNP, ("%s() ib_pnp_iou_rec_t* @ %p\nib_pnp_rec_t*:\n",\r
736                                 __FUNCTION__,pr));\r
737 \r
738 \r
739         BUS_PRINT( BUS_DBG_PNP, ("  Event %s\n",\r
740                                 ib_get_pnp_event_str(pr->pnp_rec.pnp_event) ));\r
741 \r
742         BUS_PRINT( BUS_DBG_PNP, ("  pnp_context %p\n",pr->pnp_rec.pnp_context));\r
743         BUS_PRINT( BUS_DBG_PNP, ("  context %p\n",pr->pnp_rec.context));\r
744         BUS_PRINT( BUS_DBG_PNP, ("  guid %I64x\n",pr->pnp_rec.guid));\r
745         BUS_PRINT( BUS_DBG_PNP, ("  ca_guid %I64x\n",pr->pnp_rec.ca_guid));\r
746 \r
747         BUS_PRINT( BUS_DBG_PNP, ("pnp_iou_rec_t:\n" ));\r
748         BUS_PRINT( BUS_DBG_PNP,\r
749                                 ("  guid 0x%I64x\n  ca_guid %I64x\n  chassis_guid %I64x\n",\r
750                                 pr->guid, pr->ca_guid, pr->chassis_guid ));\r
751         BUS_PRINT( BUS_DBG_PNP,\r
752                                 ("  slot 0x%x\n  vend_id 0x%x\n  dev_id 0x%x  revision 0x%x\n",\r
753                                 pr->slot, pr->vend_id, pr->dev_id, pr->revision ));\r
754         if ( pr->desc[0] ) {\r
755                 BUS_PRINT( BUS_DBG_PNP, ("  Desc %s\n",pr->desc ));\r
756         }\r
757 }\r
758 #endif\r
759 \r
760 \r
761 ib_api_status_t\r
762 port_mgr_port_add(\r
763         IN                              ib_pnp_port_rec_t*                      p_pnp_rec )\r
764 {\r
765         NTSTATUS                status;\r
766         DEVICE_OBJECT   *p_pdo; \r
767         bus_port_ext_t  *p_port_ext;\r
768         bus_filter_t    *p_bfi;\r
769         port_mgr_t              *p_port_mgr;\r
770         port_pnp_ctx_t  *p_ctx = p_pnp_rec->pnp_rec.context;\r
771         child_device_info_list_t *pCurList;\r
772         ib_ca_handle_t  h_ca = NULL;\r
773         ULONG                   pKey;\r
774         UNICODE_STRING  uniKey;\r
775 \r
776 \r
777         BUS_ENTER( BUS_DBG_PNP );\r
778 \r
779         CL_ASSERT( p_pnp_rec->p_ca_attr->ca_guid );\r
780 \r
781         p_bfi = get_set_bfi_by_ca_guid( p_pnp_rec->p_ca_attr->ca_guid );\r
782         if ( !p_bfi ) {\r
783                 BUS_TRACE_EXIT( BUS_DBG_PNP,("NULL p_bfi? ca_guid 0x%I64x\n",\r
784                                                                 p_pnp_rec->p_ca_attr->ca_guid ) );\r
785                 return IB_ERROR;\r
786         }\r
787 \r
788         /*\r
789          * Allocate a PNP context for this object. pnp_rec.context is obj unique.\r
790          */\r
791         if ( !p_ctx ) {\r
792                 p_ctx = cl_zalloc( sizeof(*p_ctx) );\r
793                 if( !p_ctx )\r
794                 {\r
795                         BUS_TRACE_EXIT(BUS_DBG_PNP,\r
796                                         ("%s ca_guid %I64x port(%d) BAD alloc PNP context\n",\r
797                                         p_bfi->whoami, p_bfi->ca_guid, \r
798                                         p_pnp_rec->p_port_attr->port_num));\r
799                         return IB_ERROR;\r
800                 }\r
801                 p_ctx->p_bus_filter = p_bfi;\r
802                 p_ctx->port_num = p_pnp_rec->p_port_attr->port_num;\r
803                 p_pnp_rec->pnp_rec.context = p_ctx;\r
804 \r
805                 BUS_PRINT(BUS_DBG_PNP,\r
806                                         ("%s ca_guid %I64x port %d ALLOC p_ctx @ %p\n",\r
807                                         p_bfi->whoami, p_bfi->ca_guid, \r
808                                         p_pnp_rec->p_port_attr->port_num,p_ctx));\r
809         }\r
810 \r
811         p_port_mgr = p_bfi->p_port_mgr;\r
812 \r
813         if( !bus_globals.b_report_port_nic )\r
814         {\r
815                 BUS_EXIT( BUS_DBG_PNP );\r
816                 return IB_NOT_DONE;\r
817         }\r
818 \r
819         /* Upon hibernating the computer IB_BUS driver doesn't remove PDO, but\r
820            marks with a flag. So we first try to find an existing PDO for this port,\r
821            marked with this flag. If it was found, we turn off the flag and use\r
822            this PDO */\r
823         status = __port_was_hibernated( p_pnp_rec, p_bfi );\r
824         if( status != IB_NOT_FOUND )\r
825         {\r
826                 BUS_EXIT( BUS_DBG_PNP );\r
827                 return status;\r
828         }\r
829 \r
830         pCurList = bus_globals.p_device_list;\r
831 \r
832         while(pCurList)\r
833         {\r
834                 /* Create the PDO for the new port device. */\r
835                 status = IoCreateDevice( bus_globals.p_driver_obj,\r
836                                                                  sizeof(bus_port_ext_t),\r
837                                                                  NULL, FILE_DEVICE_CONTROLLER,\r
838                                                                  FILE_DEVICE_SECURE_OPEN |\r
839                                                                  FILE_AUTOGENERATED_DEVICE_NAME,\r
840                                                                  FALSE, &p_pdo );\r
841                 if( !NT_SUCCESS( status ) )\r
842                 {\r
843                         BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
844                                 ("IoCreateDevice returned %08x.\n", status) );\r
845                         return IB_ERROR;\r
846                 }\r
847 \r
848                 /* clean the extension (must be before initializing) */\r
849                 p_port_ext = p_pdo->DeviceExtension;\r
850                 memset( p_port_ext, 0, sizeof(bus_port_ext_t) );\r
851 \r
852                 /* Initialize the device extension. */\r
853                 cl_init_pnp_po_ext( p_pdo, NULL, p_pdo,\r
854                                                         bus_globals.dbg_lvl, &vfptr_port_pnp,\r
855                                                         &vfptr_port_query_txt );\r
856 \r
857                 /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */\r
858                 p_pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;\r
859 \r
860                 p_port_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0;\r
861                 p_port_ext->pdo.p_parent_ext = p_bfi->p_bus_ext;\r
862                 p_port_ext->pdo.b_present = TRUE;\r
863                 p_port_ext->pdo.b_reported_missing = FALSE;\r
864                 p_port_ext->pdo.b_hibernating = FALSE;\r
865                 p_port_ext->pdo.p_po_work_item = NULL;\r
866                 p_port_ext->pdo.p_pdo_device_info = &pCurList->io_device_info;\r
867                 BUS_TRACE( BUS_DBG_PNP,\r
868                         ("Created %s %s: PDO %p,ext %p, present %d, missing %d .\n",\r
869                         p_bfi->whoami,\r
870                         p_port_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_pdo,\r
871                         p_port_ext, p_port_ext->pdo.b_present,\r
872                         p_port_ext->pdo.b_reported_missing ) );\r
873 \r
874                 /* Cache the CA GUID. */\r
875                 p_port_ext->pdo.ca_guid = p_pnp_rec->p_ca_attr->ca_guid;\r
876 \r
877                 /*Only acquire one hca for each port*/\r
878                 if(h_ca)\r
879                 {\r
880                         p_port_ext->pdo.h_ca = h_ca;\r
881                         p_port_ext->pdo.hca_acquired = FALSE;\r
882                 }else\r
883                 {\r
884                         /* Acquire CA for the first child pdo*/\r
885                         h_ca = p_port_ext->pdo.h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid );\r
886                         p_port_ext->pdo.hca_acquired = TRUE;\r
887                 }\r
888 \r
889                 if( !p_port_ext->pdo.h_ca )\r
890                 {\r
891                         BUS_TRACE( BUS_DBG_PNP, ("Deleted device: PDO %p\n", p_pdo));\r
892                         IoDeleteDevice( p_pdo);\r
893                         BUS_TRACE_EXIT( BUS_DBG_ERROR, ("acquire_ca failed to find CA.\n") );\r
894                         return IB_INVALID_GUID;\r
895                 }\r
896 \r
897                 p_port_ext->port_guid.guid = p_pnp_rec->p_port_attr->port_guid;\r
898                 p_port_ext->n_port = p_pnp_rec->p_port_attr->port_num;\r
899 \r
900                 RtlInitUnicodeString(&uniKey, pCurList->io_device_info.pkey);\r
901                 RtlUnicodeStringToInteger(&uniKey,16,&pKey);\r
902                 p_port_ext->port_guid.pkey = (ib_net16_t)pKey;\r
903 \r
904                 p_port_ext->n_ifc_ref = 0;\r
905 \r
906 \r
907                 /* Store the device extension in the port vector for future queries. */\r
908                 cl_mutex_acquire( &p_port_mgr->pdo_mutex );\r
909                 cl_qlist_insert_tail( &p_port_mgr->port_list,\r
910                                                           &p_port_ext->pdo.list_item );\r
911                 cl_mutex_release( &p_port_mgr->pdo_mutex );\r
912 \r
913                 /*\r
914                  * Set the context of the PNP event. The context is passed in for future\r
915                  * events on the same port.\r
916                  */\r
917                 if(p_port_ext->pdo.hca_acquired)\r
918                 {\r
919                         p_ctx->p_pdo_ext = p_port_ext;\r
920                 }\r
921 \r
922                 pCurList = pCurList->next_device_info;\r
923 \r
924                 /* Tell the PnP Manager to rescan for the HCA's bus relations. */\r
925                 IoInvalidateDeviceRelations(\r
926                         p_port_ext->pdo.h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
927         }\r
928 \r
929         /* Invalidate removal relations for the bus driver. */\r
930         IoInvalidateDeviceRelations(\r
931                 p_bfi->p_bus_ext->cl_ext.p_pdo, RemovalRelations );\r
932 \r
933         BUS_EXIT( BUS_DBG_PNP );\r
934         return IB_SUCCESS;\r
935 }\r
936 \r
937 \r
938 \r
939 /************************************************************************************\r
940 * name  :       port_mgr_pkey_rem\r
941 *           removes pdo for each pkey value in pkey_array \r
942 * input :       g_pkeys\r
943 * output:       none\r
944 * return:       cl_status\r
945 *************************************************************************************/\r
946 cl_status_t _port_mgr_pkey_rem( IN      pkey_array_t    *pkeys,\r
947                                                                 IN      port_mgr_t              *p_port_mgr )\r
948 {\r
949 \r
950         uint16_t                        cnt;\r
951         cl_list_item_t          *p_list_item;\r
952         bus_port_ext_t          *p_port_ext;\r
953         bus_pdo_ext_t           *p_pdo_ext = NULL;\r
954         cl_qlist_t*                     p_pdo_list = &p_port_mgr->port_list;\r
955 \r
956         BUS_ENTER( BUS_DBG_PNP );\r
957 \r
958         p_port_ext = NULL;\r
959         cl_mutex_acquire( &p_port_mgr->pdo_mutex );\r
960         \r
961         /* Count the number of child devices. */\r
962         for( p_list_item = cl_qlist_head( p_pdo_list );\r
963                 p_list_item != cl_qlist_end( p_pdo_list );\r
964                 p_list_item = cl_qlist_next( p_list_item ) )\r
965         {\r
966                 p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
967                 p_port_ext = (bus_port_ext_t*)p_pdo_ext;\r
968 \r
969                 if(p_port_ext->port_guid.guid == pkeys->port_guid)\r
970                 {\r
971                         for(cnt = 0; cnt < pkeys->pkey_num; cnt++)\r
972                         {\r
973                                 if( (p_port_ext->port_guid.pkey == pkeys->pkey_array[cnt]) &&\r
974                                         (p_port_ext->port_guid.pkey != IB_DEFAULT_PKEY))\r
975                                 {\r
976                                         p_port_ext->pdo.b_present = FALSE;\r
977                                         break;\r
978                                 }\r
979                         }\r
980                 }\r
981         }\r
982         cl_mutex_release( &p_port_mgr->pdo_mutex );\r
983 \r
984         /* Tell the PnP Manager to rescan for the HCA's bus relations. */\r
985         IoInvalidateDeviceRelations(\r
986                 p_port_ext->pdo.h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
987 \r
988         BUS_EXIT( BUS_DBG_PNP );\r
989         return CL_SUCCESS;\r
990 }\r
991 \r
992 \r
993 cl_status_t port_mgr_pkey_rem( IN pkey_array_t *pkeys )\r
994 {\r
995         bus_filter_t    *p_bfi;\r
996         cl_status_t             status;\r
997         boolean_t               GO;\r
998         int                             success_cnt=0;\r
999 \r
1000         for(p_bfi=&g_bus_filters[0]; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1001         {\r
1002                 if ( !p_bfi->p_bus_ext )\r
1003                         continue;\r
1004                 GO = FALSE;\r
1005                 lock_control_event();\r
1006                 if ( p_bfi->ca_guid && p_bfi->p_port_mgr )\r
1007                         GO = TRUE;\r
1008                 unlock_control_event();\r
1009                 if ( GO == FALSE )\r
1010                         continue;\r
1011                 status = _port_mgr_pkey_rem( pkeys, p_bfi->p_port_mgr );\r
1012                 if ( status == CL_SUCCESS )\r
1013                         success_cnt++;\r
1014         }\r
1015         return ( success_cnt ? CL_SUCCESS : CL_ERROR );\r
1016 }\r
1017 \r
1018 \r
1019 /************************************************************************************\r
1020 * name  :       port_mgr_pkey_add\r
1021 *           creates pdo for each pkey value in pkey_array \r
1022 * input :       g_pkeys\r
1023 * output:       none\r
1024 * return:       cl_status\r
1025 *************************************************************************************/\r
1026 cl_status_t _port_mgr_pkey_add( IN      pkey_array_t    *req_pkeys,\r
1027                                                                 IN      bus_filter_t    *p_bfi,\r
1028                                                                 IN      port_mgr_t              *p_port_mgr )\r
1029 {\r
1030         uint16_t                        cnt;\r
1031         NTSTATUS            status;\r
1032         cl_list_item_t          *p_list_item;\r
1033         bus_port_ext_t          *p_port_ext, *pkey_port_ext, *pmatched_guid_ext;\r
1034         DEVICE_OBJECT       *p_pdo[MAX_NUM_PKEY];\r
1035         cl_qlist_t*                     p_pdo_list = &p_port_mgr->port_list;\r
1036 \r
1037         BUS_ENTER( BUS_DBG_PNP );\r
1038 \r
1039         pmatched_guid_ext = NULL;\r
1040         p_port_ext = NULL;\r
1041         cl_mutex_acquire( &p_port_mgr->pdo_mutex );\r
1042         \r
1043         /* Count the number of child devices. */\r
1044         for( p_list_item = cl_qlist_head( p_pdo_list );\r
1045                 p_list_item != cl_qlist_end( p_pdo_list );\r
1046                 p_list_item = cl_qlist_next( p_list_item ) )\r
1047         {\r
1048                 p_port_ext = (bus_port_ext_t*)PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
1049 \r
1050                 if(p_port_ext->port_guid.guid == req_pkeys->port_guid)\r
1051                 {\r
1052                         uint16_t i;\r
1053                         for(i = 0; i < req_pkeys->pkey_num; i++)\r
1054                         {\r
1055                                 if(p_port_ext->port_guid.pkey == req_pkeys->pkey_array[i])\r
1056                                 {\r
1057                                         /* was removed previously */\r
1058                                         p_port_ext->pdo.b_present = TRUE;\r
1059                                         p_port_ext->pdo.b_reported_missing = FALSE;\r
1060                                         req_pkeys->pkey_array[i] = 0;  \r
1061                                 }\r
1062                         }\r
1063                         if(!pmatched_guid_ext)\r
1064                                 pmatched_guid_ext = p_port_ext;\r
1065                 }\r
1066         }\r
1067         cl_mutex_release( &p_port_mgr->pdo_mutex );\r
1068 \r
1069         if (!pmatched_guid_ext)\r
1070         {\r
1071                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1072                         ("No existed pdo found.\n") );\r
1073                 return CL_NOT_FOUND;\r
1074         }\r
1075 \r
1076     for (cnt = 0; cnt < req_pkeys->pkey_num; cnt++)\r
1077     {\r
1078                 if(! (cl_hton16(req_pkeys->pkey_array[cnt]) & IB_PKEY_BASE_MASK) )\r
1079                         continue;\r
1080 \r
1081                 /* Create the PDO for the new port device. */\r
1082                 status = IoCreateDevice( bus_globals.p_driver_obj, sizeof(bus_port_ext_t),\r
1083                         NULL, FILE_DEVICE_CONTROLLER,\r
1084                         FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,\r
1085                         FALSE, &p_pdo[cnt] );\r
1086                 if( !NT_SUCCESS( status ) )\r
1087                 {\r
1088                         BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1089                                 ("IoCreateDevice returned %08x.\n", status) );\r
1090                         return CL_ERROR;\r
1091                 }\r
1092         \r
1093                 /* Initialize the device extension. */\r
1094                 cl_init_pnp_po_ext( p_pdo[cnt], NULL, p_pdo[cnt], bus_globals.dbg_lvl,\r
1095                         &vfptr_port_pnp, &vfptr_port_query_txt );\r
1096         \r
1097                 /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */\r
1098                 p_pdo[cnt]->Flags |= DO_BUS_ENUMERATED_DEVICE;\r
1099         \r
1100                 pkey_port_ext = p_pdo[cnt]->DeviceExtension;\r
1101                 pkey_port_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0;\r
1102                 pkey_port_ext->pdo.p_parent_ext = p_bfi->p_bus_ext;\r
1103                 pkey_port_ext->pdo.b_present = TRUE;\r
1104                 pkey_port_ext->pdo.b_reported_missing = FALSE;\r
1105                 pkey_port_ext->pdo.b_hibernating = FALSE;\r
1106                 pkey_port_ext->pdo.p_po_work_item = NULL;\r
1107                 BUS_TRACE( BUS_DBG_PNP, ("Created device for %s: PDO %p,ext %p, present %d, missing %d .\n",\r
1108                         pkey_port_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_pdo[cnt], pkey_port_ext, pkey_port_ext->pdo.b_present, \r
1109                         pkey_port_ext->pdo.b_reported_missing ) );\r
1110         \r
1111                 /* Cache the CA GUID. */\r
1112                 pkey_port_ext->pdo.ca_guid = pmatched_guid_ext->pdo.ca_guid;\r
1113                 pkey_port_ext->pdo.h_ca = pmatched_guid_ext->pdo.h_ca;\r
1114                 pkey_port_ext->port_guid.guid = pmatched_guid_ext->port_guid.guid;\r
1115                 pkey_port_ext->n_port = pmatched_guid_ext->n_port;\r
1116                 pkey_port_ext->port_guid.pkey = req_pkeys->pkey_array[cnt];\r
1117                 /* Store the device extension in the port vector for future queries. */\r
1118                 cl_mutex_acquire( &p_port_mgr->pdo_mutex );\r
1119                 cl_qlist_insert_tail( &p_port_mgr->port_list,\r
1120                         &pkey_port_ext->pdo.list_item );\r
1121                 cl_mutex_release( &p_port_mgr->pdo_mutex );\r
1122         }\r
1123 \r
1124         /* Tell the PnP Manager to rescan for the HCA's bus relations. */\r
1125         IoInvalidateDeviceRelations(\r
1126                 pmatched_guid_ext->pdo.h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
1127 \r
1128         /* Invalidate removal relations for the bus driver. */\r
1129         IoInvalidateDeviceRelations(\r
1130                 p_bfi->p_bus_ext->cl_ext.p_pdo, RemovalRelations );\r
1131 \r
1132         BUS_EXIT( BUS_DBG_PNP );\r
1133         return CL_SUCCESS;\r
1134 }\r
1135 \r
1136 cl_status_t port_mgr_pkey_add(pkey_array_t *pkeys)\r
1137 {\r
1138         bus_filter_t    *p_bfi;\r
1139         cl_status_t             status;\r
1140         boolean_t               GO;\r
1141         int                             success_cnt=0;\r
1142 \r
1143         for(p_bfi=&g_bus_filters[0]; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1144         {\r
1145                 if ( !p_bfi->p_bus_ext )\r
1146                         continue;\r
1147                 GO = FALSE;\r
1148                 lock_control_event();\r
1149                 if ( p_bfi->ca_guid && p_bfi->p_port_mgr )\r
1150                         GO = TRUE;\r
1151                 unlock_control_event();\r
1152                 if ( GO == FALSE )\r
1153                         continue;\r
1154                 status = _port_mgr_pkey_add( pkeys, p_bfi, p_bfi->p_port_mgr );\r
1155                 if ( status == CL_SUCCESS )\r
1156                         success_cnt++;\r
1157         }\r
1158         return ( success_cnt ? CL_SUCCESS : CL_ERROR );\r
1159 }\r
1160 \r
1161 \r
1162 void\r
1163 port_mgr_port_remove(\r
1164         IN                              ib_pnp_port_rec_t*              p_pnp_rec )\r
1165 {\r
1166         bus_pdo_ext_t   *p_ext;\r
1167         port_mgr_t              *p_port_mgr;\r
1168         bus_filter_t    *p_bfi;\r
1169         port_pnp_ctx_t  *p_ctx = p_pnp_rec->pnp_rec.context;\r
1170 \r
1171         BUS_ENTER( BUS_DBG_PNP );\r
1172 \r
1173         if ( !p_ctx ) {\r
1174                 BUS_EXIT( BUS_DBG_PNP );\r
1175                 return;\r
1176         }\r
1177 \r
1178         CL_ASSERT( p_ctx->p_bus_filter->magic == BFI_MAGIC );\r
1179         p_bfi = p_ctx->p_bus_filter;\r
1180         CL_ASSERT( p_bfi );\r
1181 \r
1182         BUS_PRINT(BUS_DBG_PNP,("%s ca_guid 0x%I64x port_num %d port_mgr %p\n",\r
1183                                                 p_bfi->whoami, p_bfi->ca_guid,\r
1184                                                 p_ctx->port_num, p_bfi->p_port_mgr));\r
1185 \r
1186         /* in the process of device remove, port_mgr has been destroyed.\r
1187          * cleanup allocated PNP port context; one per port.\r
1188          * The issue is the PNP PORT_REMOVE event occurs after\r
1189          * fdo_release_resources() completes.\r
1190          */\r
1191         if ( p_bfi->ca_guid == 0ULL || !p_bfi->p_port_mgr ) {\r
1192                 cl_free( p_ctx );\r
1193                 p_pnp_rec->pnp_rec.context = NULL;\r
1194                 BUS_EXIT( BUS_DBG_PNP );\r
1195                 return;\r
1196         }\r
1197 \r
1198         p_port_mgr = p_bfi->p_port_mgr;\r
1199 \r
1200         /* Within the PNP record's context is the port extension ptr;\r
1201          * see port_was_hibernated().\r
1202          */\r
1203         p_ext = p_ctx->p_pdo_ext;\r
1204         CL_ASSERT( p_ext );\r
1205 \r
1206         /*\r
1207          * Flag the port PDO as no longer being present.  We have to wait until\r
1208          * the PnP manager removes it to clean up.  However, we do release the\r
1209          * reference on the CA object in order to allow the removal of the HCA\r
1210          * to proceed should it occur before the port's PDO is cleaned up.\r
1211          */\r
1212         if ( !p_ext->h_ca )\r
1213         {\r
1214                 BUS_TRACE_EXIT( BUS_DBG_PNP,\r
1215                                                 ("%s NULL h_ca? p_ext %p\n", p_bfi->whoami, p_ext ) );\r
1216                 return;\r
1217         }\r
1218 \r
1219         // Don't crash if p_ext->p_parent_ext is NULL\r
1220         CL_ASSERT((p_ext->p_parent_ext == NULL) || p_bfi == p_ext->p_parent_ext->bus_filter);\r
1221         \r
1222         cl_mutex_acquire( &p_port_mgr->pdo_mutex );\r
1223         CL_ASSERT( p_ext->h_ca );\r
1224 \r
1225         if( p_ext->b_hibernating )\r
1226         {\r
1227                 BUS_TRACE( BUS_DBG_PNP, ("Skip port removing for %s: PDO %p, ext %p, "\r
1228                         "present %d, missing %d, hibernating %d .\n",\r
1229                         p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do,\r
1230                         p_ext, p_ext->b_present, p_ext->b_reported_missing,\r
1231                         p_ext->b_hibernating ) );\r
1232                 goto hca_deref;\r
1233         }\r
1234 \r
1235         p_ext->b_present = FALSE;\r
1236         BUS_TRACE( BUS_DBG_PNP,\r
1237                 ("Mark removing %s: PDO %p, ext %p, present %d, missing %d .\n",\r
1238                 p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext,\r
1239                 p_ext->b_present, p_ext->b_reported_missing ) );\r
1240 \r
1241         /* Invalidate removal relations for the bus driver. */\r
1242         IoInvalidateDeviceRelations(\r
1243                 p_bfi->p_bus_ext->cl_ext.p_pdo, RemovalRelations );\r
1244 \r
1245         /* Invalidate bus relations for the HCA. */\r
1246         IoInvalidateDeviceRelations(\r
1247                 p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
1248 \r
1249         /* Free PNP context memory */\r
1250         cl_free( p_ctx );\r
1251         p_pnp_rec->pnp_rec.context = NULL;\r
1252 \r
1253 hca_deref:\r
1254         deref_al_obj( &p_ext->h_ca->obj );\r
1255         \r
1256         //      Setting h_ca to be NULL forces IPoIB to start only after re-acquiring new CA object\r
1257         // The latter happens in __port_was_hibernated or port_mgr_port_add functions \r
1258         // after arriving IB_PNP_PORT_ADD event from IBAL\r
1259         p_ext->h_ca = NULL;\r
1260 \r
1261         cl_mutex_release( &p_port_mgr->pdo_mutex );\r
1262 \r
1263         BUS_EXIT( BUS_DBG_PNP );\r
1264 }\r
1265 \r
1266 \r
1267 static NTSTATUS\r
1268 port_start(\r
1269         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1270         IN                                      IRP* const                              p_irp,\r
1271                 OUT                             cl_irp_action_t* const  p_action )\r
1272 {\r
1273         bus_pdo_ext_t   *p_ext;\r
1274 \r
1275         BUS_ENTER( BUS_DBG_PNP );\r
1276 \r
1277         UNUSED_PARAM( p_irp );\r
1278 \r
1279         p_ext = p_dev_obj->DeviceExtension;\r
1280 \r
1281         /* Notify the Power Manager that the device is started. */\r
1282         PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
1283         *p_action = IrpComplete;\r
1284         BUS_EXIT( BUS_DBG_PNP );\r
1285 \r
1286         return STATUS_SUCCESS;\r
1287 }\r
1288 \r
1289 \r
1290 static NTSTATUS\r
1291 port_query_remove(\r
1292         IN                              DEVICE_OBJECT* const    p_dev_obj,\r
1293         IN                              IRP* const                              p_irp,\r
1294                 OUT                     cl_irp_action_t* const  p_action )\r
1295 {\r
1296         bus_port_ext_t  *p_ext;\r
1297 \r
1298         BUS_ENTER( BUS_DBG_PNP );\r
1299 \r
1300         UNUSED_PARAM( p_irp );\r
1301 \r
1302         p_ext = p_dev_obj->DeviceExtension;\r
1303 \r
1304         *p_action = IrpComplete;\r
1305 \r
1306         if( p_ext->n_ifc_ref )\r
1307         {\r
1308                 /*\r
1309                  * Our interface is still being held by someone.\r
1310                  * Rollback the PnP state that was changed in the complib handler.\r
1311                  */\r
1312                 cl_rollback_pnp_state( &p_ext->pdo.cl_ext );\r
1313 \r
1314                 /* Fail the query. */\r
1315                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Failing IRP_MN_QUERY_REMOVE_DEVICE:\n"\r
1316                         "\tInterface has %d reference\n", p_ext->n_ifc_ref ) );\r
1317                 return STATUS_UNSUCCESSFUL;\r
1318         }\r
1319 \r
1320         CL_ASSERT(p_ext->pdo.p_parent_ext->bus_filter);\r
1321         BUS_TRACE_EXIT( BUS_DBG_PNP,\r
1322                         ("OK IRP_MN_QUERY_REMOVE_DEVICE:\n  %s HCA guid %I64x port %d\n",\r
1323                         p_ext->pdo.p_parent_ext->bus_filter->whoami,\r
1324                         p_ext->pdo.ca_guid, p_ext->n_port ) );\r
1325 \r
1326         return STATUS_SUCCESS;\r
1327 }\r
1328 \r
1329 \r
1330 static void\r
1331 port_release_resources(\r
1332         IN                                      DEVICE_OBJECT* const    p_dev_obj )\r
1333 {\r
1334         bus_port_ext_t  *p_ext;\r
1335         POWER_STATE             po_state;\r
1336         port_mgr_t              *p_port_mgr;\r
1337 \r
1338         BUS_ENTER( BUS_DBG_PNP );\r
1339 \r
1340         p_ext = p_dev_obj->DeviceExtension;\r
1341         p_port_mgr = p_ext->pdo.p_parent_ext->bus_filter->p_port_mgr;\r
1342 \r
1343         /* skip releasing resources if PDO has not been yet reported missing */\r
1344         if (!p_ext->pdo.b_reported_missing) {\r
1345                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("PDO is not yet reported missing - skip the removing port from vector: PDO %p, ext %p\n",\r
1346                         p_dev_obj, p_ext) );\r
1347                 return;\r
1348         }\r
1349 \r
1350         /* Remove this PDO from its list. */\r
1351         cl_mutex_acquire( &p_port_mgr->pdo_mutex );\r
1352         BUS_TRACE( BUS_DBG_PNP, ("Removing port from vector: PDO %p, ext %p\n",\r
1353                                 p_dev_obj, p_ext) );\r
1354         cl_qlist_remove_item( &p_port_mgr->port_list, &p_ext->pdo.list_item );\r
1355         cl_mutex_release( &p_port_mgr->pdo_mutex );\r
1356         po_state.DeviceState = PowerDeviceD3;\r
1357         PoSetPowerState( p_ext->pdo.cl_ext.p_pdo, DevicePowerState, po_state );\r
1358 \r
1359         BUS_EXIT( BUS_DBG_PNP );\r
1360 }\r
1361 \r
1362 \r
1363 static NTSTATUS\r
1364 port_remove(\r
1365         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1366         IN                                      IRP* const                              p_irp,\r
1367                 OUT                             cl_irp_action_t* const  p_action )\r
1368 {\r
1369         bus_port_ext_t  *p_ext;\r
1370 \r
1371         BUS_ENTER( BUS_DBG_PNP );\r
1372 \r
1373         p_ext = p_dev_obj->DeviceExtension;\r
1374 \r
1375         if( p_ext->pdo.b_present )\r
1376         {\r
1377                 CL_ASSERT( p_ext->pdo.cl_ext.pnp_state != NotStarted );\r
1378                 CL_ASSERT( !p_ext->pdo.b_reported_missing );\r
1379                 /* Reset the state to NotStarted.  CompLib set it to Deleted. */\r
1380                 cl_set_pnp_state( &p_ext->pdo.cl_ext, NotStarted );\r
1381                 /* Don't delete the device.  It may simply be disabled. */\r
1382                 *p_action = IrpComplete;\r
1383                 BUS_TRACE_EXIT( BUS_DBG_PNP,\r
1384                                 ("Device %s still present: PDO %p, ext %p\n",\r
1385                                 p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_dev_obj, p_ext) );\r
1386                 return STATUS_SUCCESS;\r
1387         }\r
1388 \r
1389         if( !p_ext->pdo.b_reported_missing )\r
1390         {\r
1391                 /* Reset the state to RemovePending.  Complib set it to Deleted. */\r
1392                 cl_rollback_pnp_state( &p_ext->pdo.cl_ext );\r
1393                 *p_action = IrpComplete;\r
1394                 BUS_TRACE_EXIT( BUS_DBG_PNP,\r
1395                                                 ("Device %s not reported missing yet: PDO %p, ext %p\n",\r
1396                                                 p_ext->pdo.cl_ext.vfptr_pnp_po->identity,\r
1397                                                 p_dev_obj, p_ext) );\r
1398                 return STATUS_SUCCESS;\r
1399         }\r
1400 \r
1401         /* Wait for all I/O operations to complete. */\r
1402         IoReleaseRemoveLockAndWait( &p_ext->pdo.cl_ext.remove_lock, p_irp );\r
1403 \r
1404         /* Release resources if it was not done yet. */\r
1405         if( p_ext->pdo.cl_ext.last_pnp_state != SurpriseRemoved )\r
1406                 p_ext->pdo.cl_ext.vfptr_pnp_po->pfn_release_resources( p_dev_obj );\r
1407 \r
1408         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
1409         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1410 \r
1411         BUS_TRACE( BUS_DBG_PNP, ("Deleted device %s: PDO %p(=%p), ext %p\n",\r
1412                 p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do,\r
1413                 p_dev_obj, p_ext ) );\r
1414 \r
1415         IoDeleteDevice( p_dev_obj );\r
1416 \r
1417         *p_action = IrpDoNothing;\r
1418         BUS_EXIT( BUS_DBG_PNP );\r
1419         return STATUS_SUCCESS;\r
1420 }\r
1421 \r
1422 \r
1423 static NTSTATUS\r
1424 port_surprise_remove(\r
1425         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1426         IN                              IRP* const                                      p_irp,\r
1427                 OUT                     cl_irp_action_t* const          p_action )\r
1428 {\r
1429         bus_port_ext_t  *p_ext;\r
1430 \r
1431         BUS_ENTER( BUS_DBG_PNP );\r
1432 \r
1433         UNUSED_PARAM( p_irp );\r
1434 \r
1435         p_ext = p_dev_obj->DeviceExtension;\r
1436         //\r
1437         // Setting 2 folloeing flags seems like the right behaviour\r
1438         // according to DDK, but it causes \r
1439         // WHQL PnP SurpriseRemoval test to fail\r
1440         // So, as a work around, they are disabled for now.\r
1441         // The best solution is to rewrite all the drivers\r
1442         // to WDF model, hoping it will handle right all PnP/Power issues\r
1443         //\r
1444 //      p_ext->pdo.b_present = FALSE;\r
1445 //      p_ext->pdo.b_reported_missing = TRUE;\r
1446         if (!p_ext->pdo.b_reported_missing) {\r
1447                 // we have not yet reported the device absence \r
1448                 cl_rollback_pnp_state( &p_ext->pdo.cl_ext );\r
1449         }\r
1450         BUS_TRACE( BUS_DBG_PNP, ("%s: PDO %p, ext %p, present %d, missing %d .\n",\r
1451                 p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, \r
1452                 p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) );\r
1453 \r
1454         *p_action = IrpComplete;\r
1455 \r
1456         BUS_EXIT( BUS_DBG_PNP );\r
1457         return STATUS_SUCCESS;\r
1458 }\r
1459 \r
1460 \r
1461 static NTSTATUS\r
1462 port_query_capabilities(\r
1463         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1464         IN                                      IRP* const                              p_irp,\r
1465                 OUT                             cl_irp_action_t* const  p_action )\r
1466 {\r
1467         DEVICE_CAPABILITIES             *p_caps;\r
1468         IO_STACK_LOCATION               *p_io_stack;\r
1469 \r
1470         BUS_ENTER( BUS_DBG_PNP );\r
1471 \r
1472         UNUSED_PARAM( p_dev_obj );\r
1473 \r
1474         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1475         p_caps = p_io_stack->Parameters.DeviceCapabilities.Capabilities;\r
1476 \r
1477         p_caps->DeviceD1 = FALSE;\r
1478         p_caps->DeviceD2 = FALSE;\r
1479         p_caps->LockSupported = FALSE;\r
1480         p_caps->EjectSupported = FALSE;\r
1481         p_caps->Removable = FALSE;\r
1482         p_caps->DockDevice = FALSE;\r
1483         p_caps->UniqueID = TRUE;\r
1484         p_caps->SilentInstall = TRUE;\r
1485         p_caps->RawDeviceOK = FALSE;\r
1486         p_caps->SurpriseRemovalOK = FALSE;\r
1487         p_caps->WakeFromD0 = FALSE;\r
1488         p_caps->WakeFromD1 = FALSE;\r
1489         p_caps->WakeFromD2 = FALSE;\r
1490         p_caps->WakeFromD3 = FALSE;\r
1491         p_caps->HardwareDisabled = FALSE;\r
1492         p_caps->DeviceState[PowerSystemWorking] = PowerDeviceD0;\r
1493         p_caps->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;\r
1494         p_caps->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;\r
1495         p_caps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;\r
1496         p_caps->DeviceState[PowerSystemHibernate] = PowerDeviceD3;\r
1497         p_caps->DeviceState[PowerSystemShutdown] = PowerDeviceD3;\r
1498         p_caps->SystemWake = PowerSystemUnspecified;\r
1499         p_caps->DeviceWake = PowerDeviceUnspecified;\r
1500         p_caps->D1Latency = 0;\r
1501         p_caps->D2Latency = 0;\r
1502         p_caps->D3Latency = 0;\r
1503 \r
1504         *p_action = IrpComplete;\r
1505         BUS_EXIT( BUS_DBG_PNP );\r
1506         return STATUS_SUCCESS;\r
1507 }\r
1508 \r
1509 \r
1510 static NTSTATUS\r
1511 port_query_target_relations(\r
1512         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1513         IN                                      IRP* const                              p_irp,\r
1514                 OUT                             cl_irp_action_t* const  p_action )\r
1515 {\r
1516         NTSTATUS                        status;\r
1517         DEVICE_RELATIONS        *p_rel;\r
1518 \r
1519         BUS_ENTER( BUS_DBG_PNP );\r
1520 \r
1521         *p_action = IrpComplete;\r
1522 \r
1523         status = cl_alloc_relations( p_irp, 1 );\r
1524         if( !NT_SUCCESS( status ) )\r
1525         {\r
1526                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1527                         ("cl_alloc_relations returned 0x%08x.\n", status) );\r
1528                 return status;\r
1529         }\r
1530 \r
1531         p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
1532         p_rel->Count = 1;\r
1533         p_rel->Objects[0] = p_dev_obj;\r
1534 \r
1535         ObReferenceObject( p_dev_obj );\r
1536 \r
1537         BUS_EXIT( BUS_DBG_PNP );\r
1538         return status;\r
1539 }\r
1540 \r
1541 \r
1542 static NTSTATUS\r
1543 port_query_device_id(\r
1544         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1545                 OUT                             IRP* const                              p_irp )\r
1546 {\r
1547         WCHAR                           *p_string;\r
1548         bus_port_ext_t          *p_ext;\r
1549         size_t                          dev_id_size;\r
1550         \r
1551         BUS_ENTER( BUS_DBG_PNP );\r
1552 \r
1553         \r
1554         p_ext = (bus_port_ext_t*)p_dev_obj->DeviceExtension;\r
1555         if( !p_ext->pdo.b_present )\r
1556         {\r
1557                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1558                 return STATUS_NO_SUCH_DEVICE;\r
1559         }\r
1560 \r
1561         dev_id_size = p_ext->pdo.p_pdo_device_info->device_id_size;\r
1562 \r
1563         /* Device ID is "IBA\SID_<sid> where <sid> is the IO device Service ID. */\r
1564         p_string = ExAllocatePoolWithTag( PagedPool, dev_id_size, 'vedq' );\r
1565         if( !p_string )\r
1566         {\r
1567                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1568                         ("Failed to allocate device ID buffer (%d bytes).\n",\r
1569                         dev_id_size) );\r
1570                 return STATUS_INSUFFICIENT_RESOURCES;\r
1571         }\r
1572 \r
1573         RtlZeroMemory(p_string, dev_id_size);\r
1574 \r
1575         cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->device_id, dev_id_size );\r
1576 \r
1577         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1578 \r
1579         BUS_EXIT( BUS_DBG_PNP );\r
1580         return STATUS_SUCCESS;\r
1581 }\r
1582 \r
1583 \r
1584 static NTSTATUS\r
1585 port_query_hardware_ids(\r
1586         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1587                 OUT                             IRP* const                              p_irp )\r
1588 {\r
1589         WCHAR                           *p_string;\r
1590         bus_port_ext_t          *p_ext;\r
1591         size_t                          dev_id_size;\r
1592 \r
1593         BUS_ENTER( BUS_DBG_PNP );\r
1594 \r
1595 \r
1596         p_ext = (bus_port_ext_t*)p_dev_obj->DeviceExtension;\r
1597 \r
1598         dev_id_size = p_ext->pdo.p_pdo_device_info->hardware_id_size;\r
1599 \r
1600         p_string = ExAllocatePoolWithTag( PagedPool, dev_id_size, 'ihqp' );\r
1601         if( !p_string )\r
1602         {\r
1603                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1604                         ("Failed to allocate hardware ID buffer (%d bytes).\n",\r
1605                         dev_id_size) );\r
1606                 return STATUS_INSUFFICIENT_RESOURCES;\r
1607         }\r
1608 \r
1609         RtlZeroMemory(p_string, dev_id_size);\r
1610 \r
1611         cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->hardware_id, dev_id_size );\r
1612 \r
1613         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1614 \r
1615         BUS_EXIT( BUS_DBG_PNP );\r
1616         return STATUS_SUCCESS;\r
1617 }\r
1618 \r
1619 \r
1620 static NTSTATUS\r
1621 port_query_compatible_ids(\r
1622         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1623                 OUT                             IRP* const                              p_irp )\r
1624 {\r
1625         WCHAR                           *p_string;\r
1626         bus_port_ext_t          *p_ext;\r
1627         size_t                          dev_id_size;\r
1628 \r
1629         BUS_ENTER( BUS_DBG_PNP );\r
1630 \r
1631         p_ext = (bus_port_ext_t*)p_dev_obj->DeviceExtension;\r
1632 \r
1633         dev_id_size = p_ext->pdo.p_pdo_device_info->compatible_id_size;\r
1634 \r
1635         p_string = ExAllocatePoolWithTag( PagedPool, dev_id_size, 'ihqp' );\r
1636         if( !p_string )\r
1637         {\r
1638                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1639                         ("Failed to allocate hardware ID buffer (%d bytes).\n",\r
1640                         dev_id_size) );\r
1641                 return STATUS_INSUFFICIENT_RESOURCES;\r
1642         }\r
1643 \r
1644         RtlZeroMemory(p_string, dev_id_size);\r
1645 \r
1646         cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->compatible_id, dev_id_size );\r
1647 \r
1648         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1649 \r
1650         BUS_EXIT( BUS_DBG_PNP );\r
1651         return STATUS_SUCCESS;\r
1652 }\r
1653 \r
1654 \r
1655 static NTSTATUS\r
1656 port_query_unique_id(\r
1657         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1658                 OUT                             IRP* const                              p_irp )\r
1659 {\r
1660         NTSTATUS                        status;\r
1661         WCHAR                           *p_string;\r
1662         bus_port_ext_t          *p_ext;\r
1663 \r
1664         BUS_ENTER( BUS_DBG_PNP );\r
1665 \r
1666         p_ext = p_dev_obj->DeviceExtension;\r
1667 \r
1668         if( !p_ext->pdo.b_present )\r
1669         {\r
1670                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1671                 return STATUS_NO_SUCH_DEVICE;\r
1672         }\r
1673 \r
1674         /* The instance ID is the port GUID. */\r
1675         p_string = ExAllocatePoolWithTag( PagedPool, sizeof(WCHAR) * 21, 'iuqp' );\r
1676         if( !p_string )\r
1677         {\r
1678                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1679                         ("Failed to allocate instance ID buffer (%d bytes).\n",\r
1680                         sizeof(WCHAR) * 21) );\r
1681                 return STATUS_NO_MEMORY;\r
1682         }\r
1683 \r
1684         status = RtlStringCchPrintfW( p_string, 21, L"%016I64x%04x",p_ext->port_guid.guid,p_ext->port_guid.pkey );\r
1685         if( !NT_SUCCESS( status ) )\r
1686         {\r
1687                 CL_ASSERT( NT_SUCCESS( status ) );\r
1688                 ExFreePool( p_string );\r
1689                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1690                         ("RtlStringCchPrintfW returned %08x.\n", status) );\r
1691                 return status;\r
1692         }\r
1693 \r
1694         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1695 \r
1696         BUS_EXIT( BUS_DBG_PNP );\r
1697         return STATUS_SUCCESS;\r
1698 }\r
1699 \r
1700 \r
1701 static NTSTATUS\r
1702 port_query_description(\r
1703         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1704                 OUT                             IRP* const                              p_irp )\r
1705 {\r
1706         WCHAR                           *p_string;\r
1707         bus_port_ext_t          *p_ext;\r
1708         \r
1709         BUS_ENTER( BUS_DBG_PNP );\r
1710 \r
1711         p_ext = p_dev_obj->DeviceExtension;\r
1712         if( !p_ext->pdo.b_present )\r
1713         {\r
1714                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1715                 return STATUS_NO_SUCH_DEVICE;\r
1716         }\r
1717 \r
1718 \r
1719         p_string = ExAllocatePoolWithTag( PagedPool, p_ext->pdo.p_pdo_device_info->description_size, 'edqp' );\r
1720 \r
1721         if( !p_string )\r
1722         {\r
1723                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1724                         ("Failed to allocate device description buffer (%d bytes).\n",\r
1725                         p_ext->pdo.p_pdo_device_info->description_size) );\r
1726                 return STATUS_INSUFFICIENT_RESOURCES;\r
1727         }\r
1728 \r
1729         RtlZeroMemory(p_string,p_ext->pdo.p_pdo_device_info->description_size);\r
1730 \r
1731         cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->description, p_ext->pdo.p_pdo_device_info->description_size );\r
1732 \r
1733         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1734 \r
1735         BUS_EXIT( BUS_DBG_PNP );\r
1736         return STATUS_SUCCESS;\r
1737 }\r
1738 \r
1739 \r
1740 static NTSTATUS\r
1741 port_query_location(\r
1742         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1743                 OUT                             IRP* const                              p_irp )\r
1744 {\r
1745         WCHAR                           *p_string;\r
1746         bus_port_ext_t          *p_ext;\r
1747         size_t                          size;\r
1748         ULONG                           len;\r
1749         NTSTATUS                        status;\r
1750         DEVICE_OBJECT           *p_hca_dev;\r
1751 \r
1752         BUS_ENTER( BUS_DBG_PNP );\r
1753 \r
1754         p_ext = p_dev_obj->DeviceExtension;\r
1755         if( !p_ext->pdo.b_present )\r
1756         {\r
1757                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1758                 return STATUS_NO_SUCH_DEVICE;\r
1759         }\r
1760 \r
1761         p_hca_dev = p_ext->pdo.h_ca->obj.p_ci_ca->verbs.p_hca_dev;\r
1762 \r
1763         /* Get the length of the HCA's location. */\r
1764         status = IoGetDeviceProperty( p_hca_dev,\r
1765                 DevicePropertyLocationInformation, 0, NULL, &len );\r
1766         if( status != STATUS_BUFFER_TOO_SMALL )\r
1767         {\r
1768                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1769                         ("IoGetDeviceProperty for device location size returned %08x.\n",\r
1770                         status) );\r
1771                 return status;\r
1772         }\r
1773 \r
1774         /*\r
1775          * Allocate the string buffer to hold the HCA's location along with the\r
1776          * port number.  The port number is 32-bits, so in decimal it can be at\r
1777          * most 10 characters.\r
1778          */\r
1779         size = len + sizeof(L", port ") + (sizeof(WCHAR) * 10);\r
1780         if( size > (USHORT)-1 )\r
1781         {\r
1782                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1783                         ("Length beyond limits.\n") );\r
1784                 return STATUS_INSUFFICIENT_RESOURCES;\r
1785         }\r
1786 \r
1787         p_string = ExAllocatePoolWithTag( PagedPool, size, 'olqp' );\r
1788         if( !p_string )\r
1789         {\r
1790                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1791                         ("Failed to allocate device location buffer (%d bytes).\n", len) );\r
1792                 return STATUS_NO_MEMORY;\r
1793         }\r
1794 \r
1795         /* Get the HCA's location information. */\r
1796         status = IoGetDeviceProperty( p_hca_dev,\r
1797                 DevicePropertyLocationInformation, len, p_string, &len );\r
1798         if( !NT_SUCCESS( status ) )\r
1799         {\r
1800                 ExFreePool( p_string );\r
1801                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1802                         ("IoGetDeviceProperty for device location returned %08x.\n",\r
1803                         status) );\r
1804                 return status;\r
1805         }\r
1806 \r
1807         /* Append the port number to the HCA's location. */\r
1808         status = RtlStringCbPrintfW( p_string + (len/2) - 1, size - len + 1,\r
1809                 L", port %d", p_ext->n_port );\r
1810         if( !NT_SUCCESS( status ) )\r
1811         {\r
1812                 CL_ASSERT( NT_SUCCESS( status ) );\r
1813                 ExFreePool( p_string );\r
1814                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1815                         ("RtlStringCbPrintfW returned %08x.\n", status) );\r
1816                 return status;\r
1817         }\r
1818 \r
1819         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1820 \r
1821         BUS_EXIT( BUS_DBG_PNP );\r
1822         return STATUS_SUCCESS;\r
1823 }\r
1824 \r
1825 \r
1826 static NTSTATUS\r
1827 port_query_bus_info(\r
1828         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1829         IN                                      IRP* const                              p_irp,\r
1830                 OUT                             cl_irp_action_t* const  p_action )\r
1831 {\r
1832         PNP_BUS_INFORMATION     *p_bus_info;\r
1833 \r
1834         BUS_ENTER( BUS_DBG_PNP );\r
1835 \r
1836         UNUSED_PARAM( p_dev_obj );\r
1837 \r
1838         *p_action = IrpComplete;\r
1839 \r
1840         p_bus_info = ExAllocatePoolWithTag( PagedPool, sizeof(PNP_BUS_INFORMATION), 'ibqp' );\r
1841         if( !p_bus_info )\r
1842         {\r
1843                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1844                         ("Failed to allocate PNP_BUS_INFORMATION (%d bytes).\n",\r
1845                         sizeof(PNP_BUS_INFORMATION)) );\r
1846                 return STATUS_INSUFFICIENT_RESOURCES;\r
1847         }\r
1848 \r
1849         p_bus_info->BusTypeGuid = GUID_BUS_TYPE_IBA;\r
1850         //TODO: Memory from Intel - storage miniport would not stay loaded unless\r
1851         //TODO: bus type was PCI.  Look here if SRP is having problems staying\r
1852         //TODO: loaded.\r
1853         p_bus_info->LegacyBusType = PNPBus;\r
1854         p_bus_info->BusNumber = 0;\r
1855 \r
1856         p_irp->IoStatus.Information = (ULONG_PTR)p_bus_info;\r
1857         BUS_EXIT( BUS_DBG_PNP );\r
1858         return STATUS_SUCCESS;\r
1859 }\r
1860 \r
1861 \r
1862 static NTSTATUS\r
1863 port_query_ipoib_ifc(\r
1864         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1865         IN                              IO_STACK_LOCATION* const        p_io_stack )\r
1866 {\r
1867         NTSTATUS                                status;\r
1868         ib_al_ifc_t                             *p_ifc;\r
1869         ib_al_ifc_data_t                *p_ifc_data;\r
1870         ipoib_ifc_data_t                *p_ipoib_data;\r
1871         bus_port_ext_t                  *p_ext;\r
1872         const GUID                              *p_guid;\r
1873 \r
1874         BUS_ENTER( BUS_DBG_PNP );\r
1875 \r
1876         CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
1877 \r
1878         p_ext = p_dev_obj->DeviceExtension;\r
1879 \r
1880         BUS_TRACE( BUS_DBG_PNP, ("Query i/f for %s: PDO %p (=%p),ext %p, present %d, missing %d, hibernated %d .\n",\r
1881                 p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, \r
1882                 p_dev_obj, p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing, p_ext->pdo.b_hibernating ) );\r
1883 \r
1884         /* Get the interface. */\r
1885         status = cl_fwd_query_ifc(\r
1886                 p_ext->pdo.p_parent_ext->cl_ext.p_self_do, p_io_stack );\r
1887         if( !NT_SUCCESS( status ) )\r
1888         {\r
1889                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1890                         ("Failed to forward interface query: %08X\n", status) );\r
1891                 return status;\r
1892         }\r
1893 \r
1894         if( !p_io_stack->Parameters.QueryInterface.InterfaceSpecificData )\r
1895         {\r
1896                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("No interface specific data!\n") );\r
1897                 return status;\r
1898         }\r
1899 \r
1900         p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
1901 \r
1902         p_ifc_data = (ib_al_ifc_data_t*)\r
1903                 p_io_stack->Parameters.QueryInterface.InterfaceSpecificData;\r
1904         p_guid = p_ifc_data->type;\r
1905         if( !IsEqualGUID( p_guid, &GUID_IPOIB_INTERFACE_DATA ) )\r
1906         {\r
1907                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Unsupported interface data: \n\t"\r
1908                         "0x%08x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x,"\r
1909                         "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x.\n",\r
1910                         p_guid->Data1, p_guid->Data2, p_guid->Data3,\r
1911                         p_guid->Data4[0], p_guid->Data4[1], p_guid->Data4[2],\r
1912                         p_guid->Data4[3], p_guid->Data4[4], p_guid->Data4[5],\r
1913                         p_guid->Data4[6], p_guid->Data4[7]) );\r
1914                 return status;\r
1915         }\r
1916 \r
1917         if( p_ifc_data->version != IPOIB_INTERFACE_DATA_VERSION )\r
1918         {\r
1919                 p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context );\r
1920                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1921                         ("Unsupported version %d, expected %d\n",\r
1922                         p_ifc_data->version, IPOIB_INTERFACE_DATA_VERSION) );\r
1923                 return STATUS_NOT_SUPPORTED;\r
1924         }\r
1925 \r
1926         ASSERT( p_ifc_data->p_data );\r
1927 \r
1928         if( p_ifc_data->size != sizeof(ipoib_ifc_data_t) )\r
1929         {\r
1930                 p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context );\r
1931                 BUS_TRACE_EXIT( BUS_DBG_PNP,\r
1932                         ("Buffer too small (%d given, %d required).\n",\r
1933                         p_ifc_data->size,\r
1934                         sizeof(ipoib_ifc_data_t)) );\r
1935                 return STATUS_BUFFER_TOO_SMALL;\r
1936         }\r
1937 \r
1938         /* Set the interface data. */\r
1939         p_ipoib_data = (ipoib_ifc_data_t*)p_ifc_data->p_data;\r
1940 \r
1941         p_ipoib_data->ca_guid = p_ext->pdo.h_ca->obj.p_ci_ca->verbs.guid;\r
1942         p_ipoib_data->port_guid = p_ext->port_guid;\r
1943         p_ipoib_data->port_num = (uint8_t)p_ext->n_port;\r
1944 \r
1945         BUS_EXIT( BUS_DBG_PNP );\r
1946         return STATUS_SUCCESS;\r
1947 }\r
1948 \r
1949 \r
1950 static NTSTATUS\r
1951 port_query_interface(\r
1952         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1953         IN                                      IRP* const                              p_irp,\r
1954                 OUT                             cl_irp_action_t* const  p_action )\r
1955 {\r
1956         bus_pdo_ext_t           *p_ext;\r
1957         NTSTATUS                        status;\r
1958         IO_STACK_LOCATION       *p_io_stack;\r
1959 \r
1960         BUS_ENTER( BUS_DBG_PNP );\r
1961 \r
1962         PAGED_CODE();\r
1963 \r
1964         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1965 \r
1966         /* Bottom of the stack - IRP must be completed. */\r
1967         *p_action = IrpComplete;\r
1968 \r
1969         /* Compare requested GUID with our supported interface GUIDs. */\r
1970         if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
1971                 &GUID_IB_AL_INTERFACE ) )\r
1972         {\r
1973                 status = port_query_ipoib_ifc( p_dev_obj, p_io_stack );\r
1974         }\r
1975         else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
1976                 &GUID_BUS_INTERFACE_STANDARD ) )\r
1977         {\r
1978                 p_ext = p_dev_obj->DeviceExtension;\r
1979                 if( !p_ext->h_ca ||\r
1980                         !p_ext->b_present ||\r
1981                         !p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev ||\r
1982                         p_ext->b_reported_missing )\r
1983                 {\r
1984                         return STATUS_NO_SUCH_DEVICE;\r
1985                 }\r
1986 \r
1987                 status = cl_fwd_query_ifc(\r
1988                         p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, p_io_stack );\r
1989         }\r
1990         else\r
1991         {\r
1992                 status = p_irp->IoStatus.Status;\r
1993         }\r
1994         \r
1995         BUS_EXIT( BUS_DBG_PNP );\r
1996         return status;\r
1997 }\r
1998 \r
1999 \r
2000 /* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
2001 static void\r
2002 __HibernateUpWorkItem(\r
2003         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
2004         IN                              void*                                           context )\r
2005 {\r
2006         IO_STACK_LOCATION       *p_io_stack;\r
2007         bus_pdo_ext_t           *p_ext;\r
2008         IRP                                     *p_irp;\r
2009         POWER_STATE powerState;\r
2010 \r
2011         BUS_ENTER( BUS_DBG_POWER );\r
2012 \r
2013         p_ext = (bus_pdo_ext_t*)p_dev_obj->DeviceExtension;\r
2014         p_irp = (IRP*)context;\r
2015         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
2016 \r
2017         IoFreeWorkItem( p_ext->p_po_work_item );\r
2018         p_ext->p_po_work_item = NULL;\r
2019 \r
2020         while (!p_ext->h_ca) {\r
2021                 BUS_TRACE( BUS_DBG_PNP, ("Waiting for the end of HCA registration ... \n"));\r
2022                 cl_thread_suspend( 200 );       /* suspend for 200 ms */\r
2023         }\r
2024 \r
2025         p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
2026         powerState = PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
2027 \r
2028         BUS_TRACE( BUS_DBG_POWER, \r
2029                 ("PoSetPowerState: old state %d, new state to %d\n", \r
2030                 powerState.DeviceState, p_ext->dev_po_state ));\r
2031 \r
2032         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
2033         PoStartNextPowerIrp( p_irp );\r
2034         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
2035         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
2036 \r
2037         BUS_EXIT( BUS_DBG_POWER );\r
2038 }\r
2039 \r
2040 \r
2041 /*\r
2042  * The PDOs created by the IB Bus driver are software devices.  As such,\r
2043  * all power states are supported.  It is left to the HCA power policy\r
2044  * owner to handle which states can be supported by the HCA.\r
2045  */\r
2046 static NTSTATUS\r
2047 port_set_power(\r
2048         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
2049         IN                              IRP* const                                      p_irp,\r
2050                 OUT                     cl_irp_action_t* const          p_action )\r
2051 {\r
2052         NTSTATUS                        status = STATUS_SUCCESS;\r
2053         IO_STACK_LOCATION       *p_io_stack;\r
2054         bus_pdo_ext_t           *p_ext;\r
2055 \r
2056         BUS_ENTER( BUS_DBG_POWER );\r
2057 \r
2058         p_ext = p_dev_obj->DeviceExtension;\r
2059         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
2060 \r
2061         BUS_TRACE( BUS_DBG_POWER, \r
2062                 ("SET_POWER for PDO %p (ext %p): type %s, state %d, action %d \n",\r
2063                 p_dev_obj, p_ext,\r
2064                 (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
2065                 p_io_stack->Parameters.Power.State.DeviceState, \r
2066                 p_io_stack->Parameters.Power.ShutdownType ));\r
2067 \r
2068         if ((p_io_stack->Parameters.Power.Type == SystemPowerState) &&\r
2069                 (p_io_stack->Parameters.Power.State.SystemState ==PowerSystemHibernate ||\r
2070                 p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 ))\r
2071         {\r
2072                 BUS_TRACE( BUS_DBG_POWER, ("Setting b_hibernating flag for PDO %p \n", p_dev_obj));\r
2073                 p_ext->b_hibernating = TRUE;\r
2074         }\r
2075 \r
2076         if( p_io_stack->Parameters.Power.Type == DevicePowerState )\r
2077         {\r
2078                 /* after hibernation PDO is not ready for work. we need to wait for finishing of the HCA registration */\r
2079                 if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && p_ext->b_hibernating)\r
2080                 {\r
2081                         /* Process in a work item - deregister_ca and HcaDeinit block. */\r
2082                         ASSERT( !p_ext->p_po_work_item );\r
2083                         p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj );\r
2084                         if( !p_ext->p_po_work_item )\r
2085                                 status = STATUS_INSUFFICIENT_RESOURCES;\r
2086                         else {\r
2087                                 /* Process in work item callback. */\r
2088                                 IoMarkIrpPending( p_irp );\r
2089                                 IoQueueWorkItem(\r
2090                                         p_ext->p_po_work_item, __HibernateUpWorkItem, DelayedWorkQueue, p_irp );\r
2091                                 *p_action = IrpDoNothing;\r
2092                                 BUS_EXIT( BUS_DBG_POWER );\r
2093                                 return STATUS_PENDING;\r
2094                         }\r
2095                 }\r
2096 \r
2097                 /* Notify the power manager. */\r
2098                 p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
2099                 PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
2100         }\r
2101 \r
2102         *p_action = IrpComplete;\r
2103         BUS_EXIT( BUS_DBG_POWER );\r
2104         return status;\r
2105 }\r
2106 \r
2107 \r
2108 \r