[IBBUS] workaround for some problems with WHQL PnP test over IPoIB. [mlnx: 3535]
[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 KEVENT                                  g_ControlEvent;\r
55 ULONG                                   g_bfi_InstanceCount;\r
56 bus_filter_t                    g_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         lock_control_event();\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                         unlock_control_event();\r
347                         return STATUS_UNSUCCESSFUL;\r
348                 }\r
349                 AL_init_here = TRUE;\r
350         }\r
351         unlock_control_event();\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         *p_action = IrpSkip;\r
432         /* The FDO driver must set the status even when passing down. */\r
433         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
434 \r
435         BUS_EXIT( BUS_DBG_PNP );\r
436         return STATUS_SUCCESS;\r
437 }\r
438 \r
439 \r
440 /*\r
441  * This function gets called after releasing the remove lock and waiting\r
442  * for all other threads to release the lock.  No more modifications will\r
443  * occur to the PDO pointer vectors.\r
444  */\r
445 static void\r
446 fdo_release_resources(\r
447         IN                                      DEVICE_OBJECT* const    p_dev_obj )\r
448 {\r
449         bus_fdo_ext_t   *p_ext;\r
450         NTSTATUS                status;\r
451         bus_filter_t    *p_bfi;\r
452         int                             ic;\r
453 \r
454         BUS_ENTER( BUS_DBG_PNP );\r
455 \r
456         p_ext = p_dev_obj->DeviceExtension;\r
457         ic = get_bfi_count();\r
458 \r
459         p_bfi = p_ext->bus_filter;\r
460         CL_ASSERT( p_bfi );\r
461 \r
462         //TODO: Fail outstanding I/O operations.\r
463 \r
464         if ( p_ext->p_port_mgr && p_bfi->p_port_mgr ) {\r
465                 cl_obj_destroy( &p_ext->p_port_mgr->obj );\r
466                 p_ext->p_port_mgr = NULL;\r
467         }\r
468 \r
469         if ( p_ext->p_iou_mgr && p_bfi->p_iou_mgr ) {\r
470                 cl_obj_destroy( &p_ext->p_iou_mgr->obj );\r
471                 p_ext->p_iou_mgr = NULL;\r
472         }\r
473 \r
474         BUS_PRINT( BUS_DBG_PNP, ("Releasing BusFilter %s\n", p_bfi->whoami ));\r
475         if (p_bfi) {\r
476                 p_ext->bus_filter = NULL;\r
477                 p_bfi->p_bus_ext = NULL;\r
478         }\r
479 \r
480         ic = free_bfi( p_bfi );\r
481 \r
482         /* if not last Buf Filter Instance, then exit, otherwise cleanup/shutdown */\r
483         if ( ic > 0 ) {\r
484                 BUS_PRINT( BUS_DBG_PNP, (" %d remaining BusFilters\n", ic ));\r
485                 return;\r
486         }\r
487 \r
488         /* Disable any exported interfaces. */\r
489         status = IoSetDeviceInterfaceState( &al_ifc_name, FALSE );\r
490         ASSERT( NT_SUCCESS( status ) );\r
491         status = IoSetDeviceInterfaceState( &ci_ifc_name, FALSE );\r
492         ASSERT( NT_SUCCESS( status ) );\r
493 \r
494         /* Release the memory allocated for the interface symbolic names. */\r
495         RtlFreeUnicodeString( &ci_ifc_name );\r
496         RtlFreeUnicodeString( &al_ifc_name );\r
497 \r
498         al_cleanup();\r
499 \r
500         BUS_EXIT( BUS_DBG_PNP );\r
501 }\r
502 \r
503 \r
504 static NTSTATUS\r
505 fdo_query_capabilities(\r
506         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
507         IN                                      IRP* const                              p_irp, \r
508                 OUT                             cl_irp_action_t* const  p_action )\r
509 {\r
510         NTSTATUS                        status;\r
511         bus_fdo_ext_t           *p_ext;\r
512         IO_STACK_LOCATION       *p_io_stack;\r
513 \r
514         BUS_ENTER( BUS_DBG_PNP );\r
515 \r
516         p_ext = p_dev_obj->DeviceExtension;\r
517 \r
518         /* Process on the way up. */\r
519         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
520 \r
521         if( !NT_SUCCESS( status ) )\r
522         {\r
523                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
524                         ("cl_do_sync_pnp returned %08x.\n", status) );\r
525                 return status;\r
526         }\r
527 \r
528         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
529 \r
530         /*\r
531          * Store the device power maping into our extension since we're\r
532          * the power policy owner.  The mapping is used when handling\r
533          * IRP_MN_SET_POWER IRPs.\r
534          */\r
535         cl_memcpy( p_ext->po_state, \r
536                 p_io_stack->Parameters.DeviceCapabilities.Capabilities->DeviceState,\r
537                 sizeof( p_ext->po_state ) );\r
538 \r
539         BUS_EXIT( BUS_DBG_PNP );\r
540         return status;\r
541 }\r
542 \r
543 \r
544 static NTSTATUS\r
545 fdo_query_bus_relations(\r
546         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
547         IN                                      IRP* const                              p_irp, \r
548                 OUT                             cl_irp_action_t* const  p_action )\r
549 {\r
550         NTSTATUS                        status;\r
551         bus_fdo_ext_t           *p_ext;\r
552         bus_filter_t            *p_bfi;\r
553 \r
554         BUS_ENTER( BUS_DBG_PNP );\r
555 \r
556         p_ext = p_dev_obj->DeviceExtension;\r
557 \r
558         if ( !p_ext->bus_filter )\r
559         {\r
560                 /* BFI has already been released */\r
561                 *p_action = IrpComplete;\r
562                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("NULL BFI\n") );\r
563                 return STATUS_SUCCESS;\r
564         }\r
565 \r
566         p_bfi = p_ext->bus_filter;\r
567         CL_ASSERT( p_bfi->magic == BFI_MAGIC );\r
568 \r
569         if ( p_bfi->ca_guid == 0ULL )\r
570         {\r
571                 /* HCA not yet bound to a BFI slot (no PNP ADD event seen), no bus\r
572                  * relations yet.\r
573                  */\r
574                 status = STATUS_SUCCESS;\r
575                 BUS_PRINT(BUS_DBG_PNP, ("%s ca_guid %I64x\n",p_bfi->whoami,\r
576                                                                 p_bfi->ca_guid));\r
577         }\r
578         else\r
579         {\r
580                 status = port_mgr_get_bus_relations( p_bfi->ca_guid, p_irp );\r
581                 if( status == STATUS_SUCCESS || \r
582                         status == STATUS_NO_SUCH_DEVICE )\r
583                 {\r
584                         status = iou_mgr_get_bus_relations( p_bfi->ca_guid, p_irp );\r
585                 }\r
586                 if( status == STATUS_NO_SUCH_DEVICE )\r
587                         status = STATUS_SUCCESS;\r
588         }\r
589 \r
590         switch( status )\r
591         {\r
592         case STATUS_NO_SUCH_DEVICE:\r
593                 *p_action = IrpSkip;\r
594                 status = STATUS_SUCCESS;\r
595                 break;\r
596 \r
597         case STATUS_SUCCESS:\r
598                 *p_action = IrpPassDown;\r
599                 break;\r
600 \r
601         default:\r
602                 *p_action = IrpComplete;\r
603                 break;\r
604         }\r
605 \r
606         BUS_EXIT( BUS_DBG_PNP );\r
607         return status;\r
608 }\r
609 \r
610 \r
611 void\r
612 al_ref_ifc(\r
613         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
614 {\r
615         bus_fdo_ext_t   *p_ext;\r
616 \r
617         BUS_ENTER( BUS_DBG_PNP );\r
618 \r
619         p_ext = p_dev_obj->DeviceExtension;\r
620 \r
621         cl_atomic_inc( &p_ext->n_al_ifc_ref );\r
622         ObReferenceObject( p_dev_obj );\r
623 \r
624         BUS_EXIT( BUS_DBG_PNP );\r
625 }\r
626 \r
627 \r
628 void\r
629 al_deref_ifc(\r
630         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
631 {\r
632         bus_fdo_ext_t   *p_ext;\r
633 \r
634         BUS_ENTER( BUS_DBG_PNP );\r
635 \r
636         p_ext = p_dev_obj->DeviceExtension;\r
637 \r
638         cl_atomic_dec( &p_ext->n_al_ifc_ref );\r
639         ObDereferenceObject( p_dev_obj );\r
640 \r
641         CL_ASSERT(p_ext->bus_filter);\r
642         BUS_PRINT( BUS_DBG_PNP, ("%s CA_guid %I64x al_ifc_ref %d\n",\r
643                                         p_ext->bus_filter->whoami, p_ext->bus_filter->ca_guid,\r
644                                         p_ext->n_al_ifc_ref) );\r
645 \r
646         BUS_EXIT( BUS_DBG_PNP );\r
647 }\r
648 \r
649 \r
650 void\r
651 al_ref_ci_ifc(\r
652         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
653 {\r
654         bus_fdo_ext_t   *p_ext;\r
655 \r
656         BUS_ENTER( BUS_DBG_PNP );\r
657 \r
658         p_ext = p_dev_obj->DeviceExtension;\r
659 \r
660         cl_atomic_inc( &p_ext->n_ci_ifc_ref );\r
661         ObReferenceObject( p_dev_obj );\r
662 \r
663         BUS_EXIT( BUS_DBG_PNP );\r
664 }\r
665 \r
666 \r
667 void\r
668 al_deref_ci_ifc(\r
669         IN                              DEVICE_OBJECT*                          p_dev_obj )\r
670 {\r
671         bus_fdo_ext_t   *p_ext;\r
672 \r
673         BUS_ENTER( BUS_DBG_PNP );\r
674 \r
675         p_ext = p_dev_obj->DeviceExtension;\r
676 \r
677         cl_atomic_dec( &p_ext->n_ci_ifc_ref );\r
678         ObDereferenceObject( p_dev_obj );\r
679 \r
680         CL_ASSERT(p_ext->bus_filter);\r
681         BUS_PRINT( BUS_DBG_PNP, ("%s CA_guid %I64x ci_ifc_ref %d\n",\r
682                                                 p_ext->bus_filter->whoami, p_ext->bus_filter->ca_guid,\r
683                                                 p_ext->n_ci_ifc_ref) );\r
684 \r
685         BUS_EXIT( BUS_DBG_PNP );\r
686 }\r
687 \r
688 \r
689 static NTSTATUS\r
690 __query_al_ifc(\r
691         IN                                      DEVICE_OBJECT* const            p_dev_obj,\r
692         IN                                      IO_STACK_LOCATION* const        p_io_stack )\r
693 {\r
694         ib_al_ifc_t             *p_ifc;\r
695 \r
696         BUS_ENTER( BUS_DBG_PNP );\r
697 \r
698         if( p_io_stack->Parameters.QueryInterface.Version != \r
699                 AL_INTERFACE_VERSION )\r
700         {\r
701                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n",\r
702                         p_io_stack->Parameters.QueryInterface.Version ) );\r
703                 return STATUS_NOT_SUPPORTED;\r
704         }\r
705 \r
706         if( p_io_stack->Parameters.QueryInterface.Size < sizeof(ib_al_ifc_t) )\r
707         {\r
708                 BUS_TRACE_EXIT( BUS_DBG_PNP, \r
709                         ("Buffer too small (%d given, %d required).\n",\r
710                         p_io_stack->Parameters.QueryInterface.Size, sizeof(ib_al_ifc_t)) );\r
711                 return STATUS_BUFFER_TOO_SMALL;\r
712         }\r
713 \r
714         // Copy the interface.\r
715         p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
716 \r
717         p_ifc->wdm.Size = sizeof(ib_al_ifc_t);\r
718         p_ifc->wdm.Version = AL_INTERFACE_VERSION;\r
719         p_ifc->wdm.Context = p_dev_obj;\r
720         p_ifc->wdm.InterfaceReference = al_ref_ifc;\r
721         p_ifc->wdm.InterfaceDereference = al_deref_ifc;\r
722 \r
723         al_set_ifc( p_ifc );\r
724 \r
725         // take the reference before returning.\r
726         al_ref_ifc( p_dev_obj );\r
727         BUS_EXIT( BUS_DBG_PNP );\r
728         return STATUS_SUCCESS;\r
729 }\r
730 \r
731 \r
732 void\r
733 al_set_ifc(\r
734                 OUT                     ib_al_ifc_t* const                      p_ifc )\r
735 {\r
736         BUS_ENTER( BUS_DBG_PNP );\r
737 \r
738         p_ifc->wdm.Size = sizeof(ib_al_ifc_t);\r
739         p_ifc->wdm.InterfaceReference = al_ref_ifc;\r
740         p_ifc->wdm.InterfaceDereference = al_deref_ifc;\r
741 \r
742         p_ifc->sync_destroy = ib_sync_destroy;\r
743         p_ifc->open_ca = ib_open_ca;\r
744         p_ifc->query_ca = ib_query_ca;\r
745         p_ifc->get_dev = get_ca_dev;\r
746         p_ifc->close_ca = ib_close_ca;\r
747         p_ifc->alloc_pd = ib_alloc_pd;\r
748         p_ifc->dealloc_pd = ib_dealloc_pd;\r
749         p_ifc->create_av = ib_create_av;\r
750         p_ifc->query_av = ib_query_av;\r
751         p_ifc->modify_av = ib_modify_av;\r
752         p_ifc->destroy_av = ib_destroy_av;\r
753         p_ifc->create_qp = ib_create_qp;\r
754         p_ifc->get_spl_qp = ib_get_spl_qp;\r
755         p_ifc->query_qp = ib_query_qp;\r
756         p_ifc->modify_qp = ib_modify_qp;\r
757         p_ifc->destroy_qp = ib_destroy_qp;\r
758         p_ifc->create_cq = ib_create_cq;\r
759         p_ifc->modify_cq = ib_modify_cq;\r
760         p_ifc->query_cq = ib_query_cq;\r
761         p_ifc->destroy_cq = ib_destroy_cq;\r
762         p_ifc->reg_mem = ib_reg_mem;\r
763         p_ifc->reg_phys = ib_reg_phys;\r
764         p_ifc->query_mr = ib_query_mr;\r
765         p_ifc->rereg_mem = ib_rereg_mem;\r
766         p_ifc->reg_shmid = ib_reg_shmid;\r
767         p_ifc->dereg_mr = ib_dereg_mr;\r
768         p_ifc->create_mw = ib_create_mw;\r
769         p_ifc->query_mw = ib_query_mw;\r
770         p_ifc->bind_mw = ib_bind_mw;\r
771         p_ifc->destroy_mw = ib_destroy_mw;\r
772         p_ifc->post_send = ib_post_send;\r
773         p_ifc->post_recv = ib_post_recv;\r
774         p_ifc->send_mad = ib_send_mad;\r
775         p_ifc->cancel_mad = ib_cancel_mad;\r
776         p_ifc->poll_cq = ib_poll_cq;\r
777         p_ifc->rearm_cq = ib_rearm_cq;\r
778         p_ifc->join_mcast = ib_join_mcast;\r
779         p_ifc->leave_mcast = ib_leave_mcast;\r
780         p_ifc->local_mad = ib_local_mad;\r
781         p_ifc->cm_listen = ib_cm_listen;\r
782         p_ifc->cm_cancel = ib_cm_cancel;\r
783         p_ifc->cm_req = ib_cm_req;\r
784         p_ifc->cm_rep = ib_cm_rep;\r
785         p_ifc->cm_rtu = ib_cm_rtu;\r
786         p_ifc->cm_rej = ib_cm_rej;\r
787         p_ifc->cm_mra = ib_cm_mra;\r
788         p_ifc->cm_lap = ib_cm_lap;\r
789         p_ifc->cm_apr = ib_cm_apr;\r
790         p_ifc->force_apm = ib_force_apm;\r
791         p_ifc->cm_dreq = ib_cm_dreq;\r
792         p_ifc->cm_drep = ib_cm_drep;\r
793         p_ifc->cm_handoff = ib_cm_handoff;\r
794         p_ifc->create_ioc = ib_create_ioc;\r
795         p_ifc->destroy_ioc = ib_destroy_ioc;\r
796         p_ifc->reg_ioc = ib_reg_ioc;\r
797         p_ifc->add_svc_entry = ib_add_svc_entry;\r
798         p_ifc->remove_svc_entry = ib_remove_svc_entry;\r
799         p_ifc->get_ca_guids = ib_get_ca_guids;\r
800         p_ifc->get_ca_by_gid = ib_get_ca_by_gid;\r
801         p_ifc->get_port_by_gid = ib_get_port_by_gid;\r
802         p_ifc->create_mad_pool = ib_create_mad_pool;\r
803         p_ifc->destroy_mad_pool = ib_destroy_mad_pool;\r
804         p_ifc->reg_mad_pool = ib_reg_mad_pool;\r
805         p_ifc->dereg_mad_pool = ib_dereg_mad_pool;\r
806         p_ifc->get_mad = ib_get_mad;\r
807         p_ifc->put_mad = ib_put_mad;\r
808         p_ifc->init_dgrm_svc = ib_init_dgrm_svc;\r
809         p_ifc->reg_mad_svc = ib_reg_mad_svc;\r
810         p_ifc->reg_svc = ib_reg_svc;\r
811         p_ifc->dereg_svc = ib_dereg_svc;\r
812         p_ifc->query = ib_query;\r
813         p_ifc->cancel_query = ib_cancel_query;\r
814         p_ifc->reg_pnp = ib_reg_pnp;\r
815         p_ifc->dereg_pnp = ib_dereg_pnp;\r
816         p_ifc->subscribe = ib_subscribe;\r
817         p_ifc->unsubscribe = ib_unsubscribe;\r
818         p_ifc->reject_ioc = ib_reject_ioc;\r
819         p_ifc->ci_call = ib_ci_call;\r
820         p_ifc->open_al = ib_open_al;\r
821         p_ifc->close_al = ib_close_al;\r
822         p_ifc->get_err_str = ib_get_err_str;\r
823         p_ifc->get_wc_status_str = ib_get_wc_status_str;\r
824         p_ifc->create_mlnx_fmr = mlnx_create_fmr;\r
825         p_ifc->map_phys_mlnx_fmr = mlnx_map_phys_fmr;\r
826         p_ifc->unmap_mlnx_fmr = mlnx_unmap_fmr;\r
827         p_ifc->destroy_mlnx_fmr = mlnx_destroy_fmr;\r
828         p_ifc->create_mlnx_fmr_pool = mlnx_create_fmr_pool;\r
829         p_ifc->destroy_mlnx_fmr_pool = mlnx_destroy_fmr_pool;\r
830         p_ifc->map_phys_mlnx_fmr_pool = mlnx_map_phys_fmr_pool;\r
831         p_ifc->unmap_mlnx_fmr_pool = mlnx_unmap_fmr_pool;\r
832         p_ifc->flush_mlnx_fmr_pool = mlnx_flush_fmr_pool;\r
833         p_ifc->create_srq = ib_create_srq;\r
834         p_ifc->modify_srq = ib_modify_srq;\r
835         p_ifc->query_srq = ib_query_srq;\r
836         p_ifc->destroy_srq = ib_destroy_srq;\r
837         p_ifc->post_srq_recv = ib_post_srq_recv;\r
838 \r
839         BUS_EXIT( BUS_DBG_PNP );\r
840 }\r
841 \r
842 \r
843 static NTSTATUS\r
844 __get_relations(\r
845         IN              const   net64_t                                         ca_guid,\r
846         IN                              IRP* const                                      p_irp )\r
847 {\r
848         UNUSED_PARAM( ca_guid );\r
849         UNUSED_PARAM( p_irp );\r
850 \r
851         BUS_ENTER( BUS_DBG_PNP );\r
852 \r
853         /*\r
854          * Now that ibbus is in the same device stack as the HCA driver, skip\r
855          * returning relations here as ibbus has already done the deed.\r
856          * This interface remains to minimize changes to HCA drivers for now.\r
857          */\r
858 \r
859         BUS_EXIT( BUS_DBG_PNP );\r
860         return STATUS_SUCCESS;\r
861 }\r
862 \r
863 \r
864 static NTSTATUS\r
865 __query_ci_ifc(\r
866         IN                                      DEVICE_OBJECT* const            p_dev_obj,\r
867         IN                                      IO_STACK_LOCATION* const        p_io_stack )\r
868 {\r
869         ib_ci_ifc_t             *p_ifc;\r
870 \r
871         BUS_ENTER( BUS_DBG_PNP );\r
872 \r
873         if( p_io_stack->Parameters.QueryInterface.Version != \r
874                 IB_CI_INTERFACE_VERSION )\r
875         {\r
876                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n",\r
877                         p_io_stack->Parameters.QueryInterface.Version ) );\r
878                 return STATUS_NOT_SUPPORTED;\r
879         }\r
880 \r
881         if( p_io_stack->Parameters.QueryInterface.Size < sizeof(ib_ci_ifc_t) )\r
882         {\r
883                 BUS_TRACE_EXIT( BUS_DBG_PNP, \r
884                         ("Buffer too small (%d given, %d required).\n",\r
885                         p_io_stack->Parameters.QueryInterface.Size, sizeof(ib_ci_ifc_t)) );\r
886                 return STATUS_BUFFER_TOO_SMALL;\r
887         }\r
888 \r
889         /* Copy the interface. */\r
890         p_ifc = (ib_ci_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
891 \r
892         p_ifc->wdm.Size = sizeof(ib_ci_ifc_t);\r
893         p_ifc->wdm.Version = IB_CI_INTERFACE_VERSION;\r
894         p_ifc->wdm.Context = p_dev_obj;\r
895         p_ifc->wdm.InterfaceReference = al_ref_ci_ifc;\r
896         p_ifc->wdm.InterfaceDereference = al_deref_ci_ifc;\r
897 \r
898         /* Set the entry points. */\r
899         p_ifc->register_ca = ib_register_ca;\r
900         p_ifc->deregister_ca = ib_deregister_ca;\r
901         p_ifc->get_relations = __get_relations;\r
902         p_ifc->get_err_str = ib_get_err_str;\r
903 \r
904         /* take the reference before returning. */\r
905         al_ref_ci_ifc( p_dev_obj );\r
906         BUS_EXIT( BUS_DBG_PNP );\r
907         return STATUS_SUCCESS;\r
908 }\r
909 \r
910 \r
911 static NTSTATUS\r
912 fdo_query_interface(\r
913         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
914         IN                                      IRP* const                              p_irp, \r
915                 OUT                             cl_irp_action_t* const  p_action )\r
916 {\r
917         NTSTATUS                        status;\r
918         IO_STACK_LOCATION       *p_io_stack;\r
919 \r
920         BUS_ENTER( BUS_DBG_PNP );\r
921 \r
922         PAGED_CODE();\r
923 \r
924         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
925         \r
926         /* Compare requested GUID with our supported interface GUIDs. */\r
927         if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
928                 &GUID_IB_AL_INTERFACE ) )\r
929         {\r
930                 status = __query_al_ifc( p_dev_obj, p_io_stack );\r
931         }\r
932         else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
933                 &GUID_IB_CI_INTERFACE ) )\r
934         {\r
935                 status = __query_ci_ifc( p_dev_obj, p_io_stack );\r
936         }\r
937         else\r
938         {\r
939                 status = p_irp->IoStatus.Status;\r
940         }\r
941 \r
942         if( NT_SUCCESS( status ) )\r
943                 *p_action = IrpSkip;\r
944         else if( status == STATUS_BUFFER_TOO_SMALL )\r
945                 *p_action = IrpComplete;\r
946         else\r
947                 *p_action = IrpIgnore;\r
948 \r
949         BUS_EXIT( BUS_DBG_PNP );\r
950         return status;\r
951 }\r
952 \r
953 \r
954 static NTSTATUS\r
955 __fdo_query_power(\r
956         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
957         IN                              IRP* const                                      p_irp,\r
958                 OUT                     cl_irp_action_t* const          p_action )\r
959 {\r
960         NTSTATUS                        status = STATUS_SUCCESS;\r
961         IO_STACK_LOCATION       *p_io_stack;\r
962 \r
963         BUS_ENTER( BUS_DBG_POWER );\r
964 \r
965         UNUSED_PARAM( p_dev_obj );\r
966 \r
967         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
968 \r
969         switch( p_io_stack->Parameters.Power.Type )\r
970         {\r
971         case SystemPowerState:\r
972                 /* Fail any requests to hibernate or sleep the system. */\r
973                 switch( p_io_stack->Parameters.Power.State.SystemState )\r
974                 {\r
975                         case PowerSystemHibernate:\r
976                         case PowerSystemSleeping1:      // STANDBY support\r
977                         case PowerSystemWorking:\r
978                         case PowerSystemShutdown:\r
979                                 break;\r
980 \r
981                         default:\r
982                                 status = STATUS_NOT_SUPPORTED;\r
983                 }\r
984                 break;\r
985 \r
986         case DevicePowerState:\r
987                 /* Fail any query for low power states. */\r
988                 switch( p_io_stack->Parameters.Power.State.DeviceState )\r
989                 {\r
990                 case PowerDeviceD0:\r
991                 case PowerDeviceD3:\r
992                         /* We only support fully powered or off power states. */\r
993                         break;\r
994 \r
995                 default:\r
996                         status = STATUS_NOT_SUPPORTED;\r
997                 }\r
998                 break;\r
999         }\r
1000 \r
1001         if( status == STATUS_NOT_SUPPORTED )\r
1002                 *p_action = IrpComplete;\r
1003         else\r
1004                 *p_action = IrpSkip;\r
1005 \r
1006         BUS_EXIT( BUS_DBG_POWER );\r
1007         return status;\r
1008 }\r
1009 \r
1010 \r
1011 static void\r
1012 __request_power_completion(\r
1013         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1014         IN                              UCHAR                                           minor_function,\r
1015         IN                              POWER_STATE                                     power_state,\r
1016         IN                              void                                            *context,\r
1017         IN                              IO_STATUS_BLOCK                         *p_io_status )\r
1018 {\r
1019         IRP                                     *p_irp;\r
1020         cl_pnp_po_ext_t         *p_ext;\r
1021 \r
1022         BUS_ENTER( BUS_DBG_PNP );\r
1023 \r
1024         UNUSED_PARAM( minor_function );\r
1025         UNUSED_PARAM( power_state );\r
1026 \r
1027         p_irp = (IRP*)context;\r
1028         p_ext = p_dev_obj->DeviceExtension;\r
1029 \r
1030         /* Propagate the device IRP status to the system IRP status. */\r
1031         p_irp->IoStatus.Status = p_io_status->Status;\r
1032 \r
1033         /* Continue Power IRP processing. */\r
1034         PoStartNextPowerIrp( p_irp );\r
1035         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1036         IoReleaseRemoveLock( &p_ext->remove_lock, p_irp );\r
1037         BUS_EXIT( BUS_DBG_PNP );\r
1038 }\r
1039 \r
1040 \r
1041 /*NOTE: Completion routines must NEVER be pageable. */\r
1042 static NTSTATUS\r
1043 __set_power_completion(\r
1044         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1045         IN                              IRP                                                     *p_irp,\r
1046         IN                              void                                            *context )\r
1047 {\r
1048         NTSTATUS                        status;\r
1049         POWER_STATE                     state;\r
1050         bus_fdo_ext_t           *p_ext;\r
1051         IO_STACK_LOCATION       *p_io_stack;\r
1052 \r
1053         BUS_ENTER( BUS_DBG_PNP );\r
1054 \r
1055         UNUSED_PARAM( context );\r
1056 \r
1057         p_ext = p_dev_obj->DeviceExtension;\r
1058         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1059 \r
1060         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
1061         {\r
1062                 PoStartNextPowerIrp( p_irp );\r
1063                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1064                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
1065                         ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n",\r
1066                         p_irp->IoStatus.Status) );\r
1067                 return STATUS_SUCCESS;\r
1068         }\r
1069 \r
1070         state.DeviceState = \r
1071                 p_ext->po_state[p_io_stack->Parameters.Power.State.SystemState];\r
1072 \r
1073         /*\r
1074          * Send a device power IRP to our devnode.  Using our device object will\r
1075          * only work on win2k and other NT based systems.\r
1076          */\r
1077         status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
1078                 __request_power_completion, p_irp, NULL );\r
1079 \r
1080         if( status != STATUS_PENDING )\r
1081         {\r
1082                 PoStartNextPowerIrp( p_irp );\r
1083                 /* Propagate the failure. */\r
1084                 p_irp->IoStatus.Status = status;\r
1085                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1086                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
1087                 BUS_TRACE( BUS_DBG_ERROR,\r
1088                         ("PoRequestPowerIrp returned %08x.\n", status) );\r
1089         }\r
1090 \r
1091         BUS_EXIT( BUS_DBG_PNP );\r
1092         return STATUS_MORE_PROCESSING_REQUIRED;\r
1093 }\r
1094 \r
1095 \r
1096 static NTSTATUS\r
1097 __fdo_set_power(\r
1098         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1099         IN                              IRP* const                                      p_irp,\r
1100                 OUT                     cl_irp_action_t* const          p_action )\r
1101 {\r
1102         NTSTATUS                        status;\r
1103         IO_STACK_LOCATION       *p_io_stack;\r
1104         bus_fdo_ext_t           *p_ext;\r
1105 \r
1106         BUS_ENTER( BUS_DBG_POWER );\r
1107 \r
1108         p_ext = p_dev_obj->DeviceExtension;\r
1109         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1110 \r
1111         BUS_TRACE( BUS_DBG_POWER, \r
1112                 ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d \n",\r
1113                 p_dev_obj, p_ext,\r
1114                 (p_io_stack->Parameters.Power.Type)\r
1115                         ? "DevicePowerState" : "SystemPowerState",\r
1116                 p_io_stack->Parameters.Power.State.DeviceState, \r
1117                 p_io_stack->Parameters.Power.ShutdownType ));\r
1118 \r
1119         switch( p_io_stack->Parameters.Power.Type )\r
1120         {\r
1121         case SystemPowerState:\r
1122                 /*\r
1123                  * Process on the way up the stack.  We cannot block since the \r
1124                  * power dispatch function can be called at elevated IRQL if the\r
1125                  * device is in a paging/hibernation/crash dump path.\r
1126                  */\r
1127                 IoMarkIrpPending( p_irp );\r
1128                 IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1129 #pragma warning( push, 3 )\r
1130                 IoSetCompletionRoutine( p_irp, __set_power_completion, NULL, \r
1131                         TRUE, TRUE, TRUE );\r
1132 #pragma warning( pop )\r
1133                 PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
1134 \r
1135                 *p_action = IrpDoNothing;\r
1136                 status = STATUS_PENDING;\r
1137                 break;\r
1138 \r
1139         case DevicePowerState:\r
1140         default:\r
1141                 /* Pass down and let the PDO driver handle it. */\r
1142                 *p_action = IrpIgnore;\r
1143                 status = STATUS_SUCCESS;\r
1144                 break;\r
1145         }\r
1146 \r
1147         BUS_EXIT( BUS_DBG_POWER );\r
1148         return status;\r
1149 }\r
1150 \r
1151 \r
1152 /*\r
1153  * A CA GUID of zero means that all devices should be reported.\r
1154  */\r
1155 NTSTATUS\r
1156 bus_get_relations(\r
1157         IN                              cl_qlist_t*     const                   p_pdo_list,\r
1158         IN              const   net64_t                                         ca_guid,\r
1159         IN                              IRP* const                                      p_irp )\r
1160 {\r
1161         NTSTATUS                        status;\r
1162         DEVICE_RELATIONS        *p_rel;\r
1163         cl_list_item_t          *p_list_item;\r
1164         bus_pdo_ext_t           *p_pdo_ext;\r
1165         size_t                          n_devs = 0;\r
1166 \r
1167         BUS_ENTER( BUS_DBG_PNP );\r
1168 \r
1169         /* Count the number of child devices. */\r
1170         for( p_list_item = cl_qlist_head( p_pdo_list );\r
1171                 p_list_item != cl_qlist_end( p_pdo_list );\r
1172                 p_list_item = cl_qlist_next( p_list_item ) )\r
1173         {\r
1174                 p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
1175 \r
1176                 if( !p_pdo_ext->b_present )\r
1177                 {\r
1178                         // mark it missing to be removed in port_remove\r
1179                         p_pdo_ext->b_reported_missing = TRUE;\r
1180                         /*\r
1181                          * We don't report a PDO that is no longer present.  This is how\r
1182                          * the PDO will get cleaned up.\r
1183                          */\r
1184                         BUS_TRACE( BUS_DBG_PNP, ("Don't report PDO! %s: PDO %p, ext %p, "\r
1185                                 "present %d, missing %d .\n",\r
1186                                 p_pdo_ext->cl_ext.vfptr_pnp_po->identity,\r
1187                                 p_pdo_ext->cl_ext.p_self_do, p_pdo_ext, p_pdo_ext->b_present,\r
1188                                 p_pdo_ext->b_reported_missing ) );\r
1189                         continue;\r
1190                 }\r
1191                 \r
1192                 if( ca_guid && p_pdo_ext->ca_guid != ca_guid )\r
1193                         continue;\r
1194 \r
1195                 n_devs++;\r
1196         }\r
1197 \r
1198         if( !n_devs )\r
1199         {\r
1200                 BUS_TRACE_EXIT( BUS_DBG_PNP, ("Found 0 PDOs ca_guid %I64x\n", ca_guid));\r
1201                 return STATUS_NO_SUCH_DEVICE;\r
1202         }\r
1203 \r
1204         BUS_TRACE( BUS_DBG_PNP, ("Found %d PDOs ca_guid %I64x\n", n_devs, ca_guid));\r
1205 \r
1206         /* Add space for our child IOUs. */\r
1207         status = cl_alloc_relations( p_irp, n_devs );\r
1208         if( !NT_SUCCESS( status ) )\r
1209         {\r
1210                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
1211                         ("cl_alloc_relations returned %08x.\n", status) );\r
1212                 return status;\r
1213         }\r
1214 \r
1215         p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
1216 \r
1217         for( p_list_item = cl_qlist_head( p_pdo_list );\r
1218                 p_list_item != cl_qlist_end( p_pdo_list );\r
1219                 p_list_item = cl_qlist_next( p_list_item ) )\r
1220         {\r
1221                 p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item );\r
1222 \r
1223                 if( !p_pdo_ext->b_present )\r
1224                         continue;\r
1225 \r
1226                 if( ca_guid && p_pdo_ext->ca_guid != ca_guid )\r
1227                         continue;\r
1228 \r
1229                 BUS_TRACE( BUS_DBG_PNP, ("Reported PDO %p(=%p), ext %p\n", \r
1230                         p_pdo_ext->cl_ext.p_self_do, p_pdo_ext->cl_ext.p_pdo, p_pdo_ext ));\r
1231                 \r
1232                 p_rel->Objects[p_rel->Count] = p_pdo_ext->cl_ext.p_pdo;\r
1233                 ObReferenceObject( p_rel->Objects[p_rel->Count++] );\r
1234         }\r
1235 \r
1236         BUS_EXIT( BUS_DBG_PNP );\r
1237         return STATUS_SUCCESS;\r
1238 }\r
1239 \r
1240 \r
1241 /*\r
1242  * find a bus filter instance (p_bfi) given an *cl_obj: port_mgr or iou_mgr. \r
1243  */\r
1244 \r
1245 bus_filter_t *\r
1246 get_bfi_by_obj(IN int obj_type, IN cl_obj_t *p_obj )\r
1247 {\r
1248         bus_filter_t    *p_bfi;\r
1249         bus_filter_t    *matched=NULL;\r
1250 \r
1251         CL_ASSERT((obj_type == BFI_PORT_MGR_OBJ) || (obj_type == BFI_IOU_MGR_OBJ));\r
1252 \r
1253         lock_control_event();\r
1254 \r
1255         for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++) {\r
1256 \r
1257                 if ( !p_bfi->p_bus_ext )\r
1258                         continue;\r
1259 \r
1260                 if ( obj_type == BFI_PORT_MGR_OBJ ) {\r
1261                         if ( p_obj == p_bfi->p_port_mgr_obj ) {\r
1262                                 matched = p_bfi;\r
1263                                 break;\r
1264                         }\r
1265                 }\r
1266                 else {\r
1267                         if ( p_obj == p_bfi->p_iou_mgr_obj ) {\r
1268                                 matched = p_bfi;\r
1269                                 break;\r
1270                         }\r
1271                 }\r
1272         }\r
1273         unlock_control_event();\r
1274 \r
1275         BUS_PRINT( BUS_DBG_PNP,\r
1276                                 ("%s() cl_obj %p type %s_MGR_OBJ --> bfi[%d] %p\n",\r
1277                                 __FUNCTION__,p_obj,\r
1278                                 (obj_type == BFI_PORT_MGR_OBJ ? "PORT": "IOU"),\r
1279                                 (matched ? (matched - g_bus_filters) : (-1)), matched ) );\r
1280 \r
1281         return matched;\r
1282 }\r
1283 \r
1284 /*\r
1285  * find a bus filter instance given an HCA guid.\r
1286  */\r
1287 \r
1288 bus_filter_t *\r
1289 get_bfi_by_ca_guid( IN net64_t ca_guid )\r
1290 {\r
1291         bus_filter_t    *p_bfi;\r
1292         bus_filter_t    *matched=NULL;\r
1293 \r
1294         if ( ca_guid == 0ULL )\r
1295         {\r
1296                 matched = g_bus_filters;\r
1297                 BUS_PRINT( BUS_DBG_PNP, ("%s() ERR guid %I64x -> bfi[0] %p\n",\r
1298                                                                 __FUNCTION__, ca_guid, matched) );\r
1299                 CL_ASSERT( ca_guid );\r
1300                 return matched;\r
1301         }\r
1302 \r
1303         lock_control_event();\r
1304 \r
1305         for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1306         {\r
1307                 if ( !p_bfi->p_bus_ext )\r
1308                         continue;\r
1309 \r
1310                 if ( ca_guid == p_bfi->ca_guid )\r
1311                 {\r
1312                         matched = p_bfi;\r
1313                         break;\r
1314                 }\r
1315         }\r
1316         unlock_control_event();\r
1317 \r
1318 #if DBG\r
1319         if ( !matched )\r
1320         {\r
1321                 BUS_PRINT( BUS_DBG_PNP, ("No Match ca_guid 0x%I64x -> bfi[%d] %p\n",\r
1322                                                                         ca_guid, -1, matched ) );\r
1323         }\r
1324 #endif\r
1325         return matched;\r
1326 }\r
1327 \r
1328 \r
1329 /*\r
1330  * find/bind the specified ca_guid to a bus filter instance.\r
1331  * Called from PORT_ADD or IOU_ADD pnp callback routines with the ca_guid from\r
1332  * the pnp event record.\r
1333  * Assumption is a BFI slot has been allocated in add_device() although the\r
1334  * ca_guid was not known at that time; hence !ca_bound. When PNP generates an\r
1335  * 'ADD' event, the port_mgr/iou_mgr pnp callback routine calls here to match\r
1336  * the input ca_guid which caused the PNP event to the BFI instance by ca_guid.\r
1337  * In the 1st call after add_device() the BFI slot is allocated but not yet \r
1338  * bound to a CA guid. If the input ca_guid is not matched, then the 1st\r
1339  * allocated but not bound BFI slot is then 'bound' by setting\r
1340  * bfi->ca_guid = input ca_guid.\r
1341  */\r
1342 \r
1343 bus_filter_t *\r
1344 get_set_bfi_by_ca_guid( IN net64_t ca_guid )\r
1345 {\r
1346         bus_filter_t    *p_bfi;\r
1347         bus_filter_t    *matched=NULL;\r
1348         boolean_t               ca_bound = FALSE;\r
1349 \r
1350         if ( ca_guid == 0ULL )\r
1351         {\r
1352                 matched = g_bus_filters;\r
1353                 BUS_PRINT( BUS_DBG_PNP, ("%s() ERR guid 0x%I64x -> bfi[0] %p\n",\r
1354                                         __FUNCTION__, ca_guid, matched) );\r
1355                 CL_ASSERT( ca_guid );\r
1356                 return matched;\r
1357         }\r
1358 \r
1359         for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1360         {\r
1361                 if ( !p_bfi->p_bus_ext )\r
1362                         continue;\r
1363 \r
1364                 if ( ca_guid == p_bfi->ca_guid )\r
1365                 {\r
1366                         matched = p_bfi;\r
1367                         break;\r
1368                 }\r
1369         }\r
1370 \r
1371         /*\r
1372          * if no match, find an 'allocated' bfi slot which does not have a bound CA.\r
1373          * Bound == ca_guid != 0ULL.\r
1374          */\r
1375         if ( !matched )\r
1376         {\r
1377                 lock_control_event();\r
1378 \r
1379                 for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1380                 {\r
1381                         if ( !p_bfi->p_bus_ext )\r
1382                                 continue;       // not allocated.\r
1383 \r
1384                         if ( p_bfi->ca_guid == 0ULL )\r
1385                         {\r
1386                                 ca_bound = TRUE;\r
1387                                 p_bfi->ca_guid = ca_guid;       // bind CA & this BFI slot; RTU.\r
1388                                 matched = p_bfi;\r
1389                                 break;\r
1390                         }\r
1391                 }\r
1392                 unlock_control_event();\r
1393         }\r
1394 \r
1395         BUS_PRINT( BUS_DBG_PNP,\r
1396                                 ("%s()%sguid 0x%I64x @ bfi[%d] %p \n",\r
1397                                 __FUNCTION__, (ca_bound ? "SET ":" "), ca_guid,\r
1398                                 (matched ? (matched - g_bus_filters) : (-1)), matched ) );\r
1399 \r
1400         return matched;\r
1401 }\r
1402 \r
1403 \r
1404 bus_filter_t *\r
1405 alloc_bfi( IN DRIVER_OBJECT  *p_driver_obj, OUT int *p_instance_count )\r
1406 {\r
1407         bus_filter_t    *p_bfi;\r
1408         bus_filter_t    *matched=NULL;\r
1409 \r
1410     /* Using unsafe function so that the IRQL remains at PASSIVE_LEVEL.\r
1411      * IoCreateDeviceSecure & IoCreateSymbolicLink must be called at\r
1412      * PASSIVE_LEVEL.\r
1413          */\r
1414         lock_control_event();\r
1415 \r
1416         // find 1st unused bfi slot.\r
1417         for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++)\r
1418         {\r
1419                 if ( !p_bfi->p_bus_ext )\r
1420                 {\r
1421                         /* temp setting until 'real' p_bus_ext is alloc; see bus_add_device.\r
1422                          * If p_bus_ext is ! 0, then bfi slot is allocated, although it\r
1423                          * may not yet have a bound CA guid; set set_get_\r
1424                          */\r
1425                         p_bfi->p_bus_ext = (bus_fdo_ext_t*)p_driver_obj;\r
1426                         matched = p_bfi;\r
1427                         *p_instance_count = ++g_bfi_InstanceCount; // record in-use\r
1428                         break;\r
1429                 }\r
1430         }\r
1431         unlock_control_event();\r
1432 \r
1433 #if DBG\r
1434         RtlStringCbPrintfA ( p_bfi->whoami,\r
1435                                                  sizeof(p_bfi->whoami),\r
1436                                                  "bfi-%d",\r
1437                                                  (g_bfi_InstanceCount - 1) );\r
1438 \r
1439         p_bfi->magic = BFI_MAGIC;\r
1440 #endif\r
1441 \r
1442         BUS_PRINT( BUS_DBG_PNP, ("%s() %s %p\n",\r
1443                                 __FUNCTION__, (matched ? matched->whoami:"Nobody"), matched) );\r
1444 \r
1445         return matched;\r
1446 }\r
1447 \r
1448 \r
1449 int\r
1450 free_bfi( IN  bus_filter_t  *p_bfi )\r
1451 {\r
1452         int     remaining;\r
1453 \r
1454         lock_control_event();\r
1455         p_bfi->p_bus_ext = NULL;\r
1456         p_bfi->ca_guid = 0ULL;\r
1457         remaining = --g_bfi_InstanceCount; // one less bfi in-use\r
1458         unlock_control_event();\r
1459         \r
1460         return remaining;\r
1461 }\r
1462 \r
1463 int\r
1464 get_bfi_count( void )\r
1465 {\r
1466         int     ic;\r
1467 \r
1468         lock_control_event();\r
1469         ic = g_bfi_InstanceCount;\r
1470         unlock_control_event();\r
1471         \r
1472         return ic;\r
1473 }\r
1474 \r
1475 #if DBG\r
1476 char *get_obj_state_str(cl_state_t state)\r
1477 {\r
1478         switch( state ) {\r
1479           case CL_UNINITIALIZED:\r
1480                 return "UNINITIALIZED";\r
1481           case CL_INITIALIZED:\r
1482                 return "INITIALIZED";\r
1483           case CL_DESTROYING:\r
1484                 return "DESTROYING";\r
1485           case CL_DESTROYED:\r
1486                 return "DESTROYED";\r
1487           default:\r
1488                 break;\r
1489         }\r
1490         return "Err - Bad obj state";\r
1491 }\r
1492 #endif\r
1493 \r