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