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