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