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