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