8d79576f6fa6f48eb5f086ec614f36f952905ae2
[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_DEVICE_ID                 L"IBA\\IPoIB"\r
48 #define IPOIB_COMPAT_ID                 L"IBA\\SID_1000066a00020000\0\0"\r
49 /* Hardware ID is a MULTI_SZ, so is terminated with a double NULL. */\r
50 #define IPOIB_HARDWARE_ID               IPOIB_DEVICE_ID L"\0"\r
51 #define IPOIB_DESCRIPTION               L"OpenIB IPoIB Adapter"\r
52 \r
53 /* {5A9649F4-0101-4a7c-8337-796C48082DA2} */\r
54 DEFINE_GUID(GUID_BUS_TYPE_IBA,\r
55 0x5a9649f4, 0x101, 0x4a7c, 0x83, 0x37, 0x79, 0x6c, 0x48, 0x8, 0x2d, 0xa2);\r
56 \r
57 \r
58 /*\r
59  * Device extension for IPoIB port PDOs.\r
60  */\r
61 typedef struct _bus_port_ext\r
62 {\r
63         bus_pdo_ext_t                   pdo;\r
64 \r
65         port_guid_pkey                  port_guid;\r
66         uint32_t                                n_port;\r
67 \r
68         /* Number of references on the upper interface. */\r
69         atomic32_t                              n_ifc_ref;\r
70 \r
71 }       bus_port_ext_t;\r
72 \r
73 \r
74 port_mgr_t*                                             gp_port_mgr = NULL;\r
75 \r
76 extern pkey_array_t  g_pkeys;\r
77 \r
78 static boolean_t pkeys_enumerated = FALSE;\r
79 /*\r
80  * Function prototypes.\r
81  */\r
82 void\r
83 destroying_port_mgr(\r
84         IN                              cl_obj_t*                                       p_obj );\r
85 \r
86 void\r
87 free_port_mgr(\r
88         IN                              cl_obj_t*                                       p_obj );\r
89 \r
90 ib_api_status_t\r
91 bus_reg_port_pnp( void );\r
92 \r
93 ib_api_status_t\r
94 port_mgr_pnp_cb(\r
95         IN                              ib_pnp_rec_t*                           p_pnp_rec );\r
96 \r
97 ib_api_status_t\r
98 port_mgr_port_add(\r
99         IN                              ib_pnp_port_rec_t*                      p_pnp_rec );\r
100 \r
101 void\r
102 port_mgr_port_remove(\r
103         IN                              ib_pnp_port_rec_t*                      p_pnp_rec );\r
104 \r
105 static NTSTATUS\r
106 port_start(\r
107         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
108         IN                              IRP* const                                      p_irp,\r
109                 OUT                     cl_irp_action_t* const          p_action );\r
110 \r
111 static NTSTATUS\r
112 port_query_remove(\r
113         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
114         IN                              IRP* const                                      p_irp,\r
115                 OUT                     cl_irp_action_t* const          p_action );\r
116 \r
117 static void\r
118 port_release_resources(\r
119         IN                              DEVICE_OBJECT* const            p_dev_obj );\r
120 \r
121 static NTSTATUS\r
122 port_remove(\r
123         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
124         IN                              IRP* const                                      p_irp,\r
125                 OUT                     cl_irp_action_t* const          p_action );\r
126 \r
127 static NTSTATUS\r
128 port_surprise_remove(\r
129         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
130         IN                              IRP* const                                      p_irp,\r
131                 OUT                     cl_irp_action_t* const          p_action );\r
132 \r
133 static NTSTATUS\r
134 port_query_capabilities(\r
135         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
136         IN                              IRP* const                                      p_irp,\r
137                 OUT                     cl_irp_action_t* const          p_action );\r
138 \r
139 static NTSTATUS\r
140 port_query_target_relations(\r
141         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
142         IN                              IRP* const                                      p_irp,\r
143                 OUT                     cl_irp_action_t* const          p_action );\r
144 \r
145 static NTSTATUS\r
146 port_query_device_id(\r
147         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
148         IN                              IRP* const                                      p_irp );\r
149 \r
150 static NTSTATUS\r
151 port_query_hardware_ids(\r
152         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
153         IN                              IRP* const                                      p_irp );\r
154 \r
155 static NTSTATUS\r
156 port_query_compatible_ids(\r
157         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
158         IN                              IRP* const                                      p_irp );\r
159 \r
160 static NTSTATUS\r
161 port_query_unique_id(\r
162         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
163         IN                              IRP* const                                      p_irp );\r
164 \r
165 static NTSTATUS\r
166 port_query_description(\r
167         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
168         IN                              IRP* const                                      p_irp );\r
169 \r
170 static NTSTATUS\r
171 port_query_location(\r
172         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
173         IN                              IRP* const                                      p_irp );\r
174 \r
175 static NTSTATUS\r
176 port_query_bus_info(\r
177         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
178         IN                              IRP* const                                      p_irp,\r
179                 OUT                     cl_irp_action_t* const          p_action );\r
180 \r
181 static NTSTATUS\r
182 port_query_ipoib_ifc(\r
183         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
184         IN                              IO_STACK_LOCATION* const        p_io_stack );\r
185 \r
186 static NTSTATUS\r
187 port_query_interface(\r
188         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
189         IN                              IRP* const                                      p_irp,\r
190                 OUT                     cl_irp_action_t* const          p_action );\r
191 \r
192 static NTSTATUS\r
193 port_set_power(\r
194         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
195         IN                              IRP* const                                      p_irp,\r
196                 OUT                     cl_irp_action_t* const          p_action );\r
197 \r
198 \r
199 /* All PnP code is called at passive, so it can all be paged out. */\r
200 #ifdef ALLOC_PRAGMA\r
201 #pragma alloc_text (PAGE, port_start)\r
202 #pragma alloc_text (PAGE, port_query_remove)\r
203 #pragma alloc_text (PAGE, port_release_resources)\r
204 #pragma alloc_text (PAGE, port_remove)\r
205 #pragma alloc_text (PAGE, port_surprise_remove)\r
206 #pragma alloc_text (PAGE, port_query_capabilities)\r
207 #pragma alloc_text (PAGE, port_query_target_relations)\r
208 #pragma alloc_text (PAGE, port_query_device_id)\r
209 #pragma alloc_text (PAGE, port_query_hardware_ids)\r
210 #pragma alloc_text (PAGE, port_query_compatible_ids)\r
211 #pragma alloc_text (PAGE, port_query_unique_id)\r
212 #pragma alloc_text (PAGE, port_query_description)\r
213 #pragma alloc_text (PAGE, port_query_location)\r
214 #pragma alloc_text (PAGE, port_query_bus_info)\r
215 #pragma alloc_text (PAGE, port_query_ipoib_ifc)\r
216 #pragma alloc_text (PAGE, port_query_interface)\r
217 #pragma alloc_text (PAGE_PNP, port_set_power)\r
218 #pragma alloc_text (PAGE, port_mgr_port_add)\r
219 #pragma alloc_text (PAGE, port_mgr_port_remove)\r
220 #endif\r
221 \r
222 \r
223 /*\r
224  * Global virtual function pointer tables shared between all\r
225  * instances of Port PDOs.\r
226  */\r
227 static const cl_vfptr_pnp_po_t          vfptr_port_pnp = {\r
228         "IPoIB",\r
229         port_start,\r
230         cl_irp_succeed,\r
231         cl_irp_succeed,\r
232         cl_irp_succeed,\r
233         port_query_remove,\r
234         port_release_resources,\r
235         port_remove,\r
236         cl_irp_succeed,\r
237         port_surprise_remove,\r
238         port_query_capabilities,\r
239         cl_irp_complete,\r
240         cl_irp_complete,\r
241         cl_irp_succeed,\r
242         cl_irp_complete,\r
243         cl_irp_complete,\r
244         cl_irp_complete,\r
245         port_query_target_relations,\r
246         cl_irp_complete,\r
247         cl_irp_complete,\r
248         cl_irp_complete,\r
249         port_query_bus_info,\r
250         port_query_interface,\r
251         cl_irp_complete,\r
252         cl_irp_complete,\r
253         cl_irp_complete,\r
254         cl_irp_complete,\r
255         cl_irp_succeed,                         // QueryPower\r
256         port_set_power,                         // SetPower\r
257         cl_irp_unsupported,                     // PowerSequence\r
258         cl_irp_unsupported                      // WaitWake\r
259 };\r
260 \r
261 \r
262 static const cl_vfptr_query_txt_t               vfptr_port_query_txt = {\r
263         port_query_device_id,\r
264         port_query_hardware_ids,\r
265         port_query_compatible_ids,\r
266         port_query_unique_id,\r
267         port_query_description,\r
268         port_query_location\r
269 };\r
270 \r
271 \r
272 /*\r
273  * Create the AL load service.\r
274  */\r
275 ib_api_status_t\r
276 create_port_mgr(\r
277                 OUT                     port_mgr_t** const                      pp_port_mgr )\r
278 {\r
279         ib_api_status_t         status;\r
280         cl_status_t                     cl_status;\r
281 \r
282         BUS_ENTER( BUS_DBG_PNP );\r
283 \r
284         CL_ASSERT( !gp_port_mgr );\r
285 \r
286         gp_port_mgr = cl_zalloc( sizeof( port_mgr_t ) );\r
287         if( !gp_port_mgr )\r
288         {\r
289                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
290                         ("Failed to allocate port manager.\n") );\r
291                 return IB_INSUFFICIENT_MEMORY;\r
292         }\r
293 \r
294         /* Construct the load service. */\r
295         cl_obj_construct( &gp_port_mgr->obj, AL_OBJ_TYPE_LOADER );\r
296         cl_mutex_construct( &gp_port_mgr->pdo_mutex );\r
297         cl_qlist_init( &gp_port_mgr->port_list );\r
298 \r
299         cl_status = cl_mutex_init( &gp_port_mgr->pdo_mutex );\r
300         if( cl_status != CL_SUCCESS )\r
301         {\r
302                 free_port_mgr( &gp_port_mgr->obj );\r
303                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
304                         ("cl_mutex_init returned %#x.\n", cl_status) );\r
305                 return ib_convert_cl_status( cl_status );\r
306         }\r
307 \r
308         /* Initialize the load service object. */\r
309         cl_status = cl_obj_init( &gp_port_mgr->obj, CL_DESTROY_SYNC,\r
310                 destroying_port_mgr, NULL, free_port_mgr );\r
311         if( cl_status != CL_SUCCESS )\r
312         {\r
313                 free_port_mgr( &gp_port_mgr->obj );\r
314                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
315                         ("cl_obj_init returned %#x.\n", cl_status) );\r
316                 return ib_convert_cl_status( cl_status );\r
317         }\r
318 \r
319         /* Register for port PnP events. */\r
320         status = bus_reg_port_pnp();\r
321         if( status != IB_SUCCESS )\r
322         {\r
323                 cl_obj_destroy( &gp_port_mgr->obj );\r
324                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
325                         ("bus_reg_port_pnp returned %s.\n", ib_get_err_str(status)) );\r
326                 return status;\r
327         }\r
328 \r
329         *pp_port_mgr = gp_port_mgr;\r
330 \r
331         BUS_EXIT( BUS_DBG_PNP );\r
332         return IB_SUCCESS;\r
333 }\r
334 \r
335 \r
336 /*\r
337  * Pre-destroy the load service.\r
338  */\r
339 void\r
340 destroying_port_mgr(\r
341         IN                              cl_obj_t*                                       p_obj )\r
342 {\r
343         ib_api_status_t                 status;\r
344 \r
345         BUS_ENTER( BUS_DBG_PNP );\r
346 \r
347         CL_ASSERT( p_obj );\r
348         CL_ASSERT( gp_port_mgr == PARENT_STRUCT( p_obj, port_mgr_t, obj ) );\r
349         UNUSED_PARAM( p_obj );\r
350 \r
351         /* Deregister for port PnP events. */\r
352         if( gp_port_mgr->h_pnp )\r
353         {\r
354                 status = ib_dereg_pnp( gp_port_mgr->h_pnp,\r
355                         (ib_pfn_destroy_cb_t)cl_obj_deref );\r
356                 CL_ASSERT( status == IB_SUCCESS );\r
357         }\r
358         BUS_EXIT( BUS_DBG_PNP );\r
359 }\r
360 \r
361 \r
362 /*\r
363  * Free the load service.\r
364  */\r
365 void\r
366 free_port_mgr(\r
367         IN                              cl_obj_t*                                       p_obj )\r
368 {\r
369         bus_pdo_ext_t   *p_ext;\r
370         cl_list_item_t  *p_list_item;\r
371 \r
372         BUS_ENTER( BUS_DBG_PNP );\r
373 \r
374         CL_ASSERT( p_obj );\r
375         CL_ASSERT( gp_port_mgr == PARENT_STRUCT( p_obj, port_mgr_t, obj ) );\r
376 \r
377         /*\r
378          * Mark all IPoIB PDOs as no longer present.  This will cause them\r
379          * to be removed when they process the IRP_MN_REMOVE_DEVICE.\r
380          */\r
381         p_list_item = cl_qlist_remove_head( &gp_port_mgr->port_list );\r
382         while( p_list_item != cl_qlist_end( &gp_port_mgr->port_list ) )\r
383         {\r
384                 p_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
385                 p_list_item = cl_qlist_remove_head( &gp_port_mgr->port_list );\r
386                 if( p_ext->cl_ext.pnp_state == SurpriseRemoved )\r
387                 {\r
388                         CL_ASSERT( !p_ext->b_present );\r
389                         p_ext->b_reported_missing = TRUE;\r
390                         BUS_TRACE( BUS_DBG_PNP, ("%s: PDO %p, ext %p, present %d, missing %d .\n",\r
391                                 p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, p_ext->b_reported_missing ) );\r
392                         continue;\r
393                 }\r
394                 if( p_ext->h_ca )\r
395                 {\r
396                         /* Invalidate bus relations for the HCA. */\r
397                         IoInvalidateDeviceRelations(\r
398                                 p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
399 \r
400                         /* Release the reference on the CA object. */\r
401                         deref_al_obj( &p_ext->h_ca->obj );\r
402                 }\r
403                 BUS_TRACE( BUS_DBG_PNP, ("Deleted device %s: PDO %p, ext %p\n",\r
404                         p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext ) );\r
405                 IoDeleteDevice( p_ext->cl_ext.p_self_do );\r
406         }\r
407 \r
408         cl_mutex_destroy( &gp_port_mgr->pdo_mutex );\r
409         cl_obj_deinit( p_obj );\r
410         cl_free( gp_port_mgr );\r
411         gp_port_mgr = NULL;\r
412         BUS_EXIT( BUS_DBG_PNP );\r
413 }\r
414 \r
415 \r
416 /*\r
417  * Register the load service for the given PnP class events.\r
418  */\r
419 ib_api_status_t\r
420 bus_reg_port_pnp( void )\r
421 {\r
422         ib_pnp_req_t                    pnp_req;\r
423         ib_api_status_t                 status;\r
424 \r
425         cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) );\r
426         pnp_req.pnp_class       = IB_PNP_PORT | IB_PNP_FLAG_REG_SYNC;\r
427         pnp_req.pnp_context = gp_port_mgr;\r
428         pnp_req.pfn_pnp_cb      = port_mgr_pnp_cb;\r
429 \r
430         status = ib_reg_pnp( gh_al, &pnp_req, &gp_port_mgr->h_pnp );\r
431 \r
432         if( status == IB_SUCCESS )\r
433         {\r
434                 /* Reference the load service on behalf of the ib_reg_pnp call. */\r
435                 cl_obj_ref( &gp_port_mgr->obj );\r
436         }\r
437 \r
438         return status;\r
439 }\r
440 \r
441 \r
442 /*\r
443  * Load service PnP event callback.\r
444  */\r
445 ib_api_status_t\r
446 port_mgr_pnp_cb(\r
447         IN                              ib_pnp_rec_t*                           p_pnp_rec )\r
448 {\r
449         ib_api_status_t         status;\r
450 \r
451         BUS_ENTER( BUS_DBG_PNP );\r
452 \r
453         CL_ASSERT( p_pnp_rec );\r
454         CL_ASSERT( gp_port_mgr == p_pnp_rec->pnp_context );\r
455 \r
456         switch( p_pnp_rec->pnp_event )\r
457         {\r
458         case IB_PNP_PORT_ADD:\r
459                 status = port_mgr_port_add( (ib_pnp_port_rec_t*)p_pnp_rec );\r
460                 break;\r
461 \r
462         case IB_PNP_PORT_REMOVE:\r
463                 port_mgr_port_remove( (ib_pnp_port_rec_t*)p_pnp_rec );\r
464 \r
465         default:\r
466                 status = IB_SUCCESS;\r
467                 break;\r
468         }\r
469         BUS_EXIT( BUS_DBG_PNP );\r
470         return status;\r
471 }\r
472 \r
473 \r
474 /*\r
475  * Called to get bus relations for an HCA.\r
476  */\r
477 NTSTATUS\r
478 port_mgr_get_bus_relations(\r
479         IN              const   net64_t                                         ca_guid,\r
480         IN                              IRP* const                                      p_irp )\r
481 {\r
482         NTSTATUS                        status;\r
483 \r
484         BUS_ENTER( BUS_DBG_PNP );\r
485 \r
486         cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
487         status = bus_get_relations( &gp_port_mgr->port_list, ca_guid, p_irp );\r
488         cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
489 \r
490         BUS_EXIT( BUS_DBG_PNP );\r
491         return STATUS_SUCCESS;\r
492 }\r
493 \r
494 static ib_api_status_t\r
495 __port_was_hibernated(\r
496         IN                              ib_pnp_port_rec_t*                      p_pnp_rec )\r
497 {\r
498         NTSTATUS                status;\r
499         cl_list_item_t          *p_list_item;\r
500         bus_port_ext_t  *p_port_ext;\r
501         bus_pdo_ext_t   *p_pdo_ext = NULL;\r
502         size_t                  n_devs = 0;\r
503         cl_qlist_t*             p_pdo_list = &gp_port_mgr->port_list;\r
504 \r
505         BUS_ENTER( BUS_DBG_PNP );\r
506         \r
507         cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
508         \r
509         /* Count the number of child devices. */\r
510         for( p_list_item = cl_qlist_head( p_pdo_list );\r
511                 p_list_item != cl_qlist_end( p_pdo_list );\r
512                 p_list_item = cl_qlist_next( p_list_item ) )\r
513         {\r
514                 p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
515                 p_port_ext = (bus_port_ext_t*)p_pdo_ext;\r
516         \r
517                 if( p_pdo_ext->b_present && p_pdo_ext->b_hibernating &&\r
518                         (p_port_ext->port_guid.guid == p_pnp_rec->p_port_attr->port_guid) )\r
519                 {\r
520                         n_devs++;\r
521                         break;\r
522                 }\r
523 \r
524                 BUS_TRACE( BUS_DBG_PNP, \r
525                         ("Skipped PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
526                         p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, \r
527                         p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
528                         p_pdo_ext->b_hibernating, p_port_ext->port_guid.guid  ) );\r
529         }\r
530 \r
531         if (n_devs)\r
532         {\r
533                 /* Take a reference on the parent HCA. */\r
534                 p_pdo_ext->h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid );\r
535                 if( !p_pdo_ext->h_ca )\r
536                 {\r
537                         BUS_TRACE( BUS_DBG_ERROR, ("acquire_ca failed to find CA by guid %I64x\n",\r
538                                 p_pnp_rec->p_ca_attr->ca_guid ) );\r
539                         status = IB_INVALID_GUID;\r
540                 }\r
541                 else \r
542                 {\r
543                         p_pdo_ext->b_hibernating = FALSE;\r
544                         p_pnp_rec->pnp_rec.context = p_pdo_ext;\r
545                         status = IB_SUCCESS;\r
546                         p_port_ext = (bus_port_ext_t*)p_pdo_ext;\r
547                         BUS_TRACE( BUS_DBG_PNP, \r
548                                 ("Found PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n",\r
549                                 p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, \r
550                                 p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, \r
551                                 p_pdo_ext->b_hibernating, p_port_ext->port_guid.guid ) );\r
552                 }\r
553         }\r
554         else \r
555         {\r
556                 BUS_TRACE( BUS_DBG_PNP, ("Failed to find PDO for guid  %I64x .\n",\r
557                         p_pnp_rec->p_ca_attr->ca_guid ) );\r
558                 status = IB_NOT_FOUND;\r
559         }\r
560 \r
561         cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
562 \r
563         BUS_EXIT( BUS_DBG_PNP );\r
564         return status;\r
565 }\r
566 \r
567 ib_api_status_t\r
568 port_mgr_port_add(\r
569         IN                              ib_pnp_port_rec_t*                      p_pnp_rec )\r
570 {\r
571         NTSTATUS                status;\r
572     DEVICE_OBJECT   *p_pdo[MAX_NUM_PKEY + 1];\r
573     uint8_t         num_pdo;\r
574         bus_port_ext_t  *p_port_ext;\r
575         ib_net16_t      pdo_cnt;\r
576         BUS_ENTER( BUS_DBG_PNP );\r
577 \r
578         if( !bus_globals.b_report_port_nic )\r
579         {\r
580                 BUS_EXIT( BUS_DBG_PNP );\r
581                 return IB_NOT_DONE;\r
582         }\r
583 \r
584         /* Upon hibernating of the computer IB_BUS driver doesn't remove PDO, but\r
585            marks with a flag. So we first try to find an existing PDO for this port,\r
586            marked with this flag. If it was found, we turn off the flag and use this PDO */\r
587         status = __port_was_hibernated(p_pnp_rec);\r
588         if( status != IB_NOT_FOUND )\r
589         {\r
590                 BUS_EXIT( BUS_DBG_PNP );\r
591                 return status;\r
592         }\r
593 \r
594     p_port_ext = NULL;\r
595 \r
596         if( pkeys_enumerated)\r
597                 pdo_cnt = 1;\r
598         else\r
599                 pdo_cnt = g_pkeys.pkey_num + 1;\r
600 \r
601     for (num_pdo = 0; num_pdo < pdo_cnt; num_pdo++)\r
602     {\r
603         /* Create the PDO for the new port device. */\r
604         status = IoCreateDevice( bus_globals.p_driver_obj, sizeof(bus_port_ext_t),\r
605                 NULL, FILE_DEVICE_CONTROLLER,\r
606                 FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,\r
607                         FALSE, &p_pdo[num_pdo] );\r
608         if( !NT_SUCCESS( status ) )\r
609         {\r
610                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
611                         ("IoCreateDevice returned %08x.\n", status) );\r
612                 return IB_ERROR;\r
613         }\r
614 \r
615         /* Initialize the device extension. */\r
616                 cl_init_pnp_po_ext( p_pdo[num_pdo], NULL, p_pdo[num_pdo], bus_globals.dbg_lvl,\r
617                 &vfptr_port_pnp, &vfptr_port_query_txt );\r
618 \r
619         /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */\r
620                 p_pdo[num_pdo]->Flags |= DO_BUS_ENUMERATED_DEVICE;\r
621 \r
622                 p_port_ext = p_pdo[num_pdo]->DeviceExtension;\r
623         p_port_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0;\r
624         p_port_ext->pdo.p_parent_ext = bus_globals.p_bus_ext;\r
625         p_port_ext->pdo.b_present = TRUE;\r
626         p_port_ext->pdo.b_reported_missing = FALSE;\r
627         p_port_ext->pdo.b_hibernating = FALSE;\r
628         p_port_ext->pdo.p_po_work_item = NULL;\r
629         BUS_TRACE( BUS_DBG_PNP, ("Created device for %s: PDO %p,ext %p, present %d, missing %d .\n",\r
630                         p_port_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_pdo[num_pdo], p_port_ext, p_port_ext->pdo.b_present, \r
631                 p_port_ext->pdo.b_reported_missing ) );\r
632 \r
633         /* Cache the CA GUID. */\r
634         p_port_ext->pdo.ca_guid = p_pnp_rec->p_ca_attr->ca_guid;\r
635 \r
636         /* Take a reference on the parent HCA. */\r
637                 if(num_pdo > 0)\r
638                 {\r
639                         p_port_ext->pdo.h_ca = ((bus_port_ext_t*)p_pdo[0]->DeviceExtension)->pdo.h_ca;\r
640                 }\r
641                 else\r
642         p_port_ext->pdo.h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid );\r
643         if( !p_port_ext->pdo.h_ca )\r
644         {\r
645                         BUS_TRACE( BUS_DBG_PNP, ("Deleted device: PDO %p\n", p_pdo[num_pdo]));\r
646                         IoDeleteDevice( p_pdo[num_pdo]);\r
647                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("acquire_ca failed to find CA.\n") );\r
648                 return IB_INVALID_GUID;\r
649         }\r
650                 p_port_ext->port_guid.guid = p_pnp_rec->p_port_attr->port_guid;\r
651         p_port_ext->n_port = p_pnp_rec->p_port_attr->port_num;\r
652                 p_port_ext->port_guid.pkey = IB_DEFAULT_PKEY;\r
653 \r
654                 if(num_pdo > 0)\r
655                 {\r
656                   p_port_ext->port_guid.pkey = g_pkeys.pkey_array[num_pdo -1];\r
657                 }\r
658         /* Store the device extension in the port vector for future queries. */\r
659         cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
660         cl_qlist_insert_tail( &gp_port_mgr->port_list,\r
661                 &p_port_ext->pdo.list_item );\r
662         cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
663 \r
664         /*\r
665          * Set the context of the PNP event.  The context is passed in for future\r
666          * events on the same port.\r
667          */\r
668                 if(num_pdo == 0)\r
669                         p_pnp_rec->pnp_rec.context = p_port_ext;\r
670         }\r
671         pkeys_enumerated = TRUE;\r
672 \r
673         /* Tell the PnP Manager to rescan for the HCA's bus relations. */\r
674         IoInvalidateDeviceRelations(\r
675                 p_port_ext->pdo.h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
676 \r
677         /* Invalidate removal relations for the bus driver. */\r
678         IoInvalidateDeviceRelations(\r
679                 bus_globals.p_bus_ext->cl_ext.p_pdo, RemovalRelations );\r
680 \r
681         BUS_EXIT( BUS_DBG_PNP );\r
682         return IB_SUCCESS;\r
683 }\r
684 \r
685 /************************************************************************************\r
686 * name  :       port_mgr_pkey_add\r
687 *           creates pdo for each pkey value in pkey_array \r
688 * input :       g_pkeys\r
689 * output:       none\r
690 * return:       cl_status\r
691 *************************************************************************************/\r
692 cl_status_t port_mgr_pkey_add(pkey_array_t *pkeys)\r
693 {\r
694         uint16_t                        cnt;\r
695         NTSTATUS            status;\r
696         cl_list_item_t          *p_list_item;\r
697         bus_port_ext_t          *p_port_ext, *pkey_port_ext;\r
698         DEVICE_OBJECT       *p_pdo[MAX_NUM_PKEY];\r
699         bus_pdo_ext_t           *p_pdo_ext = NULL;\r
700         cl_qlist_t*                     p_pdo_list = &gp_port_mgr->port_list;\r
701 \r
702         BUS_ENTER( BUS_DBG_PNP );\r
703 \r
704         p_port_ext = NULL;\r
705         cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
706         \r
707         /* Count the number of child devices. */\r
708         for( p_list_item = cl_qlist_head( p_pdo_list );\r
709                 p_list_item != cl_qlist_end( p_pdo_list );\r
710                 p_list_item = cl_qlist_next( p_list_item ) )\r
711         {\r
712                 p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
713                 p_port_ext = (bus_port_ext_t*)p_pdo_ext;\r
714 \r
715                 if(p_port_ext->port_guid.pkey != IB_DEFAULT_PKEY)\r
716                         break;\r
717         }\r
718         cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
719 \r
720         if (!p_port_ext)\r
721         {\r
722                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
723                         ("No existed pdo found.\n") );\r
724                 return CL_ERROR;\r
725         }\r
726 \r
727     for (cnt = 0; cnt < pkeys->pkey_num; cnt++)\r
728     {\r
729 \r
730                 /* Create the PDO for the new port device. */\r
731                 status = IoCreateDevice( bus_globals.p_driver_obj, sizeof(bus_port_ext_t),\r
732                         NULL, FILE_DEVICE_CONTROLLER,\r
733                         FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,\r
734                         FALSE, &p_pdo[cnt] );\r
735                 if( !NT_SUCCESS( status ) )\r
736                 {\r
737                         BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
738                                 ("IoCreateDevice returned %08x.\n", status) );\r
739                         return CL_ERROR;\r
740                 }\r
741         \r
742                 /* Initialize the device extension. */\r
743                 cl_init_pnp_po_ext( p_pdo[cnt], NULL, p_pdo[cnt], bus_globals.dbg_lvl,\r
744                         &vfptr_port_pnp, &vfptr_port_query_txt );\r
745         \r
746                 /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */\r
747                 p_pdo[cnt]->Flags |= DO_BUS_ENUMERATED_DEVICE;\r
748         \r
749                 pkey_port_ext = p_pdo[cnt]->DeviceExtension;\r
750                 pkey_port_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0;\r
751                 pkey_port_ext->pdo.p_parent_ext = bus_globals.p_bus_ext;\r
752                 pkey_port_ext->pdo.b_present = TRUE;\r
753                 pkey_port_ext->pdo.b_reported_missing = FALSE;\r
754                 pkey_port_ext->pdo.b_hibernating = FALSE;\r
755                 pkey_port_ext->pdo.p_po_work_item = NULL;\r
756                 BUS_TRACE( BUS_DBG_PNP, ("Created device for %s: PDO %p,ext %p, present %d, missing %d .\n",\r
757                         pkey_port_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_pdo[cnt], pkey_port_ext, pkey_port_ext->pdo.b_present, \r
758                         pkey_port_ext->pdo.b_reported_missing ) );\r
759         \r
760                 /* Cache the CA GUID. */\r
761                 pkey_port_ext->pdo.ca_guid = p_port_ext->pdo.ca_guid;\r
762                 pkey_port_ext->pdo.h_ca = p_port_ext->pdo.h_ca;\r
763                 pkey_port_ext->port_guid.guid = p_port_ext->port_guid.guid;\r
764                 pkey_port_ext->n_port = p_port_ext->n_port;\r
765                 pkey_port_ext->port_guid.pkey = pkeys->pkey_array[cnt];\r
766 \r
767                 /* Store the device extension in the port vector for future queries. */\r
768                 cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
769                 cl_qlist_insert_tail( &gp_port_mgr->port_list,\r
770                         &pkey_port_ext->pdo.list_item );\r
771                 cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
772         }\r
773 \r
774         /* Tell the PnP Manager to rescan for the HCA's bus relations. */\r
775         IoInvalidateDeviceRelations(\r
776                 p_port_ext->pdo.h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
777 \r
778         /* Invalidate removal relations for the bus driver. */\r
779         IoInvalidateDeviceRelations(\r
780                 bus_globals.p_bus_ext->cl_ext.p_pdo, RemovalRelations );\r
781 \r
782         BUS_EXIT( BUS_DBG_PNP );\r
783         return CL_SUCCESS;\r
784 }\r
785 \r
786 void\r
787 port_mgr_port_remove(\r
788         IN                              ib_pnp_port_rec_t*                      p_pnp_rec )\r
789 {\r
790         bus_pdo_ext_t   *p_ext;\r
791 \r
792         BUS_ENTER( BUS_DBG_PNP );\r
793 \r
794         /* The PNP record's context is the port extension. */\r
795         p_ext = p_pnp_rec->pnp_rec.context;\r
796         CL_ASSERT( p_ext );\r
797 \r
798         /*\r
799          * Flag the port PDO as no longer being present.  We have to wait until\r
800          * the PnP manager removes it to clean up.  However, we do release the\r
801          * reference on the CA object in order to allow the removal of the HCA\r
802          * to proceed should it occur before the port's PDO is cleaned up.\r
803          */\r
804         cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
805         CL_ASSERT( p_ext->h_ca );\r
806 \r
807         if( p_ext->b_hibernating )\r
808         {\r
809                 BUS_TRACE( BUS_DBG_PNP, ("Skip port removing for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d .\n",\r
810                         p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, \r
811                         p_ext->b_reported_missing, p_ext->b_hibernating ) );\r
812                 goto hca_deref;\r
813         }\r
814 \r
815         p_ext->b_present = FALSE;\r
816         BUS_TRACE( BUS_DBG_PNP, ("Mark removing %s: PDO %p, ext %p, present %d, missing %d .\n",\r
817                 p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, p_ext->b_reported_missing ) );\r
818 \r
819         /* Invalidate removal relations for the bus driver. */\r
820         IoInvalidateDeviceRelations( bus_globals.p_bus_ext->cl_ext.p_pdo,\r
821                 RemovalRelations );\r
822 \r
823         /* Invalidate bus relations for the HCA. */\r
824         IoInvalidateDeviceRelations(\r
825                 p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations );\r
826 \r
827 hca_deref:\r
828         deref_al_obj( &p_ext->h_ca->obj );\r
829         p_ext->h_ca = NULL;\r
830         cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
831 \r
832         BUS_EXIT( BUS_DBG_PNP );\r
833 }\r
834 \r
835 \r
836 static NTSTATUS\r
837 port_start(\r
838         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
839         IN                                      IRP* const                              p_irp,\r
840                 OUT                             cl_irp_action_t* const  p_action )\r
841 {\r
842         bus_pdo_ext_t   *p_ext;\r
843 \r
844         BUS_ENTER( BUS_DBG_PNP );\r
845 \r
846         UNUSED_PARAM( p_irp );\r
847 \r
848         p_ext = p_dev_obj->DeviceExtension;\r
849 \r
850         /* Notify the Power Manager that the device is started. */\r
851         PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
852         *p_action = IrpComplete;\r
853         BUS_EXIT( BUS_DBG_PNP );\r
854         return STATUS_SUCCESS;\r
855 }\r
856 \r
857 \r
858 static NTSTATUS\r
859 port_query_remove(\r
860         IN                              DEVICE_OBJECT* const    p_dev_obj,\r
861         IN                              IRP* const                              p_irp,\r
862                 OUT                     cl_irp_action_t* const  p_action )\r
863 {\r
864         bus_port_ext_t  *p_ext;\r
865 \r
866         BUS_ENTER( BUS_DBG_PNP );\r
867 \r
868         UNUSED_PARAM( p_irp );\r
869 \r
870         p_ext = p_dev_obj->DeviceExtension;\r
871 \r
872         *p_action = IrpComplete;\r
873         if( p_ext->n_ifc_ref )\r
874         {\r
875                 /*\r
876                  * Our interface is still being held by someone.\r
877                  * Rollback the PnP state that was changed in the complib handler.\r
878                  */\r
879                 cl_rollback_pnp_state( &p_ext->pdo.cl_ext );\r
880 \r
881                 /* Fail the query. */\r
882                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Failing IRP_MN_QUERY_REMOVE_DEVICE:\n"\r
883                         "\tInterface has %d reference\n", p_ext->n_ifc_ref ) );\r
884                 return STATUS_UNSUCCESSFUL;\r
885         }\r
886 \r
887         BUS_EXIT( BUS_DBG_PNP );\r
888         return STATUS_SUCCESS;\r
889 }\r
890 \r
891 \r
892 static void\r
893 port_release_resources(\r
894         IN                                      DEVICE_OBJECT* const    p_dev_obj )\r
895 {\r
896         bus_port_ext_t  *p_ext;\r
897         POWER_STATE             po_state;\r
898 \r
899         BUS_ENTER( BUS_DBG_PNP );\r
900 \r
901         p_ext = p_dev_obj->DeviceExtension;\r
902 \r
903         /* Remove this PDO from its list. */\r
904         cl_mutex_acquire( &gp_port_mgr->pdo_mutex );\r
905         BUS_TRACE( BUS_DBG_PNP, ("Removing port from vector: PDO %p, ext %p\n", p_dev_obj, p_ext) );\r
906         cl_qlist_remove_item( &gp_port_mgr->port_list, &p_ext->pdo.list_item );\r
907         cl_mutex_release( &gp_port_mgr->pdo_mutex );\r
908         po_state.DeviceState = PowerDeviceD3;\r
909         PoSetPowerState( p_ext->pdo.cl_ext.p_pdo, DevicePowerState, po_state );\r
910 \r
911         BUS_EXIT( BUS_DBG_PNP );\r
912 }\r
913 \r
914 \r
915 static NTSTATUS\r
916 port_remove(\r
917         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
918         IN                                      IRP* const                              p_irp,\r
919                 OUT                             cl_irp_action_t* const  p_action )\r
920 {\r
921         bus_port_ext_t  *p_ext;\r
922 \r
923         BUS_ENTER( BUS_DBG_PNP );\r
924 \r
925         p_ext = p_dev_obj->DeviceExtension;\r
926 \r
927         if( p_ext->pdo.b_present )\r
928         {\r
929                 CL_ASSERT( p_ext->pdo.cl_ext.pnp_state != NotStarted );\r
930                 CL_ASSERT( !p_ext->pdo.b_reported_missing );\r
931                 /* Reset the state to NotStarted.  CompLib set it to Deleted. */\r
932                 cl_set_pnp_state( &p_ext->pdo.cl_ext, NotStarted );\r
933                 /* Don't delete the device.  It may simply be disabled. */\r
934                 *p_action = IrpComplete;\r
935                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device still present: PDO %p, ext %p\n", p_dev_obj, p_ext) );\r
936                 return STATUS_SUCCESS;\r
937         }\r
938 \r
939         if( !p_ext->pdo.b_reported_missing )\r
940         {\r
941                 /* Reset the state to RemovePending.  Complib set it to Deleted. */\r
942                 cl_rollback_pnp_state( &p_ext->pdo.cl_ext );\r
943                 *p_action = IrpComplete;\r
944                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device not reported missing yet: PDO %p, ext %p\n", p_dev_obj, p_ext) );\r
945                 return STATUS_SUCCESS;\r
946         }\r
947 \r
948         /* Wait for all I/O operations to complete. */\r
949         IoReleaseRemoveLockAndWait( &p_ext->pdo.cl_ext.remove_lock, p_irp );\r
950 \r
951         /* Release resources if it was not done yet. */\r
952         if( p_ext->pdo.cl_ext.last_pnp_state != SurpriseRemoved )\r
953                 p_ext->pdo.cl_ext.vfptr_pnp_po->pfn_release_resources( p_dev_obj );\r
954 \r
955         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
956         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
957 \r
958         BUS_TRACE( BUS_DBG_PNP, ("Deleted device %s: PDO %p(=%p), ext %p\n",\r
959                 p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, p_dev_obj, p_ext ) );\r
960         IoDeleteDevice( p_dev_obj );\r
961 \r
962         *p_action = IrpDoNothing;\r
963         BUS_EXIT( BUS_DBG_PNP );\r
964         return STATUS_SUCCESS;\r
965 }\r
966 \r
967 \r
968 static NTSTATUS\r
969 port_surprise_remove(\r
970         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
971         IN                              IRP* const                                      p_irp,\r
972                 OUT                     cl_irp_action_t* const          p_action )\r
973 {\r
974         bus_port_ext_t  *p_ext;\r
975 \r
976         BUS_ENTER( BUS_DBG_PNP );\r
977 \r
978         UNUSED_PARAM( p_irp );\r
979 \r
980         p_ext = p_dev_obj->DeviceExtension;\r
981         p_ext->pdo.b_present = FALSE;\r
982         p_ext->pdo.b_reported_missing = TRUE;\r
983         BUS_TRACE( BUS_DBG_PNP, ("%s: PDO %p, ext %p, present %d, missing %d .\n",\r
984                 p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, \r
985                 p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) );\r
986 \r
987         *p_action = IrpComplete;\r
988 \r
989         BUS_EXIT( BUS_DBG_PNP );\r
990         return STATUS_SUCCESS;\r
991 }\r
992 \r
993 \r
994 static NTSTATUS\r
995 port_query_capabilities(\r
996         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
997         IN                                      IRP* const                              p_irp,\r
998                 OUT                             cl_irp_action_t* const  p_action )\r
999 {\r
1000         DEVICE_CAPABILITIES             *p_caps;\r
1001         IO_STACK_LOCATION               *p_io_stack;\r
1002 \r
1003         BUS_ENTER( BUS_DBG_PNP );\r
1004 \r
1005         UNUSED_PARAM( p_dev_obj );\r
1006 \r
1007         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1008         p_caps = p_io_stack->Parameters.DeviceCapabilities.Capabilities;\r
1009 \r
1010         p_caps->DeviceD1 = FALSE;\r
1011         p_caps->DeviceD2 = FALSE;\r
1012         p_caps->LockSupported = FALSE;\r
1013         p_caps->EjectSupported = FALSE;\r
1014         p_caps->Removable = FALSE;\r
1015         p_caps->DockDevice = FALSE;\r
1016         p_caps->UniqueID = TRUE;\r
1017         p_caps->SilentInstall = TRUE;\r
1018         p_caps->RawDeviceOK = FALSE;\r
1019         p_caps->SurpriseRemovalOK = FALSE;\r
1020         p_caps->WakeFromD0 = FALSE;\r
1021         p_caps->WakeFromD1 = FALSE;\r
1022         p_caps->WakeFromD2 = FALSE;\r
1023         p_caps->WakeFromD3 = FALSE;\r
1024         p_caps->HardwareDisabled = FALSE;\r
1025         p_caps->DeviceState[PowerSystemWorking] = PowerDeviceD0;\r
1026         p_caps->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;\r
1027         p_caps->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;\r
1028         p_caps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;\r
1029         p_caps->DeviceState[PowerSystemHibernate] = PowerDeviceD3;\r
1030         p_caps->DeviceState[PowerSystemShutdown] = PowerDeviceD3;\r
1031         p_caps->SystemWake = PowerSystemUnspecified;\r
1032         p_caps->DeviceWake = PowerDeviceUnspecified;\r
1033         p_caps->D1Latency = 0;\r
1034         p_caps->D2Latency = 0;\r
1035         p_caps->D3Latency = 0;\r
1036 \r
1037         *p_action = IrpComplete;\r
1038         BUS_EXIT( BUS_DBG_PNP );\r
1039         return STATUS_SUCCESS;\r
1040 }\r
1041 \r
1042 \r
1043 static NTSTATUS\r
1044 port_query_target_relations(\r
1045         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1046         IN                                      IRP* const                              p_irp,\r
1047                 OUT                             cl_irp_action_t* const  p_action )\r
1048 {\r
1049         NTSTATUS                        status;\r
1050         DEVICE_RELATIONS        *p_rel;\r
1051 \r
1052         BUS_ENTER( BUS_DBG_PNP );\r
1053 \r
1054         *p_action = IrpComplete;\r
1055 \r
1056         status = cl_alloc_relations( p_irp, 1 );\r
1057         if( !NT_SUCCESS( status ) )\r
1058         {\r
1059                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1060                         ("cl_alloc_relations returned 0x%08x.\n", status) );\r
1061                 return status;\r
1062         }\r
1063 \r
1064         p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
1065         p_rel->Count = 1;\r
1066         p_rel->Objects[0] = p_dev_obj;\r
1067 \r
1068         ObReferenceObject( p_dev_obj );\r
1069 \r
1070         BUS_EXIT( BUS_DBG_PNP );\r
1071         return status;\r
1072 }\r
1073 \r
1074 \r
1075 static NTSTATUS\r
1076 port_query_device_id(\r
1077         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1078                 OUT                             IRP* const                              p_irp )\r
1079 {\r
1080         WCHAR                           *p_string;\r
1081         bus_port_ext_t          *p_ext;\r
1082         \r
1083         BUS_ENTER( BUS_DBG_PNP );\r
1084 \r
1085         \r
1086         p_ext = (bus_port_ext_t*)p_dev_obj->DeviceExtension;\r
1087         if( !p_ext->pdo.b_present )\r
1088         {\r
1089                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1090                 return STATUS_NO_SUCH_DEVICE;\r
1091         }\r
1092 \r
1093         /* Device ID is "IBA\SID_<sid> where <sid> is the IPoIB Service ID. */\r
1094         p_string = ExAllocatePoolWithTag( PagedPool, sizeof(IPOIB_DEVICE_ID), 'vedq' );\r
1095         if( !p_string )\r
1096         {\r
1097                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1098                         ("Failed to allocate device ID buffer (%d bytes).\n",\r
1099                         sizeof(IPOIB_DEVICE_ID)) );\r
1100                 return STATUS_INSUFFICIENT_RESOURCES;\r
1101         }\r
1102         cl_memcpy( p_string, IPOIB_DEVICE_ID, sizeof(IPOIB_DEVICE_ID) );\r
1103         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1104 \r
1105         BUS_EXIT( BUS_DBG_PNP );\r
1106         return STATUS_SUCCESS;\r
1107 }\r
1108 \r
1109 \r
1110 static NTSTATUS\r
1111 port_query_hardware_ids(\r
1112         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1113                 OUT                             IRP* const                              p_irp )\r
1114 {\r
1115         WCHAR                           *p_string;\r
1116         bus_port_ext_t          *p_ext;\r
1117 \r
1118         BUS_ENTER( BUS_DBG_PNP );\r
1119 \r
1120 \r
1121         p_ext = (bus_port_ext_t*)p_dev_obj->DeviceExtension;\r
1122         if( !p_ext->pdo.b_present )\r
1123         {\r
1124                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1125                 return STATUS_NO_SUCH_DEVICE;\r
1126         }\r
1127 \r
1128         p_string = ExAllocatePoolWithTag( PagedPool, sizeof(IPOIB_HARDWARE_ID), 'ihqp' );\r
1129         if( !p_string )\r
1130         {\r
1131                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1132                         ("Failed to allocate hardware ID buffer (%d bytes).\n",\r
1133                         sizeof(IPOIB_HARDWARE_ID)) );\r
1134                 return STATUS_INSUFFICIENT_RESOURCES;\r
1135         }\r
1136         cl_memcpy( p_string, IPOIB_HARDWARE_ID, sizeof(IPOIB_HARDWARE_ID) );\r
1137         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1138 \r
1139         BUS_EXIT( BUS_DBG_PNP );\r
1140         return STATUS_SUCCESS;\r
1141 }\r
1142 \r
1143 \r
1144 static NTSTATUS\r
1145 port_query_compatible_ids(\r
1146         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1147                 OUT                             IRP* const                              p_irp )\r
1148 {\r
1149         WCHAR                           *p_string;\r
1150 \r
1151         BUS_ENTER( BUS_DBG_PNP );\r
1152 \r
1153         UNUSED_PARAM( p_dev_obj );\r
1154 \r
1155         p_string = ExAllocatePoolWithTag( PagedPool, sizeof(IPOIB_COMPAT_ID), 'icqp' );\r
1156         if( !p_string )\r
1157         {\r
1158                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1159                         ("Failed to allocate compatible ID buffer (%d bytes).\n",\r
1160                         sizeof(IPOIB_COMPAT_ID)) );\r
1161                 return STATUS_INSUFFICIENT_RESOURCES;\r
1162         }\r
1163         cl_memcpy( p_string, IPOIB_COMPAT_ID, sizeof(IPOIB_COMPAT_ID) );\r
1164         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1165 \r
1166         BUS_EXIT( BUS_DBG_PNP );\r
1167         return STATUS_SUCCESS;\r
1168 }\r
1169 \r
1170 \r
1171 static NTSTATUS\r
1172 port_query_unique_id(\r
1173         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1174                 OUT                             IRP* const                              p_irp )\r
1175 {\r
1176         NTSTATUS                        status;\r
1177         WCHAR                           *p_string;\r
1178         bus_port_ext_t          *p_ext;\r
1179 \r
1180         BUS_ENTER( BUS_DBG_PNP );\r
1181 \r
1182         p_ext = p_dev_obj->DeviceExtension;\r
1183 \r
1184         if( !p_ext->pdo.b_present )\r
1185         {\r
1186                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1187                 return STATUS_NO_SUCH_DEVICE;\r
1188         }\r
1189 \r
1190         /* The instance ID is the port GUID. */\r
1191         p_string = ExAllocatePoolWithTag( PagedPool, sizeof(WCHAR) * 21, 'iuqp' );\r
1192         if( !p_string )\r
1193         {\r
1194                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1195                         ("Failed to allocate instance ID buffer (%d bytes).\n",\r
1196                         sizeof(WCHAR) * 21) );\r
1197                 return STATUS_NO_MEMORY;\r
1198         }\r
1199 \r
1200         status = RtlStringCchPrintfW( p_string, 21, L"%016I64x%04x",p_ext->port_guid.guid,p_ext->port_guid.pkey );\r
1201         if( !NT_SUCCESS( status ) )\r
1202         {\r
1203                 CL_ASSERT( NT_SUCCESS( status ) );\r
1204                 ExFreePool( p_string );\r
1205                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1206                         ("RtlStringCchPrintfW returned %08x.\n", status) );\r
1207                 return status;\r
1208         }\r
1209 \r
1210         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1211 \r
1212         BUS_EXIT( BUS_DBG_PNP );\r
1213         return STATUS_SUCCESS;\r
1214 }\r
1215 \r
1216 \r
1217 static NTSTATUS\r
1218 port_query_description(\r
1219         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1220                 OUT                             IRP* const                              p_irp )\r
1221 {\r
1222         WCHAR                           *p_string;\r
1223         bus_port_ext_t          *p_ext;\r
1224         \r
1225         BUS_ENTER( BUS_DBG_PNP );\r
1226 \r
1227         p_ext = p_dev_obj->DeviceExtension;\r
1228         if( !p_ext->pdo.b_present )\r
1229         {\r
1230                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1231                 return STATUS_NO_SUCH_DEVICE;\r
1232         }\r
1233 \r
1234 \r
1235         /* The instance ID is the port GUID. */\r
1236         p_string = ExAllocatePoolWithTag( PagedPool, sizeof(IPOIB_DESCRIPTION), 'edqp' );\r
1237         if( !p_string )\r
1238         {\r
1239                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1240                         ("Failed to allocate device description buffer (%d bytes).\n",\r
1241                         sizeof(IPOIB_DESCRIPTION)) );\r
1242                 return STATUS_INSUFFICIENT_RESOURCES;\r
1243         }\r
1244         cl_memcpy( p_string, IPOIB_DESCRIPTION, sizeof(IPOIB_DESCRIPTION) );\r
1245         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1246 \r
1247         BUS_EXIT( BUS_DBG_PNP );\r
1248         return STATUS_SUCCESS;\r
1249 }\r
1250 \r
1251 \r
1252 static NTSTATUS\r
1253 port_query_location(\r
1254         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1255                 OUT                             IRP* const                              p_irp )\r
1256 {\r
1257         WCHAR                           *p_string;\r
1258         bus_port_ext_t          *p_ext;\r
1259         size_t                          size;\r
1260         ULONG                           len;\r
1261         NTSTATUS                        status;\r
1262         DEVICE_OBJECT           *p_hca_dev;\r
1263 \r
1264         BUS_ENTER( BUS_DBG_PNP );\r
1265 \r
1266         p_ext = p_dev_obj->DeviceExtension;\r
1267         if( !p_ext->pdo.b_present )\r
1268         {\r
1269                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") );\r
1270                 return STATUS_NO_SUCH_DEVICE;\r
1271         }\r
1272 \r
1273         p_hca_dev = p_ext->pdo.h_ca->obj.p_ci_ca->verbs.p_hca_dev;\r
1274 \r
1275         /* Get the length of the HCA's location. */\r
1276         status = IoGetDeviceProperty( p_hca_dev,\r
1277                 DevicePropertyLocationInformation, 0, NULL, &len );\r
1278         if( status != STATUS_BUFFER_TOO_SMALL )\r
1279         {\r
1280                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1281                         ("IoGetDeviceProperty for device location size returned %08x.\n",\r
1282                         status) );\r
1283                 return status;\r
1284         }\r
1285 \r
1286         /*\r
1287          * Allocate the string buffer to hold the HCA's location along with the\r
1288          * port number.  The port number is 32-bits, so in decimal it can be at\r
1289          * most 10 characters.\r
1290          */\r
1291         size = len + sizeof(L", port ") + (sizeof(WCHAR) * 10);\r
1292         if( size > (USHORT)-1 )\r
1293         {\r
1294                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1295                         ("Length beyond limits.\n") );\r
1296                 return STATUS_INSUFFICIENT_RESOURCES;\r
1297         }\r
1298 \r
1299         p_string = ExAllocatePoolWithTag( PagedPool, size, 'olqp' );\r
1300         if( !p_string )\r
1301         {\r
1302                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1303                         ("Failed to allocate device location buffer (%d bytes).\n", len) );\r
1304                 return STATUS_NO_MEMORY;\r
1305         }\r
1306 \r
1307         /* Get the HCA's location information. */\r
1308         status = IoGetDeviceProperty( p_hca_dev,\r
1309                 DevicePropertyLocationInformation, len, p_string, &len );\r
1310         if( !NT_SUCCESS( status ) )\r
1311         {\r
1312                 ExFreePool( p_string );\r
1313                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1314                         ("IoGetDeviceProperty for device location returned %08x.\n",\r
1315                         status) );\r
1316                 return status;\r
1317         }\r
1318 \r
1319         /* Append the port number to the HCA's location. */\r
1320         status = RtlStringCbPrintfW( p_string + (len/2) - 1, size - len + 1,\r
1321                 L", port %d", p_ext->n_port );\r
1322         if( !NT_SUCCESS( status ) )\r
1323         {\r
1324                 CL_ASSERT( NT_SUCCESS( status ) );\r
1325                 ExFreePool( p_string );\r
1326                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1327                         ("RtlStringCbPrintfW returned %08x.\n", status) );\r
1328                 return status;\r
1329         }\r
1330 \r
1331         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1332 \r
1333         BUS_EXIT( BUS_DBG_PNP );\r
1334         return STATUS_SUCCESS;\r
1335 }\r
1336 \r
1337 \r
1338 static NTSTATUS\r
1339 port_query_bus_info(\r
1340         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1341         IN                                      IRP* const                              p_irp,\r
1342                 OUT                             cl_irp_action_t* const  p_action )\r
1343 {\r
1344         PNP_BUS_INFORMATION     *p_bus_info;\r
1345 \r
1346         BUS_ENTER( BUS_DBG_PNP );\r
1347 \r
1348         UNUSED_PARAM( p_dev_obj );\r
1349 \r
1350         *p_action = IrpComplete;\r
1351 \r
1352         p_bus_info = ExAllocatePoolWithTag( PagedPool, sizeof(PNP_BUS_INFORMATION), 'ibqp' );\r
1353         if( !p_bus_info )\r
1354         {\r
1355                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1356                         ("Failed to allocate PNP_BUS_INFORMATION (%d bytes).\n",\r
1357                         sizeof(PNP_BUS_INFORMATION)) );\r
1358                 return STATUS_INSUFFICIENT_RESOURCES;\r
1359         }\r
1360 \r
1361         p_bus_info->BusTypeGuid = GUID_BUS_TYPE_IBA;\r
1362         //TODO: Memory from Intel - storage miniport would not stay loaded unless\r
1363         //TODO: bus type was PCI.  Look here if SRP is having problems staying\r
1364         //TODO: loaded.\r
1365         p_bus_info->LegacyBusType = PNPBus;\r
1366         p_bus_info->BusNumber = 0;\r
1367 \r
1368         p_irp->IoStatus.Information = (ULONG_PTR)p_bus_info;\r
1369         BUS_EXIT( BUS_DBG_PNP );\r
1370         return STATUS_SUCCESS;\r
1371 }\r
1372 \r
1373 \r
1374 static NTSTATUS\r
1375 port_query_ipoib_ifc(\r
1376         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1377         IN                              IO_STACK_LOCATION* const        p_io_stack )\r
1378 {\r
1379         NTSTATUS                                status;\r
1380         ib_al_ifc_t                             *p_ifc;\r
1381         ib_al_ifc_data_t                *p_ifc_data;\r
1382         ipoib_ifc_data_t                *p_ipoib_data;\r
1383         bus_port_ext_t                  *p_ext;\r
1384         const GUID                              *p_guid;\r
1385         \r
1386 \r
1387         BUS_ENTER( BUS_DBG_PNP );\r
1388 \r
1389         CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
1390 \r
1391         p_ext = p_dev_obj->DeviceExtension;\r
1392 \r
1393         BUS_TRACE( BUS_DBG_PNP, ("Query i/f for %s: PDO %p (=%p),ext %p, present %d, missing %d .\n",\r
1394                 p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, \r
1395                 p_dev_obj, p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) );\r
1396 \r
1397         /* Get the interface. */\r
1398         status = cl_fwd_query_ifc(\r
1399                 p_ext->pdo.p_parent_ext->cl_ext.p_self_do, p_io_stack );\r
1400         if( !NT_SUCCESS( status ) )\r
1401         {\r
1402                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1403                         ("Failed to forward interface query: %08X\n", status) );\r
1404                 return status;\r
1405         }\r
1406 \r
1407         if( !p_io_stack->Parameters.QueryInterface.InterfaceSpecificData )\r
1408         {\r
1409                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("No interface specific data!\n") );\r
1410                 return status;\r
1411         }\r
1412 \r
1413         p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
1414 \r
1415         p_ifc_data = (ib_al_ifc_data_t*)\r
1416                 p_io_stack->Parameters.QueryInterface.InterfaceSpecificData;\r
1417         p_guid = p_ifc_data->type;\r
1418         if( !IsEqualGUID( p_guid, &GUID_IPOIB_INTERFACE_DATA ) )\r
1419         {\r
1420                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Unsupported interface data: \n\t"\r
1421                         "0x%08x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x,"\r
1422                         "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x.\n",\r
1423                         p_guid->Data1, p_guid->Data2, p_guid->Data3,\r
1424                         p_guid->Data4[0], p_guid->Data4[1], p_guid->Data4[2],\r
1425                         p_guid->Data4[3], p_guid->Data4[4], p_guid->Data4[5],\r
1426                         p_guid->Data4[6], p_guid->Data4[7]) );\r
1427                 return status;\r
1428         }\r
1429 \r
1430         if( p_ifc_data->version != IPOIB_INTERFACE_DATA_VERSION )\r
1431         {\r
1432                 p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context );\r
1433                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1434                         ("Unsupported version %d, expected %d\n",\r
1435                         p_ifc_data->version, IPOIB_INTERFACE_DATA_VERSION) );\r
1436                 return STATUS_NOT_SUPPORTED;\r
1437         }\r
1438 \r
1439         ASSERT( p_ifc_data->p_data );\r
1440 \r
1441         if( p_ifc_data->size != sizeof(ipoib_ifc_data_t) )\r
1442         {\r
1443                 p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context );\r
1444                 BUS_TRACE_EXIT( BUS_DBG_PNP,\r
1445                         ("Buffer too small (%d given, %d required).\n",\r
1446                         p_ifc_data->size,\r
1447                         sizeof(ipoib_ifc_data_t)) );\r
1448                 return STATUS_BUFFER_TOO_SMALL;\r
1449         }\r
1450 \r
1451         /* Set the interface data. */\r
1452         p_ipoib_data = (ipoib_ifc_data_t*)p_ifc_data->p_data;\r
1453 \r
1454         p_ipoib_data->ca_guid = p_ext->pdo.h_ca->obj.p_ci_ca->verbs.guid;\r
1455         p_ipoib_data->port_guid = p_ext->port_guid;\r
1456         p_ipoib_data->port_num = (uint8_t)p_ext->n_port;\r
1457 \r
1458         BUS_EXIT( BUS_DBG_PNP );\r
1459         return STATUS_SUCCESS;\r
1460 }\r
1461 \r
1462 \r
1463 static NTSTATUS\r
1464 port_query_interface(\r
1465         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1466         IN                                      IRP* const                              p_irp,\r
1467                 OUT                             cl_irp_action_t* const  p_action )\r
1468 {\r
1469         bus_pdo_ext_t           *p_ext;\r
1470         NTSTATUS                        status;\r
1471         IO_STACK_LOCATION       *p_io_stack;\r
1472 \r
1473         BUS_ENTER( BUS_DBG_PNP );\r
1474 \r
1475 #pragma warning( push, 3 )\r
1476         PAGED_CODE();\r
1477 #pragma warning( pop )\r
1478 \r
1479         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1480 \r
1481         /* Bottom of the stack - IRP must be completed. */\r
1482         *p_action = IrpComplete;\r
1483 \r
1484         /* Compare requested GUID with our supported interface GUIDs. */\r
1485         if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
1486                 &GUID_IB_AL_INTERFACE ) )\r
1487         {\r
1488                 status = port_query_ipoib_ifc( p_dev_obj, p_io_stack );\r
1489         }\r
1490         else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
1491                 &GUID_BUS_INTERFACE_STANDARD ) )\r
1492         {\r
1493                 p_ext = p_dev_obj->DeviceExtension;\r
1494                 if( !p_ext->h_ca ||\r
1495                         !p_ext->b_present ||\r
1496                         p_ext->b_reported_missing )\r
1497                 {\r
1498                         return STATUS_NO_SUCH_DEVICE;\r
1499                 }\r
1500 \r
1501                 status = cl_fwd_query_ifc(\r
1502                         p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, p_io_stack );\r
1503         }\r
1504         else\r
1505         {\r
1506                 status = p_irp->IoStatus.Status;\r
1507         }\r
1508         \r
1509         BUS_EXIT( BUS_DBG_PNP );\r
1510         return status;\r
1511 }\r
1512 \r
1513 \r
1514 /* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
1515 static void\r
1516 __HibernateUpWorkItem(\r
1517         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
1518         IN                              void*                                           context )\r
1519 {\r
1520         IO_STACK_LOCATION       *p_io_stack;\r
1521         bus_pdo_ext_t           *p_ext;\r
1522         IRP                                     *p_irp;\r
1523         POWER_STATE powerState;\r
1524 \r
1525         BUS_ENTER( BUS_DBG_POWER );\r
1526 \r
1527         p_ext = (bus_pdo_ext_t*)p_dev_obj->DeviceExtension;\r
1528         p_irp = (IRP*)context;\r
1529         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1530 \r
1531         IoFreeWorkItem( p_ext->p_po_work_item );\r
1532         p_ext->p_po_work_item = NULL;\r
1533 \r
1534         while (!p_ext->h_ca) {\r
1535                 BUS_TRACE( BUS_DBG_PNP, ("Waiting for the end of HCA registration ... \n"));\r
1536                 cl_thread_suspend( 200 );       /* suspend for 200 ms */\r
1537         }\r
1538 \r
1539         p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
1540         powerState = PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
1541 \r
1542         BUS_TRACE( BUS_DBG_POWER, \r
1543                 ("PoSetPowerState: old state %d, new state to %d\n", \r
1544                 powerState.DeviceState, p_ext->dev_po_state ));\r
1545 \r
1546         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
1547         PoStartNextPowerIrp( p_irp );\r
1548         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1549         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1550 \r
1551         BUS_EXIT( BUS_DBG_POWER );\r
1552 }\r
1553 \r
1554 \r
1555 /*\r
1556  * The PDOs created by the IB Bus driver are software devices.  As such,\r
1557  * all power states are supported.  It is left to the HCA power policy\r
1558  * owner to handle which states can be supported by the HCA.\r
1559  */\r
1560 static NTSTATUS\r
1561 port_set_power(\r
1562         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1563         IN                              IRP* const                                      p_irp,\r
1564                 OUT                     cl_irp_action_t* const          p_action )\r
1565 {\r
1566         NTSTATUS                        status = STATUS_SUCCESS;\r
1567         IO_STACK_LOCATION       *p_io_stack;\r
1568         bus_pdo_ext_t           *p_ext;\r
1569 \r
1570         BUS_ENTER( BUS_DBG_POWER );\r
1571 \r
1572         p_ext = p_dev_obj->DeviceExtension;\r
1573         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1574 \r
1575         BUS_TRACE( BUS_DBG_POWER, \r
1576                 ("SET_POWER for PDO %p (ext %p): type %s, state %d, action %d \n",\r
1577                 p_dev_obj, p_ext,\r
1578                 (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState",\r
1579                 p_io_stack->Parameters.Power.State.DeviceState, \r
1580                 p_io_stack->Parameters.Power.ShutdownType ));\r
1581 \r
1582         if ((p_io_stack->Parameters.Power.Type == SystemPowerState) &&\r
1583                 (p_io_stack->Parameters.Power.State.SystemState ==PowerSystemHibernate ||\r
1584                 p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 ))\r
1585         {\r
1586                 BUS_TRACE( BUS_DBG_POWER, ("Setting b_hibernating flag for PDO %p \n", p_dev_obj));\r
1587                 p_ext->b_hibernating = TRUE;\r
1588         }\r
1589 \r
1590         if( p_io_stack->Parameters.Power.Type == DevicePowerState )\r
1591         {\r
1592                 /* after hibernation PDO is not ready for work. we need to wait for finishing of the HCA registration */\r
1593                 if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && p_ext->b_hibernating)\r
1594                 {\r
1595                         /* Process in a work item - deregister_ca and HcaDeinit block. */\r
1596                         ASSERT( !p_ext->p_po_work_item );\r
1597                         p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj );\r
1598                         if( !p_ext->p_po_work_item )\r
1599                                 status = STATUS_INSUFFICIENT_RESOURCES;\r
1600                         else {\r
1601                                 /* Process in work item callback. */\r
1602                                 IoMarkIrpPending( p_irp );\r
1603                                 IoQueueWorkItem(\r
1604                                         p_ext->p_po_work_item, __HibernateUpWorkItem, DelayedWorkQueue, p_irp );\r
1605                                 *p_action = IrpDoNothing;\r
1606                                 BUS_EXIT( BUS_DBG_POWER );\r
1607                                 return STATUS_PENDING;\r
1608                         }\r
1609                 }\r
1610 \r
1611                 /* Notify the power manager. */\r
1612                 p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
1613                 PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
1614         }\r
1615 \r
1616         *p_action = IrpComplete;\r
1617         BUS_EXIT( BUS_DBG_POWER );\r
1618         return status;\r
1619 }\r