0c2fc9e449bd8b4d5e2be156583938da4415cf9d
[mirror/winof/.git] / core / bus / kernel / bus_pnp.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 \r
35 /*\r
36  * Implemenation of all PnP functionality for FDO (power policy owners).\r
37  */\r
38 \r
39 #include "bus_pnp.h"\r
40 #include "al_ca.h"\r
41 #include "al_init.h"\r
42 #include "al_dev.h"\r
43 #include "bus_port_mgr.h"\r
44 #include "bus_iou_mgr.h"\r
45 #include "complib/cl_memory.h"\r
46 #include <initguid.h>\r
47 #include "iba/ib_ci_ifc.h"\r
48 \r
49 \r
50 /* Interface names are generated by IoRegisterDeviceInterface. */\r
51 static UNICODE_STRING   al_ifc_name;\r
52 static UNICODE_STRING   ci_ifc_name;\r
53 \r
54 FAST_MUTEX                              ControlMutex;\r
55 ULONG                                   bfi_InstanceCount;\r
56 bus_filter_t                    bus_filters[MAX_BUS_FILTERS];\r
57 \r
58 extern ib_al_handle_t   gh_al; // NULL if AL needs init.\r
59 \r
60 \r
61 static NTSTATUS\r
62 fdo_start(\r
63         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
64         IN                                      IRP* const                              p_irp, \r
65                 OUT                             cl_irp_action_t* const  p_action );\r
66 \r
67 static void\r
68 fdo_release_resources(\r
69         IN                                      DEVICE_OBJECT* const    p_dev_obj );\r
70 \r
71 static NTSTATUS\r
72 fdo_query_remove(\r
73         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
74         IN                                      IRP* const                              p_irp, \r
75                 OUT                             cl_irp_action_t* const  p_action );\r
76 \r
77 static NTSTATUS\r
78 fdo_query_capabilities(\r
79         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
80         IN                                      IRP* const                              p_irp, \r
81                 OUT                             cl_irp_action_t* const  p_action );\r
82 \r
83 static NTSTATUS\r
84 fdo_query_bus_relations(\r
85         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
86         IN                                      IRP* const                              p_irp, \r
87                 OUT                             cl_irp_action_t* const  p_action );\r
88 \r
89 static NTSTATUS\r
90 __query_al_ifc(\r
91         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
92         IN                              IO_STACK_LOCATION* const        p_io_stack );\r
93 \r
94 static NTSTATUS\r
95 __get_relations(\r
96         IN              const   net64_t                                         ca_guid,\r
97         IN                              IRP* const                                      p_irp );\r
98 \r
99 static NTSTATUS\r
100 __query_ci_ifc(\r
101         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
102         IN                              IO_STACK_LOCATION* const        p_io_stack );\r
103 \r
104 static NTSTATUS\r
105 fdo_query_interface(\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 __fdo_query_power(\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 NTSTATUS\r
117 __fdo_set_power(\r
118         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
119         IN                              IRP* const                                      p_irp,\r
120                 OUT                     cl_irp_action_t* const          p_action );\r
121 \r
122 \r
123 /* All PnP code is called at passive, so it can all be paged out. */\r
124 #ifdef ALLOC_PRAGMA\r
125 #pragma alloc_text (PAGE, bus_add_device)\r
126 #pragma alloc_text (PAGE, fdo_start)\r
127 #pragma alloc_text (PAGE, fdo_query_remove)\r
128 #pragma alloc_text (PAGE, fdo_release_resources)\r
129 #pragma alloc_text (PAGE, fdo_query_capabilities)\r
130 #pragma alloc_text (PAGE, fdo_query_bus_relations)\r
131 #pragma alloc_text (PAGE, __query_al_ifc)\r
132 #pragma alloc_text (PAGE, __query_ci_ifc)\r
133 #pragma alloc_text (PAGE, __get_relations)\r
134 #pragma alloc_text (PAGE, fdo_query_interface)\r
135 #pragma alloc_text (PAGE_PNP, __fdo_query_power)\r
136 #pragma alloc_text (PAGE_PNP, __fdo_set_power)\r
137 #endif\r
138 \r
139 \r
140 /* Global virtual function pointer tables shared between all instances of FDO. */\r
141 static const cl_vfptr_pnp_po_t          vfptr_fdo_pnp = {\r
142         "IB Bus",\r
143         fdo_start,\r
144         cl_irp_skip,\r
145         cl_irp_skip,\r
146         cl_do_sync_pnp,\r
147         fdo_query_remove,\r
148         fdo_release_resources,\r
149         cl_do_remove,\r
150         cl_do_sync_pnp,\r
151         cl_irp_skip,\r
152         fdo_query_capabilities,\r
153         cl_irp_skip,\r
154         cl_irp_skip,\r
155         cl_do_sync_pnp,\r
156         fdo_query_bus_relations,\r
157         cl_irp_ignore,\r
158         cl_irp_skip,\r
159         cl_irp_ignore,\r
160         cl_irp_ignore,\r
161         cl_irp_ignore,\r
162         cl_irp_ignore,\r
163         cl_irp_ignore,\r
164         fdo_query_interface,    /* QueryInterface */\r
165         cl_irp_ignore,\r
166         cl_irp_ignore,\r
167         cl_irp_ignore,\r
168         cl_irp_ignore,\r
169         __fdo_query_power,              /* QueryPower */\r
170         __fdo_set_power,                /* SetPower */\r
171         cl_irp_ignore,                  /* PowerSequence */\r
172         cl_irp_ignore                   /* WaitWake */\r
173 };\r
174 \r
175 \r
176 NTSTATUS\r
177 bus_add_device(\r
178         IN                              DRIVER_OBJECT                           *p_driver_obj,\r
179         IN                              DEVICE_OBJECT                           *p_pdo )\r
180 {\r
181         NTSTATUS                status;\r
182         DEVICE_OBJECT   *p_dev_obj, *p_next_do;\r
183         bus_fdo_ext_t   *p_ext=NULL;\r
184         UNICODE_STRING  dev_name, dos_name;\r
185         bus_filter_t    *p_bfi;\r
186         int                             ic;\r
187 \r
188         BUS_ENTER( BUS_DBG_PNP );\r
189 \r
190         /* allocate a Bus Filter Instance */\r
191         p_bfi = alloc_bfi( p_driver_obj, &ic );\r
192         if ( !p_bfi )\r
193         {\r
194                 BUS_TRACE_EXIT( BUS_DBG_PNP,\r
195                         ("%s() Err - Exceeded MAX_BUS_FILTERS(%d)\n",MAX_BUS_FILTERS));\r
196                 return STATUS_UNSUCCESSFUL;\r
197         }\r
198 \r
199         /* Create the FDO device object to attach to the stack. */\r
200 \r
201         /* if 1st Bus Filter Instance, then create device names for user ioctl */\r
202         if ( ic == 1 )\r
203         {\r
204                 RtlInitUnicodeString( &dev_name, AL_DEVICE_NAME );\r
205                 RtlInitUnicodeString( &dos_name, L"\\DosDevices\\Global\\ibal" );\r
206 \r
207                 status = IoCreateDevice( p_driver_obj, sizeof(bus_fdo_ext_t),\r
208                                                                  &dev_name, FILE_DEVICE_BUS_EXTENDER,\r
209                                                                  FILE_DEVICE_SECURE_OPEN, FALSE, &p_dev_obj );\r
210                 if( !NT_SUCCESS(status) )\r
211                 {\r
212                         BUS_PRINT( BUS_DBG_ERROR, \r
213                                 ("Failed to create ControlDeviceObject, status %x.\n",status) );\r
214                         goto bail;\r
215                 }\r
216                 IoDeleteSymbolicLink( &dos_name );\r
217                 status = IoCreateSymbolicLink( &dos_name, &dev_name );\r
218                 if( !NT_SUCCESS(status) )\r
219                 {\r
220                         IoDeleteDevice( p_dev_obj );\r
221                         BUS_PRINT( BUS_DBG_ERROR,\r
222                                 ("Failed to create symlink for dos name.\n") );\r
223                         goto bail;\r
224                 }\r
225         }\r
226         else {\r
227                 status = IoCreateDevice( p_driver_obj, sizeof(bus_fdo_ext_t),\r
228                                                                  NULL, FILE_DEVICE_BUS_EXTENDER,\r
229                                                                  FILE_DEVICE_SECURE_OPEN, FALSE, &p_dev_obj );\r
230                 if( !NT_SUCCESS(status) )\r
231                 {\r
232                         BUS_PRINT( BUS_DBG_ERROR, \r
233                                 ("Failed to create bus root FDO device.\n") );\r
234                         goto bail;\r
235                 }\r
236         }\r
237 \r
238         p_ext = p_dev_obj->DeviceExtension;\r
239         p_ext->n_al_ifc_ref = 0;\r
240         p_ext->n_ci_ifc_ref = 0;\r
241 \r
242         p_next_do = IoAttachDeviceToDeviceStack( p_dev_obj, p_pdo );\r
243         if( !p_next_do )\r
244         {\r
245                 IoDeleteDevice( p_dev_obj );\r
246                 BUS_PRINT( BUS_DBG_ERROR, ("IoAttachToDeviceStack failed.\n") );\r
247                 status = STATUS_NO_SUCH_DEVICE;\r
248                 goto bail;\r
249         }\r
250 \r
251         cl_init_pnp_po_ext( p_dev_obj, p_next_do, p_pdo, bus_globals.dbg_lvl,\r
252                                                 &vfptr_fdo_pnp, NULL );\r
253 \r
254         p_bfi->p_bus_ext = p_ext;\r
255         p_ext->bus_filter = p_bfi;\r
256 \r
257         /*\r
258          * if not 1st Bus Filter Instance, then finished...\r
259          */\r
260         if ( ic > 1 )\r
261                 goto adxit;\r
262 \r
263         /* Register the upper interface (the one used by clients). */\r
264         status = IoRegisterDeviceInterface( p_pdo, &GUID_IB_AL_INTERFACE, NULL,\r
265                                                                                 &al_ifc_name );\r
266         if( !NT_SUCCESS( status ) )\r
267         {\r
268                 IoDetachDevice( p_ext->cl_ext.p_next_do );\r
269                 IoDeleteDevice( p_dev_obj );\r
270                 BUS_PRINT( BUS_DBG_ERROR, \r
271                         ("IoRegisterDeviceInterface for upper interface returned %08x\n",\r
272                         status) );\r
273                 status = STATUS_NO_SUCH_DEVICE;\r
274                 goto bail;\r
275         }\r
276 \r
277         /* Register the lower (CI) interface (the one used by HCA VPDs). */\r
278         status = IoRegisterDeviceInterface( p_pdo, &GUID_IB_CI_INTERFACE, NULL,\r
279                                                                                 &ci_ifc_name );\r
280         if( !NT_SUCCESS( status ) )\r
281         {\r
282                 IoDetachDevice( p_ext->cl_ext.p_next_do );\r
283                 IoDeleteDevice( p_dev_obj );\r
284                 BUS_PRINT( BUS_DBG_ERROR, \r
285                         ("IoRegisterDeviceInterface for lower interface returned %08x\n",\r
286                         status) );\r
287                 status = STATUS_NO_SUCH_DEVICE;\r
288                 goto bail;\r
289         }\r
290 \r
291 adxit:\r
292         BUS_PRINT( BUS_DBG_PNP, ("%s exit status 0\n", p_bfi->whoami) );\r
293 \r
294         BUS_EXIT( BUS_DBG_PNP );\r
295         return STATUS_SUCCESS;\r
296 \r
297 bail:\r
298         BUS_PRINT( BUS_DBG_PNP, ("%s exit status 0x%x\n", p_bfi->whoami,status) );\r
299         ic = free_bfi(p_bfi);\r
300         /* if last Bus filter, then cleanup */\r
301         if ( ic == 0 )\r
302         {\r
303                 IoDeleteSymbolicLink( &dos_name );\r
304                 RtlFreeUnicodeString( &al_ifc_name );\r
305         }\r
306         BUS_EXIT( BUS_DBG_PNP );\r
307         return status;\r
308 }\r
309 \r
310 \r
311 static NTSTATUS\r
312 fdo_start(\r
313         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
314         IN                                      IRP* const                              p_irp, \r
315                 OUT                             cl_irp_action_t* const  p_action )\r
316 {\r
317         NTSTATUS                status;\r
318         bus_fdo_ext_t   *p_ext;\r
319         ib_api_status_t ib_status;\r
320         bus_filter_t    *p_bfi;\r
321         boolean_t               AL_init_here = FALSE;\r
322 \r
323         BUS_ENTER( BUS_DBG_PNP );\r
324 \r
325         p_ext = p_dev_obj->DeviceExtension;\r
326         p_bfi = p_ext->bus_filter;\r
327 \r
328         /* Handled on the way up. */\r
329         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
330         if( !NT_SUCCESS( status ) )\r
331         {\r
332                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
333                         ("Lower drivers failed IRP_MN_START_DEVICE.\n") );\r
334                 return status;\r
335         }\r
336 \r
337         ExAcquireFastMutexUnsafe(&ControlMutex);\r
338         if ( !gh_al ) {\r
339                 /* Initialize AL */\r
340                 ib_status = al_initialize();\r
341                 if( ib_status != IB_SUCCESS )\r
342                 {\r
343                         al_cleanup();\r
344                         BUS_TRACE_EXIT( BUS_DBG_ERROR, ("al_initialize returned %s.\n",\r
345                                                         ib_get_err_str(ib_status)) );\r
346                         ExReleaseFastMutexUnsafe(&ControlMutex);\r
347                         return STATUS_UNSUCCESSFUL;\r
348                 }\r
349                 AL_init_here = TRUE;\r
350         }\r
351         ExReleaseFastMutexUnsafe(&ControlMutex);\r
352 \r
353         /* Initialize the port manager. */\r
354         ib_status = create_port_mgr( p_ext->bus_filter, &p_ext->p_port_mgr );\r
355         if( ib_status != IB_SUCCESS )\r
356         {\r
357                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("create_port_mgr returned %s.\n",\r
358                         ib_get_err_str(ib_status)) );\r
359                 return STATUS_UNSUCCESSFUL;\r
360         }\r
361 \r
362         /* Initialize the IOU manager. */\r
363         ib_status = create_iou_mgr( p_ext->bus_filter, &p_ext->p_iou_mgr );\r
364         if( ib_status != IB_SUCCESS )\r
365         {\r
366                 BUS_TRACE_EXIT( BUS_DBG_ERROR, ("create_iou_mgr returned %s.\n",\r
367                         ib_get_err_str(ib_status)) );\r
368                 return STATUS_UNSUCCESSFUL;\r
369         }\r
370 \r
371         if ( AL_init_here ) {\r
372                 status = IoSetDeviceInterfaceState( &al_ifc_name, TRUE );\r
373                 ASSERT( NT_SUCCESS( status ) );\r
374 \r
375                 status = IoSetDeviceInterfaceState( &ci_ifc_name, TRUE );\r
376                 ASSERT( NT_SUCCESS( status ) );\r
377         }\r
378 \r
379         BUS_PRINT(BUS_DBG_PNP,\r
380                                 ("%s exit %x\n",p_bfi->whoami,status));\r
381         BUS_EXIT( BUS_DBG_PNP );\r
382 \r
383         return status;\r
384 }\r
385 \r
386 \r
387 static NTSTATUS\r
388 fdo_query_remove(\r
389         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
390         IN                                      IRP* const                              p_irp, \r
391                 OUT                             cl_irp_action_t* const  p_action )\r
392 {\r
393         bus_fdo_ext_t   *p_ext;\r
394         bus_filter_t    *p_bfi;\r
395 \r
396         BUS_ENTER( BUS_DBG_PNP );\r
397 \r
398         p_ext = p_dev_obj->DeviceExtension;\r
399 \r
400         CL_ASSERT(p_ext->bus_filter);\r
401         BUS_PRINT( BUS_DBG_PNP,\r
402                 ("IRP_MN_QUERY_REMOVE_DEVICE %s @ FDO %p refs(CI %d AL %d)\n"\r
403                 "   %s CA %I64x\n", \r
404                 p_ext->cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->n_ci_ifc_ref,\r
405                 p_ext->n_al_ifc_ref,\r
406                 p_ext->bus_filter->whoami, p_ext->bus_filter->ca_guid) );\r
407 \r
408         if( p_ext->n_ci_ifc_ref )\r
409         {\r
410                 /*\r
411                  * Our interface is still being held by someone.\r
412                  * Rollback the PnP state that was changed in the cl_ext handler.\r
413                  */\r
414                 cl_rollback_pnp_state( &p_ext->cl_ext );\r
415 \r
416                 /* Fail the query. */\r
417                 *p_action = IrpComplete;\r
418                 BUS_TRACE_EXIT( BUS_DBG_PNP, \r
419                         ("Failing IRP_MN_QUERY_REMOVE_DEVICE:\n"\r
420                         "\tLowerInterface has %d references\n", \r
421                         p_ext->n_ci_ifc_ref ) );\r
422                 return STATUS_UNSUCCESSFUL;\r
423         }\r
424 \r
425         /* remove port & iou managers */        \r
426         p_bfi = p_ext->bus_filter;\r
427         CL_ASSERT( p_bfi );\r
428 \r
429         //TODO: Fail outstanding I/O operations.\r
430 \r
431         if ( p_ext->p_port_mgr && p_bfi->p_port_mgr )\r
432                 cl_obj_destroy( &p_ext->p_port_mgr->obj );\r
433 \r
434         if ( p_ext->p_iou_mgr && p_bfi->p_iou_mgr )\r
435                 cl_obj_destroy( &p_ext->p_iou_mgr->obj );\r
436 \r
437 \r
438         *p_action = IrpSkip;\r
439         /* The FDO driver must set the status even when passing down. */\r
440         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
441 \r
442         BUS_EXIT( BUS_DBG_PNP );\r
443         return STATUS_SUCCESS;\r
444 }\r
445 \r
446 \r
447 /*\r
448  * This function gets called after releasing the remove lock and waiting\r
449  * for all other threads to release the lock.  No more modifications will\r
450  * occur to the PDO pointer vectors.\r
451  */\r
452 static void\r
453 fdo_release_resources(\r
454         IN                                      DEVICE_OBJECT* const    p_dev_obj )\r
455 {\r
456         bus_fdo_ext_t   *p_ext;\r
457         NTSTATUS                status;\r
458         bus_filter_t    *p_bfi;\r
459         int                             ic;\r
460 \r
461         BUS_ENTER( BUS_DBG_PNP );\r
462 \r
463         p_ext = p_dev_obj->DeviceExtension;\r
464         ic = get_bfi_count();\r
465 \r
466         p_bfi = p_ext->bus_filter;\r
467         CL_ASSERT( p_bfi );\r
468 \r
469         //TODO: Fail outstanding I/O operations.\r
470 \r
471         if ( p_ext->p_port_mgr && p_bfi->p_port_mgr )\r
472                 cl_obj_destroy( &p_ext->p_port_mgr->obj );\r
473 \r
474         if ( p_ext->p_iou_mgr && p_bfi->p_iou_mgr )\r
475                 cl_obj_destroy( &p_ext->p_iou_mgr->obj );\r
476 \r
477         BUS_PRINT( BUS_DBG_PNP, ("Releasing BusFilter %s\n", p_bfi->whoami ));\r
478         if (p_bfi) {\r
479                 p_ext->bus_filter = NULL;\r
480                 p_bfi->p_bus_ext = NULL;\r
481         }\r
482 \r
483         ic = free_bfi( p_bfi );\r
484 \r
485         /* if not last Buf Filter Instance, then exit, otherwise cleanup/shutdown */\r
486         if ( ic > 0 ) {\r
487                 BUS_PRINT( BUS_DBG_PNP, (" %d remaining BusFilters\n", ic ));\r
488                 return;\r
489         }\r
490 \r
491         /* Disable any exported interfaces. */\r
492         status = IoSetDeviceInterfaceState( &al_ifc_name, FALSE );\r
493         ASSERT( NT_SUCCESS( status ) );\r
494         status = IoSetDeviceInterfaceState( &ci_ifc_name, FALSE );\r
495         ASSERT( NT_SUCCESS( status ) );\r
496 \r
497         /* Release the memory allocated for the interface symbolic names. */\r
498         RtlFreeUnicodeString( &ci_ifc_name );\r
499         RtlFreeUnicodeString( &al_ifc_name );\r
500 \r
501         al_cleanup();\r
502 \r
503         BUS_EXIT( BUS_DBG_PNP );\r
504 }\r
505 \r
506 \r
507 static NTSTATUS\r
508 fdo_query_capabilities(\r
509         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
510         IN                                      IRP* const                              p_irp, \r
511                 OUT                             cl_irp_action_t* const  p_action )\r
512 {\r
513         NTSTATUS                        status;\r
514         bus_fdo_ext_t           *p_ext;\r
515         IO_STACK_LOCATION       *p_io_stack;\r
516 \r
517         BUS_ENTER( BUS_DBG_PNP );\r
518 \r
519         p_ext = p_dev_obj->DeviceExtension;\r
520 \r
521         /* Process on the way up. */\r
522         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
523 \r
524         if( !NT_SUCCESS( status ) )\r
525         {\r
526                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
527                         ("cl_do_sync_pnp returned %08x.\n", status) );\r
528                 return status;\r
529         }\r
530 \r
531         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
532 \r
533         /*\r
534          * Store the device power maping into our extension since we're\r
535          * the power policy owner.  The mapping is used when handling\r
536          * IRP_MN_SET_POWER IRPs.\r
537          */\r
538         cl_memcpy( p_ext->po_state, \r
539                 p_io_stack->Parameters.DeviceCapabilities.Capabilities->DeviceState,\r
540                 sizeof( p_ext->po_state ) );\r
541 \r
542         BUS_EXIT( BUS_DBG_PNP );\r
543         return status;\r
544 }\r
545 \r
546 \r
547 static NTSTATUS\r
548 fdo_query_bus_relations(\r
549         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
550         IN                                      IRP* const                              p_irp, \r
551                 OUT                             cl_irp_action_t* const  p_action )\r
552 {\r
553         NTSTATUS                        status;\r
554         bus_fdo_ext_t           *p_ext;\r
555         bus_filter_t            *p_bfi;\r
556 \r
557         BUS_ENTER( BUS_DBG_PNP );\r
558 \r
559         p_ext = p_dev_obj->DeviceExtension;\r
560 \r
561         if ( !p_ext->bus_filter )\r
562         {\r
563                 /* BFI has already been released */\r
564                 *p_action = IrpComplete;\r
565                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("NULL BFI\n") );\r
566                 return STATUS_SUCCESS;\r
567         }\r
568 \r
569         p_bfi = p_ext->bus_filter;\r
570         CL_ASSERT( p_bfi->magic == BFI_MAGIC );\r
571 \r
572         if ( p_bfi->ca_guid == 0ULL )\r
573         {\r
574                 /* HCA not yet bound to a BFI slot (no PNP ADD event seen), no bus\r
575                  * relations yet.\r
576                  */\r
577                 status = STATUS_SUCCESS;\r
578                 BUS_PRINT(BUS_DBG_PNP, ("%s ca_guid %I64x\n",p_bfi->whoami,\r
579                                                                 p_bfi->ca_guid));\r
580         }\r
581         else\r
582         {\r
583                 status = port_mgr_get_bus_relations( p_bfi->ca_guid, p_irp );\r
584                 if( status == STATUS_SUCCESS || \r
585                         status == STATUS_NO_SUCH_DEVICE )\r
586                 {\r
587                         status = iou_mgr_get_bus_relations( p_bfi->ca_guid, p_irp );\r
588                 }\r
589                 if( status == STATUS_NO_SUCH_DEVICE )\r
590                         status = STATUS_SUCCESS;\r
591         }\r
592 \r
593         switch( status )\r
594         {\r
595         case STATUS_NO_SUCH_DEVICE:\r
596                 *p_action = IrpSkip;\r
597                 status = STATUS_SUCCESS;\r
598                 break;\r
599 \r
600         case STATUS_SUCCESS:\r
601                 *p_action = IrpPassDown;\r
602                 break;\r
603 \r
604         default:\r
605                 *p_action = IrpComplete;\r
606                 break;\r
607         }\r
608 \r
609         BUS_EXIT( BUS_DBG_PNP );\r
610         return status;\r
611 }\r
612 \r
613 \r
614 void\r
615 al_ref_ifc(\r
616         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
617 {\r
618         bus_fdo_ext_t   *p_ext;\r
619 \r
620         BUS_ENTER( BUS_DBG_PNP );\r
621 \r
622         p_ext = p_dev_obj->DeviceExtension;\r
623 \r
624         cl_atomic_inc( &p_ext->n_al_ifc_ref );\r
625         ObReferenceObject( p_dev_obj );\r
626 \r
627         BUS_EXIT( BUS_DBG_PNP );\r
628 }\r
629 \r
630 \r
631 void\r
632 al_deref_ifc(\r
633         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
634 {\r
635         bus_fdo_ext_t   *p_ext;\r
636 \r
637         BUS_ENTER( BUS_DBG_PNP );\r
638 \r
639         p_ext = p_dev_obj->DeviceExtension;\r
640 \r
641         cl_atomic_dec( &p_ext->n_al_ifc_ref );\r
642         ObDereferenceObject( p_dev_obj );\r
643 \r
644         CL_ASSERT(p_ext->bus_filter);\r
645         BUS_PRINT( BUS_DBG_PNP, ("%s CA_guid %I64x al_ifc_ref %d\n",\r
646                                         p_ext->bus_filter->whoami, p_ext->bus_filter->ca_guid,\r
647                                         p_ext->n_al_ifc_ref) );\r
648 \r
649         BUS_EXIT( BUS_DBG_PNP );\r
650 }\r
651 \r
652 \r
653 void\r
654 al_ref_ci_ifc(\r
655         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
656 {\r
657         bus_fdo_ext_t   *p_ext;\r
658 \r
659         BUS_ENTER( BUS_DBG_PNP );\r
660 \r
661         p_ext = p_dev_obj->DeviceExtension;\r
662 \r
663         cl_atomic_inc( &p_ext->n_ci_ifc_ref );\r
664         ObReferenceObject( p_dev_obj );\r
665 \r
666         BUS_EXIT( BUS_DBG_PNP );\r
667 }\r
668 \r
669 \r
670 void\r
671 al_deref_ci_ifc(\r
672         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
673 {\r
674         bus_fdo_ext_t   *p_ext;\r
675 \r
676         BUS_ENTER( BUS_DBG_PNP );\r
677 \r
678         p_ext = p_dev_obj->DeviceExtension;\r
679 \r
680         cl_atomic_dec( &p_ext->n_ci_ifc_ref );\r
681         ObDereferenceObject( p_dev_obj );\r
682 \r
683         CL_ASSERT(p_ext->bus_filter);\r
684         BUS_PRINT( BUS_DBG_PNP, ("%s CA_guid %I64x ci_ifc_ref %d\n",\r
685                                                 p_ext->bus_filter->whoami, p_ext->bus_filter->ca_guid,\r
686                                                 p_ext->n_ci_ifc_ref) );\r
687 \r
688         BUS_EXIT( BUS_DBG_PNP );\r
689 }\r
690 \r
691 \r
692 static NTSTATUS\r
693 __query_al_ifc(\r
694         IN                                      DEVICE_OBJECT* const            p_dev_obj,\r
695         IN                                      IO_STACK_LOCATION* const        p_io_stack )\r
696 {\r
697         ib_al_ifc_t             *p_ifc;\r
698 \r
699         BUS_ENTER( BUS_DBG_PNP );\r
700 \r
701         if( p_io_stack->Parameters.QueryInterface.Version != \r
702                 AL_INTERFACE_VERSION )\r
703         {\r
704                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n",\r
705                         p_io_stack->Parameters.QueryInterface.Version ) );\r
706                 return STATUS_NOT_SUPPORTED;\r
707         }\r
708 \r
709         if( p_io_stack->Parameters.QueryInterface.Size < sizeof(ib_al_ifc_t) )\r
710         {\r
711                 BUS_TRACE_EXIT( BUS_DBG_PNP, \r
712                         ("Buffer too small (%d given, %d required).\n",\r
713                         p_io_stack->Parameters.QueryInterface.Size, sizeof(ib_al_ifc_t)) );\r
714                 return STATUS_BUFFER_TOO_SMALL;\r
715         }\r
716 \r
717         // Copy the interface.\r
718         p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
719 \r
720         p_ifc->wdm.Size = sizeof(ib_al_ifc_t);\r
721         p_ifc->wdm.Version = AL_INTERFACE_VERSION;\r
722         p_ifc->wdm.Context = p_dev_obj;\r
723         p_ifc->wdm.InterfaceReference = al_ref_ifc;\r
724         p_ifc->wdm.InterfaceDereference = al_deref_ifc;\r
725 \r
726         al_set_ifc( p_ifc );\r
727 \r
728         // take the reference before returning.\r
729         al_ref_ifc( p_dev_obj );\r
730         BUS_EXIT( BUS_DBG_PNP );\r
731         return STATUS_SUCCESS;\r
732 }\r
733 \r
734 \r
735 void\r
736 al_set_ifc(\r
737                 OUT                     ib_al_ifc_t* const                      p_ifc )\r
738 {\r
739         BUS_ENTER( BUS_DBG_PNP );\r
740 \r
741         p_ifc->wdm.Size = sizeof(ib_al_ifc_t);\r
742         p_ifc->wdm.InterfaceReference = al_ref_ifc;\r
743         p_ifc->wdm.InterfaceDereference = al_deref_ifc;\r
744 \r
745         p_ifc->sync_destroy = ib_sync_destroy;\r
746         p_ifc->open_ca = ib_open_ca;\r
747         p_ifc->query_ca = ib_query_ca;\r
748         p_ifc->get_dev = get_ca_dev;\r
749         p_ifc->close_ca = ib_close_ca;\r
750         p_ifc->alloc_pd = ib_alloc_pd;\r
751         p_ifc->dealloc_pd = ib_dealloc_pd;\r
752         p_ifc->create_av = ib_create_av;\r
753         p_ifc->query_av = ib_query_av;\r
754         p_ifc->modify_av = ib_modify_av;\r
755         p_ifc->destroy_av = ib_destroy_av;\r
756         p_ifc->create_qp = ib_create_qp;\r
757         p_ifc->get_spl_qp = ib_get_spl_qp;\r
758         p_ifc->query_qp = ib_query_qp;\r
759         p_ifc->modify_qp = ib_modify_qp;\r
760         p_ifc->destroy_qp = ib_destroy_qp;\r
761         p_ifc->create_cq = ib_create_cq;\r
762         p_ifc->modify_cq = ib_modify_cq;\r
763         p_ifc->query_cq = ib_query_cq;\r
764         p_ifc->destroy_cq = ib_destroy_cq;\r
765         p_ifc->reg_mem = ib_reg_mem;\r
766         p_ifc->reg_phys = ib_reg_phys;\r
767         p_ifc->query_mr = ib_query_mr;\r
768         p_ifc->rereg_mem = ib_rereg_mem;\r
769         p_ifc->reg_shmid = ib_reg_shmid;\r
770         p_ifc->dereg_mr = ib_dereg_mr;\r
771         p_ifc->create_mw = ib_create_mw;\r
772         p_ifc->query_mw = ib_query_mw;\r
773         p_ifc->bind_mw = ib_bind_mw;\r
774         p_ifc->destroy_mw = ib_destroy_mw;\r
775         p_ifc->post_send = ib_post_send;\r
776         p_ifc->post_recv = ib_post_recv;\r
777         p_ifc->send_mad = ib_send_mad;\r
778         p_ifc->cancel_mad = ib_cancel_mad;\r
779         p_ifc->poll_cq = ib_poll_cq;\r
780         p_ifc->rearm_cq = ib_rearm_cq;\r
781         p_ifc->join_mcast = ib_join_mcast;\r
782         p_ifc->leave_mcast = ib_leave_mcast;\r
783         p_ifc->local_mad = ib_local_mad;\r
784         p_ifc->cm_listen = ib_cm_listen;\r
785         p_ifc->cm_cancel = ib_cm_cancel;\r
786         p_ifc->cm_req = ib_cm_req;\r
787         p_ifc->cm_rep = ib_cm_rep;\r
788         p_ifc->cm_rtu = ib_cm_rtu;\r
789         p_ifc->cm_rej = ib_cm_rej;\r
790         p_ifc->cm_mra = ib_cm_mra;\r
791         p_ifc->cm_lap = ib_cm_lap;\r
792         p_ifc->cm_apr = ib_cm_apr;\r
793         p_ifc->force_apm = ib_force_apm;\r
794         p_ifc->cm_dreq = ib_cm_dreq;\r
795         p_ifc->cm_drep = ib_cm_drep;\r
796         p_ifc->cm_handoff = ib_cm_handoff;\r
797         p_ifc->create_ioc = ib_create_ioc;\r
798         p_ifc->destroy_ioc = ib_destroy_ioc;\r
799         p_ifc->reg_ioc = ib_reg_ioc;\r
800         p_ifc->add_svc_entry = ib_add_svc_entry;\r
801         p_ifc->remove_svc_entry = ib_remove_svc_entry;\r
802         p_ifc->get_ca_guids = ib_get_ca_guids;\r
803         p_ifc->get_ca_by_gid = ib_get_ca_by_gid;\r
804         p_ifc->get_port_by_gid = ib_get_port_by_gid;\r
805         p_ifc->create_mad_pool = ib_create_mad_pool;\r
806         p_ifc->destroy_mad_pool = ib_destroy_mad_pool;\r
807         p_ifc->reg_mad_pool = ib_reg_mad_pool;\r
808         p_ifc->dereg_mad_pool = ib_dereg_mad_pool;\r
809         p_ifc->get_mad = ib_get_mad;\r
810         p_ifc->put_mad = ib_put_mad;\r
811         p_ifc->init_dgrm_svc = ib_init_dgrm_svc;\r
812         p_ifc->reg_mad_svc = ib_reg_mad_svc;\r
813         p_ifc->reg_svc = ib_reg_svc;\r
814         p_ifc->dereg_svc = ib_dereg_svc;\r
815         p_ifc->query = ib_query;\r
816         p_ifc->cancel_query = ib_cancel_query;\r
817         p_ifc->reg_pnp = ib_reg_pnp;\r
818         p_ifc->dereg_pnp = ib_dereg_pnp;\r
819         p_ifc->subscribe = ib_subscribe;\r
820         p_ifc->unsubscribe = ib_unsubscribe;\r
821         p_ifc->reject_ioc = ib_reject_ioc;\r
822         p_ifc->ci_call = ib_ci_call;\r
823         p_ifc->open_al = ib_open_al;\r
824         p_ifc->close_al = ib_close_al;\r
825         p_ifc->get_err_str = ib_get_err_str;\r
826         p_ifc->get_wc_status_str = ib_get_wc_status_str;\r
827         p_ifc->create_mlnx_fmr = mlnx_create_fmr;\r
828         p_ifc->map_phys_mlnx_fmr = mlnx_map_phys_fmr;\r
829         p_ifc->unmap_mlnx_fmr = mlnx_unmap_fmr;\r
830         p_ifc->destroy_mlnx_fmr = mlnx_destroy_fmr;\r
831         p_ifc->create_mlnx_fmr_pool = mlnx_create_fmr_pool;\r
832         p_ifc->destroy_mlnx_fmr_pool = mlnx_destroy_fmr_pool;\r
833         p_ifc->map_phys_mlnx_fmr_pool = mlnx_map_phys_fmr_pool;\r
834         p_ifc->unmap_mlnx_fmr_pool = mlnx_unmap_fmr_pool;\r
835         p_ifc->flush_mlnx_fmr_pool = mlnx_flush_fmr_pool;\r
836         p_ifc->create_srq = ib_create_srq;\r
837         p_ifc->modify_srq = ib_modify_srq;\r
838         p_ifc->query_srq = ib_query_srq;\r
839         p_ifc->destroy_srq = ib_destroy_srq;\r
840         p_ifc->post_srq_recv = ib_post_srq_recv;\r
841 \r
842         BUS_EXIT( BUS_DBG_PNP );\r
843 }\r
844 \r
845 \r
846 static NTSTATUS\r
847 __get_relations(\r
848         IN              const   net64_t                                         ca_guid,\r
849         IN                              IRP* const                                      p_irp )\r
850 {\r
851         UNUSED_PARAM( ca_guid );\r
852         UNUSED_PARAM( p_irp );\r
853 \r
854         BUS_ENTER( BUS_DBG_PNP );\r
855 \r
856         /*\r
857          * Now that ibbus is in the same device stack as the HCA driver, skip\r
858          * returning relations here as ibbus has already done the deed.\r
859          * This interface remains to minimize changes to HCA drivers for now.\r
860          */\r
861 \r
862         BUS_EXIT( BUS_DBG_PNP );\r
863         return STATUS_SUCCESS;\r
864 }\r
865 \r
866 \r
867 static NTSTATUS\r
868 __query_ci_ifc(\r
869         IN                                      DEVICE_OBJECT* const            p_dev_obj,\r
870         IN                                      IO_STACK_LOCATION* const        p_io_stack )\r
871 {\r
872         ib_ci_ifc_t             *p_ifc;\r
873 \r
874         BUS_ENTER( BUS_DBG_PNP );\r
875 \r
876         if( p_io_stack->Parameters.QueryInterface.Version != \r
877                 IB_CI_INTERFACE_VERSION )\r
878         {\r
879                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n",\r
880                         p_io_stack->Parameters.QueryInterface.Version ) );\r
881                 return STATUS_NOT_SUPPORTED;\r
882         }\r
883 \r
884         if( p_io_stack->Parameters.QueryInterface.Size < sizeof(ib_ci_ifc_t) )\r
885         {\r
886                 BUS_TRACE_EXIT( BUS_DBG_PNP, \r
887                         ("Buffer too small (%d given, %d required).\n",\r
888                         p_io_stack->Parameters.QueryInterface.Size, sizeof(ib_ci_ifc_t)) );\r
889                 return STATUS_BUFFER_TOO_SMALL;\r
890         }\r
891 \r
892         /* Copy the interface. */\r
893         p_ifc = (ib_ci_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
894 \r
895         p_ifc->wdm.Size = sizeof(ib_ci_ifc_t);\r
896         p_ifc->wdm.Version = IB_CI_INTERFACE_VERSION;\r
897         p_ifc->wdm.Context = p_dev_obj;\r
898         p_ifc->wdm.InterfaceReference = al_ref_ci_ifc;\r
899         p_ifc->wdm.InterfaceDereference = al_deref_ci_ifc;\r
900 \r
901         /* Set the entry points. */\r
902         p_ifc->register_ca = ib_register_ca;\r
903         p_ifc->deregister_ca = ib_deregister_ca;\r
904         p_ifc->get_relations = __get_relations;\r
905         p_ifc->get_err_str = ib_get_err_str;\r
906 \r
907         /* take the reference before returning. */\r
908         al_ref_ci_ifc( p_dev_obj );\r
909         BUS_EXIT( BUS_DBG_PNP );\r
910         return STATUS_SUCCESS;\r
911 }\r
912 \r
913 \r
914 static NTSTATUS\r
915 fdo_query_interface(\r
916         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
917         IN                                      IRP* const                              p_irp, \r
918                 OUT                             cl_irp_action_t* const  p_action )\r
919 {\r
920         NTSTATUS                        status;\r
921         IO_STACK_LOCATION       *p_io_stack;\r
922 \r
923         BUS_ENTER( BUS_DBG_PNP );\r
924 \r
925         PAGED_CODE();\r
926 \r
927         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
928         \r
929         /* Compare requested GUID with our supported interface GUIDs. */\r
930         if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
931                 &GUID_IB_AL_INTERFACE ) )\r
932         {\r
933                 status = __query_al_ifc( p_dev_obj, p_io_stack );\r
934         }\r
935         else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
936                 &GUID_IB_CI_INTERFACE ) )\r
937         {\r
938                 status = __query_ci_ifc( p_dev_obj, p_io_stack );\r
939         }\r
940         else\r
941         {\r
942                 status = p_irp->IoStatus.Status;\r
943         }\r
944 \r
945         if( NT_SUCCESS( status ) )\r
946                 *p_action = IrpSkip;\r
947         else if( status == STATUS_BUFFER_TOO_SMALL )\r
948                 *p_action = IrpComplete;\r
949         else\r
950                 *p_action = IrpIgnore;\r
951 \r
952         BUS_EXIT( BUS_DBG_PNP );\r
953         return status;\r
954 }\r
955 \r
956 \r
957 static NTSTATUS\r
958 __fdo_query_power(\r
959         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
960         IN                              IRP* const                                      p_irp,\r
961                 OUT                     cl_irp_action_t* const          p_action )\r
962 {\r
963         NTSTATUS                        status = STATUS_SUCCESS;\r
964         IO_STACK_LOCATION       *p_io_stack;\r
965 \r
966         BUS_ENTER( BUS_DBG_POWER );\r
967 \r
968         UNUSED_PARAM( p_dev_obj );\r
969 \r
970         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
971 \r
972         switch( p_io_stack->Parameters.Power.Type )\r
973         {\r
974         case SystemPowerState:\r
975                 /* Fail any requests to hibernate or sleep the system. */\r
976                 switch( p_io_stack->Parameters.Power.State.SystemState )\r
977                 {\r
978                         case PowerSystemHibernate:\r
979                         case PowerSystemSleeping1:      // STANDBY support\r
980                         case PowerSystemWorking:\r
981                         case PowerSystemShutdown:\r
982                                 break;\r
983 \r
984                         default:\r
985                                 status = STATUS_NOT_SUPPORTED;\r
986                 }\r
987                 break;\r
988 \r
989         case DevicePowerState:\r
990                 /* Fail any query for low power states. */\r
991                 switch( p_io_stack->Parameters.Power.State.DeviceState )\r
992                 {\r
993                 case PowerDeviceD0:\r
994                 case PowerDeviceD3:\r
995                         /* We only support fully powered or off power states. */\r
996                         break;\r
997 \r
998                 default:\r
999                         status = STATUS_NOT_SUPPORTED;\r
1000                 }\r
1001                 break;\r
1002         }\r
1003 \r
1004         if( status == STATUS_NOT_SUPPORTED )\r
1005                 *p_action = IrpComplete;\r
1006         else\r
1007                 *p_action = IrpSkip;\r
1008 \r
1009         BUS_EXIT( BUS_DBG_POWER );\r
1010         return status;\r
1011 }\r
1012 \r
1013 \r
1014 static void\r
1015 __request_power_completion(\r
1016         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1017         IN                              UCHAR                                           minor_function,\r
1018         IN                              POWER_STATE                                     power_state,\r
1019         IN                              void                                            *context,\r
1020         IN                              IO_STATUS_BLOCK                         *p_io_status )\r
1021 {\r
1022         IRP                                     *p_irp;\r
1023         cl_pnp_po_ext_t         *p_ext;\r
1024 \r
1025         BUS_ENTER( BUS_DBG_PNP );\r
1026 \r
1027         UNUSED_PARAM( minor_function );\r
1028         UNUSED_PARAM( power_state );\r
1029 \r
1030         p_irp = (IRP*)context;\r
1031         p_ext = p_dev_obj->DeviceExtension;\r
1032 \r
1033         /* Propagate the device IRP status to the system IRP status. */\r
1034         p_irp->IoStatus.Status = p_io_status->Status;\r
1035 \r
1036         /* Continue Power IRP processing. */\r
1037         PoStartNextPowerIrp( p_irp );\r
1038         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1039         IoReleaseRemoveLock( &p_ext->remove_lock, p_irp );\r
1040         BUS_EXIT( BUS_DBG_PNP );\r
1041 }\r
1042 \r
1043 \r
1044 /*NOTE: Completion routines must NEVER be pageable. */\r
1045 static NTSTATUS\r
1046 __set_power_completion(\r
1047         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1048         IN                              IRP                                                     *p_irp,\r
1049         IN                              void                                            *context )\r
1050 {\r
1051         NTSTATUS                        status;\r
1052         POWER_STATE                     state;\r
1053         bus_fdo_ext_t           *p_ext;\r
1054         IO_STACK_LOCATION       *p_io_stack;\r
1055 \r
1056         BUS_ENTER( BUS_DBG_PNP );\r
1057 \r
1058         UNUSED_PARAM( context );\r
1059 \r
1060         p_ext = p_dev_obj->DeviceExtension;\r
1061         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1062 \r
1063         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1064         {\r
1065                 PoStartNextPowerIrp( p_irp );\r
1066                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1067                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
1068                         ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n",\r
1069                         p_irp->IoStatus.Status) );\r
1070                 return STATUS_SUCCESS;\r
1071         }\r
1072 \r
1073         state.DeviceState = \r
1074                 p_ext->po_state[p_io_stack->Parameters.Power.State.SystemState];\r
1075 \r
1076         /*\r
1077          * Send a device power IRP to our devnode.  Using our device object will\r
1078          * only work on win2k and other NT based systems.\r
1079          */\r
1080         status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
1081                 __request_power_completion, p_irp, NULL );\r
1082 \r
1083         if( status != STATUS_PENDING )\r
1084         {\r
1085                 PoStartNextPowerIrp( p_irp );\r
1086                 /* Propagate the failure. */\r
1087                 p_irp->IoStatus.Status = status;\r
1088                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1089                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1090                 BUS_TRACE( BUS_DBG_ERROR,\r
1091                         ("PoRequestPowerIrp returned %08x.\n", status) );\r
1092         }\r
1093 \r
1094         BUS_EXIT( BUS_DBG_PNP );\r
1095         return STATUS_MORE_PROCESSING_REQUIRED;\r
1096 }\r
1097 \r
1098 \r
1099 static NTSTATUS\r
1100 __fdo_set_power(\r
1101         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1102         IN                              IRP* const                                      p_irp,\r
1103                 OUT                     cl_irp_action_t* const          p_action )\r
1104 {\r
1105         NTSTATUS                        status;\r
1106         IO_STACK_LOCATION       *p_io_stack;\r
1107         bus_fdo_ext_t           *p_ext;\r
1108 \r
1109         BUS_ENTER( BUS_DBG_POWER );\r
1110 \r
1111         p_ext = p_dev_obj->DeviceExtension;\r
1112         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1113 \r
1114         BUS_TRACE( BUS_DBG_POWER, \r
1115                 ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d \n",\r
1116                 p_dev_obj, p_ext,\r
1117                 (p_io_stack->Parameters.Power.Type)\r
1118                         ? "DevicePowerState" : "SystemPowerState",\r
1119                 p_io_stack->Parameters.Power.State.DeviceState, \r
1120                 p_io_stack->Parameters.Power.ShutdownType ));\r
1121 \r
1122         switch( p_io_stack->Parameters.Power.Type )\r
1123         {\r
1124         case SystemPowerState:\r
1125                 /*\r
1126                  * Process on the way up the stack.  We cannot block since the \r
1127                  * power dispatch function can be called at elevated IRQL if the\r
1128                  * device is in a paging/hibernation/crash dump path.\r
1129                  */\r
1130                 IoMarkIrpPending( p_irp );\r
1131                 IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1132 #pragma warning( push, 3 )\r
1133                 IoSetCompletionRoutine( p_irp, __set_power_completion, NULL, \r
1134                         TRUE, TRUE, TRUE );\r
1135 #pragma warning( pop )\r
1136                 PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1137 \r
1138                 *p_action = IrpDoNothing;\r
1139                 status = STATUS_PENDING;\r
1140                 break;\r
1141 \r
1142         case DevicePowerState:\r
1143         default:\r
1144                 /* Pass down and let the PDO driver handle it. */\r
1145                 *p_action = IrpIgnore;\r
1146                 status = STATUS_SUCCESS;\r
1147                 break;\r
1148         }\r
1149 \r
1150         BUS_EXIT( BUS_DBG_POWER );\r
1151         return status;\r
1152 }\r
1153 \r
1154 \r
1155 /*\r
1156  * A CA GUID of zero means that all devices should be reported.\r
1157  */\r
1158 NTSTATUS\r
1159 bus_get_relations(\r
1160         IN                              cl_qlist_t*     const                   p_pdo_list,\r
1161         IN              const   net64_t                                         ca_guid,\r
1162         IN                              IRP* const                                      p_irp )\r
1163 {\r
1164         NTSTATUS                        status;\r
1165         DEVICE_RELATIONS        *p_rel;\r
1166         cl_list_item_t          *p_list_item;\r
1167         bus_pdo_ext_t           *p_pdo_ext;\r
1168         size_t                          n_devs = 0;\r
1169 \r
1170         BUS_ENTER( BUS_DBG_PNP );\r
1171 \r
1172         /* Count the number of child devices. */\r
1173         for( p_list_item = cl_qlist_head( p_pdo_list );\r
1174                 p_list_item != cl_qlist_end( p_pdo_list );\r
1175                 p_list_item = cl_qlist_next( p_list_item ) )\r
1176         {\r
1177                 p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
1178 \r
1179                 if( !p_pdo_ext->b_present )\r
1180                         continue;\r
1181                 \r
1182                 if( ca_guid && p_pdo_ext->ca_guid != ca_guid )\r
1183                         continue;\r
1184 \r
1185                 n_devs++;\r
1186         }\r
1187 \r
1188         if( !n_devs )\r
1189         {\r
1190                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Found 0 PDOs ca_guid %I64x\n", ca_guid));\r
1191                 return STATUS_NO_SUCH_DEVICE;\r
1192         }\r
1193 \r
1194         BUS_TRACE( BUS_DBG_PNP, ("Found %d PDOs ca_guid %I64x\n", n_devs, ca_guid));\r
1195 \r
1196         /* Add space for our child IOUs. */\r
1197         status = cl_alloc_relations( p_irp, n_devs );\r
1198         if( !NT_SUCCESS( status ) )\r
1199         {\r
1200                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1201                         ("cl_alloc_relations returned %08x.\n", status) );\r
1202                 return status;\r
1203         }\r
1204 \r
1205         p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
1206 \r
1207         for( p_list_item = cl_qlist_head( p_pdo_list );\r
1208                 p_list_item != cl_qlist_end( p_pdo_list );\r
1209                 p_list_item = cl_qlist_next( p_list_item ) )\r
1210         {\r
1211                 p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
1212 \r
1213                 if( !p_pdo_ext->b_present )\r
1214                 {\r
1215                         /*\r
1216                          * We don't report a PDO that is no longer present.  This is how\r
1217                          * the PDO will get cleaned up.\r
1218                          */\r
1219                         p_pdo_ext->b_reported_missing = TRUE;\r
1220                         BUS_TRACE( BUS_DBG_PNP, ("Don't report PDO! %s: PDO %p, ext %p, "\r
1221                                 "present %d, missing %d .\n",\r
1222                                 p_pdo_ext->cl_ext.vfptr_pnp_po->identity,\r
1223                                 p_pdo_ext->cl_ext.p_self_do, p_pdo_ext, p_pdo_ext->b_present,\r
1224                                 p_pdo_ext->b_reported_missing ) );\r
1225                         continue;\r
1226                 }\r
1227 \r
1228                 if( ca_guid && p_pdo_ext->ca_guid != ca_guid )\r
1229                         continue;\r
1230 \r
1231                 BUS_TRACE( BUS_DBG_PNP, ("Reported PDO %p(=%p), ext %p\n", \r
1232                         p_pdo_ext->cl_ext.p_self_do, p_pdo_ext->cl_ext.p_pdo, p_pdo_ext ));\r
1233                 \r
1234                 p_rel->Objects[p_rel->Count] = p_pdo_ext->cl_ext.p_pdo;\r
1235                 ObReferenceObject( p_rel->Objects[p_rel->Count++] );\r
1236         }\r
1237 \r
1238         BUS_EXIT( BUS_DBG_PNP );\r
1239         return STATUS_SUCCESS;\r
1240 }\r
1241 \r
1242 \r
1243 /*\r
1244  * find a bus filter instance (p_bfi) given an *cl_obj: port_mgr or iou_mgr. \r
1245  */\r
1246 \r
1247 bus_filter_t *\r
1248 get_bfi_by_obj(IN int obj_type, IN cl_obj_t *p_obj )\r
1249 {\r
1250         bus_filter_t    *p_bfi;\r
1251         bus_filter_t    *matched=NULL;\r
1252 \r
1253         CL_ASSERT((obj_type == BFI_PORT_MGR_OBJ) || (obj_type == BFI_IOU_MGR_OBJ));\r
1254 \r
1255     ExAcquireFastMutexUnsafe(&ControlMutex);\r
1256 \r
1257         for(p_bfi=bus_filters; p_bfi < &bus_filters[MAX_BUS_FILTERS]; p_bfi++) {\r
1258 \r
1259                 if ( !p_bfi->p_bus_ext )\r
1260                         continue;\r
1261 \r
1262                 if ( obj_type == BFI_PORT_MGR_OBJ ) {\r
1263                         if ( p_obj == p_bfi->p_port_mgr_obj ) {\r
1264                                 matched = p_bfi;\r
1265                                 break;\r
1266                         }\r
1267                 }\r
1268                 else {\r
1269                         if ( p_obj == p_bfi->p_iou_mgr_obj ) {\r
1270                                 matched = p_bfi;\r
1271                                 break;\r
1272                         }\r
1273                 }\r
1274         }\r
1275         ExReleaseFastMutexUnsafe(&ControlMutex);\r
1276 \r
1277         BUS_PRINT( BUS_DBG_PNP,\r
1278                                 ("%s() cl_obj %p type %s_MGR_OBJ --> bfi[%d] %p\n",\r
1279                                 __FUNCTION__,p_obj,\r
1280                                 (obj_type == BFI_PORT_MGR_OBJ ? "PORT": "IOU"),\r
1281                                 (matched ? (matched - bus_filters) : (-1)), matched ) );\r
1282 \r
1283         return matched;\r
1284 }\r
1285 \r
1286 /*\r
1287  * find a bus filter instance given an HCA guid.\r
1288  */\r
1289 \r
1290 bus_filter_t *\r
1291 get_bfi_by_ca_guid( IN net64_t ca_guid )\r
1292 {\r
1293         bus_filter_t    *p_bfi;\r
1294         bus_filter_t    *matched=NULL;\r
1295 \r
1296         if ( ca_guid == 0ULL )\r
1297         {\r
1298                 matched = bus_filters;\r
1299                 BUS_PRINT( BUS_DBG_PNP, ("%s() ERR guid %I64x -> bfi[0] %p\n",\r
1300                                                                 __FUNCTION__, ca_guid, matched) );\r
1301                 CL_ASSERT( ca_guid );\r
1302                 return matched;\r
1303         }\r
1304 \r
1305         ExAcquireFastMutexUnsafe(&ControlMutex);\r
1306 \r
1307         for(p_bfi=bus_filters; p_bfi < &bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1308         {\r
1309                 if ( !p_bfi->p_bus_ext )\r
1310                         continue;\r
1311 \r
1312                 if ( ca_guid == p_bfi->ca_guid )\r
1313                 {\r
1314                         matched = p_bfi;\r
1315                         break;\r
1316                 }\r
1317         }\r
1318         ExReleaseFastMutexUnsafe(&ControlMutex);\r
1319 \r
1320 #if DBG\r
1321         if ( !matched )\r
1322         {\r
1323                 BUS_PRINT( BUS_DBG_PNP, ("No Match ca_guid 0x%I64x -> bfi[%d] %p\n",\r
1324                                                                         ca_guid, -1, matched ) );\r
1325         }\r
1326 #endif\r
1327         return matched;\r
1328 }\r
1329 \r
1330 \r
1331 /*\r
1332  * find/bind the specified ca_guid to a bus filter instance.\r
1333  * Called from PORT_ADD or IOU_ADD pnp callback routines with the ca_guid from\r
1334  * the pnp event record.\r
1335  * Assumption is a BFI slot has been allocated in add_device() although the\r
1336  * ca_guid was not known at that time; hence !ca_bound. When PNP generates an\r
1337  * 'ADD' event, the port_mgr/iou_mgr pnp callback routine calls here to match\r
1338  * the input ca_guid which caused the PNP event to the BFI instance by ca_guid.\r
1339  * In the 1st call after add_device() the BFI slot is allocated but not yet \r
1340  * bound to a CA guid. If the input ca_guid is not matched, then the 1st\r
1341  * allocated but not bound BFI slot is then 'bound' by setting\r
1342  * bfi->ca_guid = input ca_guid.\r
1343  */\r
1344 \r
1345 bus_filter_t *\r
1346 get_set_bfi_by_ca_guid( IN net64_t ca_guid )\r
1347 {\r
1348         bus_filter_t    *p_bfi;\r
1349         bus_filter_t    *matched=NULL;\r
1350         boolean_t               ca_bound = FALSE;\r
1351 \r
1352         if ( ca_guid == 0ULL )\r
1353         {\r
1354                 matched = bus_filters;\r
1355                 BUS_PRINT( BUS_DBG_PNP, ("%s() ERR guid 0x%I64x -> bfi[0] %p\n",\r
1356                                         __FUNCTION__, ca_guid, matched) );\r
1357                 CL_ASSERT( ca_guid );\r
1358                 return matched;\r
1359         }\r
1360 \r
1361         for(p_bfi=bus_filters; p_bfi < &bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1362         {\r
1363                 if ( !p_bfi->p_bus_ext )\r
1364                         continue;\r
1365 \r
1366                 if ( ca_guid == p_bfi->ca_guid )\r
1367                 {\r
1368                         matched = p_bfi;\r
1369                         break;\r
1370                 }\r
1371         }\r
1372 \r
1373         /*\r
1374          * if no match, find an 'allocated' bfi slot which does not have a bound CA.\r
1375          * Bound == ca_guid != 0ULL.\r
1376          */\r
1377         if ( !matched )\r
1378         {\r
1379                 ExAcquireFastMutexUnsafe(&ControlMutex);\r
1380 \r
1381                 for(p_bfi=bus_filters; p_bfi < &bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1382                 {\r
1383                         if ( !p_bfi->p_bus_ext )\r
1384                                 continue;       // not allocated.\r
1385 \r
1386                         if ( p_bfi->ca_guid == 0ULL )\r
1387                         {\r
1388                                 ca_bound = TRUE;\r
1389                                 p_bfi->ca_guid = ca_guid;       // bind CA & this BFI slot; RTU.\r
1390                                 matched = p_bfi;\r
1391                                 break;\r
1392                         }\r
1393                 }\r
1394                 ExReleaseFastMutexUnsafe(&ControlMutex);\r
1395         }\r
1396 \r
1397         BUS_PRINT( BUS_DBG_PNP,\r
1398                                 ("%s()%sguid 0x%I64x @ bfi[%d] %p \n",\r
1399                                 __FUNCTION__, (ca_bound ? "SET ":" "), ca_guid,\r
1400                                 (matched ? (matched - bus_filters) : (-1)), matched ) );\r
1401 \r
1402         return matched;\r
1403 }\r
1404 \r
1405 \r
1406 bus_filter_t *\r
1407 alloc_bfi( IN DRIVER_OBJECT  *p_driver_obj, OUT int *p_instance_count )\r
1408 {\r
1409         bus_filter_t    *p_bfi;\r
1410         bus_filter_t    *matched=NULL;\r
1411 \r
1412     /* Using unsafe function so that the IRQL remains at PASSIVE_LEVEL.\r
1413      * IoCreateDeviceSecure & IoCreateSymbolicLink must be called at\r
1414      * PASSIVE_LEVEL.\r
1415          */\r
1416         ExAcquireFastMutexUnsafe(&ControlMutex);\r
1417 \r
1418         // find 1st unused bfi slot.\r
1419         for(p_bfi=bus_filters; p_bfi < &bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1420         {\r
1421                 if ( !p_bfi->p_bus_ext )\r
1422                 {\r
1423                         /* temp setting until 'real' p_bus_ext is alloc; see bus_add_device.\r
1424                          * If p_bus_ext is ! 0, then bfi slot is allocated, although it\r
1425                          * may not yet have a bound CA guid; set set_get_\r
1426                          */\r
1427                         p_bfi->p_bus_ext = (bus_fdo_ext_t*)p_driver_obj;\r
1428                         matched = p_bfi;\r
1429                         *p_instance_count = ++bfi_InstanceCount; // record in-use\r
1430                         break;\r
1431                 }\r
1432         }\r
1433         ExReleaseFastMutexUnsafe(&ControlMutex);\r
1434 \r
1435 #if DBG\r
1436         RtlStringCbPrintfA ( p_bfi->whoami,\r
1437                                                  sizeof(p_bfi->whoami),\r
1438                                                  "bfi-%d",\r
1439                                                  (bfi_InstanceCount - 1) );\r
1440 \r
1441         p_bfi->magic = BFI_MAGIC;\r
1442 #endif\r
1443 \r
1444         BUS_PRINT( BUS_DBG_PNP, ("%s() %s %p\n",\r
1445                                 __FUNCTION__, (matched ? matched->whoami:"Nobody"), matched) );\r
1446 \r
1447         return matched;\r
1448 }\r
1449 \r
1450 \r
1451 int\r
1452 free_bfi( IN  bus_filter_t  *p_bfi )\r
1453 {\r
1454         int     remaining;\r
1455 \r
1456         ExAcquireFastMutexUnsafe(&ControlMutex);\r
1457         p_bfi->p_bus_ext = NULL;\r
1458         p_bfi->ca_guid = 0ULL;\r
1459         remaining = --bfi_InstanceCount; // one less bfi in-use\r
1460         ExReleaseFastMutexUnsafe(&ControlMutex);\r
1461 \r
1462         return remaining;\r
1463 }\r
1464 \r
1465 int\r
1466 get_bfi_count( void )\r
1467 {\r
1468         int     ic;\r
1469 \r
1470         ExAcquireFastMutexUnsafe(&ControlMutex);\r
1471         ic = bfi_InstanceCount;\r
1472         ExReleaseFastMutexUnsafe(&ControlMutex);\r
1473 \r
1474         return ic;\r
1475 }\r
1476 \r
1477 #if DBG\r
1478 char *get_obj_state_str(cl_state_t state)\r
1479 {\r
1480         switch( state ) {\r
1481           case CL_UNINITIALIZED:\r
1482                 return "UNINITIALIZED";\r
1483           case CL_INITIALIZED:\r
1484                 return "INITIALIZED";\r
1485           case CL_DESTROYING:\r
1486                 return "DESTROYING";\r
1487           case CL_DESTROYED:\r
1488                 return "DESTROYED";\r
1489           default:\r
1490                 break;\r
1491         }\r
1492         return "Err - Bad obj state";\r
1493 }\r
1494 #endif\r
1495 \r